Get Block close to Polyline

Get Block close to Polyline

Sgear
Advocate Advocate
1,768 Views
10 Replies
Message 1 of 11

Get Block close to Polyline

Sgear
Advocate
Advocate

 

Hi

 

How can I get Block ID close to polyline from select point

 

 

 

Pline-Block.png

0 Likes
Accepted solutions (2)
1,769 Views
10 Replies
Replies (10)
Message 2 of 11

_Tharwat
Advisor
Advisor
Accepted solution

Hi,

 

Here is attempt and although it may not look that professional but works as expected.

Any comments are welcome and I am open to ideas.

 

[CommandMethod("Foo")]

        public static void IterateThroughPaperSpaces ()
        {
            Document Doc = App.DocumentManager.MdiActiveDocument;
            Editor ed = Doc.Editor;
            Database db = Doc.Database;

            PromptEntityOptions ent = new PromptEntityOptions("\nPick on Single polyline: ");
            ent.SetRejectMessage("\nMust select Single polyline !");
            ent.AddAllowedClass(typeof(Polyline), true);
            ent.AllowNone = false;
            PromptEntityResult rst = ed.GetEntity(ent);
            if (rst.Status != PromptStatus.OK) return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                TypedValue[] tv = { new TypedValue(0, "INSERT"), new TypedValue(410 , App.GetSystemVariable("CTAB")) };
                PromptSelectionResult sel = ed.SelectAll(new SelectionFilter(tv));
                var dis = 0.0;
                double pos = 0.0;
                ObjectIdCollection objs = new ObjectIdCollection();
                Point3d pt = rst.PickedPoint;
                if (sel.Value == null)
                {
                    ed.WriteMessage("\nNo Blocks found in this drawing !");
                    return;
                }

                foreach (ObjectId item in sel.Value.GetObjectIds())
                {
                    var blk = (BlockReference)tr.GetObject(item, OpenMode.ForRead);
                    if (blk != null)
                    {
                        if (objs.Count < 1)
                         pos = blk.Position.DistanceTo(pt);

                        dis = blk.Position.DistanceTo(pt);
                        if (dis <= pos)
                        {
                            pos = dis;
                            objs.Clear();
                            objs.Add(item);
                        }
                    }
                }
                
                if (objs.Count > 0)
                {
                    ObjectId[] ids = new ObjectId[objs.Count];
                    objs.CopyTo(ids, 0);
                    ed.SetImpliedSelection(ids);
                }
                tr.Commit();
            }
          

 

Message 3 of 11

_gile
Consultant
Consultant

Hi,

 

I'm not certain to exactly understand the request, but you probably can get some inspiration from the following snippets.

 

Get the the closest block reference Id to the specified point in the current space:

 

        private ObjectId GetClosestBlockReferenceId(Point3d point)
        {
            var brId = ObjectId.Null;
            var db = HostApplicationServices.WorkingDatabase;
            var brClass = RXObject.GetClass(typeof(BlockReference));
            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
                var query = curSpace.Cast<ObjectId>().Where(id => id.ObjectClass == brClass);
                if (query.Any())
                    brId = query
                        .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
                        .Aggregate((br1, br2) => br1.Position.DistanceTo(point) < br2.Position.DistanceTo(point) ? br1 : br2)
                        .ObjectId;
                tr.Commit();
            }
            return brId;
        }

 

Get the closest the closest block reference to the polyline (have to be called form within a transaction):

 

        private ObjectId GetClosestBlockReferenceId(Polyline pline)
        {
            var tr = pline.Database.TransactionManager.TopTransaction;
            var brId = ObjectId.Null;
            var brClass = RXObject.GetClass(typeof(BlockReference));
            var space = (BlockTableRecord)tr.GetObject(pline.OwnerId, OpenMode.ForRead);
            var query = space.Cast<ObjectId>().Where(id => id.ObjectClass == brClass);
            if (query.Any())
            {
                brId = query
                        .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead))
                        .Aggregate((br1, br2) => 
                            br1.Position.DistanceTo(pline.GetClosestPointTo(br1.Position, false)) < 
                            br2.Position.DistanceTo(pline.GetClosestPointTo(br1.Position, false)) ? 
                            br1 : 
                            br2)
                        .ObjectId;
            }
            return brId;
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 11

Sgear
Advocate
Advocate

Thanks _Tharwat and _gile  for this 🙂

0 Likes
Message 5 of 11

_Tharwat
Advisor
Advisor

Excellent. You are welcome.

I am happy that I can help. Smiley Happy

0 Likes
Message 6 of 11

Sgear
Advocate
Advocate

Hi

 

when I select Polyline (2) then I select block close to Polyline (1)
how can I select block inside 5 meters from mouse click so when the block is missing inside 5 meter radius I get warning

 

Thanks

