.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Can't select entities after clone and rotation

2 REPLIES 2
Reply
Message 1 of 3
giackserva
453 Views, 2 Replies

Can't select entities after clone and rotation

Hi,

i coded a utility to help with entities rotation. This is a part of a bigger project so i just cutted and pasted together the part of code that have this problem.

Basically i get the selection, i clone it (because this is a copy and rotate) and through a draw jig class i rotate all the entities. This works well but just sometimes when the command ends it happend this weird thing, the entities appeares  in the draw but they can't be selected. And all get back to the normally after saving, closing and reopening the draw.

This is the utility.

 

public void Run(object param)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            List<Entity> toRotate = new List<Entity>();
            PromptSelectionOptions pso = new PromptSelectionOptions();
            pso.MessageForAdding = "\nSelect objects";
            pso.AllowDuplicates = false;
            pso.AllowSubSelections = false;
            PromptSelectionResult psr = ed.GetSelection(pso);
            if (psr.Status != PromptStatus.OK)
                return;


            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                foreach (SelectedObject so in psr.Value)
                    toRotate.Add(trans.GetObject(so.ObjectId, OpenMode.ForRead) as Entity);
                trans.Commit();
            }

            PromptPointOptions ppo = new PromptPointOptions("\nSelect base point of the rotation");
            PromptPointResult ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            Point3d center = ppr.Value;

            JigReferenceRotator jig = new JigReferenceRotator(center);
            ed.Drag(jig);
            jig.Axis = false;
            PromptResult pr;
            List<Entity> reference;

            while (true)
            {
                reference = toRotate;
                toRotate = EntityListClone(toRotate);

                jig.toRotate = toRotate;
                pr = ed.Drag(jig);

                if (pr.Status != PromptStatus.OK)
                {
                    using (DocumentLock dl = doc.LockDocument())
                    {
                        using (Transaction trans = db.TransactionManager.StartTransaction())
                        {
                            foreach (Entity ent in toRotate)
                                trans.GetObject(ent.ObjectId, OpenMode.ForWrite).Erase();
                            trans.Commit();
                        }
                    }
                    ed.Regen();
                    break;
                }

                ed.Regen();
            }
}

 These are the function that clone entities.

public List<Entity> EntityListClone(List<Entity> toClone)
        {
            List<Entity> toReturn = new List<Entity>();
            ObjectIdCollection clone = new ObjectIdCollection();

            foreach (Entity ent in toClone)
                clone.Add(ent.ObjectId);

            clone = ObjectIdCollectionClone(clone);

            using (Transaction trans = Application.DocumentManager.MdiActiveDocument.Database.
                TransactionManager.StartTransaction())
            {
                foreach (ObjectId obj in clone)
                    toReturn.Add(trans.GetObject(obj, OpenMode.ForRead) as Entity);
                trans.Commit();
            }

            return toReturn;
        }

        private ObjectIdCollection ObjectIdCollectionClone(ObjectIdCollection toClone)
        {
            ObjectIdCollection dest = new ObjectIdCollection();
            Database db = Application.DocumentManager.MdiActiveDocument.Database;

            IdMapping map = new IdMapping();

            db.DeepCloneObjects(toClone, db.CurrentSpaceId, map, false);

            foreach (ObjectId obj in toClone)
                dest.Add(map[obj].Value);

            return dest;
        }

 And this is the draw jig class

public class JigReferenceRotator : DrawJig
    {
        Point3d center;
        Ray axis;
        double oldAngle, firstAngle;

        public JigReferenceRotator(Point3d center)
        {
            Axis = true;
            this.center = center;

            axis = new Ray();
            axis.BasePoint = center;
            axis.SecondPoint = Point3d.Origin;
        }

        public bool Axis
        { get; set; }

        public List<Entity> toRotate
        { get; set; }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            if (Axis)
            {
                Point3d p = prompts.AcquirePoint("\nFirst Reference").Value;
                if (p.DistanceTo(axis.SecondPoint) < 0.001 || axis.BasePoint.DistanceTo(p) < 0.001)
                    return SamplerStatus.NoChange;
                axis.SecondPoint = p;
                firstAngle = new Line(axis.BasePoint, axis.SecondPoint).Angle;
            }
            else
            {
                Point3d p = prompts.AcquirePoint("\nSecond Reference").Value;
                if (p.DistanceTo(axis.SecondPoint) < 0.001 || axis.BasePoint.DistanceTo(p) < 0.001)
                {
                    Application.DocumentManager.MdiActiveDocument.Editor.Regen();
                    return SamplerStatus.NoChange;
                }
                axis.SecondPoint = p;
            }
            return SamplerStatus.OK;
        }

        protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
        {
            if (Axis)
                draw.Geometry.Draw(axis);
            else
            {
                draw.Geometry.Draw(axis);
                double angle = firstAngle - new Line(axis.BasePoint, axis.SecondPoint).Angle;

                using (Transaction trans = Application.DocumentManager.MdiActiveDocument.Database.
                    TransactionManager.StartTransaction())
                {
                    foreach (Entity ent in toRotate)
                    {
                        (trans.GetObject(ent.ObjectId, OpenMode.ForWrite) as Entity).TransformBy(
                            Matrix3d.Rotation(oldAngle - angle, Vector3d.ZAxis, center));
                        draw.Geometry.Draw(ent);
                    }
                    trans.Commit();
                }
                oldAngle = angle;
            }
            return true;
        }
    }

 I also record a video in order to show you what happen. 

