use geometry_cs::Cartesian;
use geometry_model::{Point2D, Segment};
use geometry_overlay::predicate::{
SegmentIntersection, Sign, in_circle_2d, orientation_2d, segment_intersection,
};
use geometry_trait::Point as _;
type P = Point2D<f64, Cartesian>;
type Seg = Segment<P>;
fn xy(p: &P) -> (f64, f64) {
(p.get::<0>(), p.get::<1>())
}
#[test]
fn orientation_side_matrix() {
let p = P::new(0.0, 0.0);
let q = P::new(4.0, 0.0);
assert_eq!(orientation_2d(&p, &q, &P::new(2.0, 3.0)), Sign::Positive); assert_eq!(orientation_2d(&p, &q, &P::new(2.0, -3.0)), Sign::Negative); assert_eq!(orientation_2d(&p, &q, &P::new(2.0, 0.0)), Sign::Collinear); assert_eq!(orientation_2d(&p, &q, &p), Sign::Collinear);
assert_eq!(orientation_2d(&p, &q, &q), Sign::Collinear);
}
#[test]
fn in_circle_matrix() {
let a = P::new(1.0, 0.0);
let b = P::new(0.0, 1.0);
let c = P::new(-1.0, 0.0);
assert_eq!(in_circle_2d(&a, &b, &c, &P::new(0.0, 0.0)), Sign::Positive);
assert_eq!(
in_circle_2d(&a, &b, &c, &P::new(0.0, -1.0)),
Sign::Collinear
);
assert_eq!(in_circle_2d(&a, &b, &c, &P::new(2.0, 2.0)), Sign::Negative);
}
#[test]
fn proper_crossing_interior_point() {
let a = Seg::new(P::new(0.0, 0.0), P::new(4.0, 4.0));
let b = Seg::new(P::new(0.0, 4.0), P::new(4.0, 0.0));
match segment_intersection::<Seg, P>(&a, &b) {
SegmentIntersection::Single(p) => assert_eq!(xy(&p), (2.0, 2.0)),
other => panic!("{other:?}"),
}
}
#[test]
fn asymmetric_crossing_point() {
let a = Seg::new(P::new(0.0, 0.0), P::new(4.0, 2.0));
let b = Seg::new(P::new(0.0, 3.0), P::new(3.0, 0.0));
match segment_intersection::<Seg, P>(&a, &b) {
SegmentIntersection::Single(p) => assert_eq!(xy(&p), (2.0, 1.0)),
other => panic!("{other:?}"),
}
}
#[test]
fn t_junction_endpoint_on_interior() {
let a = Seg::new(P::new(0.0, 0.0), P::new(6.0, 0.0));
let b = Seg::new(P::new(3.0, 0.0), P::new(3.0, 5.0));
match segment_intersection::<Seg, P>(&a, &b) {
SegmentIntersection::Single(p) => assert_eq!(xy(&p), (3.0, 0.0)),
other => panic!("{other:?}"),
}
}
#[test]
fn shared_endpoint_only() {
let a = Seg::new(P::new(0.0, 0.0), P::new(2.0, 2.0));
let b = Seg::new(P::new(2.0, 2.0), P::new(4.0, 0.0));
match segment_intersection::<Seg, P>(&a, &b) {
SegmentIntersection::Single(p) => assert_eq!(xy(&p), (2.0, 2.0)),
other => panic!("{other:?}"),
}
}
#[test]
fn collinear_partial_overlap() {
let a = Seg::new(P::new(0.0, 0.0), P::new(5.0, 5.0));
let b = Seg::new(P::new(2.0, 2.0), P::new(8.0, 8.0));
match segment_intersection::<Seg, P>(&a, &b) {
SegmentIntersection::Collinear { from, to } => {
let (mut lo, mut hi) = (xy(&from), xy(&to));
if lo.0 > hi.0 {
core::mem::swap(&mut lo, &mut hi);
}
assert_eq!(lo, (2.0, 2.0));
assert_eq!(hi, (5.0, 5.0));
}
other => panic!("{other:?}"),
}
}
#[test]
fn collinear_one_inside_other() {
let a = Seg::new(P::new(0.0, 0.0), P::new(10.0, 0.0));
let b = Seg::new(P::new(3.0, 0.0), P::new(7.0, 0.0));
match segment_intersection::<Seg, P>(&a, &b) {
SegmentIntersection::Collinear { from, to } => {
let (mut lo, mut hi) = (xy(&from), xy(&to));
if lo.0 > hi.0 {
core::mem::swap(&mut lo, &mut hi);
}
assert_eq!(lo, (3.0, 0.0));
assert_eq!(hi, (7.0, 0.0));
}
other => panic!("{other:?}"),
}
}
#[test]
fn collinear_meeting_at_a_point() {
let a = Seg::new(P::new(0.0, 0.0), P::new(3.0, 0.0));
let b = Seg::new(P::new(3.0, 0.0), P::new(6.0, 0.0));
match segment_intersection::<Seg, P>(&a, &b) {
SegmentIntersection::Single(p) => assert_eq!(xy(&p), (3.0, 0.0)),
other => panic!("{other:?}"),
}
}
#[test]
fn collinear_gap_is_disjoint() {
let a = Seg::new(P::new(0.0, 0.0), P::new(2.0, 0.0));
let b = Seg::new(P::new(4.0, 0.0), P::new(6.0, 0.0));
assert_eq!(
segment_intersection::<Seg, P>(&a, &b),
SegmentIntersection::Disjoint
);
}
#[test]
fn parallel_offset_is_disjoint() {
let a = Seg::new(P::new(0.0, 0.0), P::new(5.0, 0.0));
let b = Seg::new(P::new(0.0, 2.0), P::new(5.0, 2.0));
assert_eq!(
segment_intersection::<Seg, P>(&a, &b),
SegmentIntersection::Disjoint
);
}
#[test]
fn lines_cross_outside_extents_is_disjoint() {
let a = Seg::new(P::new(0.0, 0.0), P::new(1.0, 1.0));
let b = Seg::new(P::new(5.0, 0.0), P::new(6.0, -1.0));
assert_eq!(
segment_intersection::<Seg, P>(&a, &b),
SegmentIntersection::Disjoint
);
}