3 boyutlu uzayda noktaları/nesneleri taşımak, ölçeklemek ve döndürmek için 4x4 boyutunda dönüşüm matrisi kullanılır. Bu matrisler CAD sistemlerinde önemli bir yer tutar. Dönüşüm matrisinin ilk 3 kolonu ölçekleme ve döndürme, 4. kolonu ise yer değiştirme/taşıma ile ilgilidir. Aşağıda temel dönüşüm matrislerininin nasıl oluşturulabileceğini bulabilirsiniz.

Birim dönüşüm matrisi

\[\begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 1 \end{bmatrix}\]

Döndürme matrisleri

x ekseni etrafında döndürme

\[\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & cos\theta & −sin\theta & 0\\ 0 & sin\theta & cos\theta & 0\\ 0 & 0& 0 & 1 \end{bmatrix}\]

y ekseni etrafında döndürme

\[\begin{bmatrix} cos\theta & 0 & sin\theta & 0\\ 0 & 1 & 0 & 0\\ −sin\theta & 0 & cos\theta & 0\\ 0 & 0 & 0 & 1 \end{bmatrix}\]

z ekseni etrafında döndürme

\[\begin{bmatrix} cos\theta & −sin\theta & 0& 0\\ sin\theta & cos\theta & 0& 0\\ 0& 0& 1& 0\\ 0& 0& 0& 1 \end{bmatrix}\]

Ölçekleme matrisi

\[\begin{bmatrix} S_{x}& 0& 0& 0\\ 0& S_{y}& 0& 0\\ 0& 0& S_{z}& 0\\ 0& 0& 0& 1 \end{bmatrix}\]

Yer değiştirme matrisi

\[\begin{bmatrix} 1 & 0 & 0 & t_{x}\\ 0 & 1 & 0 & t_{y}\\ 0 & 0 & 1 & t_{z}\\ 0 & 0 & 0 & 1\end{bmatrix}\]

AutoCAD.Net API ile dönüşüm matrisleri

Dönüşüm matrisi, AutoCAD.Net API’ye ait Autodesk.AutoCAD.Geometry isim uzayında bulunanan Matrix3d nesnesi ile kurulur.

Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage(Matrix3d.Identity.ToString());

((1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1))

kodu birim matrisi komut satırına yazdıracaktır.

(0, 0, 0) noktasından (3.0, 3.0, 2.0) noktasına taşımak için Matrix3d.Displacement matrisini kullanabilirsiniz.

ed.WriteMessage(Matrix3d.Displacement(new Vector3d(3.0, 3.0, 2.0)).ToString());

((1,0,0,3),(0,1,0,3),(0,0,1,2),(0,0,0,1))

Bir AutoCAD nesnesini (1.0, 1.0, 1.0) noktasını merkez alıp Z ekseni etrafında 45° döndürmek içinse kullanmanız gereken matris Matrix3d.Rotation‘dır.

ed.WriteMessage(Matrix3d.Rotation(Math.PI / 4, Vector3d.ZAxis, new Point3d(1.0, 1.0, 1.0)).ToString());

((0.707106781186547,-0.707106781186548,0,1),(0.707106781186548,0.707106781186547,0,-0.414213562373095),(0,0,1,0),(0,0,0,1))

(0.0, 0.0, 0.0) noktasını merkez alıp 5 katsayısı ile ölçekleme yapmak içinse Matrix3d.Scaling matrisi aşağıdaki gibi kullanılabilir.

ed.WriteMessage(Matrix3d.Scaling(5.0, Point3d.Origin).ToString());