This is the link

https://www.dropbox.com/s/bhjl3bj9g158e64/error.wmv

2 REPLIES 2
Message 2 of 3
norman.yuan
in reply to: giackserva

It is good you showed your code in details. It looks like your code needs big refactore, IMO.

 

The major issue is that you pass DBObject/Entity around between/outside transactions, which is big NO in AutoCAD .NET API coding. Entity taken outside transaction context may not behave as it should. For example, a blockreference to a dynamic block definition would only have its IsDynamic property being true when the BlockReference stays inside a Transaction. The situation you described is likely because you pass entities around outside transaction instead of ObjectIDs.

 

The rule of thumb is alway pass ObjectId around and only work with Entity within a transaction. You can use Entity without Transaction if you do not intend to add it into database and you are responsible to dispose it. BTW, you code in the Jig creates Line entity in order to calculate angle without dispose it. That means, a huge number of lines would be created in momory if the user keep dragging the mouse, which triggers Sampler().

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 3
fenton.webb
in reply to: giackserva

Why not just run the Jig on the opened for read entities, e.g. (not checked or compiled - just off the top of my head here - also please read my Fenton comments)

 

            PromptPointOptions ppo = new PromptPointOptions("\nSelect base point of the rotation");
            PromptPointResult ppr = ed.GetPoint(ppo);
            if (ppr.Status != PromptStatus.OK)
                return;
            Point3d center = ppr.Value;

          using (Transaction trans = db.TransactionManager.StartOpenCloseTransaction())            

          {                

             foreach (SelectedObject so in psr.Value)                    

                  toRotate.Add(trans.GetObject(so.ObjectId, OpenMode.ForRead) as Entity);

 

            JigReferenceRotator jig = new JigReferenceRotator(center);
            ed.Drag(jig);
            jig.Axis = false;
            PromptResult pr;
            List<Entity> reference;

            while (true)
            {
                reference = toRotate;
                // Fenton: why clone??

                // toRotate = EntityListClone(toRotate);

                jig.toRotate = toRotate;
                pr = ed.Drag(jig);

                if (pr.Status != PromptStatus.OK)
                {

                    // Fenton: there is only one reason to lock, that is if you are edting an entity from the application context. Also, jigs don't work at all well from the application context so this is pointless  
                    // using (DocumentLock dl = doc.LockDocument())
                    {
                        // fenton: not needed

                        // using (Transaction trans = db.TransactionManager.StartTransaction())
                        {

// Fenton: because we are rotating the originals no need to delete
                            //foreach (Entity ent in toRotate)
                                //trans.GetObject(ent.ObjectId, OpenMode.ForWrite).Erase();
                            trans.Commit();
                        }
                    }

// Fenton: if we need to call regen, we are doing something wrong somewhere
                    //ed.Regen();
                    break;
                }

// Fenton: if we need to call regen, we are doing something wrong somewhere                ed.Regen();
            }
}

 

// Fenton: jig code updates this function should be replaced from this:

 

       protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
        {
            if (Axis)
                draw.Geometry.Draw(axis);
            else
            {
                draw.Geometry.Draw(axis);
                double angle = firstAngle - new Line(axis.BasePoint, axis.SecondPoint).Angle;

                using (Transaction trans = Application.DocumentManager.MdiActiveDocument.Database.
                    TransactionManager.StartTransaction())
                {
                    foreach (Entity ent in toRotate)
                    {
                        (trans.GetObject(ent.ObjectId, OpenMode.ForWrite) as Entity).TransformBy(
                            Matrix3d.Rotation(oldAngle - angle, Vector3d.ZAxis, center));
                        draw.Geometry.Draw(ent);
                    }
                    trans.Commit();
                }
                oldAngle = angle;
            }
            return true;
        }
    }

 

// Fenton: to this (BTW ****NEVER****EVER*** use transactions in a Jig)

 

      protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
        {
            if (Axis)
                draw.Geometry.Draw(axis);
            else
            {
                draw.Geometry.Draw(axis);
                double angle = firstAngle - new Line(axis.BasePoint, axis.SecondPoint).Angle;

                    foreach (Entity ent in toRotate)
                    {
                        (trans.GetObject(ent.ObjectId, OpenMode.ForWrite) as Entity).TransformBy(
                            Matrix3d.Rotation(oldAngle - angle, Vector3d.ZAxis, center));
                        draw.Geometry.Draw(ent);
                    }
                }
                oldAngle = angle;
            }
            return true;
        }
    }

 




Fenton Webb
AutoCAD Engineering
Autodesk

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost