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

How to determine if a point is within a hatch's area

11 REPLIES 11
SOLVED
Reply
Message 1 of 12
cnicholas
3378 Views, 11 Replies

How to determine if a point is within a hatch's area

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

11 REPLIES 11
Message 2 of 12
Hallex
in reply to: cnicholas

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();


            }
        }

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 3 of 12
cnicholas
in reply to: cnicholas

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.

hatch.jpg

Message 4 of 12
Hallex
in reply to: cnicholas

Don't know ith helps, see article here
about TraceBoundary function:
http://through-the-interface.typepad.com/through_the_interface/2014/02/striking-an-enclosed-text-are...
_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 5 of 12
cnicholas
in reply to: Hallex

Perhaps it can be dealt with at a higher level in the way I am using AutoCAD to pick the hatch. If the hatch pattern is solid, I am always able to select the hatch. If the hatch pattern is made up of lines as in the image, I have to click one of the hatch pattern lines to select it. Is there a way to create a selection set that includes 'the nearest' to the selected point?
Message 6 of 12
_gile
in reply to: cnicholas

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;
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 12
Hallex
in reply to: cnicholas

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

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 8 of 12
philippe.leefsma
in reply to: Hallex

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.



Philippe Leefsma
Developer Technical Services
Autodesk Developer Network

Message 9 of 12
Hallex
in reply to: philippe.leefsma

Thanks, Philippe,I'd already tested this method, it didn't work
If you're pick a point between the hatch lines
Have a nice day 🙂
_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 10 of 12
philippe.leefsma
in reply to: Hallex

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.



Philippe Leefsma
Developer Technical Services
Autodesk Developer Network

Message 11 of 12
Hallex
in reply to: philippe.leefsma

I confirm, your code is working nice in A2014

Thanks, Philippe

Good luck 🙂

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 12 of 12
cnicholas
in reply to: Hallex

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.

 

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