Author Topic: Xclip and block insertion point  (Read 4101 times)

0 Members and 1 Guest are viewing this topic.

Bryco

  • Water Moccasin
  • Posts: 1882
Xclip and block insertion point
« on: September 20, 2011, 02:36:07 PM »
Kean has a great working example of an xclip here http://through-the-interface.typepad.com/through_the_interface/2010/11/adding-a-2d-spatial-filter-to-perform-a-simple-xclip-on-an-external-reference-in-autocad-using-net.html

However  that doesn't help me as I'm trying to update the existing clip info.
Below is a working function that changes the insertion of a block which works fine until you have an xclipped blockref.
If you run the following code with XCLIPFRAME set to 2 or 1 and a clipped blockref in the drawing you will see the clip moves to somewhere in LALALand.
The code merely copies the existing clip info then reinstates it in some idiotic form. Anyone know a what it is doing?
Code: [Select]
        [CommandMethod("ChangeInsertionpoint")]
        public static void NewInsertionPoint()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            //Get the blockreference
            PromptEntityOptions peo = new PromptEntityOptions("Pick a blockreference to change the insertion point:");
            peo.SetRejectMessage("Must be a blockreference:");
            peo.AddAllowedClass (typeof(BlockReference),true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) return;

            //New insertion point
            PromptPointResult ppo=ed.GetPoint("Pick the new insertion point:");
            if (ppo.Status != PromptStatus.OK) return;
            Matrix3d ucs=ed.CurrentUserCoordinateSystem;
            Point3d insPt = ppo.Value.TransformBy(ucs),newPt;
            bool hasAtts=false;
           
            using(Transaction tr = db.TransactionManager.StartTransaction())       
            {
                BlockReference br = tr.GetObject(per.ObjectId, OpenMode.ForWrite) as BlockReference;
                ObjectId blockId=br.BlockTableRecord;
                BlockTableRecord btr = tr.GetObject(blockId, OpenMode.ForWrite) as BlockTableRecord;
                Plane plane=new Plane(ucs.CoordinateSystem3d.Origin,ucs.CoordinateSystem3d.Zaxis);

                //Transform inspt back to the blockdef
                Matrix3d blockmatrix = br.BlockTransform;
                insPt= insPt.TransformBy(blockmatrix.Inverse());
                //Util.AddEnt.Point(insPt, 2);
                Vector3d v=btr.Origin-insPt;
                Matrix3d move=Matrix3d.Displacement(v);
                Matrix2d disp = Matrix2d.Displacement(insPt.Convert2d(plane)-btr.Origin.Convert2d(plane));
     
                //Move the ents in the block
                foreach (ObjectId id in btr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;
                    ent.TransformBy(move);
                    ent.DowngradeOpen();
                    if(ent.GetType()==typeof(AttributeDefinition))
                        hasAtts=true;
                }
                ObjectIdCollection ids = btr.GetBlockReferenceIds(false, true);

                //Move the BlockReferences
                foreach (ObjectId brefId in ids)
                {
                    bool btrans = false;
                    BlockReference b = tr.GetObject(brefId, OpenMode.ForWrite) as BlockReference;
                    if (b.BlockTableRecord == blockId)
                    {
                        newPt = insPt.TransformBy(b.BlockTransform);
                        b.TransformBy(Matrix3d.Displacement(newPt - b.Position));
                        btrans = true;
                    }
                    else
                    {
                        BlockTableRecord nestedBref = tr.GetObject(b.BlockTableRecord, OpenMode.ForWrite) as BlockTableRecord;
                        foreach (ObjectId id in nestedBref)
                        {
                            if (id == brefId)
                            {
                                newPt = insPt.TransformBy(b.BlockTransform);
                                b.TransformBy(Matrix3d.Displacement(newPt - b.Position));
                                btrans = true;
                                break;
                            }
                        }
                    }
                    if (btrans)
                    {
                        ObjectId id = b.ExtensionDictionary;
                        if (id == ObjectId.Null) continue;
                        DBDictionary dic = tr.GetObject(id, OpenMode.ForWrite) as DBDictionary;
                        const string spatialName = "SPATIAL";
                        DBDictionary FilterDic = tr.GetObject(dic.GetAt("ACAD_FILTER"), OpenMode.ForWrite) as DBDictionary;
                        if (!FilterDic.Contains(spatialName)) continue;
                        SpatialFilter sf = tr.GetObject(FilterDic.GetAt(spatialName), OpenMode.ForWrite) as SpatialFilter;
                        SpatialFilterDefinition def = sf.Definition;
                        Point2dCollection pts = new Point2dCollection();

                        foreach (Point2d pt in def.GetPoints())
                        {
                           //pts.Add(pt.TransformBy(disp));
                            pts.Add(pt);
                        }
                        SpatialFilterDefinition NewDef = new SpatialFilterDefinition
                            (def.GetPoints(), def.Normal, def.Elevation, def.FrontClip, def.BackClip, def.Enabled);

                        //SpatialFilterDefinition NewDef = new SpatialFilterDefinition
                        //    (pts, def.Normal, def.Elevation, def.FrontClip, def.BackClip, def.Enabled);
                        SpatialFilter NewSf = new SpatialFilter();
                        NewSf.Definition = NewDef;
                        FilterDic.Remove(spatialName);
                        FilterDic.SetAt(spatialName, NewSf);
                        tr.AddNewlyCreatedDBObject(NewSf, true);

                    }
                }

                if (hasAtts)
                    Blocks.blocks.UpdateAtts(blockId, db);

              tr.Commit();       
            } 
           

        } // end NewInsertionPoint

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Xclip and block insertion point
« Reply #1 on: September 20, 2011, 11:23:40 PM »
A bit closer, you must subtract the blockref position.
                foreach (Point2d pt in def.GetPoints())
                {
                    pts.Add(pt);
                }
