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

Select object inside a polyline

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
J-Rocks
5392 Views, 10 Replies

Select object inside a polyline

Hi,

 

I am trying to select Lines and Circles that reside inside a polyline but I failed , can anyone point me to the error in my codes please?

Is there any other way than highlight method to select objects as if you are selecting them in Autocad ? I mean selection with grips .

 

Thanks in advance.

 

        public static void HighLightObjects()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
          
            PromptEntityOptions sel = new PromptEntityOptions("\nSelect Polyline :");
            sel.SetRejectMessage("Must be Polyline");
            sel.AddAllowedClass(typeof(Polyline), true);
            sel.AllowNone = false;
            PromptEntityResult s = ed.GetEntity(sel);
            if (s.Status == PromptStatus.OK)
            {
                using (Transaction trans = db.TransactionManager.StartTransaction())
                {
                    try
                    {
                        Polyline pl = (Polyline)trans.GetObject(s.ObjectId, OpenMode.ForRead);
                        Double len = pl.Length;
                        Double dis = len / 250;
                        Double gap = dis;
                        int run = ((int)dis);
                        Point3dCollection lst = new Point3dCollection();
                        lst.Add(pl.GetPointAtParameter(0));
                        for (int i = 0; i < run; i++)
                        {
                            Point3d p = pl.GetPointAtDist(dis);
                            dis = dis + gap;
                            lst.Add(p);
                        }
                        PromptSelectionOptions ss = new PromptSelectionOptions();
                        TypedValue[] tv = { new TypedValue(0, "CIRCLE"), new TypedValue (0 , "LINE") };
                        SelectionFilter ftr = new SelectionFilter(tv);
                        PromptSelectionResult res = ed.SelectCrossingPolygon(lst, ftr);
                        if (res.Status == PromptStatus.OK)
                        {
                            foreach (var item in res.Value.GetObjectIds())
                            {
                                Entity c = (Entity)trans.GetObject(item, OpenMode.ForRead);
                                c.Highlight();
                            }
                        }
                    }
                    catch (System.Exception ex)
                    {
                        ed.WriteMessage(ex.Message);
                    }                   
                }
            }
        }

 

10 REPLIES 10
Message 2 of 11
SENL1362
in reply to: J-Rocks

Are you trying to get objects (completely) inside a closed polyline, using somesort of offset? Why not then offset the Selected Polyline and then using the build in Selection Methodes? Becarefull with selecting objects not on screen.
Or do you want you're own algorithm to select inside (2D) polylines.
There have been posted several samples to do that, using just plan C code and using AutoCAD functions, such as with the help of Regional Objects.


Message 3 of 11
J-Rocks
in reply to: SENL1362

Hi,

 

I am Trying to select all Lines and Circles inside a polyline by selecting the Polyline only.

Yes the objects are inside the selected polyline.

 

Thank you.

Message 4 of 11
SENL1362
in reply to: J-Rocks

Youre problem is the Selection Filter:

TypedValue[] tv = { new TypedValue(0, "CIRCLE"), new TypedValue(0, "LINE") };

Instead use: 

TypedValue[] tv = { new TypedValue(0, "CIRCLE, LINE") };   //, new TypedValue(0, "LINE") };

 Or use the AND and OR items to build a complex Filter, like explained by Kean:

