use robust::{orient2d, Coord};
use crate::types::Position;
pub(crate) fn signed_area(p0: Position, p1: Position, p2: Position) -> i32 {
let res = orient2d(
Coord { x: p0[0], y: p0[1] },
Coord { x: p1[0], y: p1[1] },
Coord { x: p2[0], y: p2[1] },
);
if res > 0.0 {
1
} else if res < 0.0 {
-1
} else {
0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn negative_area() {
assert_eq!(signed_area([0.0, 0.0], [0.0, 1.0], [1.0, 1.0]), -1);
}
#[test]
fn positive_area() {
assert_eq!(signed_area([0.0, 1.0], [0.0, 0.0], [1.0, 0.0]), 1);
}
#[test]
fn collinear_zero_area() {
assert_eq!(signed_area([0.0, 0.0], [1.0, 1.0], [2.0, 2.0]), 0);
}
#[test]
fn point_on_segment_collinear() {
assert_eq!(signed_area([-1.0, 0.0], [2.0, 3.0], [0.0, 1.0]), 0);
assert_eq!(signed_area([2.0, 3.0], [-1.0, 0.0], [0.0, 1.0]), 0);
}
#[test]
fn near_collinear_uses_robust_predicate() {
let p0 = [0.5, 0.5];
let p1 = [12.0, 12.0];
let p2 = [24.0, 24.0];
assert_eq!(signed_area(p0, p1, p2), 0);
}
#[test]
fn signed_area_is_antisymmetric_in_p0_p1_swap() {
let p0 = [1.0, 2.0];
let p1 = [3.0, 7.0];
let p2 = [5.0, 1.0];
let a = signed_area(p0, p1, p2);
let b = signed_area(p1, p0, p2);
assert_ne!(a, 0);
assert_eq!(a, -b);
}
}