Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

booleanEqual check does not properly handle precision #2530

Closed
solarissmoke opened this issue Nov 7, 2023 · 4 comments · Fixed by #2531
Closed

booleanEqual check does not properly handle precision #2530

solarissmoke opened this issue Nov 7, 2023 · 4 comments · Fixed by #2531
Assignees

Comments

@solarissmoke
Copy link
Contributor

solarissmoke commented Nov 7, 2023

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.

@smallsaucepan
Copy link
Member

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!

@solarissmoke
Copy link
Contributor Author

@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.

@smallsaucepan
Copy link
Member

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?

@solarissmoke
Copy link
Contributor Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants