How to work with block entities as if they were in the world UCS rather than inside blocks?

How to work with block entities as if they were in the world UCS rather than inside blocks?

stefanome
Collaborator Collaborator
728 Views
2 Replies
Message 1 of 3

How to work with block entities as if they were in the world UCS rather than inside blocks?

stefanome
Collaborator
Collaborator

This snapshot shows 3 blocks: the red B1, the white B2 containing one instance of B3, and the cyan B3. The 3 blocks are shown on the top just to make it clear who's who, and on the bottom to show an example of how they would be used. There are 1 instance of B1, 2 instances of B2 and 1 instance of B3 (looking at the orientation of the B3 text helps understanding which instance is at the top level and which is inside B2):

stefanomenci_0-1671466750526.png

I need to temporarily explode all the blocks and work with their entities as if they were in the world UCS. In the snapshot I am looking for all the intersections, but I may be looking for other kinds of analysis.

 

In a previous version of the add-in I'm working on now, I was using groups instead of blocks, because that add-in was working on another CAD where I can use thousands of groups without problems. I have done a few tests with AutoCAD and it turns out groups are unusable, so I am trying to use blocks. In the old add-in I have seen cases with 3000 groups and 350,000 intersections.

 

In the old add-in I was using a Line2 wrapper of the official Line class, because the Line class was too slow at calculating intersections and because I needed some methods that were not available.

 

What is the best approach with AutoCAD?

 

I was thinking of creating a Line2 wrapper, then scan all the blocks, scan all the lines in each block and create a list of Line2 objects. Each Line2 object refers to a Line that can be inside a block, sub-block, or at the top level, knows how to transform from block UCS to top level world UCS, and knows how to calculate intersections and has all the goodies that I need.

 

So my question is:

1. Does AutoCAD have a standard way to deal with entities inside blocks and sub-blocks as if they were at the top level?

2. If not, is the Line2 wrapper approach I mentioned above the correct approach?

3. Can you please point me to an example that shows how to apply the inverse transformation of the block to each line, so I can manage them as if they were at the top level world UCS?

0 Likes
Accepted solutions (1)
729 Views
2 Replies
Replies (2)
Message 2 of 3

_gile
Consultant
Consultant
Accepted solution

Hi,

 

The BlockReference type has a BlockTransform property that you can use to transform points, entities or geometric objects such as LineSegment3d from the MCS (block definition Microspace Coordinate System) to the WCS.

 

Here's an example to get all intersections of the lines inside the blocks.

        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var filter = new SelectionFilter(new[] { new TypedValue(0, "INSERT") });
            var selection = ed.GetSelection(filter);
            if (selection.Status != PromptStatus.OK)
                return;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                var segments = selection.Value.GetObjectIds()
                    .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
                    .SelectMany(br => GetSegments(br))
                    .ToArray();
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                for (int i = 0; i < segments.Length - 1; i++)
                {
                    var segment1 = segments[i];
                    for (int j = i + 1; j < segments.Length; j++)
                    {
                        var segment2 = segments[j];
                        var intersects = segment1.IntersectWith(segment2);
                        if (intersects != null)
                        {
                            foreach (var pt in intersects)
                            {
                                var point = new DBPoint(pt);
                                curSpace.AppendEntity(point);
                                tr.AddNewlyCreatedDBObject(point, true);
                            }
                        }
                    }
                }
                tr.Commit();
            }
        }

        private static IEnumerable<LineSegment3d> GetSegments(BlockTableRecord btr)
        {
            var lineClass = RXObject.GetClass(typeof(Line));
            var brClass = RXObject.GetClass(typeof(BlockReference));
            foreach (ObjectId id in btr)
            {
                if (id.ObjectClass == lineClass)
                {
                    var line = (Line)id.GetObject(OpenMode.ForRead);
                    yield return new LineSegment3d(line.StartPoint, line.EndPoint);
                }
                else if (id.ObjectClass == brClass)
                {
                    var br = (BlockReference)id.GetObject(OpenMode.ForRead);
                    foreach(var segment in GetSegments(br))
                    {
                        yield return segment;
                    }
                }
            }
        }

        private static IEnumerable<LineSegment3d> GetSegments(BlockReference br)
        {
            var btr = (BlockTableRecord)br.BlockTableRecord.GetObject(OpenMode.ForRead);
            foreach (var segment in GetSegments(btr))
            {
                segment.TransformBy(br.BlockTransform);
                yield return segment;
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 3

stefanome
Collaborator
Collaborator

Oh, WOW!!

 

You answered my question, did the job for me and answered many of my follow-up questions!

 

It turns out I will need to make a wrapper class anyway, because you are using the LineSegment3d object that doesn't know about the layer or other properties of the entity it is coming from (so I assume, I haven't checked yet and I might be wrong), so I will create a wrapper class that keeps all the additional information that I need.

 

Thank you very much for the help!!

0 Likes