Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Unexpected union of two MultiPolygons #825

Closed
grimsa opened this issue Jan 4, 2022 · 4 comments
Closed

Unexpected union of two MultiPolygons #825

grimsa opened this issue Jan 4, 2022 · 4 comments

Comments

@grimsa
Copy link
Contributor

grimsa commented Jan 4, 2022

This is likely also caused by high-precision numbers, similar to #784 and #820.

JTS version used: 1.18.2 with OverlayNG enabled.

Can be reproduced by copy-pasting WKT to JTS TestBuilder:
A:
MULTIPOLYGON (((1.4020000000000001 0.6152725855529207, 2.017272585552921 0, 0 0, 0 2.0172725855529214, 0.6152725855529207 1.4020000000000001, 1.4020000000000001 1.4020000000000001, 1.4020000000000001 0.6152725855529207)), ((3.9999999999999996 0, 2.0172725856347586 0, 3.0086362927764605 0.9913637072235397, 3.9999999999999996 0)), ((0.9913637072235395 3.0086362927764605, 0 2.017272585634758, 0 3.9999999999999996, 0.9913637072235395 3.0086362927764605)))

B:
MULTIPOLYGON (((1.4020000000000001 0.6152725856097978, 1.4020000000000001 1.4020000000000001, 0.6152725855778813 1.4020000000000001, -0.0000000000000002 2.017272585552921, 0.9913637072235395 3.0086362927764605, 3.0086362927764605 0.9913637072235397, 2.0172725856347586 0.0000000000000001, 1.4020000000000001 0.6152725856097978)))

Result of A union B:
GEOMETRYCOLLECTION (POLYGON ((2.017272585552921 0, 0 0, 0 2.017272585552921, 0 2.0172725855529214, 0.0000000000000002 2.0172725855529214, 0.9913637072235395 3.0086362927764605, 3.0086362927764605 0.9913637072235397, 2.0172725856347586 0.0000000000000001, 1.4020000000000001 0.6152725856097978, 1.4020000000000001 0.6152725855529207, 2.017272585552921 0), (0.6152725855529207 1.4020000000000001, 0.6152725855778813 1.4020000000000001, 0.0000161232623158 2.0172564622906055, 0.6152725855529207 1.4020000000000001)), POLYGON ((2.0172725856347586 0, 3.0086362927764605 0.9913637072235397, 3.9999999999999996 0, 2.0172725856347586 0)), POLYGON ((0 2.017272585634758, 0 3.9999999999999996, 0.9913637072235395 3.0086362927764605, 0 2.017272585634758)), LINESTRING (0 2.017272585552921, -0.0000000000000002 2.017272585552921))

image

Expected result:

  • Ideally, a single polygon
  • Alternatively, a multipolygon (the 3 polygons without the almost 0-length linestring)
@dr-jts
Copy link
Contributor

dr-jts commented Jan 4, 2022

This is OverlayNG working as designed.

The input is not node-aligned - as can be seen using the TestBuilder in Reveal Topology mode:
image
The union result simply reflects this misalignment.
image

The reason the result is heterogeneous (i.e. including the additional LineString) is for legacy reasons, to match the semantics of the original overlay implementation. OverlayNG does provide a strict mode, which allows forcing results to be homogeneous. This is available in the TestBuilder:
image

Or, you can remove lower-dimension elements in a post-processing step.

@dr-jts
Copy link
Contributor

dr-jts commented Jan 5, 2022

Also note that the SnappingNoder can be used explicitly with OverlayNG (in code, and in the TestBuilder). Using snapping can eliminate the input misalignment.

image

With a suitable snapping distance (here 1E-7) the result is a single triangle polygon:

POLYGON ((0 0, 0 2.0172725855529214, 0 3.9999999999999996, 0.9913637072235395 3.0086362927764605, 3.0086362927764605 0.9913637072235397, 3.9999999999999996 0, 2.017272585552921 0, 0 0))

image

@grimsa
Copy link
Contributor Author

grimsa commented Jan 5, 2022

Thank you for a quick investigation and a thorough explanation.

The Reveal Topology looks very useful, thank you. Took me a while to find it 😅
In case anyone stumbles upon this later, you can find it here:
image

It seems that ultimately we should use both SnappingNoder and the strict overlay mode in our application - that seems like a simpler solution than post-processing the result (what we currently do).

I looked into the code a bit, and did not find a way to configure this via system properties or Geometry#* operations (that we currently use).
In the other issue you mentioned OverlayNGSnappingFunctions code. It would seem that implementing some utility class/wrapper that provides a more convenient API on top of the OverlayNG operations is the intended approach when configuration knobs have to be tinkered with? I'll try that in near future.

Should I close the issue now that it's clear that it's not a bug?

@dr-jts
Copy link
Contributor

dr-jts commented Jan 5, 2022

Yes, implementing a (set of) wrapper functions providing an API for the OverlayNG settings you want is a good approach.

I'll close this now.

@dr-jts dr-jts closed this as completed Jan 5, 2022
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

2 participants