Skip to content

FIX: Work out the area of polygons with holes and stop the compare run when a consumer fails - #394

Merged
Automation51D merged 2 commits into
mainfrom
fix/area-of-polygons-with-holes
Sep 18, 2026
Merged

Automation51D merged 2 commits into
mainfrom
fix/area-of-polygons-with-holes

Conversation

@YaroslavVlasenko

Copy link
Copy Markdown
Contributor

Why:

Example_OnPremise_CompareConsole sat idle for 12 minutes on the current Enterprise data file until the test host was killed. The same night the Java examples failed on the same data with Points of LinearRing do not form a closed linestring (51Degrees/ip-intelligence-java-examples#152), and the .NET Calculations class has the same code, so this ports that fix and also removes the hang that hid the error here.

1. Holes

TransformGeometry took geometry.Coordinates, which is the points of every ring in one list, and built a single ring from them. For a polygon with holes the first point belongs to the outer boundary and the last one to the last hole, so the ring does not close and NetTopologySuite throws. The outer boundary and each hole are now transformed as separate rings and put back together as a polygon with holes. A multipolygon or collection is transformed piece by piece.

2. Intersections made of several pieces

When the intersection of an area with a grid cell has more than one piece, the loop read geo.GetGeometryN(i) where it meant intersect.GetGeometryN(i). For a polygon that returns the whole area each time, so the whole area was added once per piece and the result was too large. It now uses the pieces of the intersection.

The existing TestWkt case with three polygons expected 22803 square km, which is the inflated number this bug produced. The fixed code gives 20118, and so does the fixed Java implementation with its own geometry and projection libraries, so the expected value is updated.

3. Why it hung instead of failing

In Compare-Console each consumer catches only OperationCanceledException, so any other exception ends the consumer's task silently. The truth collection is bounded to the processor count, so once every consumer had died on a polygon with holes the producer waited for ever in TryAdd. A consumer that fails now cancels a token linked to the caller's one; the producer stops, and the exception is thrown where the consumer's task is awaited, so the run fails with the polygon in the message instead of hanging.

Tests

Two tests in TestAreas, both written first and seen to fail:

  • TestPolygonWithHole failed with points must form a closed linestring.
  • TestPolygonSplitByGridCell is a U shape whose arms are two separate pieces in the next grid cell. It returned 8759 where 3438 was expected.

Both pass now, with the other eight. The compare example's stop-on-failure path has no unit test, because Example.Run needs a real on-premise engine; CI is the check for it, as it is for Example_OnPremise_CompareConsole itself, which is skipped locally without the current data file.

@Automation51D
Automation51D merged commit cda6be6 into main Sep 18, 2026
10 checks passed
@Automation51D
Automation51D deleted the fix/area-of-polygons-with-holes branch September 18, 2026 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants