use contracts::debug_ensures; use enum_dispatch::enum_dispatch; use geo::Point; use rstar::AABB; use crate::{ drawing::{ band::BandFirstSegIndex, bend::LooseBendWeight, cane::Cane, dot::{DotIndex, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, graph::{GetMaybeNet, PrimitiveIndex}, primitive::{GetJoints, GetOtherJoint}, rules::RulesTrait, seg::{ FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, SeqLooseSegWeight, }, wraparoundable::WraparoundableIndex, Drawing, Infringement, LayoutException, }, geometry::{compound::CompoundManagerTrait, primitive::PrimitiveShapeTrait, GenericNode}, graph::{GenericIndex, GetPetgraphIndex}, layout::{ via::{Via, ViaWeight}, zone::{Zone, ZoneWeight}, }, }; #[derive(Debug, Clone, Copy)] #[enum_dispatch(GetMaybeNet)] pub enum CompoundWeight { Zone(ZoneWeight), Via(ViaWeight), } pub type NodeIndex = GenericNode>; #[derive(Debug)] pub struct Layout { drawing: Drawing, } impl Layout { pub fn new(drawing: Drawing) -> Self { Self { drawing } } pub fn insert_cane( &mut self, from: DotIndex, around: WraparoundableIndex, dot_weight: LooseDotWeight, seg_weight: SeqLooseSegWeight, bend_weight: LooseBendWeight, cw: bool, ) -> Result { self.drawing .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 + 2)] #[debug_ensures(ret.is_err() -> self.drawing.node_count() == old(self.drawing.node_count()))] pub fn add_via(&mut self, weight: ViaWeight) -> Result, Infringement> { let compound = self.drawing.add_compound(weight.into()); let mut dots = vec![]; for layer in weight.from_layer..=weight.to_layer { match self.drawing.add_fixed_dot(FixedDotWeight { circle: weight.circle, layer, maybe_net: weight.maybe_net, }) { Ok(dot) => { self.drawing.add_to_compound(dot, compound); dots.push(dot); } Err(err) => { // Remove inserted dots. self.drawing.remove_compound(compound); for dot in dots.iter().rev() { self.drawing.remove_fixed_dot(*dot); } return Err(err); } } } Ok(GenericIndex::::new(compound.petgraph_index())) } pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result { self.drawing.add_fixed_dot(weight) } pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex { self.drawing.add_fixed_dot_infringably(weight) } pub fn add_zone_fixed_dot( &mut self, weight: FixedDotWeight, zone: GenericIndex, ) -> Result { let maybe_dot = self.drawing.add_fixed_dot(weight); if let Ok(dot) = maybe_dot { self.drawing.add_to_compound(dot, zone.into()); } maybe_dot } pub fn add_zone_fixed_dot_infringably( &mut self, weight: FixedDotWeight, zone: GenericIndex, ) -> FixedDotIndex { let dot = self.drawing.add_fixed_dot_infringably(weight); self.drawing.add_to_compound(dot, zone.into()); dot } pub fn add_fixed_seg( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> Result { self.drawing.add_fixed_seg(from, to, weight) } pub fn add_fixed_seg_infringably( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> FixedSegIndex { self.drawing.add_fixed_seg_infringably(from, to, weight) } pub fn add_zone_fixed_seg( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, zone: GenericIndex, ) -> Result { let maybe_seg = self.add_fixed_seg(from, to, weight); if let Ok(seg) = maybe_seg { self.drawing.add_to_compound(seg, zone.into()); } maybe_seg } pub fn add_zone_fixed_seg_infringably( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, zone: GenericIndex, ) -> FixedSegIndex { let seg = self.add_fixed_seg_infringably(from, to, weight); self.drawing.add_to_compound(seg, zone.into()); seg } pub fn add_lone_loose_seg( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: LoneLooseSegWeight, ) -> Result { self.drawing.add_lone_loose_seg(from, to, weight) } pub fn add_seq_loose_seg( &mut self, from: DotIndex, to: LooseDotIndex, weight: SeqLooseSegWeight, ) -> Result { self.drawing.add_seq_loose_seg(from, to, weight) } pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> { self.drawing.move_dot(dot, to) } pub fn add_zone(&mut self, weight: ZoneWeight) -> GenericIndex { GenericIndex::::new( self.drawing .add_compound(CompoundWeight::Zone(weight)) .petgraph_index(), ) } pub fn remove_band(&mut self, band: BandFirstSegIndex) { self.drawing.remove_band(band); } pub fn band_length(&self, band: BandFirstSegIndex) -> f64 { match band { BandFirstSegIndex::Straight(seg) => { self.drawing.geometry().seg_shape(seg.into()).length() } BandFirstSegIndex::Bended(start_seg) => { let mut length = self.drawing.geometry().seg_shape(start_seg.into()).length(); let start_dot = self.drawing.primitive(start_seg).joints().1; let bend = self.drawing.primitive(start_dot).bend(); length += self.drawing.geometry().bend_shape(bend.into()).length(); let mut prev_dot = self.drawing.primitive(bend).other_joint(start_dot.into()); let mut seg = self.drawing.primitive(prev_dot).seg().unwrap(); length += self.drawing.geometry().seg_shape(seg.into()).length(); while let DotIndex::Loose(dot) = self.drawing.primitive(seg).other_joint(prev_dot.into()) { let bend = self.drawing.primitive(dot).bend(); length += self.drawing.geometry().bend_shape(bend.into()).length(); prev_dot = self.drawing.primitive(bend).other_joint(dot); seg = self.drawing.primitive(prev_dot).seg().unwrap(); length += self.drawing.geometry().seg_shape(seg.into()).length(); } length } } } 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 { if let CompoundWeight::Zone(..) = self.drawing.compound_weight(compound) { return Some(GenericIndex::::new(compound.petgraph_index())); } } None }) } pub fn layer_zone_nodes( &self, layer: usize, ) -> impl Iterator> + '_ { self.drawing .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 NodeIndex::Compound(compound) = wrapper.data { if let CompoundWeight::Zone(..) = self.drawing.compound_weight(compound) { return Some(GenericIndex::::new(compound.petgraph_index())); } } None }) } pub fn zone_members( &self, zone: GenericIndex, ) -> impl Iterator + '_ { self.drawing .geometry() .compound_members(GenericIndex::new(zone.petgraph_index())) } pub fn drawing(&self) -> &Drawing { &self.drawing } pub fn rules(&self) -> &R { self.drawing.rules() } pub fn rules_mut(&mut self) -> &mut R { self.drawing.rules_mut() } pub fn zone(&self, index: GenericIndex) -> Zone { Zone::new(index, self) } pub fn via(&self, index: GenericIndex) -> Via { Via::new(index, self) } }