ThinkGeo.com    |     Documentation    |     Premium Support

IComparer Exception When Buffering an Extent

We have a rectangular extent that we are trying to buffer as shown in the code below. We have significant percentage of cases where this is failing, throwing an exception in the highlighted line below, where the extent and bufferedExtent objects are ThinkGeo.MapSuite.Core.RectangleShape objects.


 


RectangleShape extent = _standardLayers.GetBestExtent(MapParameters.View);


      if (extent != null)


      {


            double margin = Math.Round(Math.Max(extent.Height, extent.Width) * MapParameters.MarginPercent / 100.0, 2);


try


{


RectangleShape bufferedExtent = extent.Buffer(margin, GeographyUnit.Meter, DistanceUnit.Meter).GetBoundingBox();


extent = bufferedExtent;


}


catch (Exception ex)


{


System.Diagnostics.Trace.WriteLine("Exception: " + ex.Message);


System.Diagnostics.Trace.WriteLine("Failed Extent as WKT:");


System.Diagnostics.Trace.WriteLine(extent.ToPolygon().GetWellKnownText());


System.Diagnostics.Trace.WriteLine("Margin: " + margin.ToString());


System.Diagnostics.Trace.WriteLine("Stack Trace:");


System.Diagnostics.Trace.WriteLine(ex.StackTrace);


}


}


 


The exception and stack trace is shown below, along with the WKT for the extent we are trying to buffer.


 


Exception: IComparer (or the IComparable methods it relies upon) did not return zero when Array.Sort called x. CompareTo(x). x: 'GisSharpBlog.NetTopologySuite.Index.Strtree.ItemBoundable'  x's type: 'ItemBoundable' The IComparer: 'GisSharpBlog.NetTopologySuite.Index.Strtree.STRtree+AnonymousYComparerImpl'.


Failed Extent as WKT:


POLYGON((827014.17127848 4430478.43293349,827326.686253674 4430478.43293349,827326.686253674 4430052.53863433,827014.17127848 4430052.53863433,827014.17127848 4430478.43293349))


Margin: 21.29


Stack Trace:


   at System.Array.SorterObjectArray.QuickSort(Int32 left, Int32 right)


   at System.Array.Sort(Array keys, Array items, Int32 index, Int32 length, IComparer comparer)


   at System.Collections.ArrayList.Sort(Int32 index, Int32 count, IComparer comparer)


   at System.Collections.ArrayList.Sort(IComparer comparer)


   at GisSharpBlog.NetTopologySuite.Index.Strtree.AbstractSTRtree.CreateParentBoundables(IList childBoundables, Int32 newLevel)


   at GisSharpBlog.NetTopologySuite.Index.Strtree.STRtree.CreateParentBoundablesFromVerticalSlices(IList[] verticalSlices, Int32 newLevel)


   at GisSharpBlog.NetTopologySuite.Index.Strtree.STRtree.CreateParentBoundables(IList childBoundables, Int32 newLevel)


   at GisSharpBlog.NetTopologySuite.Index.Strtree.AbstractSTRtree.CreateHigherLevels(IList boundablesOfALevel, Int32 level)


   at GisSharpBlog.NetTopologySuite.Index.Strtree.AbstractSTRtree.Build()


   at GisSharpBlog.NetTopologySuite.Index.Strtree.AbstractSTRtree.Query(Object searchBounds)


   at GisSharpBlog.NetTopologySuite.Index.Strtree.STRtree.Query(IEnvelope searchEnv)


   at GisSharpBlog.NetTopologySuite.Noding.MCIndexNoder.IntersectChains()


   at GisSharpBlog.NetTopologySuite.Noding.MCIndexNoder.ComputeNodes(IList inputSegStrings)


   at GisSharpBlog.NetTopologySuite.Operation.Buffer.BufferBuilder.ComputeNodedEdges(IList bufferSegStrList, IPrecisionModel precisionModel)


   at GisSharpBlog.NetTopologySuite.Operation.Buffer.BufferBuilder.Buffer(IGeometry g, Double distance)


   at GisSharpBlog.NetTopologySuite.Operation.Buffer.BufferOp.BufferOriginalPrecision()


   at GisSharpBlog.NetTopologySuite.Operation.Buffer.BufferOp.ComputeGeometry()


   at GisSharpBlog.NetTopologySuite.Operation.Buffer.BufferOp.GetResultGeometry(Double distance)


   at GisSharpBlog.NetTopologySuite.Operation.Buffer.BufferOp.Buffer(IGeometry g, Double distance, Int32 quadrantSegments, BufferStyle endCapStyle)


   at GisSharpBlog.NetTopologySuite.Geometries.Geometry.Buffer(Double distance, Int32 quadrantSegments, BufferStyle endCapStyle)


   at ThinkGeo.MapSuite.Core.BaseShape.BufferCore(Double distance, Int32 quadrantSegments, BufferCapType bufferCapType, GeographyUnit shapeUnit, DistanceUnit distanceUnit)


   at ThinkGeo.MapSuite.Core.BaseShape.Buffer(Double distance, GeographyUnit shapeUnit, DistanceUnit distanceUnit)


 



