diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs index 1c369ca..a2fa42b 100644 --- a/src/drawing/drawing.rs +++ b/src/drawing/drawing.rs @@ -1,4 +1,4 @@ -use contracts::debug_ensures; +use contracts::{debug_ensures, debug_invariant}; use enum_dispatch::enum_dispatch; use geo::Point; @@ -77,6 +77,7 @@ pub struct Drawing { rules: R, } +#[debug_invariant(self.test_if_looses_dont_infringe_each_other())] impl Drawing { pub fn new(rules: R, layer_count: usize) -> Self { Self { @@ -183,18 +184,6 @@ impl Drawing { Ok(dot) } - #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] - #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - fn add_dot_infringably + GetLayer>( - &mut self, - weight: W, - ) -> GenericIndex - where - GenericIndex: Into + Copy, - { - self.geometry_with_rtree.add_dot(weight) - } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] @@ -266,18 +255,6 @@ impl Drawing { Ok(seg) } - fn add_seg_infringably + GetLayer>( - &mut self, - from: DotIndex, - to: DotIndex, - weight: W, - ) -> GenericIndex - where - GenericIndex: Into, - { - self.geometry_with_rtree.add_seg(from, to, weight) - } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 3) || self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 4))] @@ -658,55 +635,6 @@ impl Drawing { Cane::from_dot(dot, self) } - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] - #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] - #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))] - fn fail_and_remove_if_infringes_except( - &mut self, - node: PrimitiveIndex, - maybe_except: Option<&[PrimitiveIndex]>, - ) -> Result<(), Infringement> { - if let Some(infringement) = self.detect_infringement_except(node, maybe_except) { - if let Ok(dot) = node.try_into() { - self.geometry_with_rtree.remove_dot(dot); - } else if let Ok(seg) = node.try_into() { - self.geometry_with_rtree.remove_seg(seg); - } else if let Ok(bend) = node.try_into() { - self.geometry_with_rtree.remove_bend(bend); - } - return Err(infringement); - } - Ok(()) - } - - pub fn primitive_nodes(&self) -> impl Iterator + '_ { - self.geometry_with_rtree - .rtree() - .iter() - .filter_map(|wrapper| { - if let GenericNode::Primitive(primitive_node) = wrapper.data { - Some(primitive_node) - } else { - None - } - }) - } - - pub fn layer_primitive_nodes(&self, layer: usize) -> impl Iterator + '_ { - self.geometry_with_rtree - .rtree() - .locate_in_envelope_intersecting(&AABB::from_corners( - [-f64::INFINITY, -f64::INFINITY, layer as f64], - [f64::INFINITY, f64::INFINITY, layer as f64], - )) - .filter_map(|wrapper| { - if let GenericNode::Primitive(primitive_node) = wrapper.data { - Some(primitive_node) - } else { - None - } - }) - } #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { @@ -768,6 +696,75 @@ impl Drawing { Ok(()) } + fn detect_collision(&self, node: PrimitiveIndex) -> Option { + let shape = node.primitive(self).shape(); + + self.geometry_with_rtree + .rtree() + .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) + .filter_map(|wrapper| { + if let GenericNode::Primitive(primitive_node) = wrapper.data { + Some(primitive_node) + } else { + None + } + }) + .filter(|primitive_node| !self.are_connectable(node, *primitive_node)) + .filter(|primitive_node| shape.intersects(&primitive_node.primitive(self).shape())) + .map(|primitive_node| primitive_node) + .next() + .and_then(|collidee| Some(Collision(shape, collidee))) + } +} + +impl Drawing { + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + fn add_dot_infringably + GetLayer>( + &mut self, + weight: W, + ) -> GenericIndex + where + GenericIndex: Into + Copy, + { + self.geometry_with_rtree.add_dot(weight) + } + + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))] + fn add_seg_infringably + GetLayer>( + &mut self, + from: DotIndex, + to: DotIndex, + weight: W, + ) -> GenericIndex + where + GenericIndex: Into, + { + self.geometry_with_rtree.add_seg(from, to, weight) + } + + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + #[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))] + fn fail_and_remove_if_infringes_except( + &mut self, + node: PrimitiveIndex, + maybe_except: Option<&[PrimitiveIndex]>, + ) -> Result<(), Infringement> { + if let Some(infringement) = self.detect_infringement_except(node, maybe_except) { + if let Ok(dot) = node.try_into() { + self.geometry_with_rtree.remove_dot(dot); + } else if let Ok(seg) = node.try_into() { + self.geometry_with_rtree.remove_seg(seg); + } else if let Ok(bend) = node.try_into() { + self.geometry_with_rtree.remove_bend(bend); + } + return Err(infringement); + } + Ok(()) + } + fn detect_infringement_except( &self, node: PrimitiveIndex, @@ -832,12 +829,26 @@ impl Drawing { }) } - fn detect_collision(&self, node: PrimitiveIndex) -> Option { - let shape = node.primitive(self).shape(); - + pub fn primitive_nodes(&self) -> impl Iterator + '_ { self.geometry_with_rtree .rtree() - .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) + .iter() + .filter_map(|wrapper| { + if let GenericNode::Primitive(primitive_node) = wrapper.data { + Some(primitive_node) + } else { + None + } + }) + } + + pub fn layer_primitive_nodes(&self, layer: usize) -> impl Iterator + '_ { + self.geometry_with_rtree + .rtree() + .locate_in_envelope_intersecting(&AABB::from_corners( + [-f64::INFINITY, -f64::INFINITY, layer as f64], + [f64::INFINITY, f64::INFINITY, layer as f64], + )) .filter_map(|wrapper| { if let GenericNode::Primitive(primitive_node) = wrapper.data { Some(primitive_node) @@ -845,11 +856,6 @@ impl Drawing { None } }) - .filter(|primitive_node| !self.are_connectable(node, *primitive_node)) - .filter(|primitive_node| shape.intersects(&primitive_node.primitive(self).shape())) - .map(|primitive_node| primitive_node) - .next() - .and_then(|collidee| Some(Collision(shape, collidee))) } fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool { @@ -920,6 +926,39 @@ impl Drawing { pub fn node_count(&self) -> usize { self.geometry_with_rtree.graph().node_count() } + + fn test_if_looses_dont_infringe_each_other(&self) -> bool { + !self + .primitive_nodes() + .filter(|node| match node { + PrimitiveIndex::LooseDot(..) + | PrimitiveIndex::LoneLooseSeg(..) + | PrimitiveIndex::SeqLooseSeg(..) + | PrimitiveIndex::LooseBend(..) => true, + _ => false, + }) + .any(|node| { + self.find_infringement( + node, + self.locate_possible_infringers(node) + .filter_map(|n| { + if let GenericNode::Primitive(primitive_node) = n { + Some(primitive_node) + } else { + None + } + }) + .filter(|primitive_node| match primitive_node { + PrimitiveIndex::LooseDot(..) + | PrimitiveIndex::LoneLooseSeg(..) + | PrimitiveIndex::SeqLooseSeg(..) + | PrimitiveIndex::LooseBend(..) => true, + _ => false, + }), + ) + .is_some() + }) + } } impl CompoundManagerTrait> for Drawing { diff --git a/src/layout/layout.rs b/src/layout/layout.rs index 3b4c82d..4685ce7 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -46,14 +46,6 @@ impl Layout { Self { drawing } } - pub fn remove_band(&mut self, band: BandFirstSegIndex) { - self.drawing.remove_band(band); - } - - pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) { - self.drawing.remove_cane(cane, face) - } - pub fn insert_cane( &mut self, from: DotIndex, @@ -67,6 +59,10 @@ impl Layout { .insert_cane(from, around, dot_weight, seg_weight, bend_weight, cw) } + pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) { + self.drawing.remove_cane(cane, face) + } + #[debug_ensures(ret.is_ok() -> self.drawing.node_count() == old(self.drawing.node_count()) + weight.to_layer - weight.from_layer)] #[debug_ensures(ret.is_err() -> self.drawing.node_count() == old(self.drawing.node_count()))] pub fn add_via(&mut self, weight: ViaWeight) -> Result, Infringement> { @@ -208,11 +204,8 @@ impl Layout { ) } - pub fn zones( - &self, - node: GenericIndex, - ) -> impl Iterator> + '_ { - self.drawing.compounds(node) + pub fn remove_band(&mut self, band: BandFirstSegIndex) { + self.drawing.remove_band(band); } pub fn band_length(&self, band: BandFirstSegIndex) -> f64 { @@ -247,6 +240,13 @@ impl Layout { } } + pub fn zones( + &self, + node: GenericIndex, + ) -> impl Iterator> + '_ { + self.drawing.compounds(node) + } + pub fn zone_nodes(&self) -> impl Iterator> + '_ { self.drawing.rtree().iter().filter_map(|wrapper| { if let NodeIndex::Compound(compound) = wrapper.data {