Select to view content in your preferred language

GeometryEngine.Distance much slower since Pro 3.3

279
8
2 weeks ago
BillyBuerger
Frequent Contributor

I recently noticed that a process I developed using the Pro SDK and does a lot of geometry queries and updates was running much slower on Pro 3.3 compared to the same code running on Pro 3.1.  I found a similar performance issue when testing some tools on Pro 3.6 as well.  As I was reviewing where the tool was taking the most time, I found it was in the processes that do a lot of testing for distances between feature geometries.  Specifically the GeometryEngine.Distance method.  I did some testing and found that using a sample of 5,770 features and testing the distance to a MapPoint in Pro 3.1 completes in about 100ms.  This same code running on Pro 3.3 takes about 6 seconds.  That's 60x slower.  As noted, I also have a current Pro 3.6 system and the performance seems similar to 3.3 there but they are different systems so not apples to apples.  I then installed Pro 3.2.0 through 3.2.5 on the same system as the 3.1 and 3.3 tests and those were similar to Pro 3.1.  So it seems this change started with Pro 3.3 and has continued since.

I'm assuming there was some reason for the change.  Hopefully to improve the accuracy of the result.  But the performance hit is huge making it unusable for doing any bulk processing needing to know distances.  Another test I tried was to use the GeometryEngine.NearestPoint method.  This also provides a distance result as well along with other information.  This at least is about twice as fast as DistanceTo completing in about 3 seconds.  But that's also what I see in Pro 3.1 where NearestPoint is also faster than DistanceTo completing the test in 70ms.  I haven't yet found a way to get a fast performing test between geometries to know if they are within a tolerance or to find out which is the closest.

Is this an expected result?  If so, does anyone have any recommendations for other ways to test for distances that would be as performant as this all was before Pro 3.3?  Thanks.

8 Replies
AnnetteLocke
Esri Contributor

Hi Billy, thanks for the information. I will take a look. Are you able to share your data?

0 Kudos
BillyBuerger
Frequent Contributor

I can try to pull together the specific data I was testing with.  But it doesn't appear to be a data specific issue.  You should be able to take any data and use the GeometryEngine.Distance method between geometries and run that same test on < Pro 3.3 and >= Pro 3.3 and see the difference in the execution times.

To add an additional item to the list, I was also doing some testing with the Buffer method and found a similar performance issue between Pro 3.1 which was very fast and 3.3 which was much slower.  But Buffer on Pro 3.6 seemed to be back to being fast again.  So for cases where I was using the Distance method to test for distances within a tolerance, Buffer is a good replacement assuming I can run on the latest version of Pro.  I have at least one project I'm working on which is currently targeting Pro 3.3.  So I'm stuck with that version for the time being.  In other cases where I need the distance or NearestPoint, buffer won't help me with that.

0 Kudos
BillyBuerger
Frequent Contributor

I spent some time and built out a number of identical VMs each with a different version of ArcGIS Pro installed.  I took the Naperville sample data and pulled out 5,000 points from that data (see attached) and ran some geometry methods between the points and noted the total time to complete.  The results can be seen here along with a comparison of the difference between Pro 3.1 and the other versions...

GeometryPerformance.png

Here's the code that does the calculations... 

await QueuedTask.Run(() =>
{
   var Layer = MapView.Active.Map.GetLayersAsFlattenedList().First();
   var FeatLayer = Layer as BasicFeatureLayer;
   var Feat = null as Feature;
   var Point = null as MapPoint;
   var TestFeats = new List<Feature>();
   var TestPoints = new List<MapPoint>();

   var Time1 = DateTime.Now.Ticks;

   using (var Cursor = FeatLayer.Search())
   {
      // First feature is our test point
      Cursor.MoveNext();
      Feat = Cursor.Current as Feature;
      Point = Feat.GetShape() as MapPoint;

      while (Cursor.MoveNext())
      {
         var TestFeat = Cursor.Current as Feature;
         TestFeats.Add(TestFeat);
         TestPoints.Add(TestFeat.GetShape() as MapPoint);
      }
   }

   var Time2 = DateTime.Now.Ticks;

   foreach (var TestPoint in TestPoints)
   {
      var Dist = GeometryEngine.Instance.Distance(TestPoint, Point);
   }

   var Time3 = DateTime.Now.Ticks;

   foreach (var TestPoint in TestPoints)
   {
      var NearPoint = GeometryEngine.Instance.NearestPoint(TestPoint, Point);
   }

   var Time4 = DateTime.Now.Ticks;

   foreach (var TestPoint in TestPoints)
   {
      var Buffer = GeometryEngine.Instance.Buffer(TestPoint, 5);
      var Int = GeometryEngine.Instance.Intersects(Buffer, Point);
   }

   var Time5 = DateTime.Now.Ticks;

   var CursorTime = new TimeSpan(Time2 - Time1);
   var DistanceTime = new TimeSpan(Time3 - Time2);
   var NearestTime = new TimeSpan(Time4 - Time3);
   var BufferTime = new TimeSpan(Time5 - Time4);

   var Result = $"Points:   {TestPoints.Count:#,0}\n" +
                  $"Cursor:   {CursorTime.TotalMilliseconds:0.00}ms\n" +
                  $"Distance: {DistanceTime.TotalMilliseconds:0.00}ms\n" +
                  $"Nearest:  {NearestTime.TotalMilliseconds:0.00}ms\n" +
                  $"Buffer:   {BufferTime.TotalMilliseconds:0.00}ms\n";

   System.Diagnostics.Debug.WriteLine(Result);
   MessageBox.Show(Result);
});

 

The first thing I noticed that this test takes a little over 1 second for the Distance method compared to my previous tests that was taking about 100ms which is 10x slower.  Not sure what is different between that data and the code I was using that accounts for this difference.  Everything seems to be the same.  So it makes the difference between versions less extreme.  But the differences are still there.  Pro 3.1 and 3.2 are essentially the same.  Pro 3.3 and 3.4 are about 3x slower for the three geometry methods I tested, Distance, NearestPoint and Buffer.  I also included a Intersects check with the Buffer as the goal of using these methods are to determine features within distances.  The buffer needs that additional check so I included it.  Pro 3.5 and 3.6 have similar issues with Distance and NearestPoint but something seems to have changed with the Buffer and it's about 10x faster than Pro 3.1.  So that's good to see.

Back in the day with ArcObjects, I tended to use Buffer a lot.  But the buffer method was updated at some point and became a bottleneck so I stopped using it unless I really needed it.  Often using Distance instead as that was much faster.  Fast forward to Pro 3.5+, Buffer seems to be the way to go when it's appropriate for the calculation.  I still need to know actual distances in many cases so I can't use buffer for that.  But interestingly, NearestPoint seems consistently 2x faster than Distance which seems odd.  NearestPoint does also return the distance to that nearest point so in that sense it's doing the same thing.  But I would assume NearestPoint would be doing more things potentially as for linear geometries it calculates segment and part index as well.  But I guess for a point to point, the nearest point is just the only point in the geometry (except multi-points) and it really is just calculating the distance.  This all suggests that Distance is doing something that takes more time that NearPoint isn't doing in its distance calculation.  Without knowing what that is and if it will affect my processes, I would guess NearestPoint would be the more efficient way to get the distance instead of Distance.  But of course NearestPoint still took the same performance hit that Distance did at Pro 3.3+.

With Buffer being pretty similar to NearestPoint in the worse cases, using Buffer to filter for general nearby queries and NearestPoint to get actual distances is the way to go.  It's still going to be bad in Pro 3.3 and 3.4 but the increase in Buffer performance in Pro 3.5+ should help balance it a little.  Of course if the performance of Distance and NearestPoint could improve back to where they were in Pro 3.2, that would be even better.  If there's any specific details about what is different between these methods and what changes were made between the Pro versions, that would be helpful to know so I can write my tools around those known parameters.

0 Kudos
AnnetteLocke
Esri Contributor

Thank you so much for taking the time to spell it all out. This helps a lot.

0 Kudos
AnnetteLocke
Esri Contributor

This has been fixed in 3.7, and it is faster than 3.2 now. Thanks for reporting it.

0 Kudos
BillyBuerger
Frequent Contributor

Thanks for looking into this.  I'll test it out with 3.7 is available.  Unfortunately I doubt our customers will be on 3.7 for a while so I'll still have to try to work around this for a while.  I don't assume there will be any patch updates for these existing versions to address this?

0 Kudos
AnnetteLocke
Esri Contributor

I will check on a patch and get back to you.

0 Kudos
AnnetteLocke
Esri Contributor

I see. I will let you know what I find out.

0 Kudos