use enum_dispatch::enum_dispatch; use geo::{LineString, Point, Polygon}; use petgraph::stable_graph::NodeIndex; use crate::{ drawing::{ dot::{DotIndex, FixedDotIndex}, graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight, Retag}, primitive::{GenericPrimitive, GetLimbs, Primitive}, rules::RulesTrait, seg::SegIndex, Drawing, }, geometry::{compound::CompoundManagerTrait, poly::PolyShape, GetPos}, graph::{GenericIndex, GetNodeIndex}, layout::{CompoundWeight, Layout}, }; #[enum_dispatch] pub trait MakePolyShape { fn shape(&self) -> PolyShape; } #[enum_dispatch] pub trait GetMaybeApex { fn maybe_apex(&self) -> Option; } #[derive(Debug)] pub struct Zone<'a, R: RulesTrait> { pub index: GenericIndex, layout: &'a Layout, } impl<'a, R: RulesTrait> Zone<'a, R> { pub fn new(index: GenericIndex, layout: &'a Layout) -> Self { Self { index, layout } } fn is_apex(&self, dot: FixedDotIndex) -> bool { self.layout .drawing() .primitive(dot) .segs() .iter() .find(|seg| matches!(seg, SegIndex::Fixed(..))) .is_none() && self.layout.drawing().primitive(dot).bends().is_empty() } } impl<'a, R: RulesTrait> GetLayer for Zone<'a, R> { fn layer(&self) -> u64 { if let CompoundWeight::Zone(weight) = self.layout.drawing().compound_weight(self.index.into()) { weight.layer() } else { unreachable!(); } } } impl<'a, R: RulesTrait> GetMaybeNet for Zone<'a, R> { fn maybe_net(&self) -> Option { self.layout .drawing() .compound_weight(self.index.into()) .maybe_net() } } impl<'a, R: RulesTrait> MakePolyShape for Zone<'a, R> { fn shape(&self) -> PolyShape { PolyShape { polygon: Polygon::new( LineString::from( self.layout .drawing() .geometry() .compound_members(self.index.into()) .filter_map(|primitive_node| { let PrimitiveIndex::FixedDot(dot) = primitive_node else { return None; }; if self.is_apex(dot) { return None; } else { Some( self.layout .drawing() .geometry() .dot_weight(dot.into()) .pos(), ) } }) .collect::>(), ), vec![], ), } } } impl<'a, R: RulesTrait> GetMaybeApex for Zone<'a, R> { fn maybe_apex(&self) -> Option { self.layout .drawing() .geometry() .compound_members(self.index.into()) .find_map(|primitive_node| { if let PrimitiveIndex::FixedDot(dot) = primitive_node { if self.is_apex(dot) { return Some(dot); } } None }) } } #[enum_dispatch(GetLayer, GetMaybeNet)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum ZoneWeight { Solid(SolidZoneWeight), Pour(PourZoneWeight), } impl From> for GenericIndex { fn from(zone: GenericIndex) -> Self { GenericIndex::::new(zone.node_index()) } } #[derive(Debug, Clone, Copy, PartialEq)] pub struct SolidZoneWeight { pub layer: u64, pub maybe_net: Option, } impl GetLayer for SolidZoneWeight { fn layer(&self) -> u64 { self.layer } } impl GetMaybeNet for SolidZoneWeight { fn maybe_net(&self) -> Option { self.maybe_net } } impl From> for GenericIndex { fn from(zone: GenericIndex) -> Self { GenericIndex::::new(zone.node_index()) } } #[derive(Debug, Clone, Copy, PartialEq)] pub struct PourZoneWeight { pub layer: u64, pub maybe_net: Option, } impl<'a> GetLayer for PourZoneWeight { fn layer(&self) -> u64 { self.layer } } impl<'a> GetMaybeNet for PourZoneWeight { fn maybe_net(&self) -> Option { self.maybe_net } } impl From> for GenericIndex { fn from(zone: GenericIndex) -> Self { GenericIndex::::new(zone.node_index()) } }