becomes
                Vector3d v3 = br.Position.GetAsVector();
                foreach (Point2d pt in def.GetPoints())
                {           
                    Point3d p = new Point3d(pt.X, pt.Y,def.Elevation);
                    p = p -v3;
                    pts.Add(p.Convert2d(plane));
                }

But if you copy a clipped blockref  this results in  all the clips and blockrefs going to the forst instance of the clip

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Xclip and block insertion point
« Reply #2 on: September 21, 2011, 06:11:40 AM »
That looks like a bitch of a problem to track down Bryce.
... wish I had time to play  :|

May be worth trying to tweak the interest of Stephen Preston or Kean ...
« Last Edit: September 21, 2011, 06:20:39 AM by Kerry »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Xclip and block insertion point
« Reply #3 on: September 21, 2011, 07:34:49 AM »
Thanks for the reply Kerry and your advice sounds good.
I've broken it into 2 functions
Code: [Select]
        [CommandMethod("ChangeInsertionpoint")]
        public static void NewInsertionPoint()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            PromptEntityOptions peo = new PromptEntityOptions("Pick a blockreference to change the insertion point:");
            peo.SetRejectMessage("Must be a blockreference:");
            peo.AddAllowedClass (typeof(BlockReference),true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) return;
            PromptPointResult ppo=ed.GetPoint("Pick the new insertion point:");
            if (ppo.Status != PromptStatus.OK) return;
            Matrix3d ucs=ed.CurrentUserCoordinateSystem;
            Point3d insPt = ppo.Value.TransformBy(ucs),newPt;
           

            using(Transaction tr = db.TransactionManager.StartTransaction())       
            {
                BlockReference br = tr.GetObject(per.ObjectId, OpenMode.ForWrite) as BlockReference;
                ObjectId blockId=br.BlockTableRecord;
                BlockTableRecord btr = tr.GetObject(blockId, OpenMode.ForWrite) as BlockTableRecord;
                Matrix3d blockmatrix = br.BlockTransform;
                insPt= insPt.TransformBy(blockmatrix.Inverse());
                Vector3d v=btr.Origin-insPt;
                Matrix3d move=Matrix3d.Displacement(v);
                foreach (ObjectId id in btr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;
                    ent.TransformBy(move);
                    ent.DowngradeOpen();
                }
                ObjectIdCollection ids = btr.GetBlockReferenceIds(false, true);
                foreach (ObjectId brefId in ids)
                {
                    BlockReference b = tr.GetObject(brefId, OpenMode.ForWrite) as BlockReference;
                    newPt = insPt.TransformBy(b.BlockTransform);
                    if (b.BlockTableRecord == blockId)
                    {   
                        b.TransformBy(Matrix3d.Displacement(newPt - b.Position));
                    }
                    else
                    {
                        BlockTableRecord nestedBref = tr.GetObject(b.BlockTableRecord, OpenMode.ForWrite) as BlockTableRecord;
                        foreach (ObjectId id in nestedBref)
                        {
                            if (id == brefId)
                            {
                                b.TransformBy(Matrix3d.Displacement(newPt - b.Position));
                                break;
                            }
                        }
                    }
                    UpdateClip(db, b, v);
                }
              tr.Commit();       
            }
            ed.Regen();

        } // end NewInsertionPoint


        public static void UpdateClip(Database db,BlockReference br,Vector3d v)
        {
            const string spatialName = "SPATIAL";
            ObjectId ExId = br.ExtensionDictionary;
            if (ExId == ObjectId.Null) return;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary dic = tr.GetObject(ExId, OpenMode.ForWrite) as DBDictionary;
                if (!dic.Contains("ACAD_FILTER")) return;
                DBDictionary clipDic = tr.GetObject(dic.GetAt("ACAD_FILTER"), OpenMode.ForWrite) as DBDictionary;
                if (!clipDic.Contains(spatialName)) return;
                SpatialFilter sf = tr.GetObject(clipDic.GetAt(spatialName), OpenMode.ForWrite) as SpatialFilter;
                SpatialFilterDefinition def = sf.Definition;

                Plane plane=new Plane(new Point3d(0,0,def.Elevation),def.Normal);
                Matrix3d m = br.BlockTransform;
                Matrix3d disp=Matrix3d.Displacement(v.Negate());
                Point2dCollection pts = new Point2dCollection();

                foreach (Point2d pt in def.GetPoints())
                {           
                    Point3d p = new Point3d(pt.X, pt.Y,def.Elevation);
                    p = p.TransformBy(m.Inverse());
                    pts.Add(p.Convert2d(plane));
                }

                SpatialFilterDefinition def2=new SpatialFilterDefinition(
                    pts,def.Normal,def.Elevation,def.FrontClip,def.BackClip,def.Enabled);
               
                clipDic.Remove(spatialName);
                SpatialFilter sf2 = new SpatialFilter();
                sf2.Definition = def2;
                SpatialFilterVolume sfv=sf.GetVolume();
                clipDic.SetAt(spatialName, sf2);
                tr.AddNewlyCreatedDBObject(sf2,true);
               
                tr.Commit();
            }

        } // end UpdateClip

