///|
fn abs_double(value : Double) -> Double {
if value < 0.0 {
-value
} else {
value
}
}
///|
/// Classifies orientation using a caller-provided tolerance.
///
/// Returns `1` for counter-clockwise, `-1` for clockwise, and `0` when the
/// signed area lies within the tolerance band.
pub fn orientation_sign(
a : Point,
b : Point,
c : Point,
epsilon : Double,
) -> Int {
let value = orientation(a, b, c)
let tolerance = abs_double(epsilon)
if value > tolerance {
1
} else if value < -tolerance {
-1
} else {
0
}
}
///|
/// Tolerant point-on-segment test for measured or transformed coordinates.
pub fn point_on_segment_eps(
point : Point,
segment : Segment,
epsilon : Double,
) -> Bool {
let tolerance = abs_double(epsilon)
orientation_sign(segment.start, segment.end, point, tolerance) == 0 &&
point.x >= min_double(segment.start.x, segment.end.x) - tolerance &&
point.x <= max_double(segment.start.x, segment.end.x) + tolerance &&
point.y >= min_double(segment.start.y, segment.end.y) - tolerance &&
point.y <= max_double(segment.start.y, segment.end.y) + tolerance
}
///|
/// Tolerant segment intersection including endpoint and collinear contact.
pub fn segments_intersect_eps(
a : Segment,
b : Segment,
epsilon : Double,
) -> Bool {
let o1 = orientation_sign(a.start, a.end, b.start, epsilon)
let o2 = orientation_sign(a.start, a.end, b.end, epsilon)
let o3 = orientation_sign(b.start, b.end, a.start, epsilon)
let o4 = orientation_sign(b.start, b.end, a.end, epsilon)
if o1 == 0 && point_on_segment_eps(b.start, a, epsilon) {
return true
}
if o2 == 0 && point_on_segment_eps(b.end, a, epsilon) {
return true
}
if o3 == 0 && point_on_segment_eps(a.start, b, epsilon) {
return true
}
if o4 == 0 && point_on_segment_eps(a.end, b, epsilon) {
return true
}
o1 != o2 && o3 != o4
}