Hi,
Please consider this scenario:
Current Database curDb;
|--containing one or more XREF references
|----some of them containing one or more XREF references
|--
|--
|------some of them containig exactly one BlockReference;
The only thing known at runtime is the BlockReference name, call it blName.
Now I need to find all instances of blName, retrieve each instance's insert point and transform it to the curDb World UCS.
And I need it in C#.
One thing is certain: As the nesting level is not known in advance, one must use recursion.
I was able to find the BlockDefinition of blName and I'm stuck here.
I confess I am completely lost, even after reading the - not so rich - info I was able to find here and elsewhere.
Any pointers would be much apreciated.
alex
Hi,
Please consider this scenario:
Current Database curDb;
|--containing one or more XREF references
|----some of them containing one or more XREF references
|--
|--
|------some of them containig exactly one BlockReference;
The only thing known at runtime is the BlockReference name, call it blName.
Now I need to find all instances of blName, retrieve each instance's insert point and transform it to the curDb World UCS.
And I need it in C#.
One thing is certain: As the nesting level is not known in advance, one must use recursion.
I was able to find the BlockDefinition of blName and I'm stuck here.
I confess I am completely lost, even after reading the - not so rich - info I was able to find here and elsewhere.
Any pointers would be much apreciated.
alex
We have several samples about reading the xrefs on our blog, I doubt you took a look up there:
I would also be very surprised you cannot find any .Net xref sample on Kean's blog:
hhttp://through-the-interface.typepad.com/through_the_interface/
Based on the first sample and as you mentioned, recursion, you should be able to achieve that task.
Regards,
Philippe.
We have several samples about reading the xrefs on our blog, I doubt you took a look up there:
I would also be very surprised you cannot find any .Net xref sample on Kean's blog:
hhttp://through-the-interface.typepad.com/through_the_interface/
Based on the first sample and as you mentioned, recursion, you should be able to achieve that task.
Regards,
Philippe.
Philippe,
Thank you for pointing Stephen's article to me. I must've missed it.
It, of course, works in its scope.
What I need though, and can't make it work, is to find each instance (BlockReference) of a particular block (name known), embedded in some of the xrefs.
And to complicate it even more, for each instance of the block, I need to transform its local coordinates to the parent drawing, so I have to return transform matrices all the way back the recursion.
An additional problem is that the parent xref may be itself referred multiple times in its parent.
Now, from one of Balaj's posts: "AcDbXrefGraph maps singular parent-child linkages, even for xrefs that are multiply referenced in the current drawing".
If I understand this correctly, what I need to do is impossible using this approach (of traversing the XrefGraph), but it's my first time with XrefGraph, so..
Please correct me if I'm wrong. Am I missing something?
Regards,
alex
Philippe,
Thank you for pointing Stephen's article to me. I must've missed it.
It, of course, works in its scope.
What I need though, and can't make it work, is to find each instance (BlockReference) of a particular block (name known), embedded in some of the xrefs.
And to complicate it even more, for each instance of the block, I need to transform its local coordinates to the parent drawing, so I have to return transform matrices all the way back the recursion.
An additional problem is that the parent xref may be itself referred multiple times in its parent.
Now, from one of Balaj's posts: "AcDbXrefGraph maps singular parent-child linkages, even for xrefs that are multiply referenced in the current drawing".
If I understand this correctly, what I need to do is impossible using this approach (of traversing the XrefGraph), but it's my first time with XrefGraph, so..
Please correct me if I'm wrong. Am I missing something?
Regards,
alex
The task seems easier to me than what you suggest. The xref graph allows you to list all the xrefs in a drawing, once you get the name of the BlockTableRecord you are interested in, you can access it from the BlockTable, then you can use BlockTableRecord.GetBlockReferenceIds to retrieve all references of that block in a specific database. As you mentionned, you would need to propagate the bref transformation in your recursive call, so at each level you will be able to compute the total transformation, simply by multiplying matrices, this seems rather straighforward to do, but you may struggle a bit with the details, I don't have a sample that does exactly this to provide unfortunately.
Regards,
Philippe.
The task seems easier to me than what you suggest. The xref graph allows you to list all the xrefs in a drawing, once you get the name of the BlockTableRecord you are interested in, you can access it from the BlockTable, then you can use BlockTableRecord.GetBlockReferenceIds to retrieve all references of that block in a specific database. As you mentionned, you would need to propagate the bref transformation in your recursive call, so at each level you will be able to compute the total transformation, simply by multiplying matrices, this seems rather straighforward to do, but you may struggle a bit with the details, I don't have a sample that does exactly this to provide unfortunately.
Regards,
Philippe.
Philippe,
The problem is with the regular block embedded in some of the xrefs, at some level, which is what I'm looking for.
I need to locate all its instances visible in the document.
I can't seem to be able to find it (either its BlockTableRecord, nor any references to it).
Thank you,
alex
Philippe,
The problem is with the regular block embedded in some of the xrefs, at some level, which is what I'm looking for.
I need to locate all its instances visible in the document.
I can't seem to be able to find it (either its BlockTableRecord, nor any references to it).
Thank you,
alex
As Philippe mentioned just look in the BlockTable
The name will be
blName
if brought in from xref the name will be
xrefName|blName
the xref can be nested 17,345,678 times deep but the block name will be XrefName|BlockName
Just like layer names from xrefs in the layer palette
As Philippe mentioned just look in the BlockTable
The name will be
blName
if brought in from xref the name will be
xrefName|blName
the xref can be nested 17,345,678 times deep but the block name will be XrefName|BlockName
Just like layer names from xrefs in the layer palette
Jeff,
I am aware of that, but this is just the block definition.
I just don't succeed finding the BlockReferences for xrefName|blName.
Obviously I'm missing something.
Thanks,
alex
Jeff,
I am aware of that, but this is just the block definition.
I just don't succeed finding the BlockReferences for xrefName|blName.
Obviously I'm missing something.
Thanks,
alex
As Philippe mentioned once you have the BlockTableRecord use GetBlockReferenceIds
As Philippe mentioned once you have the BlockTableRecord use GetBlockReferenceIds
Jeff,
I already got that.
Now I'm struggling with the recursion.
To ilustrate the problem I attach DAG.png, with the XrefGraph on the left and the actual objects in dwg on the right.
Please observe tha XR1 is inserted in XRC 3 times.
The regular block blName is inserted in XR3 at position X,Y in local WCS.
What I need to do is find all blName instances in dwg (there are 5) and find each's location in dwg WCS.
And I can't seem to solve the recursion.
Any ideas will be welcome.
alex
Jeff,
I already got that.
Now I'm struggling with the recursion.
To ilustrate the problem I attach DAG.png, with the XrefGraph on the left and the actual objects in dwg on the right.
Please observe tha XR1 is inserted in XRC 3 times.
The regular block blName is inserted in XR3 at position X,Y in local WCS.
What I need to do is find all blName instances in dwg (there are 5) and find each's location in dwg WCS.
And I can't seem to solve the recursion.
Any ideas will be welcome.
alex
Hi,
If I don't misunderstand the task, this seems to work.
using System.Collections.Generic; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; [assembly: CommandClass(typeof(FindBlocksInXref.CommandMethods))] namespace FindBlocksInXref { public class CommandMethods { [CommandMethod("Test")] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { db.ResolveXrefs(true, false); BlockTableRecord mspace = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite); List<Point3d> insPts = new List<Point3d>(); GetInsertPositions(db, "", Matrix3d.Identity, insPts); foreach (Point3d pt in insPts) { DBPoint dbPt = new DBPoint(pt); mspace.AppendEntity(dbPt); tr.AddNewlyCreatedDBObject(dbPt, true); } tr.Commit(); } } private void GetInsertPositions(Database db, string prefix, Matrix3d xform, List<Point3d> insPoints) { Transaction tr = db.TransactionManager.TopTransaction; BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); string blkName = prefix + "blName"; if (bt.Has(blkName)) { BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blkName], OpenMode.ForRead); foreach (ObjectId id in btr.GetBlockReferenceIds(true, false)) { BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); insPoints.Add(br.Position.TransformBy(xform)); } } XrefGraph graph = db.GetHostDwgXrefGraph(true); GraphNode root = graph.RootNode; for (int i = 0; i < root.NumOut; i++) { XrefGraphNode node = (XrefGraphNode)root.Out(i); if (node.XrefStatus == XrefStatus.Resolved) { BlockTableRecord xrBtr = (BlockTableRecord)tr.GetObject(node.BlockTableRecordId, OpenMode.ForRead); foreach (ObjectId id in xrBtr.GetBlockReferenceIds(true, false)) { BlockReference xref = (BlockReference)tr.GetObject(id, OpenMode.ForRead); ; if (xref.OwnerId == SymbolUtilityServices.GetBlockModelSpaceId(db)) GetInsertPositions(node.Database, node.Name + "|", xform * xref.BlockTransform, insPoints); } } } } } }
Hi,
If I don't misunderstand the task, this seems to work.
using System.Collections.Generic; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; [assembly: CommandClass(typeof(FindBlocksInXref.CommandMethods))] namespace FindBlocksInXref { public class CommandMethods { [CommandMethod("Test")] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { db.ResolveXrefs(true, false); BlockTableRecord mspace = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite); List<Point3d> insPts = new List<Point3d>(); GetInsertPositions(db, "", Matrix3d.Identity, insPts); foreach (Point3d pt in insPts) { DBPoint dbPt = new DBPoint(pt); mspace.AppendEntity(dbPt); tr.AddNewlyCreatedDBObject(dbPt, true); } tr.Commit(); } } private void GetInsertPositions(Database db, string prefix, Matrix3d xform, List<Point3d> insPoints) { Transaction tr = db.TransactionManager.TopTransaction; BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); string blkName = prefix + "blName"; if (bt.Has(blkName)) { BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blkName], OpenMode.ForRead); foreach (ObjectId id in btr.GetBlockReferenceIds(true, false)) { BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); insPoints.Add(br.Position.TransformBy(xform)); } } XrefGraph graph = db.GetHostDwgXrefGraph(true); GraphNode root = graph.RootNode; for (int i = 0; i < root.NumOut; i++) { XrefGraphNode node = (XrefGraphNode)root.Out(i); if (node.XrefStatus == XrefStatus.Resolved) { BlockTableRecord xrBtr = (BlockTableRecord)tr.GetObject(node.BlockTableRecordId, OpenMode.ForRead); foreach (ObjectId id in xrBtr.GetBlockReferenceIds(true, false)) { BlockReference xref = (BlockReference)tr.GetObject(id, OpenMode.ForRead); ; if (xref.OwnerId == SymbolUtilityServices.GetBlockModelSpaceId(db)) GetInsertPositions(node.Database, node.Name + "|", xform * xref.BlockTransform, insPoints); } } } } } }
Nice Gile!!
I was thinking a total different approach but I like yours!
Nice Gile!!
I was thinking a total different approach but I like yours!
Hi Gilles,
My Outlook went crazy and I didn't receive notification of your post, so I had to solve it by myself.
I like your solution better though, it's more concise and probably faster (although at some hundred blocks in a typical drawing, it probably won't make much difference).
I especially liked your forwarding the xform matrix and using it in place. In my solution I applied the transform on the returned list, which added an additionary loop.
Thanks for the lesson,
alex
Hi Gilles,
My Outlook went crazy and I didn't receive notification of your post, so I had to solve it by myself.
I like your solution better though, it's more concise and probably faster (although at some hundred blocks in a typical drawing, it probably won't make much difference).
I especially liked your forwarding the xform matrix and using it in place. In my solution I applied the transform on the returned list, which added an additionary loop.
Thanks for the lesson,
alex
Can't find what you're looking for? Ask the community or share your knowledge.