// SPDX-FileCopyrightText: 2024 Topola contributors // // SPDX-License-Identifier: MIT use contracts_try::debug_ensures; use derive_getters::Getters; use enum_dispatch::enum_dispatch; use geo::Point; use rstar::AABB; use crate::{ drawing::{ band::BandTermsegIndex, bend::{BendIndex, BendWeight, LooseBendWeight}, cane::Cane, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, gear::GearIndex, graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, primitive::MakePrimitiveShape, rules::AccessRules, seg::{ FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, SegWeight, SeqLooseSegIndex, SeqLooseSegWeight, }, Drawing, DrawingEdit, DrawingException, Infringement, }, geometry::{edit::ApplyGeometryEdit, shape::Shape, GenericNode}, graph::{GenericIndex, GetPetgraphIndex}, layout::{ poly::{MakePolyShape, Poly, PolyWeight}, via::{Via, ViaWeight}, }, }; /// Represents a weight for various compounds #[derive(Debug, Clone, Copy)] #[enum_dispatch(GetMaybeNet)] pub enum CompoundWeight { /// Represents the weight of a polygon compound, includes its basic [`Layout`] information Poly(PolyWeight), /// Represents Via weight properties, containing its [`Layout`] properties Via(ViaWeight), } /// The alias to differ node types pub type NodeIndex = GenericNode>; pub type LayoutEdit = DrawingEdit; #[derive(Debug, Getters)] /// Structure for managing the Layout design pub struct Layout { drawing: Drawing, } impl Layout { pub fn new(drawing: Drawing) -> Self { Self { drawing } } } impl Layout { /// Insert [`Cane`] object into the [`Layout`] pub fn insert_cane( &mut self, recorder: &mut LayoutEdit, from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, seg_weight: SeqLooseSegWeight, bend_weight: LooseBendWeight, cw: bool, ) -> Result { self.drawing.insert_cane( recorder, from, around, dot_weight, seg_weight, bend_weight, cw, ) } /// Remove [`Cane`] object from the [`Layout`] pub fn remove_cane(&mut self, recorder: &mut LayoutEdit, cane: &Cane, face: LooseDotIndex) { self.drawing.remove_cane(recorder, 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()))] /// Insert [`Via`] into the [`Layout`] pub fn add_via( &mut self, recorder: &mut LayoutEdit, weight: ViaWeight, ) -> Result, Infringement> { let compound = self.drawing.add_compound(recorder, weight.into()); let mut dots = vec![]; for layer in weight.from_layer..=weight.to_layer { match self.drawing.add_fixed_dot( recorder, FixedDotWeight { circle: weight.circle, layer, maybe_net: weight.maybe_net, }, ) { Ok(dot) => { self.drawing.add_to_compound(recorder, dot, compound); dots.push(dot); } Err(err) => { // Remove inserted dots. self.drawing.remove_compound(recorder, compound); for dot in dots.iter().rev() { self.drawing.remove_fixed_dot(recorder, *dot); } return Err(err); } } } Ok(GenericIndex::::new(compound.petgraph_index())) } pub fn add_fixed_dot( &mut self, recorder: &mut LayoutEdit, weight: FixedDotWeight, ) -> Result { self.drawing.add_fixed_dot(recorder, weight) } pub fn add_fixed_dot_infringably( &mut self, recorder: &mut LayoutEdit, weight: FixedDotWeight, ) -> FixedDotIndex { self.drawing.add_fixed_dot_infringably(recorder, weight) } pub fn add_poly_fixed_dot( &mut self, recorder: &mut LayoutEdit, weight: FixedDotWeight, poly: GenericIndex, ) -> Result { let maybe_dot = self.drawing.add_fixed_dot(recorder, weight); if let Ok(dot) = maybe_dot { self.drawing.add_to_compound(recorder, dot, poly.into()); } maybe_dot } pub fn add_poly_fixed_dot_infringably( &mut self, recorder: &mut LayoutEdit, weight: FixedDotWeight, poly: GenericIndex, ) -> FixedDotIndex { let dot = self.drawing.add_fixed_dot_infringably(recorder, weight); self.drawing.add_to_compound(recorder, dot, poly.into()); dot } pub fn add_fixed_seg( &mut self, recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> Result { self.drawing.add_fixed_seg(recorder, from, to, weight) } pub fn add_fixed_seg_infringably( &mut self, recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> FixedSegIndex { self.drawing .add_fixed_seg_infringably(recorder, from, to, weight) } pub fn add_poly_fixed_seg( &mut self, recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, poly: GenericIndex, ) -> Result { let maybe_seg = self.add_fixed_seg(recorder, from, to, weight); if let Ok(seg) = maybe_seg { self.drawing.add_to_compound(recorder, seg, poly.into()); } maybe_seg } pub fn add_poly_fixed_seg_infringably( &mut self, recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, poly: GenericIndex, ) -> FixedSegIndex { let seg = self.add_fixed_seg_infringably(recorder, from, to, weight); self.drawing.add_to_compound(recorder, seg, poly.into()); seg } pub fn add_lone_loose_seg( &mut self, recorder: &mut LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, weight: LoneLooseSegWeight, ) -> Result { self.drawing.add_lone_loose_seg(recorder, from, to, weight) } pub fn add_seq_loose_seg( &mut self, recorder: &mut LayoutEdit, from: DotIndex, to: LooseDotIndex, weight: SeqLooseSegWeight, ) -> Result { self.drawing.add_seq_loose_seg(recorder, from, to, weight) } pub fn move_dot( &mut self, recorder: &mut LayoutEdit, dot: DotIndex, to: Point, ) -> Result<(), Infringement> { self.drawing.move_dot(recorder, dot, to) } pub fn add_poly( &mut self, recorder: &mut LayoutEdit, weight: PolyWeight, ) -> GenericIndex { GenericIndex::::new( self.drawing .add_compound(recorder, CompoundWeight::Poly(weight)) .petgraph_index(), ) } pub fn remove_band( &mut self, recorder: &mut LayoutEdit, band: BandTermsegIndex, ) -> Result<(), DrawingException> { self.drawing.remove_band(recorder, band) } pub fn polys( &self, node: GenericIndex, ) -> impl Iterator> + '_ { self.drawing.compounds(node) } pub fn poly_nodes(&self) -> impl Iterator> + '_ { self.drawing.rtree().iter().filter_map(|wrapper| { if let NodeIndex::Compound(compound) = wrapper.data { if let CompoundWeight::Poly(..) = self.drawing.compound_weight(compound) { return Some(GenericIndex::::new(compound.petgraph_index())); } } None }) } pub fn layer_poly_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::Poly(..) = self.drawing.compound_weight(compound) { return Some(GenericIndex::::new(compound.petgraph_index())); } } None }) } pub fn poly_members( &self, poly: GenericIndex, ) -> impl Iterator + '_ { self.drawing .geometry() .compound_members(GenericIndex::new(poly.petgraph_index())) } pub fn is_node_in_layer(&self, index: NodeIndex, active_layer: usize) -> bool { use crate::drawing::graph::GetLayer; match index { NodeIndex::Primitive(primitive) => { primitive.primitive(&self.drawing).layer() == active_layer } NodeIndex::Compound(compound) => match self.drawing.compound_weight(compound) { CompoundWeight::Poly(_) => { self.poly(GenericIndex::::new(compound.petgraph_index())) .layer() == active_layer } CompoundWeight::Via(weight) => { weight.from_layer >= active_layer && weight.to_layer <= active_layer } }, } } pub fn node_shape(&self, index: NodeIndex) -> Shape { match index { NodeIndex::Primitive(primitive) => primitive.primitive(&self.drawing).shape().into(), NodeIndex::Compound(compound) => match self.drawing.compound_weight(compound) { CompoundWeight::Poly(_) => self .poly(GenericIndex::::new(compound.petgraph_index())) .shape() .into(), CompoundWeight::Via(_) => self .via(GenericIndex::::new(compound.petgraph_index())) .shape() .into(), }, } } pub fn rules(&self) -> &R { self.drawing.rules() } pub fn rules_mut(&mut self) -> &mut R { self.drawing.rules_mut() } pub fn poly(&self, index: GenericIndex) -> Poly { Poly::new(index, self) } pub fn via(&self, index: GenericIndex) -> Via { Via::new(index, self) } } impl ApplyGeometryEdit< PrimitiveWeight, DotWeight, SegWeight, BendWeight, CompoundWeight, PrimitiveIndex, DotIndex, SegIndex, BendIndex, > for Layout { fn apply(&mut self, edit: &LayoutEdit) { self.drawing.apply(edit); } }