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

Find nested blocks in XREFs

11 REPLIES 11
Reply
Message 1 of 12
alex_b
2360 Views, 11 Replies

Find nested blocks in XREFs

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

11 REPLIES 11
Message 2 of 12
philippe.leefsma
in reply to: alex_b

We have several samples about reading the xrefs on our blog, I doubt you took a look up there:

 

http://adndevblog.typepad.com/autocad/2012/06/finding-all-xrefs-in-the-current-database-using-cnet.h...

 

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 Leefsma
Developer Technical Services
Autodesk Developer Network

Message 3 of 12
alex_b
in reply to: philippe.leefsma

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

Message 4 of 12
philippe.leefsma
in reply to: alex_b

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 Leefsma
Developer Technical Services
Autodesk Developer Network

Message 5 of 12
alex_b
in reply to: philippe.leefsma

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

Message 6 of 12
jeff
in reply to: alex_b

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

You can also find your answers @ TheSwamp
Message 7 of 12
alex_b
in reply to: jeff

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

 

 

Message 8 of 12
jeff
in reply to: alex_b

As Philippe mentioned once you have the BlockTableRecord use GetBlockReferenceIds

You can also find your answers @ TheSwamp
Message 9 of 12
alex_b
in reply to: jeff

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

Message 10 of 12
_gile
in reply to: alex_b

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);
                    }
                }
            }
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 11 of 12
jeff
in reply to: _gile

Nice Gile!!

 

I was thinking a total different approach but I like yours!

You can also find your answers @ TheSwamp
Message 12 of 12
alex_b
in reply to: _gile

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.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost