Author Topic: PointMonitor troubles  (Read 8271 times)

0 Members and 1 Guest are viewing this topic.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: PointMonitor troubles
« Reply #15 on: August 05, 2014, 09:51:33 AM »
Thanks, gile, nice code! I just wish I could understand how it can help with this particular task.

Luis, I'll get a drawing for you later today. Must get ready for work and head to the office now.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: PointMonitor troubles
« Reply #16 on: August 05, 2014, 10:41:14 AM »
Here is a drawing created from the extracted polylines which define the boundaries of the Corridor Regions. As you can see there are not all that many (107) polylines, but they vary greatly in size and shape.

LE3

  • Guest
Re: PointMonitor troubles
« Reply #17 on: August 05, 2014, 11:20:23 AM »
I just tested and yes, it blinks the cursor, I was able to highlight some of the areas, but some not. Also, noticed that these areas are made of tons of points, so guess we need a more efficient is inside point method and a form to do a better arrangement of closed areas and points to use. This goes more into the use of a kd-tree -- on my closed polygon custom object, that can have internal loops and big areas that form the object, maybe like these entities, where the user can pass the cursor and each of these areas that form the closed polygon are highlighted (via a solid hatch, and different color depending on the type of area)... anyway if I can will give it a try later today -- but at least we know what works or not.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: PointMonitor troubles
« Reply #18 on: August 05, 2014, 12:21:46 PM »
Maybe I am not understanding but are looping through all the polylines to see if you are inside one, and are all of these polylines closed?

If so...
Could you use a combination of GetPickedEntities(to see entities are being hovered over) and Raw Point?
-Use GetPickedEntities to see when your mouse moves over a polyline
-check to see if next point is inside that one polyline
-If inside store id of polyline and highlight then check GetPickedEntities for id o see if next point mouse moved out or stayed inside.


Maybe one way to see if they are using same or similar approach is to sling mouse as fast as possible to see if you can find hiccups where they are getting optimizations?

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: PointMonitor troubles
« Reply #19 on: August 05, 2014, 12:58:39 PM »
Yes, Jeff, until Luis suggested his approach at minimizing the number of polylines to loop through. And yes, they are all closed polylines. But the GetPickedEntities won't work because the polylines are not Database resident, they are merely temporary objects created for the sole use in the TransientGraphics display

LE3

  • Guest
Re: PointMonitor troubles
« Reply #20 on: August 05, 2014, 05:04:54 PM »
See if this works, I tested here and all runs fine.

I changed the IsPointInside with the use of Brep:
Code - C#: [Select]
  1.         public static Boolean IsPointInside(Point3d internalPoint, ObjectId objid)
  2.         {
  3.             using (var transaction = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
  4.             {
  5.                 var polyline = transaction.GetObject(objid, OpenMode.ForRead, false) as Polyline;
  6.                 if (polyline != null)
  7.                 {
  8.                     var curves = new DBObjectCollection { polyline };
  9.                     using (var regions = Region.CreateFromCurves(curves))
  10.                     {
  11.                         if (regions != null && regions.Count == 1)
  12.                         {
  13.                             var region = regions.Cast<Region>().First();
  14.                             using (region)
  15.                             {
  16.                                 using (var brep = new Brep(region))
  17.                                 {
  18.                                     PointContainment ptContainment;
  19.                                     using (brep.GetPointContainment(internalPoint, out ptContainment))
  20.                                     {
  21.                                         return ptContainment == PointContainment.Inside ||
  22.                                                ptContainment == PointContainment.OnBoundary;
  23.                                     }
  24.                                 }
  25.                             }
  26.                         }
  27.                     }
  28.                 }
  29.                 transaction.Commit();
  30.             }
  31.             return false;
  32.         }
  33.  

And with this new method, I can do the highlight of any of the areas on your drawing Jeff.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: PointMonitor troubles
« Reply #21 on: August 05, 2014, 05:11:28 PM »
Interesting usage of using statements Luis.
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: PointMonitor troubles
« Reply #22 on: August 05, 2014, 05:33:36 PM »
Luis, that is essentially identical code to what I was using when I started this thread. And was what I have determined to be the bottleneck. I created an extension method for regions thusly:
Code - C#: [Select]
  1.         public static bool IsPointInside(this Region region, Point3d pt)
  2.         {
  3.             bool retval = false;
  4.             PointContainment contain= PointContainment.Outside;
  5.             using (Brep brep = new Brep(region))
  6.             {
  7.                 if(brep!=null)
  8.                 {
  9.                     using(BrepEntity ent = brep.GetPointContainment(pt, out contain))
  10.                     {
  11.                         if (ent is Autodesk.AutoCAD.BoundaryRepresentation.Face)
  12.                         {
  13.                             retval = true;
  14.                         }
  15.                     }
  16.                 }
  17.             }
  18.             return retval;
  19.         }
  20.  
and another extension method to convert the polylines to regions:
Code - C#: [Select]
  1.         public static bool IsPointInside(this Curve crv, Point3d pt)
  2.         {
  3.             bool retval = false;
  4.             using (DBObjectCollection objCol = new DBObjectCollection())
  5.             {
  6.                 objCol.Add(crv);
  7.                 using (DBObjectCollection dbObjColl = Region.CreateFromCurves(objCol))
  8.                 {
  9.                     using (Region region = dbObjColl.Cast<Region>().First())
  10.                     {
  11.                         retval = region.IsPointInside(pt);
  12.                     }
  13.                 }
  14.             }
  15.             return retval;
  16.         }
  17.  

I've now tested with the old "cast a Ray and if it crosses the pline an odd # of times then the point lies inside the polygon" method and it is working quickly and only throws a hiccup about 0.2% of the time (I think this is when the ray passes through a single point on one of the other polylines). But this is every bit as fast as the native 3D selection process.

But now I'm confused as to why your implementation of the same code I was using is working ok for you, yet it was dreadfully slow for me.

LE3

  • Guest
Re: PointMonitor troubles
« Reply #23 on: August 05, 2014, 05:46:34 PM »
I tried also with the faces array and got some bad issues, so end up avoiding that approach, so that's why I jumped into the region point containment, I think Tony posted something some time ago here and also on the devblog of autodesk there are some sample usage of this too.

I think that could be a good idea if I post the whole solution on show your stuff section (is there now url link on one of my post after this one below...).
« Last Edit: August 05, 2014, 06:10:14 PM by LE »

LE3

  • Guest
Re: PointMonitor troubles
« Reply #24 on: August 05, 2014, 05:50:52 PM »
Interesting usage of using statements Luis.
Thanks, Kerry --- end up adding all of them, since the check for null did not work et-al --- this is a good exercise to go back into doing something for an autocad command :)