Clint, 
  
 I cannot recreate your issue. Here is my test code and it works fine. 
 
 string strVersion = WinformsMap.GetVersion(); // "MapSuiteCore:3.1.19;DesktopEdition:3.0.199"
            string strWKT = "POLYGON((827014.17127848 4430478.43293349,827326.686253674 4430478.43293349,827326.686253674 4430052.53863433,827014.17127848 4430052.53863433,827014.17127848 4430478.43293349))";
            PolygonShape polygonShape = new PolygonShape(strWKT);
            RectangleShape bufferedExtent = polygonShape.Buffer(21.29, GeographyUnit.Meter, DistanceUnit.Meter).GetBoundingBox();
 
  
 Can you run the piece of code on your machine to see if it works well? Please make sure you are using the latest public version as well.  
  
 Thanks, 
  
 Ben

Clint, 
  
 Here is version number of my NTS assemblies, just in case you are not using the right one. 
  
 NetTopologySuite.dll           1.7.3.31740 
 GeoAPI.dll                          1.1.0.0 
  
 We used to reference a newer version of NTS but as there are some problems, we change it back to the old one. Maybe you are using some temporary versions with the new NTS assembly. 
  
 Thanks, 
  
 Ben 


Ben, Clint submitted this for us. Here are more details: 



1) We are running the 3.0.255 interim dll's that solved the TrackPolygon problem. These were accompanied by a version of NTS that is newer than that in 3.0.199. 



2) We were buffering a RectangleShape, rather than a Polygon, if that makes any difference. 



3) I have many documented instances of buffer operations that fail when run against objects that are created programmatically, but if you export to WKT and import them back, they work. I suspect that this is such a case. I contracted with someone to fix that issue last fall, and I thought we were successful, so I hope that fix is really in this version of NTS. 

 


Oh, shoot... now I see that you have gone back to the older NTS dll.    This is very distressing.   We needed to be using the new DLL because of this exact problem.    Can you tell me what NTS problems you were having with the latest build?   Maybe I can ask our contractor to address them?






 


Ted,


Here is a demo which shows why we switch back to an older version. You can see in this demo, although the result is the same with different versions of NetTopologySuite.dll, the time it takes is dramatically different. With an older version(1.7.3.31740) , it takes about 100 ms, while with a newer version (1.7.3.19489 for example), it takes almost 40 seconds!


I checked out all the available versions in the following link and generally, all the assemblies released this year has this problem.


code.google.com/p/nettopolog...loads/list


Mar 19, 2009


Release 1.7.3.17298 (Have problem)


Debug   1.7.3.17291(Have problem)


Oct 2008


1.7.3.36606 (fine)


Nov 2007


