TheSwamp
Code Red => .NET => Topic started by: Bryco 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 (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?
[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
-
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
-
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 ...
-
Thanks for the reply Kerry and your advice sounds good.
I've broken it into 2 functions
[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 .
-
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
-
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 (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
-
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.
-
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.
-
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.
[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