4

I have a polygon and a multipolygon. I want to create a geometry that is the area where the 2 geometries do not intersect. The result I get (red outline in the example) seems to have something like an extra point in the southmost and northmost part of the geometries and I don't understand why.

Can anyone help me figure out how I can get the result of having the red outline exactly around the purple area?

As a side note, I can get the result I'm looking for if I use PostGIS and do exactly ST_Difference(ST_SnapToGrid(poly1, 0.0000000001), ST_SnapToGrid(poly2, 0.0000000001)) from MYTABLE; however I don't comprehend why this works and it seems like it may be a brittle solution. Any decimal difference in 0.0000000001 doesn't work (0.000001 for example gives me the same result as the turfjs result).

var map = L.map("map").setView([19.42, -155], 9);

L.tileLayer('https://stamen-tiles.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

var poly1 = turf.polygon([[[-155.253325763,19.424193039],[-155.140558658,19.206650122],[-154.752533025,19.515649896],[-154.933670824,19.645287706],[-155.253325763,19.424193039]]]);
var poly2 = turf.multiPolygon([[[[-154.975609356,19.338005611],[-155.140558658,19.206650122],[-155.240053913,19.398589856],[-155.021104033,19.34867505],[-154.975609356,19.338005611]]],[[[-154.9542326,19.63106581],[-154.933670824,19.645287706],[-154.904729907,19.624575093],[-154.9542326,19.63106581]]]]);
var difference = turf.difference(poly1, poly2);

var myStyle = {weight: 0, fillOpacity: 0.3, fillColor: '#0000ff'};
L.geoJSON(poly1, {style: myStyle}).addTo(map);

myStyle.fillColor = '#00ff00';
L.geoJSON(poly2, {style: myStyle}).addTo(map);

myStyle = {weight: 1, opacity: 1, color: 'red', fillOpacity: 0.05, fillColor: '#ff0000'};
L.geoJSON(difference, {style: myStyle}).addTo(map);
#map {
  height: 200px;
}
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@6.5.0/turf.min.js"></script>
<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
<link href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" rel="stylesheet"/>
<div id="map"></div>
A. Mort
  • 278
  • 4
  • 12

1 Answers1

2

Precision are a common problem when working with geometries. Have to use ST_SnapToGrid or other techniques to fix topological issues before use a geoprocess is no rare

So answering one of your questions, use ST_SnapToGrid is not a bad solution. For sure it will be better that the original data exactly match but that is not always possible.

Also, just a matter of taste, but usually I found more "understable" dump multi geometries to simple geometries and operate on that, that working directly with the multi. I find easy to debug problems when using simple versions.

To fix the precision issue in turf you can try to play with truncate

var options = {precision: 4};
var poly1 = turf.truncate(poly1, options);
var poly2 = turf.truncate(poly2, options);
Francisco Puga
  • 23,869
  • 5
  • 48
  • 64
  • I found that turf/truncate still gave me the odd northmost & southmost point. I ended up doing a string match regex to keep only the first 6 decimal places. It seemed like the Math.round part of the turf/truncate function was still causing me to have the same problematic output. – A. Mort Jun 18 '22 at 21:26
  • http://jsfiddle.net/5vpnhb2a/6/ – A. Mort Jun 19 '22 at 03:30
  • Hard to say how to fix this cliend side. I think that your solution is good enougth. I don't know your use case, but if it's possible, probably I will store the geometries already "snapped" with a trigger in the database – Francisco Puga Jun 21 '22 at 18:42