finding Blocks from XREF and Text inside polylines

finding Blocks from XREF and Text inside polylines

Anonymous
Not applicable
520 Views
3 Replies
Message 1 of 4

finding Blocks from XREF and Text inside polylines

Anonymous
Not applicable

Hi All,

I have a couple of questions here.

I have a function that extract attributes from blocks inside polylines that are in the same drawing, I was wondering, how would that be when the block is from an Xref drawing and the polyline is from the actual drawing.

 

The second question is how to find Text object inside polylines.

I thought that doing a Selection Filter in a similar way as I did for the blocks (https://forums.autodesk.com/t5/net/find-block-inside-a-polyline/td-p/7586489

And by using TEXT instead of the INSERT to retrieve the ObjectId's may work, but it didn't.

 

Anyone has an idea on how to approach this 2??

 

Thanks in advance,

 

Alberto

0 Likes
521 Views
3 Replies
Replies (3)
Message 2 of 4

BKSpurgeon
Collaborator
Collaborator

hi there

 

The following code is untested, so please use with caution. Also note that there are assumptions made about the polylines (light weight) and i'm also assuming that the polylines aren't doing anything crazy, like overlapping itself a million times and that they are closed.

 

This is something that I whipped up in great haste, but I still think it will be of benefit to you. You can tailor/tweak according to your own taste.

 

I was thinking of football players (block references) within pitches (closed polylines) if you were wondering about the names:

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.EditorInput;

using System;
using System.Collections.Generic;

using System.IO;

namespace BKForums.Exercises
{
    internal class BlockInXref
    {
        private string xrefNameMustContain = "nameOfRelevantXref";
        private string nameOfPlayerBlock = "nameOfPlayerBlock";
        private List<ObjectId> closedPolylines;

        public BlockInXref()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            closedPolylines = getClosedPolylines(doc);
        }

        public List<Player> getPlayersInClosedPolylines(Document doc)
        {
            Database db = doc.Database;

            List<Player> players = new List<Player>();

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                foreach (Player player in getPlayers(tr, db))
                {
                    foreach (ObjectId polylineId in closedPolylines)
                    {
                        List<Point2d> polylinePoints = getPolylinePoints(polylineId, tr);

                        if (IsPointInPolygon(polylinePoints, player.Position))
                        {
                            players.Add(player);
                        }
                    }
                }

                tr.Commit();
            }

            return players;
        }

        private List<Point2d> getPolylinePoints(ObjectId polylineId, Transaction tr)
        {
            List<Point2d> pointsInPolyline = new List<Point2d>();

            // Use a for loop to get each vertex, one by one
            Polyline pl = tr.GetObject(polylineId, OpenMode.ForRead) as Polyline;

            int vn = pl.NumberOfVertices;
            for (int i = 0; i < vn; i++)
            {
                // Could also get the 3D point here
                Point2d pt = pl.GetPoint2dAt(i);

                if (!pointsInPolyline.Contains(pt))
                {
                    pointsInPolyline.Add(pt);
                }
            }

            return pointsInPolyline;
        }

        private List<Player> getPlayers(Transaction tr, Database db)
        {
            //  https://forums.autodesk.com/t5/net/find-nested-blocks-in-xrefs/td-p/4833475

            List<Player> players = new List<Player>();

            db.ResolveXrefs(true, false);

            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)
                {
                    if (node.Name.ToUpper().Contains(xrefNameMustContain))
                    {
                        Database xrefDatabase = node.Database;

                        BlockTable xrefBlockTable = tr.GetObject(xrefDatabase.BlockTableId, OpenMode.ForRead) as BlockTable;

                        string xRefBlockName = node.Name + "|" + nameOfPlayerBlock;

                        if (xrefBlockTable.Has(xRefBlockName))
                        {
                            BlockTableRecord playerBlockTableRecord = tr.GetObject(xrefBlockTable[xRefBlockName], OpenMode.ForRead) as BlockTableRecord;

                            foreach (ObjectId id in playerBlockTableRecord.GetBlockReferenceIds(true, false))
                            {
                                BlockReference playerBlockReference = tr.GetObject(id, OpenMode.ForRead) as BlockReference;

                                Player player = new Player(playerBlockReference, tr);
                                players.Add(player);
                            }
                        }
                    }
                }
            }

            return players;
        }

        public class Player
        {
            private Dictionary<string, string> attributes;

            private Point2d _position;

            public Point2d Position
            {
                get { return _position; }
            }

            public Player(BlockReference playerBlockReference, Transaction tr)
            {
                attributes = getAttributes(playerBlockReference, tr);
                _position = new Point2d(playerBlockReference.Position.X, playerBlockReference.Position.Y);
            }

            private Dictionary<string, string> getAttributes(BlockReference playerBlockReference, Transaction tr)
            {
                Dictionary<string, string> attributes = new Dictionary<string, string>();

                foreach (ObjectId id in playerBlockReference.AttributeCollection)
                {
                    AttributeReference attributeReference = tr.GetObject(id, OpenMode.ForRead) as AttributeReference;

                    if (attributeReference != null)
                    {
                        if (!string.IsNullOrWhiteSpace(attributeReference.TextString))
                        {
                            if (!attributes.ContainsKey(attributeReference.Tag))
                            {
                                attributes.Add(attributeReference.Tag, attributeReference.TextString);
                            }
                        }
                    }
                }

                return attributes;
            }
        }

        private List<ObjectId> getClosedPolylines(Document doc)
        {
            List<ObjectId> ids = new List<ObjectId>();
            using (Transaction tr = new OpenCloseTransaction())
            {
                BlockTableRecord ms = (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(doc.Database), OpenMode.ForRead);
                ids = ms.Cast<ObjectId>()
                        .Where(id => id.ObjectClass == RXClass.GetClass(typeof(Polyline)))
                        .Select(id => tr.GetObject(id, OpenMode.ForRead) as Polyline)
                        .Where(polyline => polyline != null)
                        .Select(polyline => polyline.ObjectId)
                        .ToList();

                tr.Abort();
            }

            return ids;
        }

        private static bool IsPointInPolygon(List<Point2d> polygon, Point2d point)
        {
            bool isInside = false;
            for (int i = 0, j = polygon.Count - 1; i < polygon.Count; j = i++)
            {
                if (((polygon[i].Y > point.Y) != (polygon[j].Y > point.Y)) &&
                (point.X < (polygon[j].X - polygon[i].X) * (point.Y - polygon[i].Y) / (polygon[j].Y - polygon[i].Y) + polygon[i].X))
                {
                    isInside = !isInside;
                }
            }
            return isInside;
        }
    }
}
0 Likes
Message 3 of 4

BKSpurgeon
Collaborator
Collaborator

as for getting the text, it's a very similar process:

 

  • Get the texts objectId
  • Open it up.
  • retrieve the string you are after.
  • retrieve the position.
  • judge whether it is inside or outside the polyline.

 

You'll find plenty of examples on how to open Text and get the values you are after in the .net documentation.

0 Likes
Message 4 of 4

Anonymous
Not applicable

Thank you so much, works perfectly.

 

And yes, your assumptions are correct all polylines this script will be using are closed and are LWPOLYLINE. And they shouldn't overlap.

 

Alberto

0 Likes