http://through-the-interface.typepad.com/through_the_interface/2008/07/conditional-sel.html

 

 

 

       [CommandMethod("SIP")]
        public static void SelectInsidePolyline()
        {
            Document doc = null;
            Database db = null;
            Editor ed = null;

            double plOffset = 10;

            try
            {
                doc = AcadApp.DocumentManager.MdiActiveDocument;
                if (doc == null)
                    throw new System.Exception("No MdiActiveDocument");
                db = doc.Database;
                ed = doc.Editor;


                TypedValue[] plTv = new TypedValue[] { new TypedValue(0, "LWPOLYLINE") };
                SelectionFilter plFlt = new SelectionFilter(plTv);
                PromptSelectionResult plSr = ed.GetSelection(plFlt);
                if (plSr.Status != PromptStatus.OK)
                    return;


                Point3dCollection polyPoints = null;
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    foreach (SelectedObject obj in plSr.Value)
                    {
                        var pl = tr.GetObject(obj.ObjectId, OpenMode.ForRead) as Polyline;

                        
                        var offsetObjs = pl.GetOffsetCurves(plOffset);
                        var offPl = offsetObjs[0] as Polyline;
                        if (offPl.Area < pl.Area)
                        {
                            offPl.Erase();
                            offsetObjs = pl.GetOffsetCurves(-plOffset);
                        }

                        curSpace.AppendEntity(offPl);
                        tr.AddNewlyCreatedDBObject(offPl, true);

                        polyPoints = new Point3dCollection();
                        for (int i = 0; i < offPl.NumberOfVertices; i++)
                            polyPoints.Add(offPl.GetPoint3dAt(i));

                    }
                    tr.Commit();
                }
                if (polyPoints == null)
                    throw new System.Exception("Failed to calculate Polyline Points");

                PromptSelectionOptions ss = new PromptSelectionOptions();
                TypedValue[] tv = { new TypedValue(0, "CIRCLE"), new TypedValue(0, "LINE") };
                SelectionFilter ftr = new SelectionFilter(tv);
                PromptSelectionResult res = ed.SelectCrossingPolygon(polyPoints); //, ftr);
                if (res.Status != PromptStatus.OK)
                    return;
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead);

                    foreach (var item in res.Value.GetObjectIds())
                    {
                        Entity c = (Entity)tr.GetObject(item, OpenMode.ForRead);

                        c.Highlight();
                    }
                    tr.Commit();
                }

            }
            catch (System.Exception ex)
            {
                if (ed != null)
                    ed.WriteMessage("\n Error in SelectInsidePolyline: {0}", ex.Message);
            }
        }

 

But be careful wil the ed.selectXXX functions because if the Selected Polyline is not completely visible the Inside Selection may not be complete.

Screenshot_2.png

 

 

And the Result is:

Screenshot_1.png

 

 

 

Message 5 of 11
J-Rocks
in reply to: SENL1362

I am sorry that doesn't work and not what I wanted.

 

Your program makes an offset of the selected polyline then it selected EVERYTHING .

 

Thank you.

Message 6 of 11
SENL1362
in reply to: J-Rocks


You can use youre own code, just change the second filter into
TypedValue[] tv = { new TypedValue(0, "CIRCLE, LINE") };

You can use my code and filter on Circles and Lines if you add the filter to the Selection methode:

change:

PromptSelectionResult res = ed.SelectCrossingPolygon(polyPoints); //, ftr);
into:
PromptSelectionResult res = ed.SelectCrossingPolygon(polyPoints, ftr);
and it will select Circles and lines within the polyline.
If you do not want the Offset Polyline, then remove that part of the code and use the vertice points of the original selected polyline.

Its that easy.

Message 7 of 11
_gile
in reply to: SENL1362

Hi,

 

You can try the following Editor.SelectByPolyline() extension method.

Add the below class to your project.

 

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;

namespace Autodesk.AutoCAD.EditorInput
{
    public enum PolygonSelectionMode { Crossing, Window }

    public static class EditorExtension
    {
        public static PromptSelectionResult SelectByPolyline(this Editor ed, Polyline pline, PolygonSelectionMode mode, params TypedValue[] filter)
        {
            Point3dCollection polygon = new Point3dCollection();
            for (int i = 0; i < pline.NumberOfVertices; i++)
            {
                polygon.Add(pline.GetPoint3dAt(i));
            }
            PromptSelectionResult result;
            ViewTableRecord view = ed.GetCurrentView();
            ed.Zoom(pline.GeometricExtents);
            if (mode == PolygonSelectionMode.Crossing)
                result = ed.SelectCrossingPolygon(polygon, new SelectionFilter(filter));
            else
                result = ed.SelectWindowPolygon(polygon, new SelectionFilter(filter));
            ed.SetCurrentView(view);
            return result;
        }

