Turfjs / turf

A modular geospatial engine written in JavaScript and TypeScript

Home Page:https://turfjs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

booleanEqual check does not properly handle precision

solarissmoke opened this issue · comments

Turf version: 6.5.0/7.0.0a

The way booleanEqual check handles precision is incorrect. The following example illustrates the problem:

const point1 = {"type": "Point", "coordinates": [100.55719328, 23.0365925]}
const point2 = {"type": "Point", "coordinates": [100.55719327926636, 23.03659249995325]}

booleanEqual(point1, point2, {precision: 7})   // returns true
booleanEqual(point1, point2, {precision: 6})   // returns false !

This is incorrect. If two points are equal to a precision of 7, then by definition they must be equal to a precision of 6 as well. The problem here arises from the underlying implementation of GeojsonEquality, which uses toFixed to round the coordinates. The problem is that this introduces rounding errors that then cause the equality check to fail:

const a = 23.0365925;
const b = 23.03659249995325;

a.toFixed(6) // returns "23.036593"
b.toFixed(6) // returns "23.036592" 

a.toFixed(7) // returns "23.0365925"
b.toFixed(7) // returns "23.0365925" 

a.toFixed(6) === b.toFixed(6) // returns false
a.toFixed(7) === b.toFixed(7) // returns true

I think the correct behaviour here is not to use toFixed() but to check that both values fall within the acceptable precision, e.g., like this:

Math.abs(a - b) < (10**-6) // returns true, as expected
Math.abs(a - b) < (10**-7) // returns true, as expected

Which likely needs to be fixed upstream in GeojsonEquality (I've filed a bug there too), or that logic replaced entirely in turf.

My suggestion is to drop the dependency on geojson-equality and implement it afresh here, which will allow updating the implementation to use typescript - more than happy to make a PR if the maintainers here agree.

Thanks for raising @solarissmoke. Given geojson-equality hasn't seen any activity for several years, it might be best to re-implement it afresh.

Would you mind sharing a few thoughts about what the PR might look like? Would it be a new module, or do you think it would fit into an existing module? Would it be end user facing, or only for internal use? Thanks!

@smallsaucepan my suggestion would be that we implement this inside the boolean-equal module, for internal use only, as the existing boolean-equal API already exposes all the functionality that is required.

I have re-implemented the logic inside geojson-equality for a project that needed to work around this bug, and think it can be done relatively cleanly - happy to make a PR to port this into turf.

Only thing to consider is geojson-equality is also a dependency of turf-boolean-overlap. So we'd need to put the implementation somewhere we can reuse it internally. Might it fit into turf-helpers or turf-meta?

Putting it in turf-helpers sounds like a good plan. I'll work on a PR.