Align Entity 3D

Align Entity 3D

Civil3DReminders_com
Mentor Mentor
1,270 Views
3 Replies
Message 1 of 4

Align Entity 3D

Civil3DReminders_com
Mentor
Mentor

I'm attempting to align an entity (BlockReference or 3D Polyline) in 3D. I'm not having much luck finding sample code that works. 

 

I've tried this post: https://adndevblog.typepad.com/autocad/2012/04/finding-transformation-matrix-for-aligning-two-entiti...

 

It's been linked to in other posts in this forum, but it doesn't appear to work correctly as shown in this screencast:  https://autode.sk/2y4D51k

 

Here is the drawing information to recreate the linework, I've also attached the drawing.

3DPoly 652492.7740,367502.1323,2867.9053 652534.3375,367499.4847,2862.0912

point 652492.7740,367502.1323,2867.9053
point 652534.7389,367499.4590,2867.5313

 

Below is the code I've been testing with, with the trans4 corrected for what I think is a typo.

 

If I run the code multiple times it converges to a more correct solution, but I don't think that should be required.

    <CommandMethod("S-Test")>
    Sub Test()
        Try
            '' Put your command code here
            'Using tr As Transaction = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction
            '    Dim pipe3dAlign As New Pipe3DAlign
            '    pipe3dAlign.RunCommandTest(tr)
            '    tr.Commit()
            'End Using
            Dim activeDoc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = activeDoc.Database

            Dim ed As Editor = activeDoc.Editor

            Dim per As PromptEntityResult = ed.GetEntity(New PromptEntityOptions("Select an entity : "))

            If (per.Status <> PromptStatus.OK) Then
                Return
            End If
            Dim oid As ObjectId = per.ObjectId
            Dim ppr1 As PromptPointResult = ed.GetPoint(New PromptPointOptions("Select src point 1"))

            If (ppr1.Status <> PromptStatus.OK) Then
                Return
            End If
            Dim sp1 As Point3d = ppr1.Value
            Dim ppr2 As PromptPointResult = ed.GetPoint(New PromptPointOptions("Select src point 2"))

            If (ppr2.Status <> PromptStatus.OK) Then
                Return
            End If
            Dim ep1 As Point3d = ppr2.Value
            Dim ppr3 As PromptPointResult = ed.GetPoint(New PromptPointOptions("Select dest point 1"))

            If (ppr3.Status <> PromptStatus.OK) Then
                Return
            End If
            Dim sp2 As Point3d = ppr3.Value
            Dim ppr4 As PromptPointResult = ed.GetPoint(New PromptPointOptions("Select dest point 2"))

            If (ppr4.Status <> PromptStatus.OK) Then
                Return
            End If
            Dim ep2 As Point3d = ppr4.Value

            Dim resMat As Matrix3d = Matrix3d.Identity

            Dim trans1 As Matrix3d = Matrix3d.Displacement(sp2 - sp1)
            sp1 = sp1.TransformBy(trans1)
            ep1 = ep1.TransformBy(trans1)
            resMat = resMat.PreMultiplyBy(trans1)

            ' // Rotation about Z axis
            Dim dir1 As Vector3d = ep1 - sp1
            Dim dir2 As Vector3d = ep2 - sp2
            Dim xy As Plane = New Plane(Point3d.Origin, Vector3d.ZAxis)

            Dim trans2 As Matrix3d = Matrix3d.Rotation(dir2.AngleOnPlane(xy) - dir1.AngleOnPlane(xy), Vector3d.ZAxis, sp1)

            sp1 = sp1.TransformBy(trans2)
            ep1 = ep1.TransformBy(trans2)
            resMat = resMat.PreMultiplyBy(trans2)

            ' // Rotation about X axis
            dir1 = ep1 - sp1
            dir2 = ep2 - sp2

            Dim yz As Plane = New Plane(Point3d.Origin, Vector3d.XAxis)

            Dim trans3 As Matrix3d = Matrix3d.Rotation(dir2.AngleOnPlane(yz) - dir1.AngleOnPlane(yz), Vector3d.XAxis, sp1)

            sp1 = sp1.TransformBy(trans3)
            ep1 = ep1.TransformBy(trans3)
            resMat = resMat.PreMultiplyBy(trans3)

            '// Rotation about Y axis
            dir1 = ep1 - sp1
            dir2 = ep2 - sp2

            Dim xz As Plane = New Plane(Point3d.Origin, Vector3d.YAxis)

            Dim trans4 As Matrix3d = Matrix3d.Rotation(dir2.AngleOnPlane(xz) - dir1.AngleOnPlane(xz), Vector3d.YAxis, sp1)

            sp1 = sp1.TransformBy(trans4)
            ep1 = ep1.TransformBy(trans4)
            resMat = resMat.PreMultiplyBy(trans4)

            '// Scaling
            dir1 = ep1 - sp1
            dir2 = ep2 - sp2

            Dim trans5 As Matrix3d = Matrix3d.Scaling(dir2.Length / dir1.Length, sp1)
            sp1 = sp1.TransformBy(trans5)
            ep1 = ep1.TransformBy(trans5)
            resMat = resMat.PreMultiplyBy(trans5)

            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim ent As Entity = tr.GetObject(oid, OpenMode.ForWrite)
                ent.TransformBy(resMat)
                tr.Commit()
            End Using
        Catch EX As System.Exception
            MsgBox("Error: " & EX.Message)
        End Try
    End Sub

 

