Hi
I'd like to determine when a user selects a point in model space if it is within a hatched area.
I started to a look at using the Editor's SelectCrossingWindow but if you zoom in and select a point in between a graphical elements nothing is selected.
Please can someone suggest how to do this?
Thanks
Craig
Solved! Go to Solution.
Solved by Hallex. Go to Solution.
Don't know if this help, anyway try it on your end
I've used SinglePickInSpace option to select hatch
and return boundary coordinates
[CommandMethod("ssh", CommandFlags.UsePickSet)] public void testHatchSelection() { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; Matrix3d ucs=ed.CurrentUserCoordinateSystem; PromptSelectionOptions pso = new PromptSelectionOptions(); pso.MessageForRemoval = "\nNothig selected"; pso.MessageForAdding = "\nSelect hatch"; pso.ForceSubSelections = false; pso.SelectEverythingInAperture = true; pso.SingleOnly = true; pso.SinglePickInSpace = true; SelectionFilter filt = new SelectionFilter(new TypedValue[]{ new TypedValue(0,"hatch")}); PromptSelectionResult res = ed.GetSelection(pso, filt); Transaction tr = doc.TransactionManager.StartTransaction(); using (tr) { BlockTable bt = (BlockTable)tr.GetObject(doc.Database.BlockTableId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); if (res.Status != PromptStatus.OK) { Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("nothing selected"); return; } SelectionSet sset = res.Value; foreach (SelectedObject sobj in sset) { Entity ent = (Entity)tr.GetObject(sobj.ObjectId, OpenMode.ForRead); if (ent != null) { Point3dCollection pts = new Point3dCollection(); Hatch hth = ent as Hatch; if (hth.GetLoopAt(0).IsPolyline) { BulgeVertexCollection bulges = hth.GetLoopAt(0).Polyline;// as Polyline; double zc = hth.Elevation; int i = 0; for (i = 0; i < bulges.Count; i++) { BulgeVertex bulg = bulges[i]; Point2d pt = bulg.Vertex; pts.Add(new Point3d(pt.X, pt.Y, zc).TransformBy(ucs)); } } PromptSelectionResult wres = ed.SelectWindowPolygon(pts); if (wres.Status != PromptStatus.OK) { Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog("nothing inside the hatch"); return; } //rest your code here SelectionSet wset = wres.Value; foreach (SelectedObject wobj in wset) { Entity went = (Entity)tr.GetObject(wobj.ObjectId, OpenMode.ForRead); if (went != null) { ed.WriteMessage("\nFound object: {0}\n" + went.GetRXClass().DxfName); } } } } tr.Commit(); } }
Hi
Thanks for the reply. There are some functions in the code that I haven't used before so I will need to familiarise myself with them.
It almost does the reverse of what I would like to achieve. What I want to be able to answer is when a point is selected, is it within the area that is hatched. In the image below, the pointer is within the area covered by the hatch but the hatch would not be selected because there appears to be no graphical element associated with the hatch below the pointer.
Hi,
I think I got a way using a MPolygon.
MPolygon is an AutoCAD MAP object but it also available in Vanilla AutoCAD.
To use it from .NET, then the project need to reference the AcMPolygonMGD.dll and it is required to load the object enabler AcMPolygonObjXX.dbx into AutoCAD prior to using MPolygon functions. Both files can be found in AutoCAD's install folder.
The MPolygon object is quite close to a Hatch an have a IsPointInsideMPolygon() method.
The method returns an IntegerCollection which is empty if the point is outside and contains the loops indices (may be several because MPolygon allows crossing loops).
It's quite easy to create a MPolygon from a Hatch but with some restrictions: as Polylines MPolygons can only be composed of arcs an line segments.
If the hatch contains more than one loop, it may be difficult to evaluate if the point is inside the hatch according to the HatchStyle (mainly with HatchStyle.Normal) and/or with non-separated hatches.
Anyway, here's a little sample to start:
// (C) Copyright 2012 by Gilles Chanteau // using System; using System.Collections.Generic; using System.Linq; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.EditorInput; using AcAp = Autodesk.AutoCAD.ApplicationServices.Application; using AcRx = Autodesk.AutoCAD.Runtime; namespace MPolygonSample { public class CommandMethods : IExtensionApplication { public void Initialize() { AcRx.SystemObjects.DynamicLinker.LoadModule( "AcMPolygonObj" + AcAp.Version.Major + ".dbx", false, false); } public void Terminate() { } [CommandMethod("Test", CommandFlags.Modal)] public void Test() { Document doc = AcAp.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nSelect a hatch: "); peo.SetRejectMessage("Only a hatch."); peo.AddAllowedClass(typeof(Hatch), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { Hatch hatch = (Hatch)tr.GetObject(per.ObjectId, OpenMode.ForRead); try { using (MPolygon mpolygon = HatchToMpolygon(hatch)) { while (true) { PromptPointOptions opts = new PromptPointOptions("\nSpecify a point: "); opts.AllowNone = true; PromptPointResult ppr = ed.GetPoint(opts); if (ppr.Status != PromptStatus.OK) break; Point3d pt = ppr.Value.TransformBy(ed.CurrentUserCoordinateSystem); IntegerCollection ints = mpolygon.IsPointInsideMPolygon(pt, 1e-9); string msg; if (ints.Count == 0) msg = "Outside"; else if (ints[0] == 0) msg = "Inside"; else switch (ints[0]) { case 1: msg = "Inside the 1st inner loop"; break; case 2: msg = "Inside the 2nd inner loop"; break; case 3: msg = "Inside the 3rd inner loop"; break; default: msg = "Inside the " + ints[0] + "th inner loop"; break; } AcAp.ShowAlertDialog(msg); } } } catch (System.Exception ex) { ed.WriteMessage("\nError: " + ex.Message); } tr.Commit(); } } private MPolygon HatchToMpolygon(Hatch hatch) { MPolygon mpolygon = new MPolygon(); mpolygon.Elevation = hatch.Elevation; mpolygon.Normal = hatch.Normal; for (int i = 0; i < hatch.NumberOfLoops; i++) { BulgeVertexCollection bulges = hatch.GetLoopAt(i).Polyline; if (bulges == null) throw new InvalidOperationException("Unable to create a MPolygon"); MPolygonLoop loop = new MPolygonLoop(); foreach (BulgeVertex bulge in bulges) { loop.Add(bulge); } mpolygon.AppendMPolygonLoop(loop, true, 1e-9); } mpolygon.BalanceTree(); return mpolygon; } } }
Found im my codes
<CommandMethod("ph")> _ Public Sub pickHatch() Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim ed As Editor = doc.Editor Dim db As Database = doc.Database Dim ppo As New PromptPointOptions(vbLf & "Pick a Point: ") Dim ppr As PromptPointResult ppr = ed.GetPoint(ppo) If ppr.Status <> PromptStatus.OK Then ed.WriteMessage(vbCrLf & "Wrong point specification!") Exit Sub End If Dim p As Point3d = ppr.Value Dim fuzz As Double = 5 '<-- change fuzz to suit '------------------------------------------------------------'' Dim vd As Vector3d = New Vector3d(fuzz, fuzz * 1.1, 0) '<-- change fuzz to suit (1.1 - to rotate fence) Dim pMin As Point3d = p - vd Dim pMax As Point3d = p + vd Dim tvs() As TypedValue = New TypedValue() {New TypedValue(0, "hatch")} Dim points As Point3dCollection = New Point3dCollection points.Add(pMin) points.Add(pMax) Dim sf As SelectionFilter = New SelectionFilter(tvs) Dim sres As PromptSelectionResult = ed.SelectFence(points, sf) If sres.Status <> PromptStatus.OK Then ed.WriteMessage("\nWrong selection!") Return End If If sres.Value.Count = 0 Then ed.WriteMessage("\nNothing selected!") Return End If ''-----------------------------------------------------------'' Using tr As Transaction = db.TransactionManager.StartTransaction() '' cast entity as Hatch Dim eid As ObjectId = sres.Value.GetObjectIds(0) Dim ent As Entity = TryCast(tr.GetObject(eid, OpenMode.ForRead), Entity) ''-----------------------------------------------------------'' Dim ht As Hatch = TryCast(ent, Hatch) If ht IsNot Nothing Then Dim pts As Point3dCollection = New Point3dCollection ht.GetStretchPoints(pts) ed.WriteMessage(vbLf + "Selected: {0} object" + vbLf + "center point: {1:f3},{2:f3},{3:f3}", ent.GetRXClass().DxfName, pts(0).X, pts(0).Y, pts(0).Z) End If ''-------------------- rest your work here ----------------'' tr.Commit() End Using End Sub
You can use Editor.GetPoint followed by a call to Editor.TraceBoundary.
Take a look at the help files for more details about that method.
Regards,
Philippe.
What do you mean it doesn't work? In the following recording, I am creating an hatch with very spaced lines, so I'm sure not to pick one, then I use the following code to find out if the selected point is inside a boundary.
Seems to work fine to me, let me know if I am missing something...
http://screencast.com/t/nhZOw7IZx
[CommandMethod("TraceBoundaryNet")] static public void TraceBoundaryNet() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptPointOptions ppo = new PromptPointOptions("\nSelect seed point: "); PromptPointResult ppr = ed.GetPoint(ppo); if(ppr.Status != PromptStatus.OK) return; PromptKeywordOptions pko = new PromptKeywordOptions("\nDraw clip boundary?"); pko.AllowNone = false; pko.Keywords.Add("Yes"); pko.Keywords.Add("No"); pko.Keywords.Default = "Yes"; PromptResult pkr = ed.GetKeywords(pko); if (pkr.Status != PromptStatus.OK) return; using (Transaction tr = doc.TransactionManager.StartTransaction()) { DBObjectCollection dbo = ed.TraceBoundary( ppr.Value, (pkr.StringResult == "Yes" ? true : false)); if (dbo != null) { BlockTableRecord btr = tr.GetObject( db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord; foreach (DBObject obj in dbo) { Entity entity = obj as Entity; entity.ColorIndex = 1; btr.AppendEntity(entity); tr.AddNewlyCreatedDBObject(obj, true); } } tr.Commit(); } }
Philippe.
I confirm, your code is working nice in A2014
Thanks, Philippe
Good luck 🙂
Yes the TraceBoundary code does work and I did look at the help files and I did try it. It drew a nice polyline around my hatch but didn't help me select the hatch, which is what I need to do. Sorry but I've had to unmark the original 'solution' as the solution.
The pickHatch works better and I will experiment with that futher with the hatch patterns we are going to use.
Thanks for all your help.