16791 (fine)


I think your buffering issue is also from NTS. Could you please switch back your NetTopologySuite assembly to 31740 to make sure I'm guessing right so we can narrow down to the NTS part? I tried rectangleShape.Buffer in my above sample and still cannot recreate this problem with either versions.  By the way, you do not need to convert a rectangle to a polygon before getting the WKT, you can directly call rectangleShape.GetWellKnownText() and get the same result.


Finally, here I have some questions about NTS, I will be appreciate it if you can let me know the answers.


1, The versioning of NTS seems confusing. Usually newer version has a larger revision number, but in NTS, that's another story. Just wonder what's the versioning strategy of NTS? Can I tell which assembly is newer just by the version numbers?


2, Every version of NTS has a different Assembly Version, which means I cannot make the app running by just grabing the latest assembly and replacing the existing one, instead, I need to rebuild the whole project with the new assembly to make it work. Can NTS just change its File Version and keep the same Assembly Version to make it easy to upgrade?


3,  Just want to let you know whenever there is a new version of NTS (no breaking change), you can replace the existing one and rebuild your MapSuite project to make it work.


Let me know if you have any issues.


Thanks,


Ben






681-TestNTS.zip (80.4 KB)

Thank you, Ben.  I will investigate this further over the weekend. 
  
 Yes, the versioning of NTS is messed up.   They have acknowledged that, and are preparing to fix it. 
  
 Yes, it is difficult to upgrade to a new assembly because of the version changes.    I’ll query them about just changing the file version.   So, that’s how it works?   We can update file versions to ensure we know what is current, and leave the assembly version alone, so that you can drop in new components w/o a rebuild? 
  
 I’m not sure I understand your comment about replacing NTS with a newer one, and MapSuite will still work.    How have you built MapSuite such that it doesn’t care what assembly version of NTS is being used? 
  
 Thanks!

Ted, 
  
 Yes, just changing the File Version should be fine. For example in Map Suite, the MapSuiteCore.dll assembly always has the same Assembly Version 3.0.0.0, and for every update we only change its File Version, in this way we can drop in new components without a rebuild.  
  
 Sorry about the last comment. What I want to say is if there is a new NTS with only the File Version changed, you can make your Map Suite project work by just replacing the assembly. I thought it’s convenient to see if there is any breaking change by rebuilding the project but now I think just replace and run should also be fine. Sorry for that confusing comment :P. 
  
 Thanks, 
  
 Ben

Ted/Clint - did reverting back to an earlier NTS version fix this for you? I realize this thread is from long ago, but I just started getting the same error. Our NTS version is 31740.

Paul, 
  
 31740 should be working fine. You can download the test sample I attached in 05-15-2009 and see if it worked as expected. The sample doesn’t need to use ThinkGeo Assemblies, it directly consumes NTS dll. 
  
 Thanks, 
  
 Ben

Paul, we are using 31740 for our geometry objects, but only as an implementatino of the GeoAPI interfaces for exposing geometry objects as properties and parameters for our classes and methods.  We have abandoned them for all but the very most basic spatial operations (like length and area).    We do all spatial operations with the SqlServer spatiial types.    They are incredibly more robust and in most cases, I can convert an NTS object to them, perform the operation, and convert back faster than I can do the operation with the NTS methods.

Paul, 
  
 I have verified that the NTS 31740 do not have this problem, you can take a try by just downloading the sample provided by Ben, what you need to do is just reference the target 31740 version NTS DLLs. 
  
 Any more questions please feel free to let me know. 
  
 Thanks. 
  
 Yale 


Thanks for confirming the version number. I do get the IComparer error in version 31740. I will start a new thread on that issue.

Paul, 
  
 Start a new thread is a good idea that can make your problem easy to be found, so if other people encounter the same problem they would quickly get related solution or workaround. 
  
 I will close this thread, Please keep an eye on the new thread.  
  
 Thanks, 
 James