Civil Reminders
http://blog.civil3dreminders.com/
http://www.CivilReminders.com/
Alumni
0 Likes
Accepted solutions (1)
1,271 Views
3 Replies
Replies (3)
Message 2 of 4

_gile
Consultant
Consultant
Accepted solution

Hi,

 

If you want to align an entity in 3D, you need to specify 3 (non colinear) source points and 3 (non colinear) destination points to be able to define the source plane and destination plane.

Here's an example:

 

        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var per = ed.GetEntity("\nSelect entity: ");
            if (per.Status != PromptStatus.OK) 
                return;

            var ppo = new PromptPointOptions("\nSpecify the first source point: ");
            var ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            var srcPt1 = ppr.Value;

            ppo.Message = "\nSpecify the second source point: ";
            ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            var srcPt2 = ppr.Value;

            ppo.Message = "\nSpecify the third source point: ";
            ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            var srcPt3 = ppr.Value;

            ppo.UseBasePoint = true;
            ppo.Message = "\nSpecify the first destinaton point: ";
            ppo.BasePoint = srcPt1;
            ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            var destPt1 = ppr.Value;

            ppo.Message = "\nSpecify the second destinaton point: ";
            ppo.BasePoint = srcPt2;
            ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            var destPt2 = ppr.Value;

            ppo.Message = "\nSpecify the first destinaton point: ";
            ppo.BasePoint = srcPt3;
            ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            var destPt3 = ppr.Value;

            var ucs = ed.CurrentUserCoordinateSystem;

            srcPt1 = srcPt1.TransformBy(ucs); 
            srcPt2 = srcPt2.TransformBy(ucs);
            srcPt3 = srcPt3.TransformBy(ucs);
            destPt1 = destPt1.TransformBy(ucs);
            destPt2 = destPt2.TransformBy(ucs);
            destPt3 = destPt3.TransformBy(ucs);

            var srcCs = CreateCoordinateSystem(srcPt1, srcPt2, srcPt3);
            var destCs = CreateCoordinateSystem(destPt1, destPt2, destPt3);
            var xform = Matrix3d.AlignCoordinateSystem(
                srcPt1, srcCs.Xaxis, srcCs.Yaxis, srcCs.Zaxis,
                destPt1, destCs.Xaxis, destCs.Yaxis, destCs.Zaxis) *
                Matrix3d.Scaling(destPt1.DistanceTo(destPt2) / srcPt1.DistanceTo(srcPt2), srcPt1);
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var ent = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
                ent.TransformBy(xform);
                tr.Commit();
            }
        }

        private static CoordinateSystem3d CreateCoordinateSystem(Point3d pt1, Point3d pt2, Point3d pt3)
        {
            var xAxis = pt1.GetVectorTo(pt2).GetNormal();
            var vec2 = pt1.GetVectorTo(pt3);
            if (xAxis.IsParallelTo(vec2))
                throw new Autodesk.AutoCAD.Runtime.Exception(ErrorStatus.InvalidAxis);
            var zAxis = xAxis.CrossProduct(vec2).GetNormal();
            var yAxis = zAxis.CrossProduct(xAxis).GetNormal();
            return new CoordinateSystem3d(pt1, xAxis, yAxis);
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 4

essam-salah
Collaborator
Collaborator

hi @_gile 


@_gile wrote:

 

 

 ... * Matrix3d.Scaling(destPt1.DistanceTo(destPt2) / srcPt1.DistanceTo(srcPt2), srcPt1);

 


why we have to scale the source object?

 i have two identical source and destination objects and tried the code without the scaling and it doesn't work, i don't know why, in my case i have <srcPt1,srcPt2> distance equals to <destPt1,destPt2> distance,  also <srcPt2,srcPt3> distance equals to <destPt2,destPt3> distance, im confused right now.

0 Likes
Message 4 of 4

_gile
Consultant
Consultant

@essam-salah  a écrit :

why we have to scale the source object?

 i have two identical source and destination objects and tried the code without the scaling and it doesn't work,


Scaling the source object is not mandatory.

it does work without scaling if you repalce:

var xform = Matrix3d.AlignCoordinateSystem(
    srcPt1, srcCs.Xaxis, srcCs.Yaxis, srcCs.Zaxis,
    destPt1, destCs.Xaxis, destCs.Yaxis, destCs.Zaxis) *
    Matrix3d.Scaling(destPt1.DistanceTo(destPt2) / srcPt1.DistanceTo(srcPt2), srcPt1);

with:

var xform = Matrix3d.AlignCoordinateSystem(
    srcPt1, srcCs.Xaxis, srcCs.Yaxis, srcCs.Zaxis,
    destPt1, destCs.Xaxis, destCs.Yaxis, destCs.Zaxis);


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes