#![allow(dead_code)]
use crate::prelude::*;
use aabb::HilbertRTree;
fn arc_bounding_box(arc: &Arc) -> (f64, f64, f64, f64) {
if arc.is_seg() {
let min_x = arc.a.x.min(arc.b.x);
let max_x = arc.a.x.max(arc.b.x);
let min_y = arc.a.y.min(arc.b.y);
let max_y = arc.a.y.max(arc.b.y);
return (min_x, max_x, min_y, max_y);
}
let min_x = arc.c.x - arc.r;
let max_x = arc.c.x + arc.r;
let min_y = arc.c.y - arc.r;
let max_y = arc.c.y + arc.r;
(min_x, min_y, max_x, max_y)
}
pub fn arcline_has_self_intersection(arcline: &Arcline) -> bool {
let n = arcline.len();
if n < 2 {
return false;
}
if n == 2 {
let arc0 = &arcline[0];
let arc1 = &arcline[1];
if is_really_intersecting(arc0, arc1) || is_really_intersecting(arc1, arc0) {
return true;
}
return false;
}
let mut tree = HilbertRTree::with_capacity(n);
for arc in arcline.iter() {
let (min_x, min_y, max_x, max_y) = arc_bounding_box(arc);
tree.add(min_x, min_y, max_x, max_y);
}
tree.build();
let mut candidates = Vec::new();
for i in 0..n {
let arc = &arcline[i];
let (min_x, min_y, max_x, max_y) = arc_bounding_box(arc);
candidates.clear();
tree.query_intersecting(min_x, min_y, max_x, max_y, &mut candidates);
for &j in candidates.iter() {
if j == i || j <= i {
continue;
}
let arc_i = &arcline[i];
let arc_j = &arcline[j];
if is_really_intersecting(arc_i, arc_j) {
return true;
}
}
}
false
}
pub fn arcline_self_intersections(arcline: &Arcline) -> Vec<(usize, usize)> {
let mut intersections = Vec::new();
let n = arcline.len();
if n < 2 {
return intersections;
}
if n == 2 {
let arc0 = &arcline[0];
let arc1 = &arcline[1];
if is_really_intersecting(arc0, arc1) {
intersections.push((0, 1));
}
return intersections;
}
let mut tree = HilbertRTree::with_capacity(n);
for arc in arcline.iter() {
let (min_x, min_y, max_x, max_y) = arc_bounding_box(arc);
tree.add(min_x, min_y, max_x, max_y);
}
tree.build();
let mut candidates = Vec::new();
for i in 0..n {
let arc_i = &arcline[i];
let (min_x, min_y, max_x, max_y) = arc_bounding_box(arc_i);
candidates.clear();
tree.query_intersecting(min_x, min_y, max_x, max_y, &mut candidates);
for &j in candidates.iter() {
if j == i || j <= i {
continue;
}
let arc_j = &arcline[j];
if is_really_intersecting(arc_i, arc_j) {
intersections.push((i, j));
}
}
}
if n >= 2 {
let last_arc = &arcline[n - 1];
let first_arc = &arcline[0];
if is_really_intersecting(last_arc, first_arc) {
intersections.push((0, n - 1));
}
}
intersections
}
#[derive(Debug, Clone, PartialEq)]
pub enum SelfIntersectionStatus {
Clean,
HasIntersections(Vec<(usize, usize)>),
}
pub fn arcline_self_intersection_status(arcline: &Arcline) -> SelfIntersectionStatus {
let intersections = arcline_self_intersections(arcline);
if intersections.is_empty() {
SelfIntersectionStatus::Clean
} else {
SelfIntersectionStatus::HasIntersections(intersections)
}
}
pub fn arcline_has_self_intersection_aabb(arcline: &Arcline) -> bool {
arcline_has_self_intersection(arcline)
}
pub fn arcline_self_intersections_aabb(arcline: &Arcline) -> Vec<(usize, usize)> {
arcline_self_intersections(arcline)
}
#[cfg(test)]
mod tests {
#[test]
fn test_arcseg_no_intersection() {
let seg1 = arcseg(point(0.0, 0.0), point(1.0, 0.0));
let seg2 = arcseg(point(0.0, 1.0), point(1.0, 1.0));
let arcline = vec![seg1, seg2];
assert!(!arcline_has_self_intersection(&arcline));
assert!(arcline_self_intersections(&arcline).is_empty());
}
#[test]
fn test_arcseg_intersection() {
let seg1 = arcseg(point(0.0, 0.0), point(1.0, 1.0));
let seg2 = arcseg(point(0.0, 1.0), point(1.0, 0.0));
let arcline = vec![seg1, seg2];
assert!(arcline_has_self_intersection(&arcline));
let ints = arcline_self_intersections(&arcline);
assert_eq!(ints, vec![(0, 1)]);
}
#[test]
fn test_arc_and_arcseg_no_intersection() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let seg = arcseg(point(2.0, 2.0), point(3.0, 2.0));
let arcline = vec![arc1, seg];
assert!(!arcline_has_self_intersection(&arcline));
assert!(arcline_self_intersections(&arcline).is_empty());
}
#[test]
fn test_arc_and_arcseg_intersection() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let seg = arcseg(point(0.5, 0.5), point(0.5, -1.0));
let arcline = vec![arc1, seg];
assert!(arcline_has_self_intersection(&arcline));
let ints = arcline_self_intersections(&arcline);
assert_eq!(ints, vec![(0, 1)]);
}
#[test]
fn test_arcseg_and_arc_intersection() {
let seg = arcseg(point(0.5, 0.5), point(0.5, -1.0));
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let arcline = vec![seg, arc1];
assert!(arcline_has_self_intersection(&arcline));
let ints = arcline_self_intersections(&arcline);
assert_eq!(ints, vec![(0, 1)]);
}
use super::*;
#[test]
fn test_simple_non_intersecting_arcline() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let arc2 = arc(point(1.0, 0.0), point(2.0, 0.0), point(1.5, 0.5), 1.0);
let arcline = vec![arc1, arc2];
assert!(!arcline_has_self_intersection(&arcline));
assert_eq!(
arcline_self_intersection_status(&arcline),
SelfIntersectionStatus::Clean
);
}
#[test]
fn test_three_arc_no_intersection() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let arc2 = arc(point(1.0, 0.0), point(2.0, 0.0), point(1.5, 0.5), 1.0);
let arc3 = arc(point(2.0, 0.0), point(3.0, 0.0), point(2.5, 0.5), 1.0);
let arcline = vec![arc1, arc2, arc3];
assert!(!arcline_has_self_intersection(&arcline));
}
#[test]
fn test_single_arc() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let arcline = vec![arc1];
assert!(!arcline_has_self_intersection(&arcline));
}
#[test]
fn test_empty_arcline() {
let arcline: Arcline = vec![];
assert!(!arcline_has_self_intersection(&arcline));
}
#[test]
fn test_two_arcs_no_intersection() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let arc2 = arc(point(1.0, 0.0), point(0.0, 0.0), point(0.5, -0.5), 1.0);
let arcline = vec![arc1, arc2];
assert!(!arcline_has_self_intersection(&arcline));
}
#[test]
fn test_intersections_list_empty() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let arc2 = arc(point(1.0, 0.0), point(2.0, 0.0), point(1.5, 0.5), 1.0);
let arc3 = arc(point(2.0, 0.0), point(3.0, 0.0), point(2.5, 0.5), 1.0);
let arcline = vec![arc1, arc2, arc3];
let intersections = arcline_self_intersections(&arcline);
assert!(intersections.is_empty());
}
#[test]
fn test_intersections_list_not_empty() {
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let arc2 = arc(point(1.0, 0.0), point(2.0, 0.0), point(1.5, 0.5), 1.0);
let arc3 = arc(point(0.5, -1.0), point(1.5, -1.0), point(1.0, -0.5), 1.0);
let arcline = vec![arc1, arc2, arc3];
let intersections = arcline_self_intersections(&arcline);
let _ = intersections; }
#[test]
fn test_arcseg_arc_asymmetry() {
let seg = arcseg(point(0.5, 0.5), point(0.5, -1.0));
let arc1 = arc(point(0.0, 0.0), point(1.0, 0.0), point(0.5, 0.5), 1.0);
let ab = is_really_intersecting(&arc1, &seg);
let ba = is_really_intersecting(&seg, &arc1);
assert_eq!(ab, ba, "is_really_intersecting not symmetric for arc/seg");
}
#[test]
fn test_arc_arc_asymmetry() {
let arc1 = arc(point(-1.0, 0.0), point(1.0, 0.0), point(0.0, 1.0), 1.0);
let arc2 = arc(point(0.0, -1.0), point(0.0, 1.0), point(1.0, 0.0), 1.0);
let ab = is_really_intersecting(&arc1, &arc2);
let ba = is_really_intersecting(&arc2, &arc1);
assert_eq!(ab, ba, "is_really_intersecting not symmetric for arc/arc");
}
#[test]
fn test_arcseg_arcseg_asymmetry() {
let seg1 = arcseg(point(0.0, 0.0), point(1.0, 1.0));
let seg2 = arcseg(point(0.0, 1.0), point(1.0, 0.0));
let ab = is_really_intersecting(&seg1, &seg2);
let ba = is_really_intersecting(&seg2, &seg1);
assert_eq!(ab, ba, "is_really_intersecting not symmetric for seg/seg");
}
}