Hello,
I need to know if a point is into a polygon, developing in VB.NET fro Autocad 2010.
Is this possible? Or is any method to do something similar?
Thanks!
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Solved by _gile. Go to Solution.
Hi,
You can use a MPolygon, a MAP entity which is also available in vanilla while the AcMPolygonObj##.dbx module is loaded.
In your project, you'll also have to add a reference to the AcMPolygonMGD.dll (you'll find it in the AutoCAD installation folder.
Here's a little sample with a testing command, it implements IExtensionApplication interface to load the module at startup.
using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; namespace PointInside { public class CommandMethods : IExtensionApplication { public void Initialize() { SystemObjects.DynamicLinker.LoadModule( "AcMPolygonObj" + Application.Version.Major + ".dbx", false, false); } public void Terminate() { } private bool IsPointInside(Point3d point, Polyline pline) { double tolerance = Tolerance.Global.EqualPoint; using (MPolygon mpg = new MPolygon()) { mpg.AppendLoopFromBoundary(pline, true, tolerance); return mpg.IsPointInsideMPolygon(point, tolerance).Count == 1; } } [CommandMethod("Test")] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nSelect a polyline: "); peo.SetRejectMessage("Only a polyline !"); peo.AddAllowedClass(typeof(Polyline), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction()) { Polyline pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForRead); PromptPointOptions ppo = new PromptPointOptions("\nPick a point <quit>: "); ppo.AllowNone = true; while (true) { PromptPointResult ppr = ed.GetPoint(ppo); if (ppr.Status != PromptStatus.OK) break; Application.ShowAlertDialog( IsPointInside(ppr.Value, pline) ? "Inside" : "Outside"); } } } } }
Thanks Gilles!
I am testing your code, and it crashes in method "IsPointInside" when trying to create the MPolygon object. Exception throws this message:
"Se produjo una excepción de tipo 'System.IO.FileLoadException' en AcMPolygonMGD.dll pero no se controló en el código del usuario
Información adicional: acmpolygonobj18d.dbx"
What is the problem?
Hi,
There are many ways to test if a point it's inside a polygon, the more direct from the API is editor.TraceBoundary(TestPoint) it returns a dbObjectCollection, if empty the point it's outside, otherwise you have your point.
Also this link may help : Containment
Gaston Nunez
Oh yes, I remember now.
There's a bug in the AutoCad 2010 version of AcMPolygonMGD.dll which tries to load AcMPolygonObj18d.dll instead of AcMPolygonObj18.dll (AFAIK this bug haven't been fixed for this version).
As Gaston said, you can use the Editor.TraceBoundary() method or use the boundary representation API (Brep) as shown by Tony Tanzillo in the link Gaston provided.
So, you can try the Brep route as shown by Tony Tanzillo here (you have to add reference to acdbmgdbrep.dll and Import Autodesk.AutoCAD.BoundaryRepresentation namespace).
Here's a little example largely inspired by Tony's one which works with polylines on AutoCAD 2010.
[CommandMethod("TEST")] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nSelect a polyline: "); peo.SetRejectMessage("Only a polyline !"); peo.AddAllowedClass(typeof(Polyline), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction()) { Polyline pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForRead); if (!pline.Closed) { ed.WriteMessage("\nPolyline must be closed."); return; } DBObjectCollection curves = new DBObjectCollection(); curves.Add(pline); try { using (DBObjectCollection regions = Region.CreateFromCurves(curves)) using (Region region = (Region)regions[0]) { PromptPointOptions ppo = new PromptPointOptions("\nPick a point <quit>: "); ppo.AllowNone = true; while (true) { PromptPointResult ppr = ed.GetPoint(ppo); if (ppr.Status != PromptStatus.OK) break; Application.ShowAlertDialog( GetPointContainment(region, ppr.Value).ToString()); } } } catch (System.Exception exn) { ed.WriteMessage("\nError: " + exn.Message); } } } private PointContainment GetPointContainment(Region region, Point3d point) { PointContainment result = PointContainment.Outside; using (Brep brep = new Brep(region)) { if (brep != null) { using (BrepEntity ent = brep.GetPointContainment(point, out result)) { if (ent is Autodesk.AutoCAD.BoundaryRepresentation.Face) { result = PointContainment.Inside; } } } } return result; }
Thanks Gilles!
It works! Now, I have to make some changes to work as I want. First of all, do you know how can I select a polyline from my dwg without user interaction?
Hi,
You can use Editor.SelectAll() method with an appropriate selection filter or iterate through the entities contained in the model space (and/or paper spaces) to look for polylines.
If you want to select a particular polyline, you'd have to check for some particularity (geometry, xdata, ...) of this polyline.
Hi Giles
Thank you for your time.
i wrote polyline instead of polygon mistakenly in the title, sorry for that.
I tried the two ways, they work fine with normal polyline. i tried to use the code with polygone but it reads the polygon as a polyline>
Also tried to convert the polygon to a polyline but i failed.
My problem exactly that i need to search for BlockReferences or polygons on PS or MS, then find any Text (Inside) the block or (Inside) the polygon.
The BlockReferences option is my favourite, but it is not necessary.
Any help please.
Thanks.
Can't find what you're looking for? Ask the community or share your knowledge.