gistools/geometry/tools/lines/
point_on_line.rs

1use crate::geometry::orient2d;
2use libm::{fabs, fmax, fmin};
3use s2json::GetXY;
4
5/// Check to see if a point is on a line. Uses predicates to ensure the point is truly on the line
6///
7/// ## Parameters
8/// - `line`: the line to check against
9/// - `point`: the point to check if it is on the line
10/// - `epsilon`: the buffer to use to check if the point is on the line within epsilon. Defaults to 0
11///
12/// ## Returns
13/// True if the point is on the line
14pub fn point_on_line<P: GetXY, Q: GetXY>(line: &[P], point: &Q, eps: Option<f64>) -> bool {
15    let eps = eps.unwrap_or(0.0);
16
17    if line.len() < 2 {
18        return false;
19    }
20
21    let mut i = 0;
22    while i < line.len() - 1 {
23        // check if in bounding box of each segment
24        let a = &line[i];
25        let b = &line[i + 1];
26        if point.x() >= fmin(a.x(), b.x())
27            && point.x() <= fmax(a.x(), b.x())
28            && point.y() >= fmin(a.y(), b.y())
29            && point.y() <= fmax(a.y(), b.y())
30        {
31            // lastly check if the point is on the segment
32            let cross = orient2d(a.x(), a.y(), b.x(), b.y(), point.x(), point.y());
33            if fabs(cross) <= eps {
34                return true;
35            }
36        }
37
38        i += 1;
39    }
40
41    false
42}