diff --git a/committed.toml b/committed.toml index 5ec9641..fafed2e 100644 --- a/committed.toml +++ b/committed.toml @@ -17,7 +17,7 @@ allowed_scopes = [ "topola-egui", # Generated using - # `find src -type f | awk '!/lib.rs|mod.rs/ { print "\"" substr($1, 1 + 4, length($1) - 4 - 3) "\","; }' | sort`. + # `find src -type f | awk '!/lib.rs/ { print "\"" substr($1, 1 + 4, length($1) - 4 - 3) "\","; }' | sort`. "autorouter/autoroute", "autorouter/autorouter", "autorouter/compare_detours", @@ -25,11 +25,13 @@ allowed_scopes = [ "autorouter/history", "autorouter/invoker", "autorouter/measure_length", + "autorouter/mod", "autorouter/place_via", "autorouter/pointroute", "autorouter/ratsnest", "autorouter/remove_bands", "autorouter/selection", + "board/mod", "drawing/band", "drawing/bend", "drawing/cane", @@ -41,11 +43,13 @@ allowed_scopes = [ "drawing/guide", "drawing/head", "drawing/loose", + "drawing/mod", "drawing/primitive", "drawing/seg", "geometry/compound", "geometry/edit", "geometry/geometry", + "geometry/mod", "geometry/polygon", "geometry/primitive", "geometry/recording_with_rtree", @@ -55,22 +59,26 @@ allowed_scopes = [ "interactor/activity", "interactor/interaction", "interactor/interactor", + "interactor/mod", "interactor/route_plan", "layout/collect_bands", "layout/layout", + "layout/mod", "layout/poly", - "layout/via", "math/cyclic_search", "math/line", + "math/mod", "math/polygon_tangents", "math/tangents", "math/tunnel", "router/draw", + "router/mod", "router/navcord", "router/navcorder", "router/navmesh", "router/ng/eval", "router/ng/floating", + "router/ng/mod", "router/ng/poly", "router/ng/router", "router/prenavmesh", @@ -78,6 +86,7 @@ allowed_scopes = [ "router/router", "router/thetastar", "specctra/design", + "specctra/mod", "stepper", "triangulation", ] diff --git a/crates/topola-cli/src/main.rs b/crates/topola-cli/src/main.rs index 8b660fd..94e1f7d 100644 --- a/crates/topola-cli/src/main.rs +++ b/crates/topola-cli/src/main.rs @@ -5,14 +5,9 @@ use clap::Parser; use std::fs::File; use std::io::BufReader; -use topola::autorouter::execution::Command; -use topola::autorouter::history::History; use topola::autorouter::invoker::Invoker; -use topola::autorouter::selection::PinSelection; use topola::autorouter::Autorouter; -use topola::autorouter::AutorouterOptions; use topola::layout::LayoutEdit; -use topola::router::RouterOptions; use topola::specctra::design::SpecctraDesign; pub mod cli; @@ -33,22 +28,8 @@ fn main() -> Result<(), std::io::Error> { let commands_bufread = BufReader::new(command_file); serde_json::from_reader(commands_bufread)? } else { - let mut history = History::new(); - history.do_( - Command::Autoroute( - PinSelection::new_select_layer(&board, 0), - AutorouterOptions { - presort_by_pairwise_detours: false, - router_options: RouterOptions { - wrap_around_bands: true, - squeeze_through_under_bends: false, - routed_band_width: 100.0, - }, - }, - ), - None, - ); - history + eprintln!("no commands given"); + return Ok(()); }; let mut invoker = Invoker::new(Autorouter::new(board).unwrap()); diff --git a/crates/topola-egui/src/actions.rs b/crates/topola-egui/src/actions.rs index bb4d538..91aa271 100644 --- a/crates/topola-egui/src/actions.rs +++ b/crates/topola-egui/src/actions.rs @@ -266,10 +266,9 @@ impl PlaceActions { pub fn render_menu( &mut self, - ctx: &Context, + _ctx: &Context, ui: &mut Ui, have_workspace: bool, - is_placing_via: &mut bool, ) -> egui::InnerResponse<()> { ui.add_enabled_ui(have_workspace, |ui| { self.place_via.toggle_widget(ui, is_placing_via); diff --git a/crates/topola-egui/src/menu_bar.rs b/crates/topola-egui/src/menu_bar.rs index 098e60b..d92a3a4 100644 --- a/crates/topola-egui/src/menu_bar.rs +++ b/crates/topola-egui/src/menu_bar.rs @@ -6,10 +6,14 @@ use std::{collections::BTreeSet, ops::ControlFlow, path::Path, sync::mpsc::Sende use topola::{ autorouter::{ - execution::Command, invoker::InvokerError, selection::Selection, AutorouterOptions, + execution::Command, + invoker::InvokerError, + selection::{PinSelector, Selection}, + AutorouterOptions, }, board::AccessMesadata, interactor::{interaction::InteractionStepper, route_plan::RoutePlan}, + layout::NodeIndex, router::RouterOptions, specctra::{design::SpecctraDesign, ParseError, ParseErrorContext as SpecctraLoadingError}, }; @@ -25,7 +29,6 @@ use crate::{ pub struct MenuBar { pub autorouter_options: AutorouterOptions, - pub is_placing_via: bool, pub show_ratsnest: bool, pub show_navmesh: bool, pub show_triangulation: bool, @@ -49,7 +52,6 @@ impl MenuBar { squeeze_through_under_bends: true, }, }, - is_placing_via: false, show_ratsnest: true, show_navmesh: false, show_triangulation: false, @@ -137,12 +139,9 @@ impl MenuBar { // those outside... ui.menu_button(tr.text("tr-menu-place"), |ui| { - actions.place.render_menu( - ctx, - ui, - maybe_workspace.is_some(), - &mut self.is_placing_via, - ) + actions + .place + .render_menu(ctx, ui, maybe_workspace.is_some()) }); ui.menu_button(tr.text("tr-menu-route"), |ui| { @@ -299,19 +298,24 @@ impl MenuBar { ) { let mut selection = workspace.overlay.take_selection(); if let Some(active_layer) = workspace.appearance_panel.active_layer { - let active_layer = workspace - .interactor - .invoker() - .autorouter() - .board() - .layout() - .rules() - .layer_layername(active_layer) - .expect("unknown active layer"); - selection - .pin_selection - .0 - .retain(|i| i.layer == active_layer); + let valid_pins: BTreeSet<_> = { + let board = workspace.interactor.invoker().autorouter().board(); + board + .layout() + .drawing() + .layer_primitive_nodes(active_layer) + .filter_map(|node| { + board.node_pinname(&NodeIndex::Primitive(node)) + }) + .cloned() + .map(|pin| PinSelector { pin }) + .collect() + }; + selection.pin_selection.0 = + core::mem::take(&mut selection.pin_selection.0) + .intersection(&valid_pins) + .cloned() + .collect(); } if let Err(err) = workspace.interactor.schedule(op(selection)) { error_dialog.push_error("tr-module-invoker", format!("{}", err)); @@ -344,8 +348,10 @@ impl MenuBar { }); } } else if actions.route.autoroute.consume_key_triggered(ctx, ui) { - schedule(error_dialog, workspace, |selection| { - Command::Autoroute(selection.pin_selection, opts) + schedule(error_dialog, workspace, |selection| Command::Autoroute { + pins: selection.pin_selection, + active_layer, + options: opts, }); } else if actions .inspect @@ -353,7 +359,11 @@ impl MenuBar { .consume_key_triggered(ctx, ui) { schedule(error_dialog, workspace, |selection| { - Command::CompareDetours(selection.pin_selection, opts) + Command::CompareDetours { + pins: selection.pin_selection + active_layer, + options: opts, + } }); } else if actions .inspect diff --git a/src/autorouter/autoroute.rs b/src/autorouter/autoroute.rs index d165117..1d93d92 100644 --- a/src/autorouter/autoroute.rs +++ b/src/autorouter/autoroute.rs @@ -36,6 +36,8 @@ pub enum AutorouteContinueStatus { pub struct AutorouteExecutionStepper { /// An iterator over ratlines that tracks which segments still need to be routed. ratlines_iter: Box>>, + /// The layer on which the routing should be done. + layer: usize, /// The options for the autorouting process, defining how routing should be carried out. options: AutorouterOptions, /// Stores the current route being processed, if any. @@ -53,6 +55,7 @@ impl AutorouteExecutionStepper { pub fn new( autorouter: &mut Autorouter, ratlines: impl IntoIterator> + 'static, + layer: usize, options: AutorouterOptions, ) -> Result { let mut ratlines_iter = Box::new(ratlines.into_iter()); @@ -66,11 +69,13 @@ impl AutorouteExecutionStepper { Ok(Self { ratlines_iter, + layer, options, route: Some(router.route( LayoutEdit::new(), origin, destination, + layer, options.router_options.routed_band_width, )?), curr_ratline: Some(curr_ratline), @@ -154,6 +159,7 @@ impl Step, Option, AutorouteContinu recorder, source, target, + self.layer, self.options.router_options.routed_band_width, )?); } else { diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index 7d2e02b..5a78500 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -14,7 +14,7 @@ use crate::{ board::{AccessMesadata, Board}, drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement}, graph::MakeRef, - layout::{via::ViaWeight, LayoutEdit}, + layout::LayoutEdit, router::{navmesh::NavmeshError, ng, thetastar::ThetastarError, RouterOptions}, triangulation::GetTrianvertexNodeIndex, }; @@ -23,7 +23,6 @@ use super::{ autoroute::AutorouteExecutionStepper, compare_detours::CompareDetoursExecutionStepper, measure_length::MeasureLengthExecutionStepper, - place_via::PlaceViaExecutionStepper, pointroute::PointrouteExecutionStepper, ratsnest::{Ratsnest, RatvertexIndex}, remove_bands::RemoveBandsExecutionStepper, @@ -69,6 +68,7 @@ impl Autorouter { pub fn pointroute( &mut self, selection: &PinSelection, + layer: usize, point: Point, options: AutorouterOptions, ) -> Result { @@ -84,7 +84,7 @@ impl Autorouter { RatvertexIndex::Poly(poly) => poly.ref_(self.board.layout()).apex(), }; - PointrouteExecutionStepper::new(self, origin_dot, point, options) + PointrouteExecutionStepper::new(self, origin_dot, layer, point, options) } pub fn undo_pointroute(&mut self, band: BandTermsegIndex) -> Result<(), AutorouterError> { @@ -97,17 +97,19 @@ impl Autorouter { pub fn autoroute( &mut self, selection: &PinSelection, + layer: usize, options: AutorouterOptions, ) -> Result { - self.autoroute_ratlines(self.selected_ratlines(selection), options) + self.autoroute_ratlines(self.selected_ratlines(selection), layer, options) } pub(super) fn autoroute_ratlines( &mut self, ratlines: Vec>, + layer: usize, options: AutorouterOptions, ) -> Result { - AutorouteExecutionStepper::new(self, ratlines, options) + AutorouteExecutionStepper::new(self, ratlines, layer, options) } pub fn undo_autoroute(&mut self, selection: &PinSelection) -> Result<(), AutorouterError> { @@ -249,22 +251,24 @@ impl Autorouter { pub fn compare_detours( &mut self, selection: &PinSelection, + layer: usize, options: AutorouterOptions, ) -> Result { let ratlines = self.selected_ratlines(selection); - if ratlines.len() < 2 { + if ratlines.len() != 2 { return Err(AutorouterError::NeedExactlyTwoRatlines); } - self.compare_detours_ratlines(ratlines[0], ratlines[1], options) + self.compare_detours_ratlines(ratlines[0], ratlines[1], layer, options) } pub(super) fn compare_detours_ratlines( &mut self, ratline1: EdgeIndex, ratline2: EdgeIndex, + layer: usize, options: AutorouterOptions, ) -> Result { - CompareDetoursExecutionStepper::new(self, ratline1, ratline2, options) + CompareDetoursExecutionStepper::new(self, ratline1, ratline2, layer, options) } pub fn measure_length( diff --git a/src/autorouter/compare_detours.rs b/src/autorouter/compare_detours.rs index cbb69d7..a8e35e7 100644 --- a/src/autorouter/compare_detours.rs +++ b/src/autorouter/compare_detours.rs @@ -39,11 +39,16 @@ impl CompareDetoursExecutionStepper { autorouter: &mut Autorouter, ratline1: EdgeIndex, ratline2: EdgeIndex, + layer: usize, options: AutorouterOptions, ) -> Result { Ok(Self { - autoroute: autorouter.autoroute_ratlines(vec![ratline1, ratline2], options)?, - next_autoroute: Some(autorouter.autoroute_ratlines(vec![ratline2, ratline1], options)?), + autoroute: autorouter.autoroute_ratlines(vec![ratline1, ratline2], layer, options)?, + next_autoroute: Some(autorouter.autoroute_ratlines( + vec![ratline2, ratline1], + layer, + options, + )?), ratline1, ratline2, total_length1: 0.0, diff --git a/src/autorouter/execution.rs b/src/autorouter/execution.rs index 840a30d..1f208e6 100644 --- a/src/autorouter/execution.rs +++ b/src/autorouter/execution.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::{ board::AccessMesadata, - layout::{via::ViaWeight, LayoutEdit}, + layout::LayoutEdit, router::ng, stepper::{Abort, Step}, }; @@ -25,11 +25,13 @@ use super::{ Autorouter, AutorouterOptions, }; -type Type = PinSelection; - #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Command { - Autoroute(PinSelection, AutorouterOptions), + Autoroute { + pins: PinSelection, + active_layer: usize, + options: AutorouterOptions, + }, TopoAutoroute { selection: PinSelection, #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] @@ -37,9 +39,13 @@ pub enum Command { active_layer: String, routed_band_width: f64, }, - PlaceVia(ViaWeight), + PlaceVia(DotWeight), RemoveBands(BandSelection), - CompareDetours(Type, AutorouterOptions), + CompareDetours { + pins: PinSelection, + active_layer: usize, + options: AutorouterOptions, + }, MeasureLength(BandSelection), } diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index 4112081..6aa0c12 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -33,7 +33,6 @@ use super::{ execution::{Command, ExecutionStepper}, history::{History, HistoryError}, measure_length::MeasureLengthExecutionStepper, - place_via::PlaceViaExecutionStepper, remove_bands::RemoveBandsExecutionStepper, Autorouter, AutorouterError, }; @@ -166,14 +165,18 @@ impl Invoker { #[debug_requires(self.ongoing_command.is_none())] fn dispatch_command(&mut self, command: &Command) -> Result, InvokerError> { Ok(match command { - Command::Autoroute(selection, options) => { - let mut ratlines = self.autorouter.selected_ratlines(selection); + Command::Autoroute { + pins, + active_layer, + options, + } => { + let mut ratlines = self.autorouter.selected_ratlines(pins); if options.presort_by_pairwise_detours { ratlines.sort_unstable_by(|a, b| { let mut compare_detours = self .autorouter - .compare_detours_ratlines(*a, *b, *options) + .compare_detours_ratlines(*a, *b, *active_layer, *options) .unwrap(); if let Ok((al, bl)) = compare_detours.finish(&mut self.autorouter) { PartialOrd::partial_cmp(&al, &bl).unwrap() @@ -183,7 +186,11 @@ impl Invoker { }); } - ExecutionStepper::Autoroute(self.autorouter.autoroute_ratlines(ratlines, *options)?) + ExecutionStepper::Autoroute(self.autorouter.autoroute_ratlines( + ratlines, + *active_layer, + *options, + )?) } Command::TopoAutoroute { selection, @@ -216,9 +223,15 @@ impl Invoker { Command::RemoveBands(selection) => { ExecutionStepper::RemoveBands(self.autorouter.remove_bands(selection)?) } - Command::CompareDetours(selection, options) => ExecutionStepper::CompareDetours( - self.autorouter.compare_detours(selection, *options)?, - ), + Command::CompareDetours { + pins, + active_layer, + options, + } => ExecutionStepper::CompareDetours(self.autorouter.compare_detours( + pins, + *active_layer, + *options, + )?), Command::MeasureLength(selection) => { ExecutionStepper::MeasureLength(self.autorouter.measure_length(selection)?) } diff --git a/src/autorouter/place_via.rs b/src/autorouter/place_via.rs index 01a0d44..711fe58 100644 --- a/src/autorouter/place_via.rs +++ b/src/autorouter/place_via.rs @@ -6,21 +6,18 @@ //! the process of inserting a via with a specified weight and //! checks if the via has already been placed. -use crate::{ - board::AccessMesadata, - layout::{via::ViaWeight, LayoutEdit}, -}; +use crate::{board::AccessMesadata, layout::LayoutEdit}; use super::{invoker::GetDebugOverlayData, Autorouter, AutorouterError}; #[derive(Debug)] pub struct PlaceViaExecutionStepper { - weight: ViaWeight, + weight: FixedDotWeight, done: bool, } impl PlaceViaExecutionStepper { - pub fn new(weight: ViaWeight) -> Result { + pub fn new(weight: FixedDotWeight) -> Result { Ok(Self { weight, done: false, @@ -38,7 +35,7 @@ impl PlaceViaExecutionStepper { autorouter .board .layout_mut() - .add_via(&mut edit, self.weight)?; + .add_fixed_dot(&mut edit, self.weight)?; Ok(Some(edit)) } else { Ok(None) diff --git a/src/autorouter/pointroute.rs b/src/autorouter/pointroute.rs index 7a37d63..d02ebe8 100644 --- a/src/autorouter/pointroute.rs +++ b/src/autorouter/pointroute.rs @@ -7,19 +7,20 @@ use std::ops::ControlFlow; use geo::Point; use crate::{ + autorouter::{Autorouter, AutorouterError, AutorouterOptions}, board::AccessMesadata, drawing::{ band::BandTermsegIndex, dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight}, }, + geometry::NodeMetadata, + graph::GetPetgraphIndex, layout::LayoutEdit, math::Circle, router::{RouteStepper, Router}, stepper::Step, }; -use super::{Autorouter, AutorouterError, AutorouterOptions}; - pub struct PointrouteExecutionStepper { route: RouteStepper, options: AutorouterOptions, @@ -29,18 +30,28 @@ impl PointrouteExecutionStepper { pub fn new( autorouter: &mut Autorouter, origin: FixedDotIndex, + layer: usize, point: Point, options: AutorouterOptions, ) -> Result { let destination = autorouter.board.add_fixed_dot_infringably( &mut LayoutEdit::new(), + NodeMetadata { + from_layer: layer, + to_layer: layer, + maybe_net: autorouter + .board + .layout() + .drawing() + .geometry() + .metadata(origin.petgraph_index()) + .maybe_net, + }, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: point, r: options.router_options.routed_band_width / 2.0, }, - layer: 0, - maybe_net: None, }), None, ); @@ -52,6 +63,7 @@ impl PointrouteExecutionStepper { LayoutEdit::new(), origin, destination, + layer, options.router_options.routed_band_width, )?, options, diff --git a/src/autorouter/ratsnest.rs b/src/autorouter/ratsnest.rs index f33c69d..b28fc92 100644 --- a/src/autorouter/ratsnest.rs +++ b/src/autorouter/ratsnest.rs @@ -23,11 +23,11 @@ use crate::{ drawing::{ band::BandTermsegIndex, dot::FixedDotIndex, - graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex}, + graph::{MakePrimitive, PrimitiveIndex}, primitive::MakePrimitiveShape, rules::AccessRules, }, - geometry::shape::AccessShape, + geometry::{shape::AccessShape, GetMetadata}, graph::{GenericIndex, GetPetgraphIndex, MakeRef}, layout::{ poly::{MakePolygon, PolyWeight}, @@ -110,7 +110,7 @@ impl Ratsnest { if let PrimitiveIndex::FixedDot(dot) = node { if layout.drawing().compounds(dot).next().is_none() { handle_rvw( - layout.drawing().primitive(dot).maybe_net(), + layout.drawing().primitive(dot).metadata().maybe_net, RatvertexIndex::FixedDot(dot), node.primitive(layout.drawing()).shape().center(), )?; @@ -120,7 +120,11 @@ impl Ratsnest { for poly in layout.layer_poly_nodes(layer) { handle_rvw( - layout.drawing().compound_weight(poly.into()).maybe_net(), + layout + .drawing() + .geometry() + .metadata(poly.petgraph_index()) + .maybe_net, RatvertexIndex::Poly(poly), poly.ref_(layout).shape().center(), )?; diff --git a/src/autorouter/selection.rs b/src/autorouter/selection.rs index 959d25b..ca38b0b 100644 --- a/src/autorouter/selection.rs +++ b/src/autorouter/selection.rs @@ -9,22 +9,17 @@ use serde::{Deserialize, Serialize}; use crate::{ board::{AccessMesadata, BandName, Board, ResolvedSelector}, - drawing::{ - graph::{MakePrimitive, PrimitiveIndex}, - Collect, - }, + drawing::{graph::PrimitiveIndex, Collect}, geometry::{ shape::{AccessShape, Shape}, - GenericNode, GetLayer, + GenericNode, }, - graph::{GenericIndex, GetPetgraphIndex, MakeRef}, - layout::{poly::PolyWeight, CompoundWeight, NodeIndex}, + layout::NodeIndex, }; #[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] pub struct PinSelector { pub pin: String, - pub layer: String, } impl PinSelector { @@ -32,43 +27,8 @@ impl PinSelector { board: &Board, node: NodeIndex, ) -> Option { - let layer = match node { - NodeIndex::Primitive(primitive) => { - primitive.primitive(board.layout().drawing()).layer() - } - NodeIndex::Compound(compound) => { - if let CompoundWeight::Poly(..) = board.layout().drawing().compound_weight(compound) - { - GenericIndex::::new(compound.petgraph_index()) - .ref_(board.layout()) - .layer() - } else { - unreachable!() - } - } - }; - - if let (Some(pinname), Some(layername)) = ( - board.node_pinname(&node), - board.layout().rules().layer_layername(layer), - ) { - Some(PinSelector { - pin: pinname.to_string(), - layer: layername.to_string(), - }) - } else { - None - } - } - - pub fn try_from_pin_and_layer_id( - board: &Board, - pin: &str, - layer: usize, - ) -> Option { - Some(PinSelector { - pin: pin.to_string(), - layer: board.layout().rules().layer_layername(layer)?.to_string(), + board.node_pinname(&node).map(|pinname| PinSelector { + pin: pinname.to_string(), }) } } @@ -255,11 +215,10 @@ impl Selection { self.band_selection.0.insert(x); } } - ResolvedSelector::Pin { pin_name, layer } => { - if let Some(x) = PinSelector::try_from_pin_and_layer_id(board, pin_name, layer) - { - self.pin_selection.0.insert(x); - } + ResolvedSelector::Pin { pin_name } => { + self.pin_selection.0.insert(PinSelector { + pin: pin_name.to_string(), + }); } } } diff --git a/src/board/mod.rs b/src/board/mod.rs index 7a51a30..99cba9c 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -22,8 +22,8 @@ use crate::{ seg::{FixedSegIndex, FixedSegWeight, SegIndex, SegWeight}, Collect, DrawingException, }, - geometry::{edit::ApplyGeometryEdit, GenericNode, GetLayer}, - graph::{GenericIndex, MakeRef}, + geometry::{edit::ApplyGeometryEdit, GenericNode, NodeMetadata}, + graph::GenericIndex, layout::{poly::PolyWeight, CompoundEntryLabel, CompoundWeight, Layout, LayoutEdit, NodeIndex}, router::ng::EtchedPath, }; @@ -34,40 +34,30 @@ pub type BandName = planar_incr_embed::navmesh::OrderedPair; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum ResolvedSelector<'a> { Band { band_uid: BandUid }, - Pin { pin_name: &'a str, layer: usize }, + Pin { pin_name: &'a str }, } impl<'a> ResolvedSelector<'a> { pub fn try_from_node(board: &'a Board, node: NodeIndex) -> Option { - use crate::{drawing::graph::MakePrimitive, graph::GetPetgraphIndex}; - - let (layer, loose) = match node { - NodeIndex::Primitive(primitive) => ( - primitive.primitive(board.layout().drawing()).layer(), - primitive.try_into().ok(), - ), + let loose = match node { + NodeIndex::Primitive(primitive) => primitive.try_into().ok(), NodeIndex::Compound(compound) => { match board.layout().drawing().compound_weight(compound) { - CompoundWeight::Poly(..) => ( - GenericIndex::::new(compound.petgraph_index()) - .ref_(board.layout()) - .layer(), - None, - ), - _ => return None, + CompoundWeight::Poly(..) => None, } } }; - if let Some(pin_name) = board.node_pinname(&node) { - Some(ResolvedSelector::Pin { pin_name, layer }) - } else { - loose.and_then(|loose| { - Some(ResolvedSelector::Band { - band_uid: board.layout().drawing().loose_band_uid(loose).ok()?, + board + .node_pinname(&node) + .map(|pin_name| ResolvedSelector::Pin { pin_name }) + .or_else(|| { + loose.and_then(|loose| { + Some(ResolvedSelector::Band { + band_uid: board.layout().drawing().loose_band_uid(loose).ok()?, + }) }) }) - } } } @@ -110,10 +100,13 @@ impl Board { pub fn add_fixed_dot_infringably( &mut self, recorder: &mut LayoutEdit, + meta: NodeMetadata, weight: FixedDotWeight, maybe_pin: Option, ) -> FixedDotIndex { - let dot = self.layout.add_fixed_dot_infringably(recorder, weight); + let dot = self + .layout + .add_fixed_dot_infringably(recorder, meta, weight); if let Some(pin) = maybe_pin { self.node_to_pinname @@ -129,6 +122,7 @@ impl Board { pub fn add_fixed_seg_infringably( &mut self, recorder: &mut LayoutEdit, + meta: NodeMetadata, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, @@ -136,7 +130,7 @@ impl Board { ) -> FixedSegIndex { let seg = self .layout - .add_fixed_seg_infringably(recorder, from, to, weight); + .add_fixed_seg_infringably(recorder, meta, from, to, weight); if let Some(pin) = maybe_pin { self.node_to_pinname @@ -152,11 +146,14 @@ impl Board { pub fn add_poly_with_nodes( &mut self, recorder: &mut LayoutEdit, + meta: NodeMetadata, weight: PolyWeight, maybe_pin: Option, nodes: &[PrimitiveIndex], ) -> GenericIndex { - let (poly, apex) = self.layout.add_poly_with_nodes(recorder, weight, nodes); + let (poly, apex) = self + .layout + .add_poly_with_nodes(recorder, meta, weight, nodes); if let Some(pin) = maybe_pin { for i in nodes { diff --git a/src/drawing/band.rs b/src/drawing/band.rs index 4bd9e81..31415df 100644 --- a/src/drawing/band.rs +++ b/src/drawing/band.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use crate::{ - geometry::{shape::MeasureLength, GetLayer}, + geometry::{shape::MeasureLength, GetMetadata}, graph::MakeRef, }; @@ -40,9 +40,11 @@ impl<'a, CW: 'a, Cel: 'a, R: 'a> BandRef<'a, CW, Cel, R> { } } -impl GetLayer for BandRef<'_, CW, Cel, R> { - fn layer(&self) -> usize { - self.first_seg.primitive(self.drawing).layer() +impl BandRef<'_, CW, Cel, R> { + pub fn layer(&self) -> usize { + let meta = self.first_seg.primitive(self.drawing).metadata(); + debug_assert_eq!(meta.from_layer, meta.to_layer); + meta.from_layer } } diff --git a/src/drawing/bend.rs b/src/drawing/bend.rs index c4d50e0..ce0d80d 100644 --- a/src/drawing/bend.rs +++ b/src/drawing/bend.rs @@ -6,12 +6,12 @@ use enum_dispatch::enum_dispatch; use crate::{ drawing::{ - graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, + graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight}, primitive::{GenericPrimitive, Primitive}, rules::AccessRules, Drawing, }, - geometry::{GetLayer, GetOffset, GetWidth, SetOffset}, + geometry::{GetOffset, GetWidth, SetOffset}, graph::{GenericIndex, GetPetgraphIndex}, }; @@ -45,7 +45,7 @@ impl TryFrom for BendIndex { } } -#[enum_dispatch(GetOffset, SetOffset, GetWidth, GetLayer)] +#[enum_dispatch(GetOffset, SetOffset, GetWidth)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum BendWeight { Fixed(FixedBendWeight), @@ -109,20 +109,6 @@ impl SetOffset for LooseBendWeight { pub struct GeneralBendWeight { pub width: f64, pub offset: f64, - pub layer: usize, - pub maybe_net: Option, -} - -impl GetLayer for GeneralBendWeight { - fn layer(&self) -> usize { - self.layer - } -} - -impl GetMaybeNet for GeneralBendWeight { - fn maybe_net(&self) -> Option { - self.maybe_net - } } impl GetOffset for GeneralBendWeight { diff --git a/src/drawing/dot.rs b/src/drawing/dot.rs index 66d98e9..f57a07c 100644 --- a/src/drawing/dot.rs +++ b/src/drawing/dot.rs @@ -9,12 +9,12 @@ use petgraph::stable_graph::NodeIndex; use crate::{ drawing::{ - graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, + graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight}, primitive::{GenericPrimitive, Primitive}, rules::AccessRules, Drawing, }, - geometry::{GetLayer, GetSetPos, GetWidth}, + geometry::{GetSetPos, GetWidth}, graph::{GenericIndex, GetPetgraphIndex}, math::Circle, }; @@ -47,7 +47,7 @@ impl TryFrom for DotIndex { } } -#[enum_dispatch(GetSetPos, GetWidth, GetLayer)] +#[enum_dispatch(GetSetPos, GetWidth)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum DotWeight { Fixed(FixedDotWeight), @@ -104,20 +104,6 @@ impl GetSetPos for LooseDotWeight { #[derive(Debug, Clone, Copy, PartialEq)] pub struct GeneralDotWeight { pub circle: Circle, - pub layer: usize, - pub maybe_net: Option, -} - -impl GetLayer for GeneralDotWeight { - fn layer(&self) -> usize { - self.layer - } -} - -impl GetMaybeNet for GeneralDotWeight { - fn maybe_net(&self) -> Option { - self.maybe_net - } } impl GetSetPos for GeneralDotWeight { diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs index c47a18b..5167cd9 100644 --- a/src/drawing/drawing.rs +++ b/src/drawing/drawing.rs @@ -18,7 +18,7 @@ use crate::{ collect::Collect, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, gear::{GearIndex, GetNextGear}, - graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, + graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight}, guide::Guide, loose::{GetPrevNextLoose, Loose, LooseIndex}, primitive::{ @@ -36,7 +36,7 @@ use crate::{ recording_with_rtree::RecordingGeometryWithRtree, with_rtree::BboxedIndex, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, - GetLayer, GetOffset, GetSetPos, GetWidth, + GetMetadata, GetOffset, GetSetPos, GetWidth, NodeMetadata, }, graph::MakeRef, graph::{GenericIndex, GetPetgraphIndex}, @@ -297,10 +297,12 @@ impl Drawing { pub fn add_fixed_dot( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, weight: FixedDotWeight, ) -> Result { self.add_dot_with_infringement_filtering( recorder, + meta, weight, &|_drawing, _infringer, _infringee| true, ) @@ -318,23 +320,25 @@ impl Drawing { pub fn add_fixed_dot_infringably( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, weight: FixedDotWeight, ) -> FixedDotIndex { - self.add_dot_infringably(recorder, weight) + self.add_dot_infringably(recorder, meta, weight) } #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))] - fn add_dot_with_infringement_filtering + GetLayer>( + fn add_dot_with_infringement_filtering>( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, weight: W, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool, ) -> Result, Infringement> where GenericIndex: Into + Copy, { - let dot = self.add_dot_infringably(recorder, weight); + let dot = self.add_dot_infringably(recorder, meta, weight); self.fail_and_remove_if_infringes_except(recorder, dot.into(), predicate)?; Ok(dot) @@ -346,12 +350,14 @@ impl Drawing { pub fn add_fixed_seg( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> Result { self.add_seg_with_infringement_filtering( recorder, + meta, from.into(), to.into(), weight, @@ -364,11 +370,12 @@ impl Drawing { pub fn add_fixed_seg_infringably( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, ) -> FixedSegIndex { - self.add_seg_infringably(recorder, from.into(), to.into(), weight) + self.add_seg_infringably(recorder, meta, from.into(), to.into(), weight) } #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))] @@ -378,12 +385,14 @@ impl Drawing { pub fn add_lone_loose_seg( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: FixedDotIndex, to: FixedDotIndex, weight: LoneLooseSegWeight, ) -> Result { let seg = self.add_seg_with_infringement_filtering( recorder, + meta, from.into(), to.into(), weight, @@ -399,12 +408,14 @@ impl Drawing { pub fn add_seq_loose_seg( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: DotIndex, to: LooseDotIndex, weight: SeqLooseSegWeight, ) -> Result { let seg = self.add_seg_with_infringement_filtering( recorder, + meta, from, to.into(), weight, @@ -429,9 +440,10 @@ impl Drawing { #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().edge_count() >= old(self.recording_geometry_with_rtree.graph().edge_count() + 2))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))] - fn add_seg_with_infringement_filtering + GetLayer>( + fn add_seg_with_infringement_filtering>( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: DotIndex, to: DotIndex, weight: W, @@ -440,7 +452,7 @@ impl Drawing { where GenericIndex: Into + Copy, { - let seg = self.add_seg_infringably(recorder, from, to, weight); + let seg = self.add_seg_infringably(recorder, meta, from, to, weight); self.fail_and_remove_if_infringes_except(recorder, seg.into(), predicate)?; // Raise a collision exception if the currently created cane's seg @@ -469,8 +481,8 @@ impl Drawing { // Check whether the the seg is terminal, that is, whether at // least one of its two joints is a fixed dot. if matches!(from, DotIndex::Fixed(..)) || matches!(to, DotIndex::Fixed(..)) { - collider.primitive(drawing).maybe_net() - != collidee.primitive(drawing).maybe_net() + collider.primitive(drawing).metadata().maybe_net + != collidee.primitive(drawing).metadata().maybe_net } else { // Cane is non-initial. true @@ -494,6 +506,7 @@ impl Drawing { fn add_loose_bend_with_infringement_filtering( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: LooseDotIndex, to: LooseDotIndex, around: GearIndex, @@ -502,15 +515,14 @@ impl Drawing { ) -> Result { // It makes no sense to wrap something around or under one of its connectables. // - if let Some(net) = weight.maybe_net() { - if let Some(around_net) = around.primitive(self).maybe_net() { + if let Some(net) = meta.maybe_net { + if let Some(around_net) = around.primitive(self).metadata().maybe_net { if net == around_net { return Err(AlreadyConnected(net, around.into()).into()); } } - // if let Some(next_gear) = around.ref_(self).next_gear() { - if let Some(next_gear_net) = next_gear.primitive(self).maybe_net() { + if let Some(next_gear_net) = next_gear.primitive(self).metadata().maybe_net { if net == next_gear_net { return Err(AlreadyConnected(net, next_gear.into()).into()); } @@ -522,6 +534,7 @@ impl Drawing { GearIndex::FixedDot(core) => self .add_core_bend_with_infringement_filtering( recorder, + meta, from.into(), to.into(), core, @@ -532,6 +545,7 @@ impl Drawing { GearIndex::FixedBend(around) => self .add_outer_bend_with_infringement_filtering( recorder, + meta, from, to, around.into(), @@ -542,6 +556,7 @@ impl Drawing { GearIndex::LooseBend(around) => self .add_outer_bend_with_infringement_filtering( recorder, + meta, from, to, around.into(), @@ -556,11 +571,10 @@ impl Drawing { #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count() + 3))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))] - fn add_core_bend_with_infringement_filtering< - W: AccessBendWeight + Into + GetLayer, - >( + fn add_core_bend_with_infringement_filtering>( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: DotIndex, to: DotIndex, core: FixedDotIndex, @@ -570,9 +584,14 @@ impl Drawing { where GenericIndex: Into + Copy, { - let bend = - self.recording_geometry_with_rtree - .add_bend(recorder, from, to, core.into(), weight); + let bend = self.recording_geometry_with_rtree.add_bend( + recorder, + meta, + from, + to, + core.into(), + weight, + ); self.fail_and_remove_if_infringes_except(recorder, bend.into(), predicate)?; Ok(bend) @@ -585,6 +604,7 @@ impl Drawing { fn add_outer_bend_with_infringement_filtering( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: LooseDotIndex, to: LooseDotIndex, inner: BendIndex, @@ -616,6 +636,7 @@ impl Drawing { let bend = self.recording_geometry_with_rtree.add_bend( recorder, + meta, from.into(), to.into(), core.into(), @@ -659,6 +680,7 @@ impl Drawing { pub fn insert_cane( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, @@ -669,6 +691,7 @@ impl Drawing { let maybe_next_gear = around.ref_(self).next_gear(); let cane = self.add_cane_with_infringement_filtering( recorder, + meta, from, around, dot_weight, @@ -794,6 +817,7 @@ impl Drawing { pub fn add_cane( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, @@ -803,6 +827,7 @@ impl Drawing { ) -> Result { self.add_cane_with_infringement_filtering( recorder, + meta, from, around, dot_weight, @@ -820,6 +845,7 @@ impl Drawing { fn add_cane_with_infringement_filtering( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: DotIndex, around: GearIndex, dot_weight: LooseDotWeight, @@ -828,13 +854,15 @@ impl Drawing { sense: RotationSense, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool, ) -> Result { - let seg_to = self.add_dot_with_infringement_filtering(recorder, dot_weight, predicate)?; + let seg_to = + self.add_dot_with_infringement_filtering(recorder, meta, dot_weight, predicate)?; // we just checked that we can insert a dot there - let to = self.add_dot_infringably(recorder, dot_weight); + let to = self.add_dot_infringably(recorder, meta, dot_weight); let seg = self .add_seg_with_infringement_filtering( recorder, + meta, from, seg_to.into(), seg_weight, @@ -855,6 +883,7 @@ impl Drawing { let bend = self .add_loose_bend_with_infringement_filtering( recorder, + meta, bend_from, bend_to, around, @@ -1009,22 +1038,25 @@ impl Drawing { impl Drawing { #[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))] - fn add_dot_infringably + GetLayer>( + fn add_dot_infringably>( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, weight: W, ) -> GenericIndex where GenericIndex: Into + Copy, { - self.recording_geometry_with_rtree.add_dot(recorder, weight) + self.recording_geometry_with_rtree + .add_dot(recorder, meta, weight) } #[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count() + 2))] - fn add_seg_infringably + GetLayer>( + fn add_seg_infringably>( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, from: DotIndex, to: DotIndex, weight: W, @@ -1033,16 +1065,17 @@ impl Drawing { GenericIndex: Into, { self.recording_geometry_with_rtree - .add_seg(recorder, from, to, weight) + .add_seg(recorder, meta, from, to, weight) } pub fn add_compound( &mut self, recorder: &mut DrawingEdit, + meta: NodeMetadata, weight: CW, ) -> GenericIndex { self.recording_geometry_with_rtree - .add_compound(recorder, weight) + .add_compound(recorder, meta, weight) } pub fn remove_compound( @@ -1117,7 +1150,8 @@ impl Drawing { ) -> impl Iterator>> + '_ { let limiting_shape = node.primitive(self).shape().inflate( node.primitive(self) - .maybe_net() + .metadata() + .maybe_net .map(|net| self.rules.largest_clearance(Some(net))) .unwrap_or(0.0), ); @@ -1125,7 +1159,7 @@ impl Drawing { self.recording_geometry_with_rtree .rtree() .locate_in_envelope_intersecting( - &limiting_shape.envelope_3d(0.0, node.primitive(self).layer()), + &limiting_shape.envelope_3d_from_meta(0.0, node.primitive(self).metadata()), ) .map(|wrapper| wrapper.data) } @@ -1167,7 +1201,7 @@ impl Drawing { self.recording_geometry_with_rtree .rtree() - .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) + .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0)) .filter_map(|wrapper| { if let GenericNode::Primitive(collidee) = wrapper.data { Some(collidee) @@ -1224,40 +1258,28 @@ impl Drawing { &self, index: GenericNode>, active_layer: usize, - ) -> bool - where - CW: super::graph::IsInLayer, - { - match index { - GenericNode::Primitive(primitive) => primitive.primitive(self).layer() == active_layer, - GenericNode::Compound(compound) => { - self.compound_weight(compound).is_in_layer(active_layer) - } - } + ) -> bool { + self.recording_geometry_with_rtree + .geometry() + .metadata(index) + .is_in_layer(active_layer) } pub fn is_node_in_any_layer_of( &self, index: GenericNode>, layers: &[bool], - ) -> bool - where - CW: IsInLayer, - { - match index { - GenericNode::Primitive(primitive) => { - primitive.primitive(self).is_in_any_layer_of(layers) - } - GenericNode::Compound(compound) => { - self.compound_weight(compound).is_in_any_layer_of(layers) - } - } + ) -> bool { + self.recording_geometry_with_rtree + .geometry() + .metadata(index) + .is_in_any_layer_of(layers) } fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool { if let (Some(node1_net), Some(node2_net)) = ( - node1.primitive(self).maybe_net(), - node2.primitive(self).maybe_net(), + node1.primitive(self).metadata().maybe_net, + node2.primitive(self).metadata().maybe_net, ) { node1_net == node2_net } else { diff --git a/src/drawing/graph.rs b/src/drawing/graph.rs index 035fa34..4b44523 100644 --- a/src/drawing/graph.rs +++ b/src/drawing/graph.rs @@ -5,10 +5,7 @@ use enum_dispatch::enum_dispatch; use petgraph::stable_graph::NodeIndex; -use crate::{ - geometry::GetLayer, - graph::{GenericIndex, GetPetgraphIndex}, -}; +use crate::graph::{GenericIndex, GetPetgraphIndex}; use super::{ bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, @@ -22,29 +19,6 @@ use super::{ Drawing, }; -#[enum_dispatch] -pub trait IsInLayer { - fn is_in_layer(&self, layer: usize) -> bool; - - fn is_in_any_layer_of(&self, layers: &[bool]) -> bool; -} - -impl IsInLayer for T { - #[inline] - fn is_in_layer(&self, layer: usize) -> bool { - self.layer() == layer - } - - fn is_in_any_layer_of(&self, layers: &[bool]) -> bool { - *layers.get(self.layer()).unwrap_or(&false) - } -} - -#[enum_dispatch] -pub trait GetMaybeNet { - fn maybe_net(&self) -> Option; -} - #[enum_dispatch] pub trait MakePrimitive { fn primitive<'a, CW: Clone, Cel: Copy, R: AccessRules>( @@ -55,18 +29,6 @@ pub trait MakePrimitive { macro_rules! impl_weight_forward { ($weight_struct:ty, $weight_variant:ident, $index_struct:ident) => { - impl GetLayer for $weight_struct { - fn layer(&self) -> usize { - self.0.layer() - } - } - - impl GetMaybeNet for $weight_struct { - fn maybe_net(&self) -> Option { - self.0.maybe_net() - } - } - impl GetWidth for $weight_struct { fn width(&self) -> f64 { self.0.width() @@ -100,7 +62,7 @@ pub enum PrimitiveIndex { LooseBend(LooseBendIndex), } -#[enum_dispatch(GetWidth, GetLayer)] +#[enum_dispatch(GetWidth)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum PrimitiveWeight { FixedDot(FixedDotWeight), diff --git a/src/drawing/primitive.rs b/src/drawing/primitive.rs index e8c1105..01b72c9 100644 --- a/src/drawing/primitive.rs +++ b/src/drawing/primitive.rs @@ -9,12 +9,15 @@ use crate::{ drawing::{ bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, - graph::{GetMaybeNet, PrimitiveIndex, PrimitiveWeight}, + graph::{PrimitiveIndex, PrimitiveWeight}, rules::{AccessRules, Conditions, GetConditions}, seg::{FixedSegWeight, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight}, Drawing, }, - geometry::{primitive::PrimitiveShape, GenericNode, GetLayer, GetOffset, GetWidth, Retag}, + geometry::{ + primitive::PrimitiveShape, GenericNode, GetMetadata, GetOffset, GetWidth, NodeMetadata, + Retag, + }, graph::{GenericIndex, GetPetgraphIndex}, }; @@ -126,18 +129,6 @@ macro_rules! impl_primitive { } } } - - impl GetLayer for $primitive_struct<'_, CW, Cel, R> { - fn layer(&self) -> usize { - self.weight().layer() - } - } - - impl GetMaybeNet for $primitive_struct<'_, CW, Cel, R> { - fn maybe_net(&self) -> Option { - self.weight().maybe_net() - } - } }; } @@ -153,14 +144,7 @@ macro_rules! impl_loose_primitive { }; } -#[enum_dispatch( - GetLayer, - GetMaybeNet, - GetWidth, - GetDrawing, - MakePrimitiveShape, - GetLimbs -)] +#[enum_dispatch(GetDrawing, GetMetadata, GetWidth, MakePrimitiveShape, GetLimbs)] pub enum Primitive<'a, CW, Cel, R> { FixedDot(FixedDot<'a, CW, Cel, R>), LooseDot(LooseDot<'a, CW, Cel, R>), @@ -203,14 +187,26 @@ impl<'a, W, CW, Cel, R> GenericPrimitive<'a, W, CW, Cel, R> { .graph() .node_weight(self.index.petgraph_index()) .unwrap() + .kind { - *weight + weight } else { unreachable!() } } } +impl GetMetadata for GenericPrimitive<'_, W, CW, Cel, R> { + fn metadata(&self) -> NodeMetadata { + self.drawing + .geometry() + .graph() + .node_weight(self.index.petgraph_index()) + .unwrap() + .meta + } +} + impl GetInterior for GenericPrimitive<'_, W, CW, Cel, R> { fn interior(&self) -> Vec { vec![self.tagged_weight().retag(self.index.petgraph_index())] @@ -241,12 +237,9 @@ where } } -impl<'a, W, CW, Cel, R> GetConditions<'a> for &GenericPrimitive<'a, W, CW, Cel, R> -where - GenericPrimitive<'a, W, CW, Cel, R>: GetMaybeNet, -{ +impl<'a, W, CW, Cel, R> GetConditions<'a> for &GenericPrimitive<'a, W, CW, Cel, R> { fn conditions(self) -> Option> { - self.maybe_net().map(|net| Conditions { + self.metadata().maybe_net.map(|net| Conditions { net, maybe_region: Some("A".into()), maybe_layer: Some("F.Cu".into()), diff --git a/src/drawing/seg.rs b/src/drawing/seg.rs index 20be78a..439e335 100644 --- a/src/drawing/seg.rs +++ b/src/drawing/seg.rs @@ -6,13 +6,13 @@ use enum_dispatch::enum_dispatch; use crate::{ drawing::{ - graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, + graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight}, loose::LooseIndex, primitive::{GenericPrimitive, Primitive}, rules::AccessRules, Drawing, }, - geometry::{GetLayer, GetWidth}, + geometry::GetWidth, graph::{GenericIndex, GetPetgraphIndex}, }; @@ -98,7 +98,7 @@ impl TryFrom for SegIndex { } } -#[enum_dispatch(GetWidth, GetLayer)] +#[enum_dispatch(GetWidth)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum SegWeight { Fixed(FixedSegWeight), @@ -144,20 +144,6 @@ impl_weight_forward!(SeqLooseSegWeight, SeqLooseSeg, SeqLooseSegIndex); #[derive(Debug, Clone, Copy, PartialEq)] pub struct GeneralSegWeight { pub width: f64, - pub layer: usize, - pub maybe_net: Option, -} - -impl GetLayer for GeneralSegWeight { - fn layer(&self) -> usize { - self.layer - } -} - -impl GetMaybeNet for GeneralSegWeight { - fn maybe_net(&self) -> Option { - self.maybe_net - } } impl GetWidth for GeneralSegWeight { diff --git a/src/geometry/compound.rs b/src/geometry/compound.rs index d8cbf1b..ea91fb8 100644 --- a/src/geometry/compound.rs +++ b/src/geometry/compound.rs @@ -2,13 +2,16 @@ // // SPDX-License-Identifier: MIT -use crate::graph::{GenericIndex, GetPetgraphIndex}; +use crate::{ + geometry::NodeMetadata, + graph::{GenericIndex, GetPetgraphIndex}, +}; pub trait ManageCompounds { type GeneralIndex: Copy; type EntryLabel: Copy; - fn add_compound(&mut self, weight: CW) -> GenericIndex; + fn add_compound(&mut self, meta: NodeMetadata, weight: CW) -> GenericIndex; fn remove_compound(&mut self, compound: GenericIndex); fn add_to_compound(&mut self, node: I, label: Self::EntryLabel, compound: GenericIndex) where diff --git a/src/geometry/edit.rs b/src/geometry/edit.rs index 814e79b..fb966d2 100644 --- a/src/geometry/edit.rs +++ b/src/geometry/edit.rs @@ -6,12 +6,12 @@ use std::collections::{btree_map::Entry, BTreeMap}; use crate::graph::{GenericIndex, GetPetgraphIndex}; -use super::{AccessBendWeight, AccessDotWeight, AccessSegWeight, GetLayer}; +use super::{AccessBendWeight, AccessDotWeight, AccessSegWeight, NodeMetadata}; pub trait ApplyGeometryEdit< - DW: AccessDotWeight + GetLayer, - SW: AccessSegWeight + GetLayer, - BW: AccessBendWeight + GetLayer, + DW: AccessDotWeight, + SW: AccessSegWeight, + BW: AccessBendWeight, CW: Clone, Cel: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, @@ -25,17 +25,34 @@ pub trait ApplyGeometryEdit< #[derive(Debug, Clone)] pub struct GeometryEdit { - pub(super) dots: BTreeMap, Option)>, - pub(super) segs: BTreeMap, Option<((DI, DI), SW)>)>, - pub(super) bends: BTreeMap, Option<((DI, DI, DI), BW)>)>, - pub(super) compounds: - BTreeMap, (Option<(Vec<(Cel, PI)>, CW)>, Option<(Vec<(Cel, PI)>, CW)>)>, + pub(super) dots: BTreeMap, Option<(NodeMetadata, DW)>)>, + pub(super) segs: BTreeMap< + SI, + ( + Option<(NodeMetadata, (DI, DI), SW)>, + Option<(NodeMetadata, (DI, DI), SW)>, + ), + >, + pub(super) bends: BTreeMap< + BI, + ( + Option<(NodeMetadata, (DI, DI, DI), BW)>, + Option<(NodeMetadata, (DI, DI, DI), BW)>, + ), + >, + pub(super) compounds: BTreeMap< + GenericIndex, + ( + Option<(NodeMetadata, Vec<(Cel, PI)>, CW)>, + Option<(NodeMetadata, Vec<(Cel, PI)>, CW)>, + ), + >, } impl< - DW: AccessDotWeight + GetLayer, - SW: AccessSegWeight + GetLayer, - BW: AccessBendWeight + GetLayer, + DW: AccessDotWeight, + SW: AccessSegWeight, + BW: AccessBendWeight, CW: Clone, Cel: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, diff --git a/src/geometry/geometry.rs b/src/geometry/geometry.rs index 7774e28..cf97bb8 100644 --- a/src/geometry/geometry.rs +++ b/src/geometry/geometry.rs @@ -34,8 +34,8 @@ pub trait Retag { } #[enum_dispatch] -pub trait GetLayer { - fn layer(&self) -> usize; +pub trait GetMetadata { + fn metadata(&self) -> NodeMetadata; } #[enum_dispatch] @@ -67,7 +67,7 @@ pub enum GeometryLabel { Compound(Cel), } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, Hash)] pub enum GenericNode { Primitive(P), Compound(C), @@ -82,6 +82,47 @@ impl GetPetgraphIndex for GenericNode< } } +#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, Hash)] +pub struct NodeMetadata { + pub from_layer: usize, + pub to_layer: usize, + pub maybe_net: Option, +} + +impl NodeMetadata { + pub fn from_layer_and_net(layer: usize, maybe_net: Option) -> Self { + Self { + from_layer: layer, + to_layer: layer, + maybe_net, + } + } + + pub fn is_in_layer(&self, layer: usize) -> bool { + (self.from_layer..=self.to_layer).contains(&layer) + } + + pub fn is_in_any_layer_of(&self, layers: &[bool]) -> bool { + layers + .get(self.from_layer..=core::cmp::min(self.to_layer, layers.len())) + .map(|i| i.iter().any(|j| *j)) + .unwrap_or(false) + } +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, Hash)] +pub struct Node { + pub meta: NodeMetadata, + pub kind: GenericNode, +} + +impl GetMetadata for Node { + #[inline(always)] + fn metadata(&self) -> NodeMetadata { + self.meta + } +} + pub trait AccessDotWeight: GetSetPos + GetWidth + Copy {} impl AccessDotWeight for T {} @@ -93,7 +134,7 @@ impl AccessBendWeight for T {} #[derive(Debug)] pub struct Geometry { - graph: StableDiGraph, GeometryLabel, usize>, + graph: StableDiGraph, GeometryLabel, usize>, primitive_weight_marker: PhantomData, dot_weight_marker: PhantomData, seg_weight_marker: PhantomData, @@ -144,16 +185,21 @@ impl Geometry &StableDiGraph, GeometryLabel, usize> { + pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { &self.graph } + pub fn metadata(&self, index: impl GetPetgraphIndex) -> NodeMetadata { + let Node { meta, .. } = self.graph.node_weight(index.petgraph_index()).unwrap(); + *meta + } + fn primitive_weight(&self, index: NodeIndex) -> PW where PW: Copy, { - if let GenericNode::Primitive(weight) = self.graph.node_weight(index).unwrap() { - *weight + if let GenericNode::Primitive(weight) = self.graph.node_weight(index).unwrap().kind { + weight } else { unreachable!() } @@ -173,27 +219,43 @@ impl< BI: GetPetgraphIndex + Into + Copy, > Geometry { - pub fn add_dot>(&mut self, weight: W) -> GenericIndex { - GenericIndex::::new(self.graph.add_node(GenericNode::Primitive(weight.into()))) + pub fn add_dot>( + &mut self, + meta: NodeMetadata, + weight: W, + ) -> GenericIndex { + GenericIndex::::new(self.graph.add_node(Node { + meta, + kind: GenericNode::Primitive(weight.into()), + })) } pub(super) fn add_dot_at_index>( &mut self, dot: GenericIndex, + meta: NodeMetadata, weight: W, ) { - self.graph - .update_node(dot.petgraph_index(), GenericNode::Primitive(weight.into())); + self.graph.update_node( + dot.petgraph_index(), + Node { + meta, + kind: GenericNode::Primitive(weight.into()), + }, + ); } pub fn add_seg>( &mut self, + meta: NodeMetadata, from: DI, to: DI, weight: W, ) -> GenericIndex { - let seg = - GenericIndex::::new(self.graph.add_node(GenericNode::Primitive(weight.into()))); + let seg = GenericIndex::::new(self.graph.add_node(Node { + meta, + kind: GenericNode::Primitive(weight.into()), + })); self.init_seg_joints(seg, from, to); seg } @@ -201,12 +263,18 @@ impl< pub(super) fn add_seg_at_index>( &mut self, seg: GenericIndex, + meta: NodeMetadata, from: DI, to: DI, weight: W, ) { - self.graph - .update_node(seg.petgraph_index(), GenericNode::Primitive(weight.into())); + self.graph.update_node( + seg.petgraph_index(), + Node { + meta, + kind: GenericNode::Primitive(weight.into()), + }, + ); self.init_seg_joints(seg, from, to); } @@ -249,13 +317,16 @@ impl< pub fn add_bend>( &mut self, + meta: NodeMetadata, from: DI, to: DI, core: DI, weight: W, ) -> GenericIndex { - let bend = - GenericIndex::::new(self.graph.add_node(GenericNode::Primitive(weight.into()))); + let bend = GenericIndex::::new(self.graph.add_node(Node { + meta, + kind: GenericNode::Primitive(weight.into()), + })); self.init_bend_joints_and_core(bend, from, to, core); bend } @@ -263,19 +334,35 @@ impl< pub(super) fn add_bend_at_index>( &mut self, bend: GenericIndex, + meta: NodeMetadata, from: DI, to: DI, core: DI, weight: W, ) { - self.graph - .update_node(bend.petgraph_index(), GenericNode::Primitive(weight.into())); + self.graph.update_node( + bend.petgraph_index(), + Node { + meta, + kind: GenericNode::Primitive(weight.into()), + }, + ); self.init_bend_joints_and_core(bend, from, to, core); } - pub(super) fn add_compound_at_index(&mut self, compound: GenericIndex, weight: CW) { - self.graph - .update_node(compound.petgraph_index(), GenericNode::Compound(weight)); + pub(super) fn add_compound_at_index( + &mut self, + compound: GenericIndex, + meta: NodeMetadata, + weight: CW, + ) { + self.graph.update_node( + compound.petgraph_index(), + Node { + meta, + kind: GenericNode::Compound(weight), + }, + ); } fn init_bend_joints_and_core>( @@ -309,15 +396,19 @@ impl< pub fn move_dot(&mut self, dot: DI, to: Point) { let mut weight = self.dot_weight(dot); weight.set_pos(to); - *self.graph.node_weight_mut(dot.petgraph_index()).unwrap() = - GenericNode::Primitive(weight.into()); + self.graph + .node_weight_mut(dot.petgraph_index()) + .unwrap() + .kind = GenericNode::Primitive(weight.into()); } pub fn shift_bend(&mut self, bend: BI, offset: f64) { let mut weight = self.bend_weight(bend); weight.set_offset(offset); - *self.graph.node_weight_mut(bend.petgraph_index()).unwrap() = - GenericNode::Primitive(weight.into()); + self.graph + .node_weight_mut(bend.petgraph_index()) + .unwrap() + .kind = GenericNode::Primitive(weight.into()); } pub fn flip_bend(&mut self, bend: BI) { @@ -426,16 +517,6 @@ impl< .unwrap_or_else(|_| unreachable!()) } - pub fn compound_weight(&self, compound: GenericIndex) -> &CW { - if let GenericNode::Compound(weight) = - self.graph.node_weight(compound.petgraph_index()).unwrap() - { - weight - } else { - unreachable!() - } - } - fn core_weight(&self, bend: BI) -> DW { self.graph .edges_directed(bend.petgraph_index(), Outgoing) @@ -589,8 +670,11 @@ impl, DW, SW, BW, CW: Clone, Cel: Copy, PI: Copy, D type GeneralIndex = PI; type EntryLabel = Cel; - fn add_compound(&mut self, weight: CW) -> GenericIndex { - GenericIndex::::new(self.graph.add_node(GenericNode::Compound(weight))) + fn add_compound(&mut self, meta: NodeMetadata, weight: CW) -> GenericIndex { + GenericIndex::::new(self.graph.add_node(Node { + meta, + kind: GenericNode::Compound(weight), + })) } fn remove_compound(&mut self, compound: GenericIndex) { @@ -609,8 +693,11 @@ impl, DW, SW, BW, CW: Clone, Cel: Copy, PI: Copy, D } fn compound_weight(&self, compound: GenericIndex) -> &CW { - if let GenericNode::Compound(weight) = - self.graph.node_weight(compound.petgraph_index()).unwrap() + if let GenericNode::Compound(ref weight) = self + .graph + .node_weight(compound.petgraph_index()) + .unwrap() + .kind { weight } else { diff --git a/src/geometry/primitive.rs b/src/geometry/primitive.rs index 11701fd..f22c37d 100644 --- a/src/geometry/primitive.rs +++ b/src/geometry/primitive.rs @@ -12,7 +12,7 @@ use rstar::{RTreeObject, AABB}; use crate::{ geometry::{ shape::{AccessShape, MeasureLength}, - GetWidth, + GetWidth, NodeMetadata, }, math::{self, Circle}, }; @@ -31,17 +31,29 @@ pub trait AccessPrimitiveShape: AccessShape + GetWidth { ) } - fn full_height_envelope_3d(&self, margin: f64, layer_count: usize) -> AABB<[f64; 3]> { + fn envelope_3d_from_meta(&self, margin: f64, meta: NodeMetadata) -> AABB<[f64; 3]> { let envelope = self.bbox(margin); AABB::from_corners( - [envelope.lower()[0], envelope.lower()[1], 0.0], + [ + envelope.lower()[0], + envelope.lower()[1], + meta.from_layer as f64, + ], [ envelope.upper()[0], envelope.upper()[1], - (layer_count - 1) as f64, + meta.to_layer as f64, ], ) } + + fn full_height_envelope_3d(&self, margin: f64) -> AABB<[f64; 3]> { + let envelope = self.bbox(margin); + AABB::from_corners( + [envelope.lower()[0], envelope.lower()[1], 0.0], + [envelope.upper()[0], envelope.upper()[1], f64::INFINITY], + ) + } } #[enum_dispatch(AccessShape, AccessPrimitiveShape, GetWidth, MeasureLength)] diff --git a/src/geometry/recording_with_rtree.rs b/src/geometry/recording_with_rtree.rs index e4718a5..10ab0ca 100644 --- a/src/geometry/recording_with_rtree.rs +++ b/src/geometry/recording_with_rtree.rs @@ -15,7 +15,7 @@ use super::{ edit::{ApplyGeometryEdit, GeometryEdit}, with_rtree::{BboxedIndex, GeometryWithRtree}, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, - GetLayer, GetWidth, Retag, + GetWidth, Node, NodeMetadata, Retag, }; #[derive(Debug)] @@ -48,16 +48,16 @@ impl *self.geometry_with_rtree.layer_count() } - pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { + pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { self.geometry_with_rtree.graph() } } impl< - PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, - DW: AccessDotWeight + Into + GetLayer, - SW: AccessSegWeight + Into + GetLayer, - BW: AccessBendWeight + Into + GetLayer, + PW: GetWidth + TryInto + TryInto + TryInto + Retag + Copy, + DW: AccessDotWeight + Into, + SW: AccessSegWeight + Into, + BW: AccessBendWeight + Into, CW: Clone, Cel: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, @@ -72,30 +72,35 @@ impl< } } - pub fn add_dot + GetLayer>( + pub fn add_dot>( &mut self, recorder: &mut GeometryEdit, + meta: NodeMetadata, weight: W, ) -> GenericIndex where GenericIndex: Into, { - let dot = self.geometry_with_rtree.add_dot(weight); + let dot = self.geometry_with_rtree.add_dot(meta, weight); recorder.dots.insert( Into::::into(dot) .try_into() .unwrap_or_else(|_| unreachable!()), ( None, - Some(weight.into().try_into().unwrap_or_else(|_| unreachable!())), + Some(( + meta, + weight.into().try_into().unwrap_or_else(|_| unreachable!()), + )), ), ); dot } - pub fn add_seg + GetLayer>( + pub fn add_seg>( &mut self, recorder: &mut GeometryEdit, + meta: NodeMetadata, from: DI, to: DI, weight: W, @@ -103,7 +108,7 @@ impl< where GenericIndex: Into, { - let seg = self.geometry_with_rtree.add_seg(from, to, weight); + let seg = self.geometry_with_rtree.add_seg(meta, from, to, weight); recorder.segs.insert( Into::::into(seg) .try_into() @@ -111,6 +116,7 @@ impl< ( None, Some(( + meta, (from, to), weight.into().try_into().unwrap_or_else(|_| unreachable!()), )), @@ -119,9 +125,10 @@ impl< seg } - pub fn add_bend + GetLayer>( + pub fn add_bend>( &mut self, recorder: &mut GeometryEdit, + meta: NodeMetadata, from: DI, to: DI, core: DI, @@ -130,7 +137,9 @@ impl< where GenericIndex: Into, { - let bend = self.geometry_with_rtree.add_bend(from, to, core, weight); + let bend = self + .geometry_with_rtree + .add_bend(meta, from, to, core, weight); recorder.bends.insert( Into::::into(bend) .try_into() @@ -138,6 +147,7 @@ impl< ( None, Some(( + meta, (from, to, core), weight.into().try_into().unwrap_or_else(|_| unreachable!()), )), @@ -149,12 +159,13 @@ impl< pub fn add_compound( &mut self, recorder: &mut GeometryEdit, + meta: NodeMetadata, weight: CW, ) -> GenericIndex { - let compound = self.geometry_with_rtree.add_compound(weight.clone()); + let compound = self.geometry_with_rtree.add_compound(meta, weight.clone()); recorder .compounds - .insert(compound, (None, Some((vec![], weight)))); + .insert(compound, (None, Some((meta, vec![], weight)))); compound } @@ -166,6 +177,7 @@ impl< compound: GenericIndex, ) { let geometry = self.geometry_with_rtree.geometry(); + let meta = geometry.metadata(compound); let old_members = geometry.compound_members(compound).collect(); let old_weight = geometry.compound_weight(compound).clone(); @@ -179,8 +191,8 @@ impl< recorder .compounds .entry(compound) - .or_insert((Some((old_members, old_weight)), None)) - .1 = Some((new_members, new_weight)); + .or_insert((Some((meta, old_members, old_weight)), None)) + .1 = Some((meta, new_members, new_weight)); } pub fn remove_dot( @@ -188,9 +200,11 @@ impl< recorder: &mut GeometryEdit, dot: DI, ) -> Result<(), ()> { - let weight = self.geometry_with_rtree.geometry().dot_weight(dot); + let geometry = self.geometry_with_rtree.geometry(); + let meta = geometry.metadata(dot); + let weight = geometry.dot_weight(dot); self.geometry_with_rtree.remove_dot(dot)?; - edit_remove_from_map(&mut recorder.dots, dot, weight); + edit_remove_from_map(&mut recorder.dots, dot, (meta, weight)); Ok(()) } @@ -200,10 +214,11 @@ impl< seg: SI, ) { let geometry = self.geometry_with_rtree.geometry(); + let meta = geometry.metadata(seg); let weight = geometry.seg_weight(seg); let joints = geometry.seg_joints(seg); self.geometry_with_rtree.remove_seg(seg); - edit_remove_from_map(&mut recorder.segs, seg, (joints, weight)); + edit_remove_from_map(&mut recorder.segs, seg, (meta, joints, weight)); } pub fn remove_bend( @@ -212,6 +227,7 @@ impl< bend: BI, ) { let geometry = self.geometry_with_rtree.geometry(); + let meta = geometry.metadata(bend); let weight = geometry.bend_weight(bend); let joints = geometry.bend_joints(bend); let core = geometry.core(bend); @@ -219,7 +235,7 @@ impl< edit_remove_from_map( &mut recorder.bends, bend, - ((joints.0, joints.1, core), weight), + (meta, (joints.0, joints.1, core), weight), ); } @@ -229,10 +245,11 @@ impl< compound: GenericIndex, ) { let geometry = self.geometry_with_rtree.geometry(); + let meta = geometry.metadata(compound); let weight = geometry.compound_weight(compound).clone(); let members = geometry.compound_members(compound).collect(); self.geometry_with_rtree.remove_compound(compound); - edit_remove_from_map(&mut recorder.compounds, compound, (members, weight)); + edit_remove_from_map(&mut recorder.compounds, compound, (meta, members, weight)); } pub fn move_dot( @@ -241,6 +258,7 @@ impl< dot: DI, to: Point, ) { + let meta = self.geometry_with_rtree.geometry().metadata(dot); let old_weight = self.geometry_with_rtree.geometry().dot_weight(dot); self.geometry_with_rtree.move_dot(dot, to); let new_weight = self.geometry_with_rtree.geometry().dot_weight(dot); @@ -248,8 +266,8 @@ impl< recorder .dots .entry(dot) - .or_insert((Some(old_weight), None)) - .1 = Some(new_weight); + .or_insert((Some((meta, old_weight)), None)) + .1 = Some((meta, new_weight)); } fn modify_bend( @@ -261,6 +279,7 @@ impl< F: FnOnce(&mut GeometryWithRtree, BI), { let geometry = self.geometry_with_rtree.geometry(); + let meta = geometry.metadata(bend); let old_joints = geometry.bend_joints(bend); let old_core = geometry.core(bend); let old_weight = geometry.bend_weight(bend); @@ -276,10 +295,10 @@ impl< .bends .entry(bend) .or_insert(( - Some(((old_joints.0, old_joints.1, old_core), old_weight)), + Some((meta, (old_joints.0, old_joints.1, old_core), old_weight)), None, )) - .1 = Some(((new_joints.0, new_joints.1, new_core), new_weight)); + .1 = Some((meta, (new_joints.0, new_joints.1, new_core), new_weight)); } pub fn shift_bend( @@ -347,10 +366,10 @@ fn edit_remove_from_map( } impl< - PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, - DW: AccessDotWeight + Into + GetLayer, - SW: AccessSegWeight + Into + GetLayer, - BW: AccessBendWeight + Into + GetLayer, + PW: GetWidth + TryInto + TryInto + TryInto + Retag + Copy, + DW: AccessDotWeight + Into, + SW: AccessSegWeight + Into, + BW: AccessBendWeight + Into, CW: Clone, Cel: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, @@ -386,29 +405,30 @@ impl< } for (dot, (.., maybe_new_data)) in &edit.dots { - if let Some(weight) = maybe_new_data { - self.geometry_with_rtree.add_dot_at_index(*dot, *weight); + if let Some((meta, weight)) = maybe_new_data { + self.geometry_with_rtree + .add_dot_at_index(*dot, *meta, *weight); } } for (seg, (.., maybe_new_data)) in &edit.segs { - if let Some(((from, to), weight)) = maybe_new_data { + if let Some((meta, (from, to), weight)) = maybe_new_data { self.geometry_with_rtree - .add_seg_at_index(*seg, *from, *to, *weight); + .add_seg_at_index(*seg, *meta, *from, *to, *weight); } } for (bend, (.., maybe_new_data)) in &edit.bends { - if let Some(((from, to, core), weight)) = maybe_new_data { + if let Some((meta, (from, to, core), weight)) = maybe_new_data { self.geometry_with_rtree - .add_bend_at_index(*bend, *from, *to, *core, *weight); + .add_bend_at_index(*bend, *meta, *from, *to, *core, *weight); } } for (compound, (.., maybe_new_data)) in &edit.compounds { - if let Some((members, weight)) = maybe_new_data { + if let Some((meta, members, weight)) = maybe_new_data { self.geometry_with_rtree - .add_compound_at_index(*compound, weight.clone()); + .add_compound_at_index(*compound, *meta, weight.clone()); for (entry_label, member) in members { self.geometry_with_rtree.add_to_compound( diff --git a/src/geometry/with_rtree.rs b/src/geometry/with_rtree.rs index 8240669..d9d2265 100644 --- a/src/geometry/with_rtree.rs +++ b/src/geometry/with_rtree.rs @@ -13,7 +13,7 @@ use crate::{ compound::ManageCompounds, primitive::{AccessPrimitiveShape, PrimitiveShape}, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, - GetLayer, GetWidth, Retag, + GetWidth, Node, NodeMetadata, Retag, }, graph::{GenericIndex, GetPetgraphIndex}, }; @@ -60,7 +60,7 @@ impl Clone impl GeometryWithRtree { - pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { + pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { self.geometry.graph() } } @@ -68,10 +68,10 @@ impl #[debug_invariant(self.test_envelopes())] #[debug_invariant(self.geometry.graph().node_count() == self.rtree.size())] impl< - PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, - DW: AccessDotWeight + Into + GetLayer, - SW: AccessSegWeight + Into + GetLayer, - BW: AccessBendWeight + Into + GetLayer, + PW: GetWidth + TryInto + TryInto + TryInto + Retag + Copy, + DW: AccessDotWeight + Into, + SW: AccessSegWeight + Into, + BW: AccessBendWeight + Into, CW: Clone, Cel: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + PartialEq + Copy, @@ -88,30 +88,33 @@ impl< } } - pub fn add_dot + GetLayer>( + pub fn add_dot>( &mut self, + meta: NodeMetadata, weight: W, ) -> GenericIndex where GenericIndex: Into, { - let dot = self.geometry.add_dot(weight); - self.init_dot_bbox(dot.into().try_into().unwrap_or_else(|_| unreachable!())); + let dot = self.geometry.add_dot(meta, weight); + self.init_bbox(dot); dot } - pub(super) fn add_dot_at_index + GetLayer>( + pub(super) fn add_dot_at_index>( &mut self, dot: DI, + meta: NodeMetadata, weight: W, ) { self.geometry - .add_dot_at_index(GenericIndex::::new(dot.petgraph_index()), weight); - self.init_dot_bbox(dot); + .add_dot_at_index(GenericIndex::::new(dot.petgraph_index()), meta, weight); + self.init_bbox(dot); } - pub fn add_seg + GetLayer>( + pub fn add_seg>( &mut self, + meta: NodeMetadata, from: DI, to: DI, weight: W, @@ -119,29 +122,32 @@ impl< where GenericIndex: Into, { - let seg = self.geometry.add_seg(from, to, weight); - self.init_seg_bbox(seg.into().try_into().unwrap_or_else(|_| unreachable!())); + let seg = self.geometry.add_seg(meta, from, to, weight); + self.init_bbox(seg); seg } - pub(super) fn add_seg_at_index + GetLayer>( + pub(super) fn add_seg_at_index>( &mut self, seg: SI, + meta: NodeMetadata, from: DI, to: DI, weight: W, ) { self.geometry.add_seg_at_index( GenericIndex::::new(seg.petgraph_index()), + meta, from, to, weight, ); - self.init_seg_bbox(seg); + self.init_bbox(seg); } - pub fn add_bend + GetLayer>( + pub fn add_bend>( &mut self, + meta: NodeMetadata, from: DI, to: DI, core: DI, @@ -150,14 +156,15 @@ impl< where GenericIndex: Into, { - let bend = self.geometry.add_bend(from, to, core, weight); - self.init_bend_bbox(bend.into().try_into().unwrap_or_else(|_| unreachable!())); + let bend = self.geometry.add_bend(meta, from, to, core, weight); + self.init_bbox(bend); bend } - pub(super) fn add_bend_at_index + GetLayer>( + pub(super) fn add_bend_at_index>( &mut self, bend: BI, + meta: NodeMetadata, from: DI, to: DI, core: DI, @@ -165,17 +172,26 @@ impl< ) { self.geometry.add_bend_at_index( GenericIndex::::new(bend.petgraph_index()), + meta, from, to, core, weight, ); - self.init_bend_bbox(bend); + self.init_bbox(bend); } - pub(super) fn add_compound_at_index(&mut self, compound: GenericIndex, weight: CW) { - self.geometry - .add_compound_at_index(GenericIndex::::new(compound.petgraph_index()), weight); + pub(super) fn add_compound_at_index( + &mut self, + compound: GenericIndex, + meta: NodeMetadata, + weight: CW, + ) { + self.geometry.add_compound_at_index( + GenericIndex::::new(compound.petgraph_index()), + meta, + weight, + ); } pub fn add_to_compound( @@ -199,18 +215,18 @@ impl< return Err(()); } - self.rtree.remove(&self.make_dot_bbox(dot)); + self.rtree.remove(&self.make_bbox(dot.into())); self.geometry.remove_primitive(dot.into()); Ok(()) } pub fn remove_seg(&mut self, seg: SI) { - self.rtree.remove(&self.make_seg_bbox(seg)); + self.rtree.remove(&self.make_bbox(seg.into())); self.geometry.remove_primitive(seg.into()); } pub fn remove_bend(&mut self, bend: BI) { - self.rtree.remove(&self.make_bend_bbox(bend)); + self.rtree.remove(&self.make_bbox(bend.into())); self.geometry.remove_primitive(bend.into()); } @@ -221,23 +237,23 @@ impl< pub fn move_dot(&mut self, dot: DI, to: Point) { for seg in self.geometry.joined_segs(dot) { - self.rtree.remove(&self.make_seg_bbox(seg)); + self.rtree.remove(&self.make_bbox(seg.into())); } for bend in self.geometry.joined_bends(dot) { - self.rtree.remove(&self.make_bend_bbox(bend)); + self.rtree.remove(&self.make_bbox(bend.into())); } - self.rtree.remove(&self.make_dot_bbox(dot)); + self.rtree.remove(&self.make_bbox(dot.into())); self.geometry.move_dot(dot, to); - self.rtree.insert(self.make_dot_bbox(dot)); + self.rtree.insert(self.make_bbox(dot.into())); for bend in self.geometry.joined_bends(dot) { - self.rtree.insert(self.make_bend_bbox(bend)); + self.rtree.insert(self.make_bbox(bend.into())); } for seg in self.geometry.joined_segs(dot) { - self.rtree.insert(self.make_seg_bbox(seg)); + self.rtree.insert(self.make_bbox(seg.into())); } } @@ -245,18 +261,18 @@ impl< let mut rail = bend; while let Some(outer) = self.geometry.outer(rail) { - self.rtree.remove(&self.make_bend_bbox(outer)); + self.rtree.remove(&self.make_bbox(outer.into())); rail = outer; } - self.rtree.remove(&self.make_bend_bbox(bend)); + self.rtree.remove(&self.make_bbox(bend.into())); self.geometry.shift_bend(bend, offset); - self.rtree.insert(self.make_bend_bbox(bend)); + self.rtree.insert(self.make_bbox(bend.into())); rail = bend; while let Some(outer) = self.geometry.outer(rail) { - self.rtree.insert(self.make_bend_bbox(outer)); + self.rtree.insert(self.make_bbox(outer.into())); rail = outer; } } @@ -270,28 +286,28 @@ impl< let mut rail = bend; while let Some(outer) = self.geometry.outer(rail) { - self.rtree.remove(&self.make_bend_bbox(outer)); + self.rtree.remove(&self.make_bbox(outer.into())); rail = outer; } - self.rtree.remove(&self.make_bend_bbox(bend)); + self.rtree.remove(&self.make_bbox(bend.into())); self.geometry.reattach_bend(bend, maybe_new_inner); - self.rtree.insert(self.make_bend_bbox(bend)); + self.rtree.insert(self.make_bbox(bend.into())); rail = bend; while let Some(outer) = self.geometry.outer(rail) { - self.rtree.insert(self.make_bend_bbox(outer)); + self.rtree.insert(self.make_bbox(outer.into())); rail = outer; } } } impl< - PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, - DW: AccessDotWeight + Into + GetLayer, - SW: AccessSegWeight + Into + GetLayer, - BW: AccessBendWeight + Into + GetLayer, + PW: GetWidth + TryInto + TryInto + TryInto + Retag + Copy, + DW: AccessDotWeight + Into, + SW: AccessSegWeight + Into, + BW: AccessBendWeight + Into, CW: Clone, Cel: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + PartialEq + Copy, @@ -300,60 +316,17 @@ impl< BI: GetPetgraphIndex + Into + Copy, > GeometryWithRtree { - fn init_dot_bbox(&mut self, dot: DI) { - self.rtree.insert(self.make_dot_bbox(dot)); - } - - fn init_seg_bbox(&mut self, seg: SI) { - self.rtree.insert(self.make_seg_bbox(seg)); - } - - fn init_bend_bbox(&mut self, bend: BI) { - self.rtree.insert(self.make_bend_bbox(bend)); + fn init_bbox(&mut self, primitive: impl Into) { + self.rtree.insert(self.make_bbox(primitive.into())); } fn make_bbox(&self, primitive: PI) -> BboxedIndex>> { - if let Ok(dot) = >::try_into(primitive) { - self.make_dot_bbox(dot) - } else if let Ok(seg) = >::try_into(primitive) { - self.make_seg_bbox(seg) - } else if let Ok(bend) = >::try_into(primitive) { - self.make_bend_bbox(bend) - } else { - unreachable!(); - } - } - - fn make_dot_bbox(&self, dot: DI) -> BboxedIndex>> { BboxedIndex::new( Bbox::new( - self.geometry - .dot_shape(dot) - .envelope_3d(0.0, self.layer(dot.into())), + self.shape(primitive) + .envelope_3d_from_meta(0.0, self.metadata(primitive)), ), - GenericNode::Primitive(dot.into()), - ) - } - - fn make_seg_bbox(&self, seg: SI) -> BboxedIndex>> { - BboxedIndex::new( - Bbox::new( - self.geometry - .seg_shape(seg) - .envelope_3d(0.0, self.layer(seg.into())), - ), - GenericNode::Primitive(seg.into()), - ) - } - - fn make_bend_bbox(&self, bend: BI) -> BboxedIndex>> { - BboxedIndex::new( - Bbox::new( - self.geometry - .bend_shape(bend) - .envelope_3d(0.0, self.layer(bend.into())), - ), - GenericNode::Primitive(bend.into()), + GenericNode::Primitive(primitive), ) } @@ -384,16 +357,8 @@ impl< } } - fn layer(&self, primitive: PI) -> usize { - if let Ok(dot) = >::try_into(primitive) { - self.geometry.dot_weight(dot).layer() - } else if let Ok(seg) = >::try_into(primitive) { - self.geometry.seg_weight(seg).layer() - } else if let Ok(bend) = >::try_into(primitive) { - self.geometry.bend_weight(bend).layer() - } else { - unreachable!(); - } + pub fn metadata(&self, node: impl GetPetgraphIndex) -> NodeMetadata { + self.geometry.metadata(node) } fn test_envelopes(&self) -> bool { @@ -403,24 +368,24 @@ impl< return false; }; let shape = self.shape(primitive_node); - let layer = self.layer(primitive_node); + let metadata = self.metadata(primitive_node); let wrapper = BboxedIndex::new( - Bbox::new(shape.envelope_3d(0.0, layer)), + Bbox::new(shape.envelope_3d_from_meta(0.0, metadata)), GenericNode::Primitive(primitive_node), ); !self .rtree - .locate_in_envelope(&shape.envelope_3d(0.0, layer)) + .locate_in_envelope(&shape.envelope_3d_from_meta(0.0, metadata)) .any(|w| *w == wrapper) }) } } impl< - PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, - DW: AccessDotWeight + Into + GetLayer, - SW: AccessSegWeight + Into + GetLayer, - BW: AccessBendWeight + Into + GetLayer, + PW: GetWidth + TryInto + TryInto + TryInto + Retag + Copy, + DW: AccessDotWeight + Into, + SW: AccessSegWeight + Into, + BW: AccessBendWeight + Into, CW: Clone, Cel: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + PartialEq + Copy, @@ -432,8 +397,8 @@ impl< type GeneralIndex = PI; type EntryLabel = Cel; - fn add_compound(&mut self, weight: CW) -> GenericIndex { - let compound = self.geometry.add_compound(weight); + fn add_compound(&mut self, meta: NodeMetadata, weight: CW) -> GenericIndex { + let compound = self.geometry.add_compound(meta, weight); self.rtree.insert(self.make_compound_bbox(compound)); compound } diff --git a/src/layout/layout.rs b/src/layout/layout.rs deleted file mode 100644 index d5ee3bb..0000000 --- a/src/layout/layout.rs +++ /dev/null @@ -1,406 +0,0 @@ -// 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}, - dot::{ - DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, GeneralDotWeight, LooseDotIndex, - LooseDotWeight, - }, - gear::GearIndex, - graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, - primitive::MakePrimitiveShape, - rules::AccessRules, - seg::{ - FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, - SegWeight, SeqLooseSegIndex, SeqLooseSegWeight, - }, - Cane, Drawing, DrawingEdit, DrawingException, Infringement, - }, - geometry::{ - compound::ManageCompounds, - edit::ApplyGeometryEdit, - shape::{AccessShape, Shape}, - GenericNode, GetLayer, GetSetPos, - }, - graph::{GenericIndex, GetPetgraphIndex, MakeRef}, - layout::{ - poly::{add_poly_with_nodes_intern, MakePolygon, PolyWeight}, - via::{Via, ViaWeight}, - }, - math::RotationSense, -}; - -/// Represents a weight for various compounds -#[derive(Clone, Copy, Debug)] -#[enum_dispatch(GetMaybeNet, IsInLayer)] -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), -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum CompoundEntryLabel { - Normal, - NotInConvexHull, -} - -/// The alias to differ node types -pub type NodeIndex = GenericNode>; -pub type LayoutEdit = DrawingEdit; - -#[derive(Clone, Debug, Getters)] -/// Structure for managing the Layout design -pub struct Layout { - pub(super) 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, - sense: RotationSense, - ) -> Result { - self.drawing.insert_cane( - recorder, - from, - around, - dot_weight, - seg_weight, - bend_weight, - sense, - ) - } - - /// 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) - } - - pub fn remove_termseg(&mut self, recorder: &mut LayoutEdit, termseg: BandTermsegIndex) { - self.drawing.remove_termseg(recorder, termseg) - } - - #[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(GeneralDotWeight { - circle: weight.circle, - layer, - maybe_net: weight.maybe_net, - }), - ) { - Ok(dot) => { - self.drawing.add_to_compound( - recorder, - dot, - CompoundEntryLabel::Normal, - 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_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_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(), - ) - } - - /// insert a polygon based upon the border nodes, and computes + returns the - /// associated apex - pub fn add_poly_with_nodes( - &mut self, - recorder: &mut LayoutEdit, - weight: PolyWeight, - nodes: &[PrimitiveIndex], - ) -> (GenericIndex, FixedDotIndex) { - let layer = weight.layer(); - let maybe_net = weight.maybe_net(); - let poly = self.add_poly(recorder, weight); - ( - poly, - add_poly_with_nodes_intern(self, recorder, poly, nodes, layer, maybe_net), - ) - } - - pub fn remove_band( - &mut self, - recorder: &mut LayoutEdit, - band: BandTermsegIndex, - ) -> Result<(), DrawingException> { - self.drawing.remove_band(recorder, band) - } - - 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())) - } - - fn compound_shape(&self, compound: GenericIndex) -> Shape { - match self.drawing.compound_weight(compound) { - CompoundWeight::Poly(_) => GenericIndex::::new(compound.petgraph_index()) - .ref_(self) - .shape() - .into(), - CompoundWeight::Via(weight) => weight.shape().into(), - } - } - - pub fn node_shape(&self, index: NodeIndex) -> Shape { - match index { - NodeIndex::Primitive(primitive) => primitive.primitive(&self.drawing).shape().into(), - NodeIndex::Compound(compound) => self.compound_shape(compound), - } - } - - /// Checks if a node is not a primitive part of a compound, and if yes, returns its apex and center - pub fn apex_of_compoundless_node( - &self, - node: NodeIndex, - active_layer: usize, - ) -> Option<(FixedDotIndex, Point)> { - fn handle_fixed_dot( - drawing: &Drawing, - index: PrimitiveIndex, - ) -> Option<(FixedDotIndex, &FixedDotWeight)> { - let PrimitiveIndex::FixedDot(dot) = index else { - return None; - }; - if let GenericNode::Primitive(PrimitiveWeight::FixedDot(weight)) = drawing - .geometry() - .graph() - .node_weight(dot.petgraph_index()) - .unwrap() - { - Some((dot, weight)) - } else { - unreachable!() - } - } - - match node { - NodeIndex::Primitive(primitive) => { - if self - .drawing() - .geometry() - .compounds(GenericIndex::<()>::new(primitive.petgraph_index())) - .next() - .is_some() - { - return None; - } - handle_fixed_dot(&self.drawing, primitive).map(|(dot, weight)| (dot, weight.pos())) - } - NodeIndex::Compound(compound) => Some(match self.drawing.compound_weight(compound) { - CompoundWeight::Poly(_) => { - let poly = - GenericIndex::::new(compound.petgraph_index()).ref_(self); - (poly.apex(), poly.shape().center()) - } - CompoundWeight::Via(weight) => { - let mut dots = self.drawing.geometry().compound_members(compound); - let apex = loop { - // this returns None if the via is not present on this layer - let (entry_label, dot) = dots.next()?; - if entry_label == CompoundEntryLabel::NotInConvexHull { - if let Some((dot, weight)) = handle_fixed_dot(&self.drawing, dot) { - if weight.layer() == active_layer { - break dot; - } - } - } - }; - (apex, weight.shape().center()) - } - }), - } - } - - pub fn rules(&self) -> &R { - self.drawing.rules() - } - - pub fn rules_mut(&mut self) -> &mut R { - self.drawing.rules_mut() - } - - pub fn via(&self, index: GenericIndex) -> Via { - Via::new(index, self.drawing()) - } -} - -impl - ApplyGeometryEdit< - DotWeight, - SegWeight, - BendWeight, - CompoundWeight, - CompoundEntryLabel, - PrimitiveIndex, - DotIndex, - SegIndex, - BendIndex, - > for Layout -{ - fn apply(&mut self, edit: &LayoutEdit) { - self.drawing.apply(edit); - } -} diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 3e619b1..8d46f15 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,12 +1,345 @@ // SPDX-FileCopyrightText: 2024 Topola contributors // // SPDX-License-Identifier: MIT - //! Layout module for handling board geometry. mod collect_bands; -mod layout; pub mod poly; -pub mod via; -pub use layout::*; +use derive_getters::Getters; +use geo::Point; +use rstar::AABB; + +use crate::{ + drawing::{ + band::{BandTermsegIndex, BandUid}, + bend::{BendIndex, BendWeight, LooseBendWeight}, + dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, + gear::GearIndex, + graph::{MakePrimitive, PrimitiveIndex}, + loose::LooseIndex, + primitive::{GetWeight, MakePrimitiveShape, Primitive}, + rules::AccessRules, + seg::{ + FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, + SegWeight, SeqLooseSegIndex, SeqLooseSegWeight, + }, + Cane, Collect, Drawing, DrawingEdit, DrawingException, Infringement, + }, + geometry::{ + compound::ManageCompounds, + edit::ApplyGeometryEdit, + primitive::{AccessPrimitiveShape, PrimitiveShape, SegShape}, + shape::{AccessShape, Shape}, + GenericNode, GetSetPos, NodeMetadata, + }, + graph::{GenericIndex, GetPetgraphIndex, MakeRef}, + layout::poly::{add_poly_with_nodes_intern, MakePolygon, PolyWeight}, + math::{LineIntersection, NormalLine, RotationSense}, +}; + +/// Represents a weight for various compounds +#[derive(Clone, Copy, Debug)] +pub enum CompoundWeight { + /// Represents the weight of a polygon compound, includes its basic [`Layout`] information + Poly(PolyWeight), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CompoundEntryLabel { + Normal, + NotInConvexHull, +} + +/// The alias to differ node types +pub type NodeIndex = GenericNode>; +pub type LayoutEdit = DrawingEdit; + +#[derive(Clone, Debug, Getters)] +/// Structure for managing the Layout design +pub struct Layout { + pub(super) 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, + meta: NodeMetadata, + from: DotIndex, + around: GearIndex, + dot_weight: LooseDotWeight, + seg_weight: SeqLooseSegWeight, + bend_weight: LooseBendWeight, + sense: RotationSense, + ) -> Result { + self.drawing.insert_cane( + recorder, + meta, + from, + around, + dot_weight, + seg_weight, + bend_weight, + sense, + ) + } + + /// 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) + } + + pub fn remove_termseg(&mut self, recorder: &mut LayoutEdit, termseg: BandTermsegIndex) { + self.drawing.remove_termseg(recorder, termseg) + } + + pub fn add_fixed_dot( + &mut self, + recorder: &mut LayoutEdit, + meta: NodeMetadata, + weight: FixedDotWeight, + ) -> Result { + self.drawing.add_fixed_dot(recorder, meta, weight) + } + + pub fn add_fixed_dot_infringably( + &mut self, + recorder: &mut LayoutEdit, + meta: NodeMetadata, + weight: FixedDotWeight, + ) -> FixedDotIndex { + self.drawing + .add_fixed_dot_infringably(recorder, meta, weight) + } + + pub fn add_fixed_seg( + &mut self, + recorder: &mut LayoutEdit, + meta: NodeMetadata, + from: FixedDotIndex, + to: FixedDotIndex, + weight: FixedSegWeight, + ) -> Result { + self.drawing.add_fixed_seg(recorder, meta, from, to, weight) + } + + pub fn add_fixed_seg_infringably( + &mut self, + recorder: &mut LayoutEdit, + meta: NodeMetadata, + from: FixedDotIndex, + to: FixedDotIndex, + weight: FixedSegWeight, + ) -> FixedSegIndex { + self.drawing + .add_fixed_seg_infringably(recorder, meta, from, to, weight) + } + + pub fn add_lone_loose_seg( + &mut self, + recorder: &mut LayoutEdit, + meta: NodeMetadata, + from: FixedDotIndex, + to: FixedDotIndex, + weight: LoneLooseSegWeight, + ) -> Result { + self.drawing + .add_lone_loose_seg(recorder, meta, from, to, weight) + } + + pub fn add_seq_loose_seg( + &mut self, + recorder: &mut LayoutEdit, + meta: NodeMetadata, + from: DotIndex, + to: LooseDotIndex, + weight: SeqLooseSegWeight, + ) -> Result { + self.drawing + .add_seq_loose_seg(recorder, meta, 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, + meta: NodeMetadata, + weight: PolyWeight, + ) -> GenericIndex { + GenericIndex::::new( + self.drawing + .add_compound(recorder, meta, CompoundWeight::Poly(weight)) + .petgraph_index(), + ) + } + + /// insert a polygon based upon the border nodes, and computes + returns the + /// associated apex + pub fn add_poly_with_nodes( + &mut self, + recorder: &mut LayoutEdit, + meta: NodeMetadata, + weight: PolyWeight, + nodes: &[PrimitiveIndex], + ) -> (GenericIndex, FixedDotIndex) { + let poly = self.add_poly(recorder, meta, weight); + ( + poly, + add_poly_with_nodes_intern(self, recorder, poly, nodes, meta), + ) + } + + pub fn remove_band( + &mut self, + recorder: &mut LayoutEdit, + band: BandTermsegIndex, + ) -> Result<(), DrawingException> { + self.drawing.remove_band(recorder, band) + } + + pub fn poly_nodes(&self) -> impl Iterator> + '_ { + self.drawing.rtree().iter().filter_map(|wrapper| { + if let NodeIndex::Compound(compound) = wrapper.data { + 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 { + 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())) + } + + fn compound_shape(&self, compound: GenericIndex) -> Shape { + match self.drawing.compound_weight(compound) { + CompoundWeight::Poly(_) => GenericIndex::::new(compound.petgraph_index()) + .ref_(self) + .shape() + .into(), + } + } + + pub fn node_shape(&self, index: NodeIndex) -> Shape { + match index { + NodeIndex::Primitive(primitive) => primitive.primitive(&self.drawing).shape().into(), + NodeIndex::Compound(compound) => self.compound_shape(compound), + } + } + + /// Checks if a node is not a primitive part of a compound, and if yes, returns its apex and center + pub fn apex_of_compoundless_node( + &self, + node: NodeIndex, + active_layer: usize, + ) -> Option<(FixedDotIndex, Point)> { + fn handle_fixed_dot( + drawing: &Drawing, + index: PrimitiveIndex, + ) -> Option<(FixedDotIndex, &FixedDotWeight)> { + let PrimitiveIndex::FixedDot(dot) = index else { + return None; + }; + if let GenericNode::Primitive(PrimitiveWeight::FixedDot(weight)) = drawing + .geometry() + .graph() + .node_weight(dot.petgraph_index()) + .unwrap() + { + Some((dot, weight)) + } else { + unreachable!() + } + } + + match node { + NodeIndex::Primitive(primitive) => { + if self + .drawing() + .geometry() + .compounds(GenericIndex::<()>::new(primitive.petgraph_index())) + .next() + .is_some() + { + return None; + } + handle_fixed_dot(&self.drawing, primitive).map(|(dot, weight)| (dot, weight.pos())) + } + NodeIndex::Compound(compound) => Some(match self.drawing.compound_weight(compound) { + CompoundWeight::Poly(_) => { + let poly = + GenericIndex::::new(compound.petgraph_index()).ref_(self); + (poly.apex(), poly.shape().center()) + } + }), + } + } + + pub fn rules(&self) -> &R { + self.drawing.rules() + } + + pub fn rules_mut(&mut self) -> &mut R { + self.drawing.rules_mut() + } +} + +impl + ApplyGeometryEdit< + DotWeight, + SegWeight, + BendWeight, + CompoundWeight, + CompoundEntryLabel, + PrimitiveIndex, + DotIndex, + SegIndex, + BendIndex, + > for Layout +{ + fn apply(&mut self, edit: &LayoutEdit) { + self.drawing.apply(edit); + } +} diff --git a/src/layout/poly.rs b/src/layout/poly.rs index 01c62f0..4acacd6 100644 --- a/src/layout/poly.rs +++ b/src/layout/poly.rs @@ -14,13 +14,13 @@ use geo::{ use crate::{ drawing::{ dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight}, - graph::{GetMaybeNet, PrimitiveIndex}, + graph::PrimitiveIndex, primitive::GetLimbs, rules::AccessRules, seg::SegIndex, Drawing, }, - geometry::{compound::ManageCompounds, GetLayer, GetSetPos}, + geometry::{compound::ManageCompounds, GetMetadata, GetSetPos, NodeMetadata}, graph::{GenericIndex, GetPetgraphIndex, MakeRef}, layout::{CompoundEntryLabel, CompoundWeight, Layout, LayoutEdit}, math::Circle, @@ -49,8 +49,7 @@ pub(super) fn add_poly_with_nodes_intern( recorder: &mut LayoutEdit, poly: GenericIndex, nodes: &[PrimitiveIndex], - layer: usize, - maybe_net: Option, + meta: NodeMetadata, ) -> FixedDotIndex { #[derive(Clone, Copy)] struct Rto { @@ -99,13 +98,12 @@ pub(super) fn add_poly_with_nodes_intern( let apex = layout.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: shape.centroid().unwrap(), r: 100.0, }, - layer, - maybe_net, }), ); @@ -180,19 +178,9 @@ impl<'a, R> PolyRef<'a, R> { } } -impl GetLayer for PolyRef<'_, R> { - fn layer(&self) -> usize { - if let CompoundWeight::Poly(weight) = self.drawing.compound_weight(self.index.into()) { - weight.layer() - } else { - unreachable!(); - } - } -} - -impl GetMaybeNet for PolyRef<'_, R> { - fn maybe_net(&self) -> Option { - self.drawing.compound_weight(self.index.into()).maybe_net() +impl GetMetadata for PolyRef<'_, R> { + fn metadata(&self) -> NodeMetadata { + self.drawing.geometry().metadata(self.index) } } @@ -221,11 +209,10 @@ impl MakePolygon for PolyRef<'_, R> { } } -#[enum_dispatch(GetLayer, GetMaybeNet)] #[derive(Debug, Clone, Copy, PartialEq)] pub enum PolyWeight { - Solid(SolidPolyWeight), - Pour(PourPolyWeight), + Solid, + Pour, } impl From> for GenericIndex { @@ -233,51 +220,3 @@ impl From> for GenericIndex { GenericIndex::::new(poly.petgraph_index()) } } - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct SolidPolyWeight { - pub layer: usize, - pub maybe_net: Option, -} - -impl GetLayer for SolidPolyWeight { - fn layer(&self) -> usize { - self.layer - } -} - -impl GetMaybeNet for SolidPolyWeight { - fn maybe_net(&self) -> Option { - self.maybe_net - } -} - -impl From> for GenericIndex { - fn from(poly: GenericIndex) -> Self { - GenericIndex::::new(poly.petgraph_index()) - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct PourPolyWeight { - pub layer: usize, - pub maybe_net: Option, -} - -impl GetLayer for PourPolyWeight { - fn layer(&self) -> usize { - self.layer - } -} - -impl GetMaybeNet for PourPolyWeight { - fn maybe_net(&self) -> Option { - self.maybe_net - } -} - -impl From> for GenericIndex { - fn from(poly: GenericIndex) -> Self { - GenericIndex::::new(poly.petgraph_index()) - } -} diff --git a/src/layout/via.rs b/src/layout/via.rs deleted file mode 100644 index c590aab..0000000 --- a/src/layout/via.rs +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Topola contributors -// -// SPDX-License-Identifier: MIT - -//! Module for handling Vias properties - -use serde::{Deserialize, Serialize}; - -use crate::{ - drawing::{ - graph::{GetMaybeNet, IsInLayer}, - primitive::MakePrimitiveShape, - rules::AccessRules, - Drawing, - }, - geometry::primitive::{DotShape, PrimitiveShape}, - graph::{GenericIndex, GetPetgraphIndex}, - layout::{CompoundEntryLabel, CompoundWeight}, - math::Circle, -}; - -#[derive(Debug)] -pub struct Via<'a, R> { - pub index: GenericIndex, - drawing: &'a Drawing, -} - -impl<'a, R> Via<'a, R> { - pub fn new( - index: GenericIndex, - drawing: &'a Drawing, - ) -> Self { - Self { index, drawing } - } -} - -impl GetMaybeNet for Via<'_, R> { - fn maybe_net(&self) -> Option { - self.drawing.compound_weight(self.index.into()).maybe_net() - } -} - -impl MakePrimitiveShape for Via<'_, R> { - fn shape(&self) -> PrimitiveShape { - if let CompoundWeight::Via(weight) = self.drawing.compound_weight(self.index.into()) { - weight.shape() - } else { - unreachable!(); - } - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct ViaWeight { - pub from_layer: usize, - pub to_layer: usize, - pub circle: Circle, - pub maybe_net: Option, -} - -impl From> for GenericIndex { - fn from(via: GenericIndex) -> Self { - GenericIndex::::new(via.petgraph_index()) - } -} - -impl GetMaybeNet for ViaWeight { - fn maybe_net(&self) -> Option { - self.maybe_net - } -} - -impl IsInLayer for ViaWeight { - fn is_in_layer(&self, layer: usize) -> bool { - (self.from_layer..=self.to_layer).contains(&layer) - } - - fn is_in_any_layer_of(&self, layers: &[bool]) -> bool { - layers - .get(self.from_layer..=core::cmp::min(self.to_layer, layers.len())) - .map(|i| i.iter().any(|j| *j)) - .unwrap_or(false) - } -} - -impl MakePrimitiveShape for ViaWeight { - fn shape(&self) -> PrimitiveShape { - DotShape { - circle: self.circle, - } - .into() - } -} diff --git a/src/router/draw.rs b/src/router/draw.rs index bdbd663..fb534b1 100644 --- a/src/router/draw.rs +++ b/src/router/draw.rs @@ -14,14 +14,14 @@ use crate::{ bend::{BendIndex, GeneralBendWeight, LooseBendWeight}, dot::{DotIndex, FixedDotIndex, GeneralDotWeight, LooseDotIndex, LooseDotWeight}, gear::GearIndex, - graph::{GetMaybeNet, MakePrimitive}, + graph::MakePrimitive, head::{CaneHead, GetFace, Head}, primitive::GetOtherJoint, rules::AccessRules, seg::{GeneralSegWeight, LoneLooseSegWeight, SeqLooseSegWeight}, DrawingException, Guide, Infringement, }, - geometry::{GetLayer, GetSetPos}, + geometry::{GetMetadata, GetSetPos}, layout::{Layout, LayoutEdit}, math::{Circle, NoTangents, RotationSense}, }; @@ -87,11 +87,7 @@ impl Draw for Layout { .drawing() .head_into_dot_segment(&head, into, width) .map_err(Into::::into)?; - - let (layer, maybe_net) = { - let face = head.face().primitive(self.drawing()); - (face.layer(), face.maybe_net()) - }; + let meta = head.face().primitive(self.drawing()).metadata(); self.extend_head( recorder, @@ -101,25 +97,19 @@ impl Draw for Layout { DotIndex::Fixed(dot) => this .add_lone_loose_seg( recorder, + meta, dot, into, - LoneLooseSegWeight(GeneralSegWeight { - width, - layer, - maybe_net, - }), + LoneLooseSegWeight(GeneralSegWeight { width }), ) .map(BandTermsegIndex::Lone), DotIndex::Loose(dot) => this .add_seq_loose_seg( recorder, + meta, into.into(), dot, - SeqLooseSegWeight(GeneralSegWeight { - width, - layer, - maybe_net, - }), + SeqLooseSegWeight(GeneralSegWeight { width }), ) .map(BandTermsegIndex::Seq), }, @@ -284,10 +274,10 @@ impl DrawPrivate for Layout { width: f64, offset: f64, ) -> Result { - let layer = head.face().primitive(self.drawing()).layer(); - let maybe_net = head.face().primitive(self.drawing()).maybe_net(); + let meta = head.face().primitive(self.drawing()).metadata(); let cane = self.insert_cane( recorder, + meta, head.face(), around, LooseDotWeight(GeneralDotWeight { @@ -295,20 +285,9 @@ impl DrawPrivate for Layout { pos: to, r: width / 2.0, }, - layer, - maybe_net, - }), - SeqLooseSegWeight(GeneralSegWeight { - width, - layer, - maybe_net, - }), - LooseBendWeight(GeneralBendWeight { - width, - offset, - layer, - maybe_net, }), + SeqLooseSegWeight(GeneralSegWeight { width }), + LooseBendWeight(GeneralBendWeight { width, offset }), sense, )?; Ok(CaneHead { diff --git a/src/router/navmesh.rs b/src/router/navmesh.rs index 9101002..f1b28a9 100644 --- a/src/router/navmesh.rs +++ b/src/router/navmesh.rs @@ -24,11 +24,11 @@ use crate::{ dot::FixedDotIndex, gear::{GearIndex, GetNextGear}, graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex}, - primitive::Primitive, + primitive::{MakePrimitiveShape, Primitive}, rules::AccessRules, Drawing, }, - geometry::GetLayer, + geometry::shape::AccessShape, graph::{GetPetgraphIndex, MakeRef}, layout::Layout, math::RotationSense, @@ -116,6 +116,12 @@ pub struct NavnodeWeight { pub enum NavmeshError { #[error("failed to insert vertex in navmesh")] Insertion(#[from] InsertionError), + + #[error("a selected pin is not in layer")] + NotInLayer(usize), + + #[error("pins are in different networks")] + DifferentNetworks(Option, Option), } /// The navmesh holds the entire Topola's search space represented as a graph. @@ -147,9 +153,10 @@ impl Navmesh { layout: &Layout, origin: FixedDotIndex, destination: FixedDotIndex, + layer: usize, options: RouterOptions, ) -> Result { - let prenavmesh = Prenavmesh::new(layout, origin, destination, options)?; + let prenavmesh = Prenavmesh::new(layout, origin, destination, layer, options)?; Self::new_from_prenavmesh(layout, prenavmesh, origin, destination, options) } diff --git a/src/router/prenavmesh.rs b/src/router/prenavmesh.rs index c04e503..9c6a0f5 100644 --- a/src/router/prenavmesh.rs +++ b/src/router/prenavmesh.rs @@ -131,6 +131,7 @@ impl Prenavmesh { layout: &Layout, origin: FixedDotIndex, destination: FixedDotIndex, + layer: usize, _options: RouterOptions, ) -> Result { let mut this = Self { @@ -138,13 +139,26 @@ impl Prenavmesh { constraints: vec![], }; - let layer = layout.drawing().primitive(origin).layer(); - let maybe_net = layout.drawing().primitive(origin).maybe_net(); + let meta_origin = layout.drawing().geometry().metadata(origin); + let meta_destination = layout.drawing().geometry().metadata(destination); + + if !meta_origin.is_in_layer(layer) || !meta_destination.is_in_layer(layer) { + return Err(NavmeshError::NotInLayer(layer)); + } + + let maybe_net = meta_origin.maybe_net; + if maybe_net != meta_destination.maybe_net { + return Err(NavmeshError::DifferentNetworks( + maybe_net, + meta_destination.maybe_net, + )); + } for node in layout.drawing().layer_primitive_nodes(layer) { let primitive = node.primitive(layout.drawing()); + let meta = layout.drawing().geometry().metadata(node); - if let Some(primitive_net) = primitive.maybe_net() { + if let Some(primitive_net) = meta.maybe_net { if node == origin.into() || node == destination.into() || Some(primitive_net) != maybe_net @@ -176,8 +190,9 @@ impl Prenavmesh { for node in layout.drawing().layer_primitive_nodes(layer) { let primitive = node.primitive(layout.drawing()); + let meta = layout.drawing().geometry().metadata(node); - if let Some(primitive_net) = primitive.maybe_net() { + if let Some(primitive_net) = meta.maybe_net { if node == origin.into() || node == destination.into() || Some(primitive_net) != maybe_net diff --git a/src/router/route.rs b/src/router/route.rs index 229ee1c..bd7cabc 100644 --- a/src/router/route.rs +++ b/src/router/route.rs @@ -36,9 +36,10 @@ impl RouteStepper { recorder: LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, + layer: usize, width: f64, ) -> Result { - let navmesh = Navmesh::new(router.layout(), from, to, *router.options())?; + let navmesh = Navmesh::new(router.layout(), from, to, layer, *router.options())?; Ok(Self::new_from_navmesh(router, recorder, navmesh, width)) } diff --git a/src/router/router.rs b/src/router/router.rs index 8790de3..56d22bd 100644 --- a/src/router/router.rs +++ b/src/router/router.rs @@ -152,9 +152,10 @@ impl<'a, R: AccessRules> Router<'a, R> { recorder: LayoutEdit, from: FixedDotIndex, to: FixedDotIndex, + layer: usize, width: f64, ) -> Result { - RouteStepper::new(self, recorder, from, to, width) + RouteStepper::new(self, recorder, from, to, layer, width) } pub fn layout_mut(&mut self) -> &mut Layout { diff --git a/src/specctra/design.rs b/src/specctra/design.rs index 8c0c027..8c6d446 100644 --- a/src/specctra/design.rs +++ b/src/specctra/design.rs @@ -14,13 +14,13 @@ use crate::{ board::{AccessMesadata, Board}, drawing::{ dot::{FixedDotWeight, GeneralDotWeight}, - graph::{GetMaybeNet, MakePrimitive}, + graph::MakePrimitive, primitive::MakePrimitiveShape, seg::{FixedSegWeight, GeneralSegWeight}, Drawing, }, - geometry::{primitive::PrimitiveShape, GetLayer, GetWidth}, - layout::{poly::SolidPolyWeight, Layout, LayoutEdit}, + geometry::{primitive::PrimitiveShape, GetMetadata, GetWidth, NodeMetadata}, + layout::{poly::PolyWeight, Layout, LayoutEdit}, math::{Circle, PointWithRotation}, specctra::{ mesadata::SpecctraMesadata, @@ -77,78 +77,77 @@ impl SpecctraDesign { let mut net_outs = BTreeMap::::new(); for index in drawing.primitive_nodes() { let primitive = index.primitive(drawing); + let meta = primitive.metadata(); - if let Some(net) = primitive.maybe_net() { - let coords = match primitive.shape() { - PrimitiveShape::Seg(seg) => { - vec![ - structure::Point { - x: seg.from.x(), - y: seg.from.y(), - }, - structure::Point { - x: seg.to.x(), - y: seg.to.y(), - }, - ] - } + let Some(net) = meta.maybe_net else { + continue; + }; - PrimitiveShape::Bend(bend) => { - // Since general circle arcs don't seem to be supported - // we're downgrading each one to a chain of straight - // line segments. - // TODO: make this configurable? pick a smarter value? - let segment_count: usize = 100; - bend.render_discretization(segment_count + 1) - .map(Into::into) - .collect() - } - - // Intentionally skipped for now. - // Topola stores trace segments and dots joining them - // as separate objects, but the Specctra formats and KiCad - // appear to consider them implicit. - // TODO: Vias - PrimitiveShape::Dot(_) => continue, - }; - - let wire = structure::WireOut { - path: structure::Path { - layer: mesadata - .layer_layername(primitive.layer()) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!( - "tried to reference invalid primitive layer {}", - primitive.layer() - ), - ) - })? - .to_owned(), - width: primitive.width(), - coords, - }, - }; - - let net_out = match net_outs.entry(net) { - BTreeMapEntry::Occupied(occ) => occ.into_mut(), - BTreeMapEntry::Vacant(vac) => vac.insert(structure::NetOut { - name: mesadata - .net_netname(net) - .ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("tried to reference invalid net ID {}", net), - ) - })? - .to_owned(), - wire: Vec::new(), - via: Vec::new(), - }), - }; - net_out.wire.push(wire); + // object spans multiple layers + // TODO: these are Vias + if meta.from_layer != meta.to_layer { + continue; } + + let layer = meta.from_layer; + + let coords: Vec = match primitive.shape() { + PrimitiveShape::Seg(seg) => { + vec![seg.from.into(), seg.to.into()] + } + + PrimitiveShape::Bend(bend) => { + // Since general circle arcs don't seem to be supported + // we're downgrading each one to a chain of straight + // line segments. + // TODO: make this configurable? pick a smarter value? + let segment_count: usize = 100; + bend.render_discretization(segment_count + 1) + .map(Into::into) + .collect() + } + + // Intentionally skipped for now. + // Topola stores trace segments and dots joining them + // as separate objects, but the Specctra formats and KiCad + // appear to consider them implicit. + // TODO: Vias + PrimitiveShape::Dot(_) => continue, + }; + + let wire = structure::WireOut { + path: structure::Path { + layer: mesadata + .layer_layername(layer) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("tried to reference invalid primitive layer {}", layer), + ) + })? + .to_owned(), + width: primitive.width(), + coords, + }, + }; + + let net_out = match net_outs.entry(net) { + BTreeMapEntry::Occupied(occ) => occ.into_mut(), + BTreeMapEntry::Vacant(vac) => vac.insert(structure::NetOut { + name: mesadata + .net_netname(net) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("tried to reference invalid net ID {}", net), + ) + })? + .to_owned(), + wire: Vec::new(), + via: Vec::new(), + }), + }; + net_out.wire.push(wire); } let ses = structure::SesFile { @@ -249,8 +248,7 @@ impl SpecctraDesign { place.point_with_rotation(), pin.point_with_rotation(), circle.diameter / 2.0, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), Some(pinname.clone()), ) } @@ -265,8 +263,7 @@ impl SpecctraDesign { rect.y1, rect.x2, rect.y2, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), Some(pinname.clone()), ) } @@ -279,8 +276,7 @@ impl SpecctraDesign { pin.point_with_rotation(), &path.coords, path.width, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), Some(pinname.clone()), ) } @@ -293,8 +289,7 @@ impl SpecctraDesign { pin.point_with_rotation(), &polygon.coords, polygon.width, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), Some(pinname.clone()), ) } @@ -325,8 +320,7 @@ impl SpecctraDesign { PointWithRotation::from_xy(via.x, via.y), PointWithRotation::default(), circle.diameter / 2.0, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), None, ) } @@ -341,8 +335,7 @@ impl SpecctraDesign { rect.y1, rect.x2, rect.y2, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), None, ) } @@ -355,8 +348,7 @@ impl SpecctraDesign { PointWithRotation::default(), &path.coords, path.width, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), None, ) } @@ -369,8 +361,7 @@ impl SpecctraDesign { PointWithRotation::default(), &polygon.coords, polygon.width, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), None, ) } @@ -394,8 +385,7 @@ impl SpecctraDesign { PointWithRotation::default(), &wire.path.coords, wire.path.width, - layer, - net, + NodeMetadata::from_layer_and_net(layer, net), None, ); } @@ -429,8 +419,7 @@ impl SpecctraDesign { place: PointWithRotation, pin: PointWithRotation, r: f64, - layer: usize, - maybe_net: Option, + meta: NodeMetadata, maybe_pin: Option, ) { let circle = Circle { @@ -440,11 +429,8 @@ impl SpecctraDesign { board.add_fixed_dot_infringably( recorder, - FixedDotWeight(GeneralDotWeight { - circle, - layer, - maybe_net, - }), + meta, + FixedDotWeight(GeneralDotWeight { circle }), maybe_pin, ); } @@ -458,108 +444,92 @@ impl SpecctraDesign { y1: f64, x2: f64, y2: f64, - layer: usize, - maybe_net: Option, + meta: NodeMetadata, maybe_pin: Option, ) { // Corners. let dot_1_1 = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: Self::pos(place, pin, x1, y1), r: 0.5, }, - layer, - maybe_net, }), None, ); let dot_2_1 = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: Self::pos(place, pin, x2, y1), r: 0.5, }, - layer, - maybe_net, }), None, ); let dot_2_2 = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: Self::pos(place, pin, x2, y2), r: 0.5, }, - layer, - maybe_net, }), None, ); let dot_1_2 = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: Self::pos(place, pin, x1, y2), r: 0.5, }, - layer, - maybe_net, }), None, ); // Sides. let seg1 = board.add_fixed_seg_infringably( recorder, + meta, dot_1_1, dot_2_1, - FixedSegWeight(GeneralSegWeight { - width: 1.0, - layer, - maybe_net, - }), + FixedSegWeight(GeneralSegWeight { width: 1.0 }), None, ); let seg2 = board.add_fixed_seg_infringably( recorder, + meta, dot_2_1, dot_2_2, - FixedSegWeight(GeneralSegWeight { - width: 1.0, - layer, - maybe_net, - }), + FixedSegWeight(GeneralSegWeight { width: 1.0 }), None, ); let seg3 = board.add_fixed_seg_infringably( recorder, + meta, dot_2_2, dot_1_2, - FixedSegWeight(GeneralSegWeight { - width: 1.0, - layer, - maybe_net, - }), + FixedSegWeight(GeneralSegWeight { width: 1.0 }), None, ); let seg4 = board.add_fixed_seg_infringably( recorder, + meta, dot_1_2, dot_1_1, - FixedSegWeight(GeneralSegWeight { - width: 1.0, - layer, - maybe_net, - }), + FixedSegWeight(GeneralSegWeight { width: 1.0 }), None, ); board.add_poly_with_nodes( recorder, - SolidPolyWeight { layer, maybe_net }.into(), + meta, + PolyWeight::Solid.into(), maybe_pin, &[ dot_1_1.into(), @@ -581,21 +551,19 @@ impl SpecctraDesign { pin: PointWithRotation, coords: &[structure::Point], width: f64, - layer: usize, - maybe_net: Option, + meta: NodeMetadata, maybe_pin: Option, ) { // add the first coordinate in the wire path as a dot and save its index let mut prev_pos = Self::pos(place, pin, coords[0].x, coords[0].y); let mut prev_index = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: prev_pos, r: width / 2.0, }, - layer, - maybe_net, }), maybe_pin.clone(), ); @@ -610,13 +578,12 @@ impl SpecctraDesign { let index = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos, r: width / 2.0, }, - layer, - maybe_net, }), maybe_pin.clone(), ); @@ -624,13 +591,10 @@ impl SpecctraDesign { // add a seg between the current and previous coords let _ = board.add_fixed_seg_infringably( recorder, + meta, prev_index, index, - FixedSegWeight(GeneralSegWeight { - width, - layer, - maybe_net, - }), + FixedSegWeight(GeneralSegWeight { width }), maybe_pin.clone(), ); @@ -646,8 +610,7 @@ impl SpecctraDesign { pin: PointWithRotation, mut coords: &[structure::Point], width: f64, - layer: usize, - maybe_net: Option, + meta: NodeMetadata, maybe_pin: Option, ) { let mut nodes = Vec::with_capacity(coords.len() * 2 - 1); @@ -655,13 +618,12 @@ impl SpecctraDesign { // add the first coordinate in the wire path as a dot and save its index let first_index = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: Self::pos(place, pin, coords[0].x, coords[0].y), r: width / 2.0, }, - layer, - maybe_net, }), None, ); @@ -674,23 +636,18 @@ impl SpecctraDesign { coords = &coords[..coords.len() - 1]; } - let seg_weight = FixedSegWeight(GeneralSegWeight { - width, - layer, - maybe_net, - }); + let seg_weight = FixedSegWeight(GeneralSegWeight { width }); // iterate through path coords starting from the second for coord in &coords[1..] { let index = board.add_fixed_dot_infringably( recorder, + meta, FixedDotWeight(GeneralDotWeight { circle: Circle { pos: Self::pos(place, pin, coord.x, coord.y), r: width / 2.0, }, - layer, - maybe_net, }), None, ); @@ -699,7 +656,7 @@ impl SpecctraDesign { // add a seg between the current and previous coords nodes.push( board - .add_fixed_seg_infringably(recorder, prev_index, index, seg_weight, None) + .add_fixed_seg_infringably(recorder, meta, prev_index, index, seg_weight, None) .into(), ); @@ -709,13 +666,21 @@ impl SpecctraDesign { // add a seg between the last and first coords nodes.push( board - .add_fixed_seg_infringably(recorder, prev_index, first_index, seg_weight, None) + .add_fixed_seg_infringably( + recorder, + meta, + prev_index, + first_index, + seg_weight, + None, + ) .into(), ); board.add_poly_with_nodes( recorder, - SolidPolyWeight { layer, maybe_net }.into(), + meta, + PolyWeight::Solid.into(), maybe_pin, &nodes[..], ); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 8e21180..fc8fe70 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -12,8 +12,7 @@ use topola::{ Autorouter, }, board::{AccessMesadata, Board}, - drawing::graph::GetMaybeNet, - geometry::{shape::MeasureLength, GenericNode, GetLayer}, + geometry::{shape::MeasureLength, GenericNode, GetMetadata}, graph::{GetPetgraphIndex, MakeRef}, layout::LayoutEdit, router::{navmesh::Navmesh, RouterOptions}, @@ -74,6 +73,7 @@ pub fn assert_navnode_count( autorouter: &mut Autorouter, origin_pin: &str, destination_pin: &str, + layer: usize, expected_count: usize, ) { let (origin, destination) = autorouter @@ -104,6 +104,7 @@ pub fn assert_navnode_count( autorouter.board().layout(), origin, destination, + layer, RouterOptions { wrap_around_bands: true, squeeze_through_under_bends: false, @@ -119,56 +120,23 @@ pub fn assert_single_layer_groundless_autoroute( layername: &str, ) { let unionfind = unionfind(autorouter); + let drawing = autorouter.board().layout().drawing(); + let layer = drawing + .rules() + .layername_layer(layername) + .expect("layer should exist"); for ratline in autorouter.ratsnest().graph().edge_indices() { let (origin_dot, destination_dot) = autorouter.ratline_endpoints(ratline); - let origin_layer = autorouter - .board() - .layout() - .drawing() - .primitive(origin_dot) - .layer(); - let destination_layer = autorouter - .board() - .layout() - .drawing() + assert!(drawing.primitive(origin_dot).metadata().is_in_layer(layer)); + assert!(drawing .primitive(destination_dot) - .layer(); + .metadata() + .is_in_layer(layer)); - if let (Some(origin_layername), Some(destination_layername)) = ( - autorouter - .board() - .layout() - .rules() - .layer_layername(origin_layer), - autorouter - .board() - .layout() - .rules() - .layer_layername(destination_layer), - ) { - assert_eq!(origin_layername, destination_layername); - - if origin_layername != layername { - continue; - } - } else { - assert!(false); - } - - let origin_net = autorouter - .board() - .layout() - .drawing() - .primitive(origin_dot) - .maybe_net(); - let destination_net = autorouter - .board() - .layout() - .drawing() - .primitive(destination_dot) - .maybe_net(); + let origin_net = drawing.primitive(origin_dot).metadata().maybe_net; + let destination_net = drawing.primitive(destination_dot).metadata().maybe_net; assert_eq!(origin_net, destination_net); let net = origin_net.unwrap(); diff --git a/tests/multilayer.rs b/tests/multilayer.rs index 7d9b8c2..2ee2e86 100644 --- a/tests/multilayer.rs +++ b/tests/multilayer.rs @@ -5,7 +5,6 @@ use topola::{ autorouter::{execution::Command, invoker::InvokerError, AutorouterError}, board::AccessMesadata, - layout::via::ViaWeight, math::Circle, }; diff --git a/tests/single_layer.rs b/tests/single_layer.rs index dc290de..d4df67d 100644 --- a/tests/single_layer.rs +++ b/tests/single_layer.rs @@ -3,12 +3,9 @@ // SPDX-License-Identifier: MIT use topola::{ - autorouter::{ - execution::Command, - invoker::{Invoker, InvokerError}, - AutorouterError, - }, - layout::via::ViaWeight, + drawing::dot::{GeneralDotWeight, LooseDotWeight}, + geometry::NodeMetadata, + layout::LayoutEdit, math::Circle, }; @@ -63,22 +60,25 @@ fn test_tht_diode_bridge_rectifier() { //common::assert_number_of_conncomps(&mut autorouter, 4); common::assert_band_length(autorouter.board(), "J2-2", "D4-2", 15906.760439007436, 0.01); - let mut invoker = Invoker::new(autorouter); - let result = invoker.execute(Command::PlaceVia(ViaWeight { - from_layer: 0, - to_layer: 1, - circle: Circle { - pos: [0.0, 0.0].into(), - r: 200000.0, - }, - maybe_net: Some(1234), - })); - assert!(matches!( - result, - Err(InvokerError::Autorouter(AutorouterError::CouldNotPlaceVia( - .. - ))) - )); + let result = autorouter + .board() + .layout() + .drawing() + .add_dot_with_infringement_filtering( + &mut LayoutEdit::new(), + NodeMetadata { + from_layer: 0, + to_layer: 1, + maybe_net: Some(1234), + }, + LooseDotWeight(GeneralDotWeight { + circle: Circle { + pos: [0.0, 0.0].into(), + r: 200000.0, + }, + }), + ); + assert!(matches!(result, Err(_))); } #[test]