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

booleanPointOnLine fails for aligned points #2826

Open
cdeclerck opened this issue Jan 21, 2025 · 5 comments
Open

booleanPointOnLine fails for aligned points #2826

cdeclerck opened this issue Jan 21, 2025 · 5 comments

Comments

@cdeclerck
Copy link

📝 Description

The function turf.booleanPointOnLine incorrectly returns false when checking if a point lies on a line, even when the point is perfectly aligned with the line segment. This behavior occurs under the following conditions:

📍 Coordinates

  • Point to check: [1.1491048489081164, 47.97013091862306]
  • Line segment:
    • Point 1: [1.1497411448453079, 47.97009507298361]
    • Point 2: [1.1489123422593934, 47.970141763457235]

🔍 Steps to Reproduce

import * as turf from '@turf/turf';

// Define the line segment
const line = turf.lineString([
    [1.1497411448453079, 47.97009507298361],
    [1.1489123422593934, 47.970141763457235],
]);

// Define the point
const point = turf.point([1.1491048489081164, 47.97013091862306]);

// Check if the point is on the line
const result = turf.booleanPointOnLine(point, line);

console.log("Is the point on the line?", result); // Expected: true, but returns false
@smallsaucepan smallsaucepan changed the title 📌 Bug Report: booleanPointOnLine fails for aligned points booleanPointOnLine fails for aligned points Jan 22, 2025
@cdeclerck
Copy link
Author

I kept on digging and I used a function allowing me to reproduce my need and it works correctly. I don't know if there's a difference with the function you're using.

isPointOnLine: function (point, lineStart, lineEnd, tolerance = 0.00001) {
    const [x, y] = point
    const [x1, y1] = lineStart
    const [x2, y2] = lineEnd

    // Calculer l'équation de la ligne (distance point -> ligne)
    const distance
    = Math.abs((y2 - y1) * x - (x2 - x1) * y + x2 * y1 - y2 * x1)
    / Math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2)

    // Vérifier si la distance est inférieure ou égale à la tolérance
    return distance <= tolerance
  }

@stevage
Copy link
Collaborator

stevage commented Jan 29, 2025

booleanPointOnLine does take an epsilon parameter, much like the tolerance one in the function you used.

In this case, with the data you provided:

turf.booleanPointOnLine(point, line, { epsilon:0.000000000000000001 });
=> true

Perhaps the question is, should epsilon default to something greater than 0?

@smallsaucepan
Copy link
Member

Sensible suggestion. Couple of thoughts:

  1. Should we call it tolerance instead? epsilon has special meaning floating point wise so isn't really describing what this is.
  2. Additionally we're using that value in some calculation part way through the process (the cross product?), which makes it difficult for the caller to give a meaningful real world value. Makes more sense to be distance across the ground.
  3. Section 11.2 of the spec talks about six decimal places in degrees being about 10cm and suitable precision for most purposes.

So default tolerance becomes whatever amounts to 0.000001 degrees / 10cm?

@stevage
Copy link
Collaborator

stevage commented Jan 30, 2025

That suggestion makes sense to me. The current behaviour, expecting floating point calculations to somehow yield exact equality does not.

(Shame the spec doesn't quite come out as far as recommending 6 DPs. It sort of tiptoes all around it, but doesn't quite say it.)

@smallsaucepan
Copy link
Member

Maybe 10 years ago the "cost" of those extra bytes felt like a more firm handed warning 🤷

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

No branches or pull requests

3 participants