Testing whether a point is inside or above an AutoCAD solid using .NET

Today's post resulted from an internal discussion: Miroslav Schonauer โ€“ with the help of Jan Liska โ€“ put together some code for a recent consulting engagement that they felt was important to share with the community. They wanted to test point containment for a particular 3D solid, but also to test whether the selected point โ€“ if outside the solid โ€“ was above it.

Selecting a point in a solid

They achieved this using AutoCAD's Brep API. Here is the C# they put together (with some minor, cosmetic edits from my side):

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.BoundaryRepresentation;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

using System;

 

namespace BrepTest

{

  public class Commands

  {

    [CommandMethod("PISO")]

    public void PointInSolid()

    {

      var doc = Application.DocumentManager.MdiActiveDocument;

      var db = doc.Database;

      var ed = doc.Editor;

 

      try

      {

        // Select Solid3d

 

        var peo = new PromptEntityOptions("\nSelect a 3D solid");

        peo.SetRejectMessage("\nMust be a 3D solid.");

        peo.AddAllowedClass(typeof(Solid3d), true);

 

        var per = ed.GetEntity(peo);

        if (per.Status != PromptStatus.OK)

          return;

 

        using (var tr = db.TransactionManager.StartTransaction())

        {

          // Open the selected Solid3d

 

          var sol = tr.GetObject(per.ObjectId, OpenMode.ForRead) as Solid3d;

          if (sol != null) // Should always be true

          {

            // Create the sub-entity path to it

 

            var ids = new ObjectId[] { per.ObjectId };

            var path =

              new FullSubentityPath(

                ids, new SubentityId(SubentityType.Null, IntPtr.Zero)

              );

 

            // Create a Brep from the path

 

            using (var brep = new Brep(path))

            {

              while (true)

              {

                // Select point

 

                var ppr = ed.GetPoint("\nSelect a point");

            
60;   if (ppr.Status != PromptStatus.OK)

                  break;

                var pt = ppr.Value;

 

                // 1) Check point containment w.r.t selected solid

 

                var pc = new PointContainment();

                using (var brepEnt = brep.GetPointContainment(pt, out pc))

                {

                  ed.WriteMessage("\nPt {0}: {1}", pt, pc);

                }

 

                // 2) If Outside, check whether the solid is "below":

 

                if (pc == PointContainment.Outside)

                {

                  // Fire a -Z Ray from the point to find if it hits the Brep

 

                  var ray = new Ray3d(pt, -Vector3d.ZAxis);

                  var hits = brep.GetLineContainment(ray, 1);

 

                  if (hits == null || hits.Length == 0)

                  {

                    ed.WriteMessage("\nSolid is NOT below point.");

                  }

                  else

                  {

                    ed.WriteMessage(

                      "\nSolid IS below point, distance = {0}",

                      pt.DistanceTo(hits[0].Point)

                    );

                  }

                }

              }

            }

          }

          tr.Commit();

        }

      }

      catch (System.Exception ex)

      {

        ed.WriteMessage("Error: {0}\r\n at {1}", ex.Message, ex.StackTrace);

      }

    }

  }

}

 

To give it a try, just run the PISO command (for PointInSolid), then select a Solid3d and start picking points. You'll see on the application report via the command-line whether the selected point is contained within the solids and, if not, whether the point is above it (i.e. that the solid is below the point).

A big thanks to Miro & Jan for sharing this useful code! ๐Ÿ™‚

6 responses to “Testing whether a point is inside or above an AutoCAD solid using .NET”

  1. Hi Kean,
    the algorithm of firing a -Z Ray is not correct if the solid has a concav vertical section...meaning that the solid has a "cave" in 3D sense ! Any point within this cave will be regognized as beiing above the solid although there is a part of solid above it ...!
    A possible solution could be to fire additionally a +Z Ray and make sure there aren't any hit points above the selected point...
    See the attached image, the yellow point fails , the green is correct

    1. Kean Walmsley Avatar

      Hi Konstantin,

      Good point... I dare say this implementation was intended to handle certain types of geometry (probably buildings, but I could be wrong) where this wasn't an issue.

      I'll pass this on to Miro, in case, and think about whether it makes sense to update the post.

      Regards,

      Kean

    2. good pick up i hadn't noticed. and that solutions sounds about right!
      rgds
      Ben

  2. Hi Kean,

    Hello,

    Is there is change in intersectWith function in ACAD 2015 my code work with Object arx 2014 but in 2015 it returns false.

    Below is sample command to get intersection

    static void CheckIntersection()

    {

    double m_DH = 2000.0;

    AcGePoint3d org(0,0,0);

    AcGeVector3d m_xAxis(1,0,0);

    AcGeCylinder cylA(m_DH/2, org, m_xAxis);

    AcGeLineSeg3d intLine;

    AcGePoint3d pt1(0.52257073158706313,10.637171608585087,-1000.0000000000000);

    AcGePoint3d pt2(0.52257073158700185,10.637171608585087,0.00000000000000000);

    intLine.set(pt1, pt2);

    int nrInt;

    AcGePoint3d p3, p4;

    //AcGeTol TOL;

    //TOL.setEqualPoint(1.1);

    //TOL.setEqualVector(1.1);

    Adesk::Boolean stat = cylA.intersectWith(intLine, nrInt, p3, p4);

    if(stat == Adesk::kTrue)

    {

    ads_printf(L"cylA.intersectWith successfull");

    }

    else

    {

    ads_printf(L"cylA.intersectWith FAIL");

    }

    }

    here in 2014 arx ylA.intersectWith returns true and in 2015 it returns false.

    Please help...

    Regards,
    Dhanraj

    1. Hi Dhanraj,

      There may well have been a change, but I'm not aware of it. Please submit this through normal channels, whether by sending it to ADN or posting to the discussion group (I really don't have time to provide support).

      Regards,

      Kean

      1. Ok, Thanks Kean, yep already posted in discussion group waiting for answer..

Leave a Reply to Kean Walmsley Cancel reply

Your email address will not be published. Required fields are marked *