diff --git a/src/edge.rs b/src/edge.rs index 826d1ec..e06a85a 100644 --- a/src/edge.rs +++ b/src/edge.rs @@ -8,8 +8,8 @@ pub type E = Rc>>; pub struct Edge { pub idx: usize, pub c: S, - pub i0: N, - pub i1: N, + pub n0: N, + pub n1: N, pub t0: D, pub t1: D, pub containers: Vec>, @@ -75,8 +75,8 @@ impl< f, "C{}: {}({}) → {}({}), containers: [{}], expected_visits: {}", self.c.borrow().idx(), - self.i0.borrow().idx, self.t0.clone().into().deg_str(), - self.i1.borrow().idx, self.t1.clone().into().deg_str(), + self.n0.borrow().idx, self.t0.clone().into().deg_str(), + self.n1.borrow().idx, self.t1.clone().into().deg_str(), containers.join(","), self.expected_visits, ) diff --git a/src/intersections.rs b/src/intersections.rs index 5fc2017..cc2bc23 100644 --- a/src/intersections.rs +++ b/src/intersections.rs @@ -1,7 +1,8 @@ use core::f64; -use std::{cell::RefCell, rc::Rc, f64::consts::TAU, collections::{BTreeSet, BTreeMap}, ops::{Neg, Add, Sub, Mul, Div}, fmt::Display}; +use std::{cell::RefCell, rc::Rc, f64::consts::TAU, collections::BTreeSet, ops::{Neg, Add, Sub, Mul, Div}, fmt::Display}; use log::{error, debug}; +use ordered_float::OrderedFloat; use crate::{node::{N, Node}, edge::{self, E}, distance::Distance, region::{Region, RegionArg}, shape::{S, Shape}, segment::Segment, theta_points::ThetaPoints, intersect::{Intersect, IntersectShapesArg}, r2::R2, transform::CanTransform, intersection::Intersection, dual::Dual, to::To, math::deg::Deg, fmt::Fmt}; @@ -56,12 +57,14 @@ where f64: IntersectionsFloat, { pub fn new(shapes: Vec>) -> Intersections { - let n = (&shapes).len(); + let num_shapes = (&shapes).len(); let duals: Vec> = shapes.clone().into_iter().map(|s| Rc::new(RefCell::new(s))).collect(); let mut nodes: Vec> = Vec::new(); let merge_threshold = 1e-7; + + // Intersect all shapes, pair-wise for (idx, dual) in duals.iter().enumerate() { - for jdx in (idx + 1)..n { + for jdx in (idx + 1)..num_shapes { let intersections = dual.borrow().intersect(&duals[jdx].borrow()); for i in intersections { let mut merged = false; @@ -71,6 +74,7 @@ where // This intersection is close enough to an existing node; merge them let mut node = node.borrow_mut(); node.merge(i.clone()); + debug!("Merged: {} into {}", i, node); merged = true; break; } @@ -91,27 +95,21 @@ where } } + debug!("{} nodes", (&nodes).len()); + for (idx, node) in nodes.iter().enumerate() { + debug!(" Node {}: {}", idx, node.borrow()); + } + debug!(""); + let mut nodes_by_shape: Vec>> = Vec::new(); - // let mut nodes_by_shapes: Vec>>> = Vec::new(); - for _idx in 0..n { + for _idx in 0..num_shapes { nodes_by_shape.push(Vec::new()); - // let mut shapes_nodes: Vec>> = Vec::new(); - // for _jdx in 0..n { - // shapes_nodes.push(Vec::new()); - // } - // nodes_by_shapes.push(shapes_nodes); } - - // Sort each circle's nodes in order of where they appear on the circle (from -PI to PI) - // for (idx, nodes) in nodes_by_shape.iter_mut().enumerate() { - // nodes.sort_by_cached_key(|n| OrderedFloat(n.borrow().theta(idx).into())) - // } - // Compute connected components (shape -> shape -> bool) let mut is_connected: Vec> = Vec::new(); - for idx in 0..n { + for idx in 0..num_shapes { let mut connected: Vec = Vec::new(); - for jdx in 0..n { + for jdx in 0..num_shapes { connected.push(idx == jdx); } is_connected.push(connected); @@ -123,9 +121,9 @@ where is_connected[*i0][*i1] = true; is_connected[*i1][*i0] = true; if !is_connected[*i0][*i1] { - for i2 in 0..n { + for i2 in 0..num_shapes { if is_connected[*i0][i2] && !is_connected[*i1][i2] { - for i3 in 0..n { + for i3 in 0..num_shapes { if is_connected[*i1][i3] && !is_connected[i2][i3] { is_connected[i2][i3] = true; is_connected[i3][i2] = true; @@ -137,35 +135,31 @@ where }) }); } - - debug!("{} nodes", (&nodes).len()); - for (idx, node) in nodes.iter().enumerate() { - debug!(" Node {}: {}", idx, node.borrow()); + // Sort each circle's nodes in order of where they appear on the circle (from -PI to PI) + for (idx, nodes) in nodes_by_shape.iter_mut().enumerate() { + nodes.sort_by_cached_key(|n| OrderedFloat(n.borrow().theta(idx).into())) } - debug!(""); - // Compute edges between nodes + // Construct edges let mut edges: Vec> = Vec::new(); - let mut edges_by_shape: Vec>> = Vec::new(); let mut total_expected_visits = 0; - for idx in 0..n { - let nodes = &nodes_by_shape[idx]; - let mut shape_edges: Vec> = Vec::new(); - let m = n; - let n = nodes.len(); - let c = duals[idx].clone(); - for jdx in 0..n { - let i0 = nodes[jdx].clone(); - let i1 = nodes[(jdx + 1) % n].clone(); - let t0 = i0.borrow().theta(idx); - let t1 = i1.borrow().theta(idx); - let t1 = if &t1 < &t0 { t1 + TAU } else { t1 }; - let arc_midpoint = duals[idx].borrow().arc_midpoint(t0.clone(), t1.clone()); + for shape_idx in 0..num_shapes { + let nodes = &nodes_by_shape[shape_idx]; + debug!("{} nodes for shape {}: {}", nodes.len(), shape_idx, nodes.iter().map(|n| n.borrow().theta(shape_idx).deg_str()).collect::>().join(", ")); + let num_shape_nodes = nodes.len(); + let c = duals[shape_idx].clone(); + for node_idx in 0..num_shape_nodes { + let cur_node = nodes[node_idx].clone(); + let nxt_node = nodes[(node_idx + 1) % num_shape_nodes].clone(); + let cur_theta = cur_node.borrow().theta(shape_idx); + let nxt_theta = nxt_node.borrow().theta(shape_idx); + let nxt_theta = if &nxt_theta < &cur_theta { nxt_theta + TAU } else { nxt_theta }; + let arc_midpoint = duals[shape_idx].borrow().arc_midpoint(cur_theta.clone(), nxt_theta.clone()); let mut is_component_boundary = true; let mut containers: Vec> = Vec::new(); let mut containments: Vec = Vec::new(); - for cdx in 0..m { - if cdx == idx { + for cdx in 0..num_shapes { + if cdx == shape_idx { continue; } let container = duals[cdx].clone(); @@ -173,32 +167,28 @@ where if contained { // Shape cdx contains this edge containers.push(container.clone()); - if is_connected[idx][cdx] { + if is_connected[shape_idx][cdx] { is_component_boundary = false; } } containments.push(contained); } - // let c0idx = i0.borrow().other(idx); - // let c1idx = i1.borrow().other(idx); let expected_visits = if is_component_boundary { 1 } else { 2 }; total_expected_visits += expected_visits; let edge = Rc::new(RefCell::new(edge::Edge { idx: edges.len(), c: c.clone(), - i0, i1, - t0, t1, + n0: cur_node, n1: nxt_node, + t0: cur_theta, t1: nxt_theta, containers, containments, expected_visits, visits: 0, })); edges.push(edge.clone()); - shape_edges.push(edge.clone()); - edge.borrow_mut().i0.borrow_mut().add_edge(edge.clone()); - edge.borrow_mut().i1.borrow_mut().add_edge(edge.clone()); + edge.borrow_mut().n0.borrow_mut().add_edge(edge.clone()); + edge.borrow_mut().n1.borrow_mut().add_edge(edge.clone()); } - edges_by_shape.push(shape_edges); } debug!("{} edges", (&edges).len()); @@ -234,7 +224,7 @@ where let nxt_idxs = nxt.borrow().all_idxs(); let both = container_idxs.intersection(&nxt_idxs).cloned().collect::>(); // Recursively traverse the graph, trying to add each eligible Segment to the list we've seeded here, accumulating valid Regions in `regions` along the way. - Intersections::traverse(&start, n, &mut regions, &mut segments, &both, &mut visited_nodes, edges.len()); + Intersections::traverse(&start, num_shapes, &mut regions, &mut segments, &both, &mut visited_nodes, edges.len()); assert_eq!(segments.len(), 2); segments.pop(); visited_nodes.remove(&segment_end_idx); @@ -434,7 +424,6 @@ pub mod tests { use crate::ellipses::xyrr::XYRR; use crate::fmt::Fmt; use crate::r2::R2; - use ordered_float::OrderedFloat; use super::*; use test_log::test; @@ -689,18 +678,18 @@ pub mod tests { assert_node_strs( &intersections, vec![ - "I( 0.866, 0.500, C0( 30)/C1( -30))", - "I(-0.866, 0.500, C0( 150)/C1(-150))", - "I( 0.500, 0.866, C0( 60)/C2( 120))", - "I( 0.500, -0.866, C0( -60)/C2(-120))", - "I( 0.000, 1.000, C0( 90)/C3( 180))", - "I( 1.000, 0.000, C0( 0)/C3( -90))", - "I( 1.000, 1.000, C1( 0)/C2( 90))", - "I( 0.000, 0.000, C1( -90)/C2( 180))", - "I( 0.500, 1.866, C1( 60)/C3( 120))", - "I( 0.500, 0.134, C1( -60)/C3(-120))", - "I( 1.866, 0.500, C2( 30)/C3( -30))", - "I( 0.134, 0.500, C2( 150)/C3(-150))", + "N0( 0.866, 0.500: C0( 30), C1( -30))", + "N1(-0.866, 0.500: C0( 150), C1(-150))", + "N2( 0.500, 0.866: C0( 60), C2( 120))", + "N3( 0.500, -0.866: C0( -60), C2(-120))", + "N4( 0.000, 1.000: C0( 90), C3( 180))", + "N5( 1.000, 0.000: C0( 0), C3( -90))", + "N6( 1.000, 1.000: C1( 0), C2( 90))", + "N7( 0.000, 0.000: C1( -90), C2( 180))", + "N8( 0.500, 1.866: C1( 60), C3( 120))", + "N9( 0.500, 0.134: C1( -60), C3(-120))", + "N10( 1.866, 0.500: C2( 30), C3( -30))", + "N11( 0.134, 0.500: C2( 150), C3(-150))", ] ); } @@ -719,21 +708,16 @@ pub mod tests { assert_node_strs( &intersections, vec![ - "I( 0.500, 0.866, C0( 60)/C1( 120))", - "I( 0.500, -0.866, C0( -60)/C1(-120))", - "I( 1.000, 0.000, C0( 0)/C2( -60))", - "I(-0.500, 0.866, C0( 120)/C2( 180))", - "I( 1.000, 0.000, C0( 0)/C3( 60))", - "I(-0.500, -0.866, C0(-120)/C3(-180))", - "I( 1.500, 0.866, C1( 60)/C2( 0))", - "I( 0.000, 0.000, C1( 180)/C2(-120))", - "I( 1.500, -0.866, C1( -60)/C3( 0))", - "I( 0.000, 0.000, C1( 180)/C3( 120))", - "I( 1.000, 0.000, C2( -60)/C3( 60))", - "I(-0.000, 0.000, C2(-120)/C3( 120))", + "N0( 0.500, 0.866: C0( 60), C1( 120))", + "N1( 0.500, -0.866: C0( -60), C1(-120))", + "N2( 1.000, 0.000: C0( 0), C2( -60), C3( 60))", + "N3(-0.500, 0.866: C0( 120), C2( 180))", + "N4(-0.500, -0.866: C0(-120), C3(-180))", + "N5( 1.500, 0.866: C1( 60), C2( 0))", + "N6(-0.000, 0.000: C1( 180), C2(-120), C3( 120))", + "N7( 1.500, -0.866: C1( -60), C3( 0))", ] ); - assert_eq!(intersections.regions.len(), 11); } @@ -780,8 +764,8 @@ pub mod tests { assert_node_strs( &intersections, vec![ - "I( 0.897, 0.119, C0( -57)/C1(-123))", - "I( 0.897, 3.459, C0( 57)/C1( 123))", + "N0( 0.897, 0.119: C0( -57), C1(-123))", + "N1( 0.897, 3.459: C0( 57), C1( 123))", ] ); } @@ -801,14 +785,14 @@ pub mod tests { assert_node_strs( &intersections, vec![ - "I( 0.897, 0.119, C0( -57)/C1(-123))", - "I( 0.897, 3.459, C0( 57)/C1( 123))", - "I( 1.297, 2.416, C0( 18)/C2( 104))", - "I( 1.115, 0.506, C0( -40)/C2(-110))", - "I( 2.399, 2.399, C1( 18)/C2( 72))", - "I( 0.469, 2.198, C1( 168)/C2( 131))", - "I( 0.632, 0.632, C1(-145)/C2(-125))", - "I( 2.198, 0.469, C1( -41)/C2( -78))", + "N0( 0.897, 0.119: C0( -57), C1(-123))", + "N1( 0.897, 3.459: C0( 57), C1( 123))", + "N2( 1.297, 2.416: C0( 18), C2( 104))", + "N3( 1.115, 0.506: C0( -40), C2(-110))", + "N4( 2.399, 2.399: C1( 18), C2( 72))", + "N5( 0.469, 2.198: C1( 168), C2( 131))", + "N6( 0.632, 0.632: C1(-145), C2(-125))", + "N7( 2.198, 0.469: C1( -41), C2( -78))", ] ); } diff --git a/src/node.rs b/src/node.rs index c57155d..6ff55ea 100644 --- a/src/node.rs +++ b/src/node.rs @@ -53,6 +53,12 @@ where y: p.y * n / (n + 1.) + o.y / (n + 1.), }; // self.p = p * n / (n + 1.) + o / (n + 1.); + if !self.shape_thetas.contains_key(&intersection.c0idx) { + self.shape_thetas.insert(intersection.c0idx, intersection.t0.clone()); + } + if !self.shape_thetas.contains_key(&intersection.c1idx) { + self.shape_thetas.insert(intersection.c1idx, intersection.t1.clone()); + } self.intersections.push(intersection); } } diff --git a/src/region.rs b/src/region.rs index 821c68d..a85ffde 100644 --- a/src/region.rs +++ b/src/region.rs @@ -63,10 +63,13 @@ where { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( - f, "R({})", + f, "R({}\n\t{}\n)", + self.container_idxs.iter().map(|i| { + format!("{}", i) + }).collect::>().join(", "), self.segments.iter().map(|s| { - format!("{}", s.edge.borrow()) - }).collect::>().join(", ") + format!("{}", s) + }).collect::>().join(",\n\t") ) } } \ No newline at end of file diff --git a/src/regions.rs b/src/regions.rs index b6d2391..6f3aba8 100644 --- a/src/regions.rs +++ b/src/regions.rs @@ -53,8 +53,8 @@ impl Regions { }).collect(); let edges = intersections.edges.iter().map(|e| Edge { cidx: e.borrow().c.borrow().idx(), - i0: e.borrow().i0.borrow().idx, - i1: e.borrow().i1.borrow().idx, + i0: e.borrow().n0.borrow().idx, + i1: e.borrow().n1.borrow().idx, t0: e.borrow().t0.v(), t1: e.borrow().t1.v(), containers: e.borrow().containers.iter().map(|c| c.borrow().idx()).collect(), diff --git a/src/segment.rs b/src/segment.rs index 2802089..6361dce 100644 --- a/src/segment.rs +++ b/src/segment.rs @@ -18,12 +18,12 @@ where } pub fn start(&self) -> N { let e = self.edge.borrow(); - let i = if self.fwd { &e.i0 } else { &e.i1 }; + let i = if self.fwd { &e.n0 } else { &e.n1 }; i.clone() } pub fn end(&self) -> N { let e = self.edge.borrow(); - let i = if self.fwd { &e.i1 } else { &e.i0 }; + let i = if self.fwd { &e.n1 } else { &e.n0 }; i.clone() } pub fn successors(&self) -> Vec> { @@ -34,7 +34,7 @@ where let successors = end.borrow().edges.iter().filter(|e| { e.borrow().c.borrow().idx() != idx && e.borrow().visits < e.borrow().expected_visits }).map(|e| { - let p: R2 = e.borrow().i0.borrow().p.clone().to(); + let p: R2 = e.borrow().n0.borrow().p.clone().to(); let fwd = p == end_p; Segment { edge: e.clone(), fwd } }).collect();