And This works the first time on most but  the second time it throws a wobbler. Also if you clip a blockref then rotate it it gets it wrong, so the compound matrix needs to be one step back in time. In the beginning I thought I had to move the clip relative to the new insertion point but I don't .

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Xclip and block insertion point
« Reply #4 on: October 28, 2014, 04:48:36 PM »
I tried this again using 2015 with VS2012 express and crash,   in fact running Kean's code crashes as well. I was hoping someone could try Keans code in 2015

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Xclip and block insertion point
« Reply #5 on: March 17, 2015, 05:24:38 PM »
http://through-the-interface.typepad.com/through_the_interface/2010/11/adding-a-2d-spatial-filter-to-perform-a-simple-xclip-on-an-external-reference-in-autocad-using-net.html
Just in case someone else is interested in  clips. This crashes for me ACAD 2015 mechanical using vanilla.  Kean said he tried it on 2015 and it didn't crash, so I am a bit lost. Hoping someone else may give it a shot

Jeff H

  • Needs a day job
  • Posts: 6144
Re: Xclip and block insertion point
« Reply #6 on: March 18, 2015, 04:09:58 AM »
I can get Kean and this example http://adndevblog.typepad.com/autocad/2013/01/spatial-filter-xclip-command-command-in-c.html to add a clip to an xref.

But if it will not invert and if edit the clip using a grip it crashes.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Xclip and block insertion point
« Reply #7 on: March 18, 2015, 01:32:29 PM »
Thanks for trying Jeff,  I think I'll give up on it. If I step thru the code it didn't crash but I couldn't edit the clip either,  sometimes I could delete the clip but not reclip it.

The newer code looks like it will need updating with a newer cad version so I will probably skip that too.
A shame as otherwise the change insertion point code is really handy.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Xclip and block insertion point
« Reply #8 on: April 29, 2016, 07:44:11 PM »
This seems to work ok.
It does not allow for a clip being on a different plane than the blockref.
The clip grips do not show up until you save close and reopen.