        public static void Zoom(this Editor ed, Extents3d extents)
        {
            using (ViewTableRecord view = ed.GetCurrentView())
            {
                Matrix3d worldToEye =
                    Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) *
                    Matrix3d.Displacement(view.Target - Point3d.Origin) *
                    Matrix3d.PlaneToWorld(view.ViewDirection)
                    .Inverse();
                extents.TransformBy(worldToEye);
                view.Width = extents.MaxPoint.X - extents.MinPoint.X;
                view.Height = extents.MaxPoint.Y - extents.MinPoint.Y;
                view.CenterPoint = new Point2d(
                    (extents.MaxPoint.X + extents.MinPoint.X) / 2.0,
                    (extents.MaxPoint.Y + extents.MinPoint.Y) / 2.0);
                ed.SetCurrentView(view);
            }
        }
    }
}

 

Then you can call the Editor.SelectByPolyline() as an Editor instance method.

It requires as parameters:

- a polyline instance

- a PolygonSelectionMode instance (Crossing or Window)

- optionally, one or more TypedValue instance(s) as selection filter

 

 

Here's a command example which does what I understand you're trying to do.

All the magic is here:

PromptSelectionResult selection = 
    ed.SelectByPolyline(pline, PolygonSelectionMode.Window, new TypedValue(0, "CIRCLE,LINE"));

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(SelectInsidePolygonSample.Commands))]

namespace SelectInsidePolygonSample
{
    public class Commands
    {
        [CommandMethod("CMD1")]
        public void Cmd1()
        {
            Document doc = AcAp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            var options = new PromptEntityOptions("\nSelect polyline: ");
            options.SetRejectMessage("\nMust be a polyline.");
            options.AddAllowedClass(typeof(Polyline), true);
            var result = ed.GetEntity(options);
            if (result.Status != PromptStatus.OK) return;

            using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                Polyline pline = (Polyline)tr.GetObject(result.ObjectId, OpenMode.ForRead);
                PromptSelectionResult selection = 
ed.SelectByPolyline(pline, PolygonSelectionMode.Window, new TypedValue(0, "CIRCLE,LINE")); if (selection.Status == PromptStatus.OK) ed.SetImpliedSelection(selection.Value); tr.Commit(); } } } }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 of 11
J-Rocks
in reply to: _gile

Thank you gile.

 

That works great if the polyline doesn't have an arc segment and Circle,Line do not reside in that arc's area , and that's why I intended to use getpointatdist method to avoid missing objects in arc segment if are there.

 

I modified my codes that I posted in the first post and revised the filter to be as recommended by SENL like below without any luck

.

TypedValue[] tv = { new TypedValue(0, "CIRCLE,LINE") };

Can you please tell me why my below codes does not work or what cause the program not to work propeply?

 

ed.SelectCrossingPolygon(lst, ftr);

 Thank you

Message 9 of 11
_gile
in reply to: J-Rocks

It seems to me you're confusing distances (gap, dis) and number of iterations (run)

 

Double len = pl.Length;
Double dis = len / 250;
Double gap = dis;
int run = ((int)dis);

run should be equal to 250 (plus or minus 1 according to the way you use it).



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 10 of 11
J-Rocks
in reply to: _gile

That's it , thank you.

Message 11 of 11
SENL1362
in reply to: J-Rocks

A nice article describing the iteration over a polyline(curve), like DIVIDE.
Use it to generate the selection points over the arc segments.
http://through-the-interface.typepad.com/through_the_interface/2009/12/faceting-autocad-curves-using...

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