Sgear

 

      Public Sub inntext()



            Class_keep_string.popupstring = ""
            Dim Doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim ed As Editor = Doc.Editor
            Dim db As Database = Doc.Database

            Dim ent As New PromptEntityOptions(vbLf & Class_keep_string.popupstring & " Select Polyline close to Block: ")
            ent.SetRejectMessage(vbLf & "this is not Polyline !")
            ent.AddAllowedClass(GetType(Polyline), True)
            ent.AllowNone = True
            While True
                ent.Message = Class_keep_string.popupstring & vbLf & " <---  Select Polyline close to Block: "

                Dim rst As PromptEntityResult = ed.GetEntity(ent)

                If rst.Status = PromptStatus.None Then
                    Exit While
                End If

                If rst.Status <> PromptStatus.OK Then
                    Return
                End If



                '    Using trx As Transaction = db.TransactionManager.StartTransaction()
                Using tr = db.TransactionManager.StartTransaction()
                    Dim tv As TypedValue() = {New TypedValue(0, "INSERT"), New TypedValue(410, Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("CTAB"))}
                    Dim sel As PromptSelectionResult = ed.SelectAll(New SelectionFilter(tv))
                    Dim dis = 0.0
                    Dim pos As Double = 0.0
                    Dim objs As New ObjectIdCollection()
                    Dim pt As Point3d = rst.PickedPoint
                    If sel.Value Is Nothing Then
                        ed.WriteMessage(vbLf & "No block!")
                        Return
                    End If

                    For Each item As ObjectId In sel.Value.GetObjectIds()
                        Dim blk = CType(tr.GetObject(item, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead), BlockReference)
                        If blk IsNot Nothing Then
                            If objs.Count < 1 Then
                                pos = blk.Position.DistanceTo(pt)

                            End If

                            dis = blk.Position.DistanceTo(pt)
                            If dis <= pos Then
                                pos = dis
                                objs.Clear()
                                objs.Add(item)
                                ed.WriteMessage(vbLf & dis.ToString)
                                ed.WriteMessage(vbLf & pos.ToString)
                            End If
                        End If
                    Next

                    If objs.Count > 0 Then
                        Dim ids As ObjectId() = New ObjectId(objs.Count - 1) {}
                        objs.CopyTo(ids, 0)

                        Dim ent2 As Entity

                        ent2 = TryCast(tr.GetObject(objs.Item(0), Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite), Entity)

                        'If pos >= 4.19796655251786 Then

                        'Else
                        '    ent2.ColorIndex = "3"
                        'End If

                    End If
                    tr.Commit()

                End Using
            End While
            '   End Using
        End Sub

image.png

0 Likes
Message 7 of 11

_gile
Consultant
Consultant

Hi,

 

Perhaps you can get some inspiration from this method using Linq to get the closest block reference to a specified point within a distance (if any).

 

        private BlockReference SelectClosestBlockWihinRadius(Point3d center, double radius, BlockTableRecord space)
        {
            return space
                .Cast<ObjectId>()
                .Where(id => id.ObjectClass.DxfName == "INSERT")
                .Select(id => (BlockReference)id.GetObject(OpenMode.ForRead))
                .Where(br => br.Position.DistanceTo(center) < radius)
                .OrderBy(br => br.Position.DistanceTo(center))
                .FirstOrDefault();
        }

using example:

                using (var tr = db.TransactionManager.StartTransaction())
                {
                    var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);
                    var br = SelectClosestBlockWihinRadius(center, 5.0, curSpace);
                    if (br != null)
                    {
                        br.UpgradeOpen();
                        br.ColorIndex = 3;
                    }
                    tr.Commit();
                }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 8 of 11

_gile
Consultant
Consultant
Accepted solution

Imperative way:

 

        private BlockReference SelectClosestBlockWihinRadius(Point3d center, double radius, BlockTableRecord space)
        {
            BlockReference result = null;
            foreach (ObjectId id in space)
            {
                if (id.ObjectClass.DxfName == "INSERT")
                {
                    var br = (BlockReference)id.GetObject(OpenMode.ForRead);
                    double dist = br.Position.DistanceTo(center);
                    if (dist < radius)
                    {
                        result = br;
                        radius = dist;
                    }
                }
            }
            return result;
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 11

Sgear
Advocate
Advocate

Thanks

 

 

I try to use http://converter.telerik.com/ to convert to VB.NET

 

 Dim br = SelectClosestBlockWihinRadius(center, 5.0, curSpace)

 

 

'center' is not declared. It may be inaccessible due to its protection level.

 

 

Using tr = db.TransactionManager.StartTransaction()
	Dim curSpace = DirectCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead), BlockTableRecord)
	Dim br = SelectClosestBlockWihinRadius(center, 5.0, curSpace)
	If br IsNot Nothing Then
		br.UpgradeOpen()
		br.ColorIndex = 3
	End If
	tr.Commit()
End Using


Private Function SelectClosestBlockWihinRadius(center As Point3d, radius As Double, space As BlockTableRecord) As BlockReference
	Dim result As BlockReference = Nothing
	For Each id As ObjectId In space
		If id.ObjectClass.DxfName = "INSERT" Then
			Dim br = DirectCast(id.GetObject(OpenMode.ForRead), BlockReference)
			Dim dist As Double = br.Position.DistanceTo(center)
			If dist < radius Then
				result = br
				radius = dist
			End If
		End If
	Next
	Return result
End Function
0 Likes
Message 10 of 11

_gile
Consultant
Consultant

That was just one example.

'center' is the center (Point3d) of the circle in which you are looking for a block. IOW, if I understand what you are trying to do: the picked point from which you are looking for a block at 5 meters maximum.

 

EDIT:

From the code you posted:

  Dim center As Point3d = rst.PickedPoint.TransformBy(ed.CurrentCoordinateSystem)


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 11 of 11

Sgear
Advocate
Advocate

 

 

Finish to fix this and works well

 

Yes I am tray to do this "looking for a block at 5 meters maximum from Point3d."

 

 

Thanks 

 

      Dim br = SelectClosestBlockWihinRadius(rst.PickedPoint, 5.0, curSpace)

 

Regards

Sgear

 

0 Likes