Author Topic: CompoundObjectTransform  (Read 2462 times)

0 Members and 1 Guest are viewing this topic.

Bryco

  • Water Moccasin
  • Posts: 1883
CompoundObjectTransform
« on: September 14, 2008, 09:22:28 PM »
CompoundObjectTransform gives a matrix that always is the same as the BlockTransform so I am hoping I am using it wrong and the following function can be written better. The function seems to work well in 2d, but I still have to figure out changing the picked point from the current ucs to the nested objects ocs. I have done this in vba but I am still messing with the conversion. Curve doesn't expose a normal vector and the ecs is useless. If someone has this worked out I'll gladly copy it.
Messing around with this I am surprised to find no nested matrix and have had to make one like below. I use this function to add leaders to an entity or blockref and have the leader land on the chosen object. Perhaps in C# you can merely change the snap to nearest and pull it off if there is an escape but I haven't looked at that.

Code: [Select]
        [CommandMethod("ne")]
         public void TestNearestPointOnObject()
        {
            Point3d p;
            if( NearestPointOnObject(ref p))
               // Util.AddEnt.Point(p); add a point function
        }

        public bool NearestPointOnObject(ref Point3d P2)
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            BlockReference b;
            PromptNestedEntityResult pne=ed.GetNestedEntity("\nPick ent");
            if (pne.Status!=PromptStatus.OK) return false;
            Point3d P1 = pne.PickedPoint;
            ObjectId id = pne.ObjectId;
            ObjectId[] Cons = pne.GetContainers();
            Matrix3d m=Matrix3d.Identity;

            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                Entity ent = tr.GetObject( id,OpenMode.ForRead) as Entity;
                Curve curve = (Curve)ent;           

                if (Cons.Length > 0)  //owner is a blockref
                {
                    for (int i = 0; i < Cons.Length; i++)
                    {
                        b = tr.GetObject(Cons[i], OpenMode.ForRead) as BlockReference;
                        m = m.PreMultiplyBy(b.BlockTransform);
                        //m = m.PreMultiplyBy(b.CompoundObjectTransform);
                    }
                    P1 = P1.TransformBy(m.Inverse());   
                }
                P2 = curve.GetClosestPointTo(P1,false);
                P2 = P2.TransformBy(m);
     
                tr.Commit();
                return true;
            }

        }

Bryco

  • Water Moccasin
  • Posts: 1883
Re: CompoundObjectTransform
« Reply #1 on: September 19, 2008, 08:35:18 AM »
Well the following seems to work.
There's not much code but it took a long time to get the timing right.
When I found the ecs z axis gives  the normal I  thought I had saved checking each object's type but for some odd reason an ellipse and a spline follow different rules and always show an ecs Z of 0,0,1. Odd.This works for xrefs as well.
The sequense for picking an entity within a block is:
Derive the wcs picked point
Find the entity's normal
Multiply the blocks matricies of each nested block refs and transform the picked point to the primary block definition's plane.
Transform the viewdirection to the match the primary block definition's plane.
Get the point along the translated view direction on the picked entity's plane.
Use GetClosestPointTo to get the desired point on the picked entity.
Translate that point back to world.
Bob's your uncle.


Code: [Select]
       static public Point3d PickedPtToPlane(Point3d p, Vector3d v, Vector3d n, Editor ed, Point3d ptonplane)
        {
            double Elev = ElevationFromPt(ptonplane, n);
            double Dist=(Elev-(p.X*n.X)-(p.Y*n.Y)-(p.Z*n.Z))/((v.X*n.X)+(v.Y*n.Y)+(v.Z*n.Z));
            return new Point3d(p.X+Dist*v.X,p.Y+Dist*v.Y,p.Z+Dist*v.Z);
        }

        static public double ElevationFromPt(Point3d pt ,Vector3d N )
            //Ax+ By + Cz + d = 0 formula for a plane where d=-LWPolyline.Elevation
        {
            return (pt.X * N.X) + (pt.Y * N.Y) + (pt.Z * N.Z);
        }


        [CommandMethod("ne")]
         public void TestNearestPointOnObject()
        {
            Point3d p;
            if (!NearestPointOnObject(ref p)) return;
            DBPoint Pt = new DBPoint(p);
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                Database db = HostApplicationServices.WorkingDatabase;
                BlockTableRecord btr = tr.GetObject
                    (db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
                if (btr != null)
                {
                    Pt.SetDatabaseDefaults(db);
                    btr.AppendEntity(Pt);
                    tr.AddNewlyCreatedDBObject(Pt, true);
                    tr.Commit();
                }
            }
        }

        public bool NearestPointOnObject(ref Point3d P2)
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            BlockReference b; Ellipse ellipse; Spline spline;
            Matrix3d ucs = ed.CurrentUserCoordinateSystem;
            PromptNestedEntityResult pne=ed.GetNestedEntity("\nPick ent");
            if (pne.Status!=PromptStatus.OK) return false;
            Point3d P1 = pne.PickedPoint.TransformBy(ucs);//wcs point
            ObjectId id = pne.ObjectId;
            ObjectId[] Cons = pne.GetContainers();
            Matrix3d m=Matrix3d.Identity;
            Vector3d normal;
            Vector3d v = ed.GetCurrentView().ViewDirection.GetNormal();
         
            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                Entity ent = tr.GetObject( id,OpenMode.ForRead) as Entity;
                if ( !(ent  is  Curve)) return false;
                Curve curve = (Curve)ent;
                normal = ent.Ecs.CoordinateSystem3d.Zaxis;
                if (ent is Ellipse)
                {
                    ellipse = (Ellipse)ent;
                    normal = ellipse.Normal;
                }
                if (ent is Spline)
                {
                    spline = (Spline)ent;
                    Plane pn=spline.GetPlane();
                    normal = pn.Normal;
                }
                //normal = curve.Ecs.CoordinateSystem3d.Zaxis;
                if (Cons.Length > 0)  //owner is a blockref
                {
                    for (int i = 0; i < Cons.Length; i++)
                    {
                        b = tr.GetObject(Cons[i], OpenMode.ForRead) as BlockReference;
                        m = m.PreMultiplyBy(b.BlockTransform);
                    }
                    //transform the viewdirection to the match the most nested block
                    //(primary block)
                    v=v.TransformBy(m.Inverse()).GetNormal();
                }
                //transform the picked point to the primary block definition's plane
                P1 = P1.TransformBy(m.Inverse());
                //Get the point along the translated view direction on the
                //picked entity's plane
                P1 = PickedPtToPlane(P1,v,normal,  ed, curve.StartPoint);
                P2 = curve.GetClosestPointTo(P1,false);
                P2 = P2.TransformBy(m);   
                tr.Commit();
                return true;
            }

        }