LE3

  • Guest
Re: PointMonitor troubles
« Reply #25 on: August 05, 2014, 06:09:11 PM »
Hi Jeff,
End up placing my whole class for this test here:

http://www.theswamp.org/index.php?topic=18383.msg525131#msg525131

Let me know if works.

Thanks,
Luis.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: PointMonitor troubles
« Reply #26 on: August 05, 2014, 06:17:05 PM »
Luis, before I test yours I decided to go back and retest mine, replacing the bit of code where I checked for the Face object with the bool IsInside || Onboundary. It now is running quickly as well. So that one check for the Face seems to be where the slowdown occurred (I got that part of the code from one of Tony's posts here.)

Thanks for all the help on this, LE, really appreciate it!

LE3

  • Guest
Re: PointMonitor troubles
« Reply #27 on: August 05, 2014, 06:19:43 PM »
Luis, before I test yours I decided to go back and retest mine, replacing the bit of code where I checked for the Face object with the bool IsInside || Onboundary. It now is running quickly as well. So that one check for the Face seems to be where the slowdown occurred (I got that part of the code from one of Tony's posts here.)

Thanks for all the help on this, LE, really appreciate it!

That's good news, glad at least I was of some help my friend... Have fun !

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Re: PointMonitor troubles
« Reply #28 on: August 06, 2014, 12:34:36 PM »
Well, after all of that, I still never got this working properly/quickly with my application. Something about using Brep just slows it down too much. I finally located an algorithm to check if a point is inside an array of points (i.e. a closed polyline) over at the CodeProject which is short, concise, and fast. This has sure been a learning experience for me, though. I've modified the code to suit my code by accepting a Point2dCollection and to return a bool:
Code - C#: [Select]
  1.         public static bool IsPointInside(this Polyline poly, Point2d testpt, Point2dCollection verts)
  2.         {
  3.             if (!poly.Closed)
  4.             {
  5.                 throw new System.ArgumentException("Polyline must be closed!");
  6.             }
  7.             int i, j = 0;
  8.             bool c = false;
  9.             int nvert = verts.Count;
  10.             double testx = testpt.X, testy = testpt.Y;
  11.             for (i = 0, j = nvert - 1; i < nvert; j = i++)
  12.             {
  13.                 double vertx = verts[i].X, verty = verts[i].Y;
  14.                 double prevx = verts[j].X, prevy = verts[j].Y;
  15.                 if (((verty > testy) != ( prevy> testy)) &&
  16.                  (testx < (prevx - vertx) * (testy - verty) / (prevy - verty) + vertx))
  17.                     c = !c;
  18.             }
  19.             return c;
  20.         }
  21.  

LE3

  • Guest
Re: PointMonitor troubles
« Reply #29 on: August 06, 2014, 01:16:55 PM »
^ that does not looks like takes into account curvatures, but at least you have something that works now - good.

To bad, there is no (at least that I am aware) avail the AcDbMPolygon wrapper in .NET ? with this you could avoid the use of Brep at all and work with these temp geometry objects...

In example from one of my arx stuff.... that could it be easy to port to c#.....
Code - C++: [Select]
  1. inline Location IsPointInEzone(AcGePoint3d p, AcDbPolyline *pPoly)
  2. {
  3.         double fuzz = AcGeContext::gTol.equalPoint();
  4.         AcGePoint3d pointOnCurve;
  5.         pPoly->getClosestPointTo(p, pointOnCurve);
  6.         if (p.distanceTo(pointOnCurve) <= fuzz) return On;
  7.         AcDbMPolygon mpol;
  8.         if (pPoly)
  9.         {
  10.                 if (mpol.appendLoopFromBoundary(pPoly, false) != Acad::eOk) return Error;
  11.         }
  12.         else
  13.                 return Error; // invalid entity
  14.         AcGeIntArray ar;
  15.         if (mpol.isPointInsideMPolygon(p, ar) > 0) return Inside;
  16.         else return Outside;
  17. }
  18.