((5,0,0,0),(0,5,0,0),(0,0,5,0),(0,0,0,1)

Ayrıca Matrix3d sınıfı, PreMultiplyBy, PostMultiplyBy fonksiyonlarıyla birleştirilmiş dönüşüm matrisleri oluşturmanıza imkan sağladığı gibi izdüşüm (Projection) ve aynalama (Mirroring) için dönüşüm matrisleri de içerir.

Matrix3d.Displacement dönüşüm matrisi

AutoCAD nesnelerinin bir noktadan diğerine nasıl taşınacağını göstermek için genişlik ve yükseklik değerlerini parametre olarak kabul eden CreateRectangle(...) yordamını oluşturacağız öncelikle.

public static ObjectId CreateRectangle(double width, double height)
{
    Database db = HostApplicationServices.WorkingDatabase;
    ObjectId id = ObjectId.Null;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    Matrix3d ucs2wcs = ed.CurrentUserCoordinateSystem;

    PromptPointOptions pPtOpts = 
        new PromptPointOptions("\nBaşlangıç noktasını seçin: ");
    PromptPointResult pPtRes = ed.GetPoint(pPtOpts);
    if (pPtRes.Status != PromptStatus.OK)
        return id;
    Point2d startPt = new Point2d(pPtRes.Value.X, pPtRes.Value.Y);

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        Polyline pl = new Polyline();
        pl.SetDatabaseDefaults();
        pl.AddVertexAt(0, startPt, 0.0, 0.0, 0.0);
        pl.AddVertexAt(1, startPt.Add(new Vector2d(width, 0.0)), 0.0, 0.0, 0.0);
        pl.AddVertexAt(2, startPt.Add(new Vector2d(width, height)), 0.0, 0.0, 0.0);
        pl.AddVertexAt(3, startPt.Add(new Vector2d(0.0, height)), 0.0, 0.0, 0.0);
        pl.Closed = true;
        pl.ColorIndex = 1;

        BlockTableRecord btRecord =
            (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

        id = btRecord.AppendEntity(pl);
        tr.AddNewlyCreatedDBObject(pl, true);
        pl.TransformBy(ucs2wcs);
        tr.Commit();

        ed.WriteMessage(pl.StartPoint.ToString());
    }
    return id;
}

Yukardaki metotta dikkate edilmesi gereken iki önemli nokta var; ilki, Editor sınıfı GetPoint(...) metodu ile elde edilen noktanın etkin kullanıcı tanımlı koordinat sisteminde (UCS’de) olması, ikincisi ise Polyline‘ın, veritabanına eklendikten sonra UCS’den WCS’ye TransformBy metoduyla dönüşümünün yapılmış olmasıdır. Bu dönüşümün nedeni Editor.GetPoint() metoduyla elde edilen noktanın UCS’de tanımlı olması ve AutoCAD nesnelerinin geometrik bilgilerinin WCS’de saklanmasıdır.

Aslında AutoCAD.Net API ile geliştirilen her uygulamayı UCS’de denemek önemlidir. Çünkü AutoCAD grafik nesnelerine erişirken, onları veritabanına eklerken ve komut satırından nokta bilgisi alırken, API’nin kullandığı koordinat sistemleri arasındaki dönüşümleri doğru yapmak gerekir. Ayrıca UCS’de doğru çalışan bir uygulama, WCS’nin UCS’nin özel bir hali olması nedeniyle, WCS’de de sorunsuz çalışacaktır. Kullanıcı koordinat sistemine Editor sınıfının CurrentUserCoordinateSystem özelliğiyle ulaşılabilirsiniz.

UCS’den WCS’ye ve WCS’den UCS’ye dönüşüm için aşağıdaki matrisleri kullanabilirsiniz.

Matrix3d ucs2wcs = ed.CurrentUserCoordinateSystem;
Matrix3d wcs2ucs = ed.CurrentUserCoordinateSystem.Inverse();

MoveEntity metodu, seçilen herhangi bir noktadan başlayarak, 5.0 birim genişlik ve yükseklikte çizilen bir dikdörtgenin (5,5,0) vektörüyle nasıl taşınabileceğinin bir örneğini sergilemektedir.

public static void MoveEntity()
{
    Database db = HostApplicationServices.WorkingDatabase;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    Matrix3d ucs2wcs = ed.CurrentUserCoordinateSystem;

    ObjectId id = CreateRectangle(5.0, 5.0);

    PromptPointOptions pPtOpts =
        new PromptPointOptions("\nNesnenin taşınacağı noktayı seçin: ");
    PromptPointResult pPtRes = ed.GetPoint(pPtOpts);
    if (pPtRes.Status != PromptStatus.OK)
        return;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        if (id != ObjectId.Null)
        {
            Polyline ent = (Polyline)tr.GetObject(id, OpenMode.ForWrite);
            Vector3d displacementVector = pPtRes.Value.TransformBy(ucs2wcs) - ent.StartPoint;

            Matrix3d displacementMatrix = Matrix3d.Displacement(displacementVector);
            Entity displacedEnt = ent.GetTransformedCopy(displacementMatrix);

            displacedEnt.ColorIndex = 2;

            BlockTableRecord btRecord =
                (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

            btRecord.AppendEntity(displacedEnt);
            tr.AddNewlyCreatedDBObject(displacedEnt, true);

            tr.Commit();
        }
    }
}

MoveEntity metodu, yerdeğiştirmenin daha rahat takip edilebilmesi için oluşturulan dikdörtgen yerine, onun dönüştürülmüş bir kopyasını taşımakta ve bu işlem için Entity sınıfının GetTransformedCopy yordamını kullanmaktadır. Ayrıca dikdörtgenin başlangıç noktası dünya koordinat sisteminde (WCS’de) olduğundan, yer değiştrime vektörü, seçilen taşıma noktası UCS’den WCS’ye dönüştürülerek kurulmuştur.

Şekil-1

Şekil-1: MoveEntity metodunun etkin UCS’de çalıştırılmasıyla elde edilen sonuç.

Matrix3d.Scaling dönüşüm matrisi

AutoCAD nesnelerini ölçekleyebilmek için,

  • Öncelikle, ölçekleme değeri ve noktası kullanılarak Matrix3d.Scaling dönüşüm matrisi kurulmaldır.
  • Daha sonra ölçeklenecek nesneye, ölçekleme matrisini parametre olarak kabul eden Entity sınıfının GetTransformedCopy metodu uygulanmalıdır.

XY planında çizdirilen bir dikdörtgeni 3 katına çıkararak kopyalayan ScaleEntity(...) metodu ise aşağıdaki gibi olacaktır

public static void ScaleEntity()
{
    Database db = HostApplicationServices.WorkingDatabase;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    Matrix3d ucs2wcs = ed.CurrentUserCoordinateSystem;

    ObjectId id = CreateRectangle(5.0, 5.0);

    PromptPointOptions pPtOpts =
        new PromptPointOptions("\nÖlçekleme noktasını seçin: ");
    PromptPointResult pPtRes = ed.GetPoint(pPtOpts);
    if (pPtRes.Status != PromptStatus.OK)
        return;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        if (id != ObjectId.Null)
        {
            Polyline ent = (Polyline)tr.GetObject(id, OpenMode.ForWrite);
     
            Matrix3d scaleMatrix = Matrix3d.Scaling(3.0, pPtRes.Value.TransformBy(ucs2wcs));
            Entity scaledEnt = ent.GetTransformedCopy(scaleMatrix);

            scaledEnt.ColorIndex = 2;

            BlockTableRecord btRecord =
                (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

            btRecord.AppendEntity(scaledEnt);
            tr.AddNewlyCreatedDBObject(scaledEnt, true);

            tr.Commit();
        }
    }
}

Şekil-2

Şekil-2: ScaleEntity metodunun etkin UCS’de çalıştırılmasıyla elde edilen sonuç.

Matrix3d.Rotation dönüşüm matrisi

  • Öncelikle, nesnenin etrafında döndürüleceği eksen ve nokta kullanılarak Matrix3d.Rotation dönüşüm matrisi kurulmalıdır.
  • Daha sonra döndürülecek nesneye, döndürme matrisini parametre olarak kabul eden Entity sınıfının GetTransformedCopy metodu uygulanmalıdır.

XY planında çizdirilen bir dikdörtgeni Z ekseni etrafında 45° döndüren RotateEntity(...) metodu ise aşağıdaki gibi olacaktır.

public static void RotateEntity()
{
    Database db = HostApplicationServices.WorkingDatabase;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    Matrix3d ucs2wcs = ed.CurrentUserCoordinateSystem;

    ObjectId id = CreateRectangle(5.0, 5.0);

    PromptPointOptions pPtOpts =
        new PromptPointOptions("\nDöndürme noktasını seçin: ");
    PromptPointResult pPtRes = ed.GetPoint(pPtOpts);
    if (pPtRes.Status != PromptStatus.OK)
        return;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        if (id != ObjectId.Null)
        {
            Polyline ent = (Polyline)tr.GetObject(id, OpenMode.ForWrite);

            Matrix3d rotationMatrix = Matrix3d.Rotation(Math.PI/4.0, Vector3d.ZAxis, pPtRes.Value.TransformBy(ucs2wcs));
            Entity rotatedEnt = ent.GetTransformedCopy(rotationMatrix);

            rotatedEnt.ColorIndex = 2;

            BlockTableRecord btRecord =
                (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

            btRecord.AppendEntity(rotatedEnt);
            tr.AddNewlyCreatedDBObject(rotatedEnt, true);

            tr.Commit();
        }
    }
}

Şekil-3

Şekil-3: RotateEntity metodunun WCS’de çalıştırılmasıyla elde edilen sonuç.

Birleştirilmiş dönüşüm matrisinin uygulanması

Yukarıda gerçekleştirilen taşıma, ölçekleme ve döndürme işlemlerini Matrix3d sınıfının PreMultiplyBy metodu ile bir kerede yapabilirsiniz. Bunun bir örneğini aşağıdaki MoveScaleRotateEntity() metodunda bulabilirsiniz.

public static void MoveScaleRotateEntity()
{
    Database db = HostApplicationServices.WorkingDatabase;
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    Matrix3d ucs2wcs = ed.CurrentUserCoordinateSystem;

    ObjectId id = CreateRectangle(5.0, 5.0);

    PromptPointOptions pPtOpts =
        new PromptPointOptions("\nBir nokta seçin: ");
    PromptPointResult pPtRes = ed.GetPoint(pPtOpts);
    if (pPtRes.Status != PromptStatus.OK)
        return;

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        if (id != ObjectId.Null)
        {
            Polyline ent = (Polyline)tr.GetObject(id, OpenMode.ForWrite);
            Vector3d displacementVector = pPtRes.Value.TransformBy(ucs2wcs) - ent.StartPoint;

            Matrix3d displacementMatrix = Matrix3d.Displacement(displacementVector);
            Matrix3d scaleMatrix = Matrix3d.Scaling(3.0, pPtRes.Value.TransformBy(ucs2wcs));
            Matrix3d rotationMatrix = Matrix3d.Rotation(Math.PI / 4.0, Vector3d.ZAxis, 
                pPtRes.Value.TransformBy(ucs2wcs));

            Entity modEnt = 
                ent.GetTransformedCopy(displacementMatrix.PreMultiplyBy(scaleMatrix).PreMultiplyBy(rotationMatrix));

            modEnt.ColorIndex = 2;

            BlockTableRecord btRecord =
                (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

            btRecord.AppendEntity(modEnt);
            tr.AddNewlyCreatedDBObject(modEnt, true);

            tr.Commit();
        }
    }
}

Yorum yapın