Code: [Select]

        [CommandMethod("ChangeInsertionpoint")]
        public static void NewInsertionPoint()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            //Get the blockreference
            PromptEntityOptions peo = new PromptEntityOptions("\nPick a blockreference to change the insertion point:");
            peo.SetRejectMessage("Must be a blockreference:");
            peo.AddAllowedClass (typeof(BlockReference),true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) return;

            //New insertion point
            PromptPointResult ppo=ed.GetPoint("\nPick the new insertion point:");
            if (ppo.Status != PromptStatus.OK) return;
            Matrix3d ucs=ed.CurrentUserCoordinateSystem;
            Point3d insPt = ppo.Value.TransformBy(ucs),newPt=Point3d.Origin;
            bool hasAtts=false;
           
            using(Transaction tr = db.TransactionManager.StartTransaction())       
            {
                //Get the blockref
                BlockReference br = tr.GetObject(per.ObjectId, OpenMode.ForWrite) as BlockReference;
                ObjectId blockId=br.BlockTableRecord;
                //get it's blockdef
                BlockTableRecord btr = tr.GetObject(blockId, OpenMode.ForWrite) as BlockTableRecord;
   
                //Transform inspt back to the blockdef
                Matrix3d blockmatrix = br.BlockTransform;
                insPt= insPt.TransformBy(blockmatrix.Inverse());
                Matrix3d move = Matrix3d.Displacement(btr.Origin - insPt);
     
                //Move the ents in the block
                foreach (ObjectId id in btr)
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;
                    ent.TransformBy(move);
                    if(ent.GetType()==typeof(AttributeDefinition))
                        hasAtts=true;
                }

                ObjectIdCollection ids = btr.GetBlockReferenceIds(false, true);

                //Move the BlockReferences
                Matrix3d mBref = new Matrix3d();
               
                foreach (ObjectId brefId in ids)
                {
                    bool btrans = false;
                    BlockReference b = tr.GetObject(brefId, OpenMode.ForWrite) as BlockReference;
                    Point3d bposition = b.Position;
                    if (b.BlockTableRecord == blockId)//has to unless nested
                    {
                        newPt = insPt.TransformBy(b.BlockTransform);
                        mBref=Matrix3d.Displacement(newPt - b.Position);
                        b.TransformBy(mBref);
                        btrans = true;
                    }
                    else
                    {
                        BlockTableRecord nestedBref = tr.GetObject(b.BlockTableRecord, OpenMode.ForWrite) as BlockTableRecord;
                        foreach (ObjectId id in nestedBref)
                        {
                            if (id == brefId)
                            {
                                newPt = insPt.TransformBy(b.BlockTransform);
                                b.TransformBy(mBref);
                                btrans = true;
                                break;
                            }
                        }
                    }
                    if (btrans)
                    {
                        ObjectId id = b.ExtensionDictionary;
                        if (id == ObjectId.Null) continue;
                        DBDictionary dic = tr.GetObject(id, OpenMode.ForWrite) as DBDictionary;
                        const string spatialName = "SPATIAL";
                        if (!dic.Contains("ACAD_FILTER")) continue;

                        DBDictionary FilterDic = tr.GetObject(dic.GetAt("ACAD_FILTER"), OpenMode.ForWrite) as DBDictionary;
                        if (!FilterDic.Contains(spatialName)) continue;
                        SpatialFilter sf = tr.GetObject(FilterDic.GetAt(spatialName), OpenMode.ForWrite) as SpatialFilter;
                        SpatialFilterDefinition def = sf.Definition;
                        Point2dCollection pts = new Point2dCollection();
                        Matrix3d m = sf.OriginalInverseBlockTransform;
                       // Matrix3d w= sf.ClipSpaceToWorldCoordinateSystemTransform;
                        //need this for clips on a different plane than the blockref
                   
                        CoordinateSystem3d cs = m.CoordinateSystem3d;                     
                        Plane plane = new Plane(cs.Origin, cs.Zaxis);     
                        Matrix2d disp = Matrix2d.Displacement(newPt.Convert2d(plane) - b.Position.Convert2d(plane));

                        foreach (Point2d pt in def.GetPoints())
                        {
                            Point3d l = new Point3d(plane, pt);
                            l = l.TransformBy(move);
                            l = l.TransformBy(m);
                            pts.Add(l.Convert2d(plane));
                        }
                        pts.TrimToSize();
                        SpatialFilterDefinition NewDef = new SpatialFilterDefinition
                            (pts,Vector3d.ZAxis,0, def.FrontClip, def.BackClip, true);
                        SpatialFilter NewSf = new SpatialFilter();
                        NewSf.Definition = NewDef;
                       
                        FilterDic.Remove(spatialName);//REMOVE the old filter
                        FilterDic.SetAt(spatialName, NewSf);
                        tr.AddNewlyCreatedDBObject(NewSf, true);                       
                   }
                    if (hasAtts)
                        Blocks.blocks.UpdateAtts(blockId, db);
                }
               
              tr.Commit();       
            }

            ed.Regen();
        } // end NewInsertionPoint