feat: implicit Vias (all nodes store a layer range)

This commit is contained in:
Ellen Emilia Anna Zscheile 2025-05-28 23:58:12 +02:00
parent 29dc59df04
commit 909046afe6
40 changed files with 1139 additions and 1388 deletions

View File

@ -17,7 +17,7 @@ allowed_scopes = [
"topola-egui", "topola-egui",
# Generated using # 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/autoroute",
"autorouter/autorouter", "autorouter/autorouter",
"autorouter/compare_detours", "autorouter/compare_detours",
@ -25,11 +25,13 @@ allowed_scopes = [
"autorouter/history", "autorouter/history",
"autorouter/invoker", "autorouter/invoker",
"autorouter/measure_length", "autorouter/measure_length",
"autorouter/mod",
"autorouter/place_via", "autorouter/place_via",
"autorouter/pointroute", "autorouter/pointroute",
"autorouter/ratsnest", "autorouter/ratsnest",
"autorouter/remove_bands", "autorouter/remove_bands",
"autorouter/selection", "autorouter/selection",
"board/mod",
"drawing/band", "drawing/band",
"drawing/bend", "drawing/bend",
"drawing/cane", "drawing/cane",
@ -41,11 +43,13 @@ allowed_scopes = [
"drawing/guide", "drawing/guide",
"drawing/head", "drawing/head",
"drawing/loose", "drawing/loose",
"drawing/mod",
"drawing/primitive", "drawing/primitive",
"drawing/seg", "drawing/seg",
"geometry/compound", "geometry/compound",
"geometry/edit", "geometry/edit",
"geometry/geometry", "geometry/geometry",
"geometry/mod",
"geometry/polygon", "geometry/polygon",
"geometry/primitive", "geometry/primitive",
"geometry/recording_with_rtree", "geometry/recording_with_rtree",
@ -55,22 +59,26 @@ allowed_scopes = [
"interactor/activity", "interactor/activity",
"interactor/interaction", "interactor/interaction",
"interactor/interactor", "interactor/interactor",
"interactor/mod",
"interactor/route_plan", "interactor/route_plan",
"layout/collect_bands", "layout/collect_bands",
"layout/layout", "layout/layout",
"layout/mod",
"layout/poly", "layout/poly",
"layout/via",
"math/cyclic_search", "math/cyclic_search",
"math/line", "math/line",
"math/mod",
"math/polygon_tangents", "math/polygon_tangents",
"math/tangents", "math/tangents",
"math/tunnel", "math/tunnel",
"router/draw", "router/draw",
"router/mod",
"router/navcord", "router/navcord",
"router/navcorder", "router/navcorder",
"router/navmesh", "router/navmesh",
"router/ng/eval", "router/ng/eval",
"router/ng/floating", "router/ng/floating",
"router/ng/mod",
"router/ng/poly", "router/ng/poly",
"router/ng/router", "router/ng/router",
"router/prenavmesh", "router/prenavmesh",
@ -78,6 +86,7 @@ allowed_scopes = [
"router/router", "router/router",
"router/thetastar", "router/thetastar",
"specctra/design", "specctra/design",
"specctra/mod",
"stepper", "stepper",
"triangulation", "triangulation",
] ]

View File

@ -5,14 +5,9 @@
use clap::Parser; use clap::Parser;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use topola::autorouter::execution::Command;
use topola::autorouter::history::History;
use topola::autorouter::invoker::Invoker; use topola::autorouter::invoker::Invoker;
use topola::autorouter::selection::PinSelection;
use topola::autorouter::Autorouter; use topola::autorouter::Autorouter;
use topola::autorouter::AutorouterOptions;
use topola::layout::LayoutEdit; use topola::layout::LayoutEdit;
use topola::router::RouterOptions;
use topola::specctra::design::SpecctraDesign; use topola::specctra::design::SpecctraDesign;
pub mod cli; pub mod cli;
@ -33,22 +28,8 @@ fn main() -> Result<(), std::io::Error> {
let commands_bufread = BufReader::new(command_file); let commands_bufread = BufReader::new(command_file);
serde_json::from_reader(commands_bufread)? serde_json::from_reader(commands_bufread)?
} else { } else {
let mut history = History::new(); eprintln!("no commands given");
history.do_( return Ok(());
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
}; };
let mut invoker = Invoker::new(Autorouter::new(board).unwrap()); let mut invoker = Invoker::new(Autorouter::new(board).unwrap());

View File

@ -266,10 +266,9 @@ impl PlaceActions {
pub fn render_menu( pub fn render_menu(
&mut self, &mut self,
ctx: &Context, _ctx: &Context,
ui: &mut Ui, ui: &mut Ui,
have_workspace: bool, have_workspace: bool,
is_placing_via: &mut bool,
) -> egui::InnerResponse<()> { ) -> egui::InnerResponse<()> {
ui.add_enabled_ui(have_workspace, |ui| { ui.add_enabled_ui(have_workspace, |ui| {
self.place_via.toggle_widget(ui, is_placing_via); self.place_via.toggle_widget(ui, is_placing_via);

View File

@ -6,10 +6,14 @@ use std::{collections::BTreeSet, ops::ControlFlow, path::Path, sync::mpsc::Sende
use topola::{ use topola::{
autorouter::{ autorouter::{
execution::Command, invoker::InvokerError, selection::Selection, AutorouterOptions, execution::Command,
invoker::InvokerError,
selection::{PinSelector, Selection},
AutorouterOptions,
}, },
board::AccessMesadata, board::AccessMesadata,
interactor::{interaction::InteractionStepper, route_plan::RoutePlan}, interactor::{interaction::InteractionStepper, route_plan::RoutePlan},
layout::NodeIndex,
router::RouterOptions, router::RouterOptions,
specctra::{design::SpecctraDesign, ParseError, ParseErrorContext as SpecctraLoadingError}, specctra::{design::SpecctraDesign, ParseError, ParseErrorContext as SpecctraLoadingError},
}; };
@ -25,7 +29,6 @@ use crate::{
pub struct MenuBar { pub struct MenuBar {
pub autorouter_options: AutorouterOptions, pub autorouter_options: AutorouterOptions,
pub is_placing_via: bool,
pub show_ratsnest: bool, pub show_ratsnest: bool,
pub show_navmesh: bool, pub show_navmesh: bool,
pub show_triangulation: bool, pub show_triangulation: bool,
@ -49,7 +52,6 @@ impl MenuBar {
squeeze_through_under_bends: true, squeeze_through_under_bends: true,
}, },
}, },
is_placing_via: false,
show_ratsnest: true, show_ratsnest: true,
show_navmesh: false, show_navmesh: false,
show_triangulation: false, show_triangulation: false,
@ -137,12 +139,9 @@ impl MenuBar {
// those outside... // those outside...
ui.menu_button(tr.text("tr-menu-place"), |ui| { ui.menu_button(tr.text("tr-menu-place"), |ui| {
actions.place.render_menu( actions
ctx, .place
ui, .render_menu(ctx, ui, maybe_workspace.is_some())
maybe_workspace.is_some(),
&mut self.is_placing_via,
)
}); });
ui.menu_button(tr.text("tr-menu-route"), |ui| { ui.menu_button(tr.text("tr-menu-route"), |ui| {
@ -299,19 +298,24 @@ impl MenuBar {
) { ) {
let mut selection = workspace.overlay.take_selection(); let mut selection = workspace.overlay.take_selection();
if let Some(active_layer) = workspace.appearance_panel.active_layer { if let Some(active_layer) = workspace.appearance_panel.active_layer {
let active_layer = workspace let valid_pins: BTreeSet<_> = {
.interactor let board = workspace.interactor.invoker().autorouter().board();
.invoker() board
.autorouter() .layout()
.board() .drawing()
.layout() .layer_primitive_nodes(active_layer)
.rules() .filter_map(|node| {
.layer_layername(active_layer) board.node_pinname(&NodeIndex::Primitive(node))
.expect("unknown active layer"); })
selection .cloned()
.pin_selection .map(|pin| PinSelector { pin })
.0 .collect()
.retain(|i| i.layer == active_layer); };
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)) { if let Err(err) = workspace.interactor.schedule(op(selection)) {
error_dialog.push_error("tr-module-invoker", format!("{}", err)); 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) { } else if actions.route.autoroute.consume_key_triggered(ctx, ui) {
schedule(error_dialog, workspace, |selection| { schedule(error_dialog, workspace, |selection| Command::Autoroute {
Command::Autoroute(selection.pin_selection, opts) pins: selection.pin_selection,
active_layer,
options: opts,
}); });
} else if actions } else if actions
.inspect .inspect
@ -353,7 +359,11 @@ impl MenuBar {
.consume_key_triggered(ctx, ui) .consume_key_triggered(ctx, ui)
{ {
schedule(error_dialog, workspace, |selection| { schedule(error_dialog, workspace, |selection| {
Command::CompareDetours(selection.pin_selection, opts) Command::CompareDetours {
pins: selection.pin_selection
active_layer,
options: opts,
}
}); });
} else if actions } else if actions
.inspect .inspect

View File

@ -36,6 +36,8 @@ pub enum AutorouteContinueStatus {
pub struct AutorouteExecutionStepper { pub struct AutorouteExecutionStepper {
/// An iterator over ratlines that tracks which segments still need to be routed. /// An iterator over ratlines that tracks which segments still need to be routed.
ratlines_iter: Box<dyn Iterator<Item = EdgeIndex<usize>>>, ratlines_iter: Box<dyn Iterator<Item = EdgeIndex<usize>>>,
/// The layer on which the routing should be done.
layer: usize,
/// The options for the autorouting process, defining how routing should be carried out. /// The options for the autorouting process, defining how routing should be carried out.
options: AutorouterOptions, options: AutorouterOptions,
/// Stores the current route being processed, if any. /// Stores the current route being processed, if any.
@ -53,6 +55,7 @@ impl AutorouteExecutionStepper {
pub fn new( pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: impl IntoIterator<Item = EdgeIndex<usize>> + 'static, ratlines: impl IntoIterator<Item = EdgeIndex<usize>> + 'static,
layer: usize,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<Self, AutorouterError> { ) -> Result<Self, AutorouterError> {
let mut ratlines_iter = Box::new(ratlines.into_iter()); let mut ratlines_iter = Box::new(ratlines.into_iter());
@ -66,11 +69,13 @@ impl AutorouteExecutionStepper {
Ok(Self { Ok(Self {
ratlines_iter, ratlines_iter,
layer,
options, options,
route: Some(router.route( route: Some(router.route(
LayoutEdit::new(), LayoutEdit::new(),
origin, origin,
destination, destination,
layer,
options.router_options.routed_band_width, options.router_options.routed_band_width,
)?), )?),
curr_ratline: Some(curr_ratline), curr_ratline: Some(curr_ratline),
@ -154,6 +159,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<LayoutEdit>, AutorouteContinu
recorder, recorder,
source, source,
target, target,
self.layer,
self.options.router_options.routed_band_width, self.options.router_options.routed_band_width,
)?); )?);
} else { } else {

View File

@ -14,7 +14,7 @@ use crate::{
board::{AccessMesadata, Board}, board::{AccessMesadata, Board},
drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement}, drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement},
graph::MakeRef, graph::MakeRef,
layout::{via::ViaWeight, LayoutEdit}, layout::LayoutEdit,
router::{navmesh::NavmeshError, ng, thetastar::ThetastarError, RouterOptions}, router::{navmesh::NavmeshError, ng, thetastar::ThetastarError, RouterOptions},
triangulation::GetTrianvertexNodeIndex, triangulation::GetTrianvertexNodeIndex,
}; };
@ -23,7 +23,6 @@ use super::{
autoroute::AutorouteExecutionStepper, autoroute::AutorouteExecutionStepper,
compare_detours::CompareDetoursExecutionStepper, compare_detours::CompareDetoursExecutionStepper,
measure_length::MeasureLengthExecutionStepper, measure_length::MeasureLengthExecutionStepper,
place_via::PlaceViaExecutionStepper,
pointroute::PointrouteExecutionStepper, pointroute::PointrouteExecutionStepper,
ratsnest::{Ratsnest, RatvertexIndex}, ratsnest::{Ratsnest, RatvertexIndex},
remove_bands::RemoveBandsExecutionStepper, remove_bands::RemoveBandsExecutionStepper,
@ -69,6 +68,7 @@ impl<M: AccessMesadata> Autorouter<M> {
pub fn pointroute( pub fn pointroute(
&mut self, &mut self,
selection: &PinSelection, selection: &PinSelection,
layer: usize,
point: Point, point: Point,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<PointrouteExecutionStepper, AutorouterError> { ) -> Result<PointrouteExecutionStepper, AutorouterError> {
@ -84,7 +84,7 @@ impl<M: AccessMesadata> Autorouter<M> {
RatvertexIndex::Poly(poly) => poly.ref_(self.board.layout()).apex(), 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> { pub fn undo_pointroute(&mut self, band: BandTermsegIndex) -> Result<(), AutorouterError> {
@ -97,17 +97,19 @@ impl<M: AccessMesadata> Autorouter<M> {
pub fn autoroute( pub fn autoroute(
&mut self, &mut self,
selection: &PinSelection, selection: &PinSelection,
layer: usize,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<AutorouteExecutionStepper, AutorouterError> { ) -> Result<AutorouteExecutionStepper, AutorouterError> {
self.autoroute_ratlines(self.selected_ratlines(selection), options) self.autoroute_ratlines(self.selected_ratlines(selection), layer, options)
} }
pub(super) fn autoroute_ratlines( pub(super) fn autoroute_ratlines(
&mut self, &mut self,
ratlines: Vec<EdgeIndex<usize>>, ratlines: Vec<EdgeIndex<usize>>,
layer: usize,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<AutorouteExecutionStepper, AutorouterError> { ) -> Result<AutorouteExecutionStepper, AutorouterError> {
AutorouteExecutionStepper::new(self, ratlines, options) AutorouteExecutionStepper::new(self, ratlines, layer, options)
} }
pub fn undo_autoroute(&mut self, selection: &PinSelection) -> Result<(), AutorouterError> { pub fn undo_autoroute(&mut self, selection: &PinSelection) -> Result<(), AutorouterError> {
@ -249,22 +251,24 @@ impl<M: AccessMesadata> Autorouter<M> {
pub fn compare_detours( pub fn compare_detours(
&mut self, &mut self,
selection: &PinSelection, selection: &PinSelection,
layer: usize,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<CompareDetoursExecutionStepper, AutorouterError> { ) -> Result<CompareDetoursExecutionStepper, AutorouterError> {
let ratlines = self.selected_ratlines(selection); let ratlines = self.selected_ratlines(selection);
if ratlines.len() < 2 { if ratlines.len() != 2 {
return Err(AutorouterError::NeedExactlyTwoRatlines); 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( pub(super) fn compare_detours_ratlines(
&mut self, &mut self,
ratline1: EdgeIndex<usize>, ratline1: EdgeIndex<usize>,
ratline2: EdgeIndex<usize>, ratline2: EdgeIndex<usize>,
layer: usize,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<CompareDetoursExecutionStepper, AutorouterError> { ) -> Result<CompareDetoursExecutionStepper, AutorouterError> {
CompareDetoursExecutionStepper::new(self, ratline1, ratline2, options) CompareDetoursExecutionStepper::new(self, ratline1, ratline2, layer, options)
} }
pub fn measure_length( pub fn measure_length(

View File

@ -39,11 +39,16 @@ impl CompareDetoursExecutionStepper {
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
ratline1: EdgeIndex<usize>, ratline1: EdgeIndex<usize>,
ratline2: EdgeIndex<usize>, ratline2: EdgeIndex<usize>,
layer: usize,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<Self, AutorouterError> { ) -> Result<Self, AutorouterError> {
Ok(Self { Ok(Self {
autoroute: autorouter.autoroute_ratlines(vec![ratline1, ratline2], options)?, autoroute: autorouter.autoroute_ratlines(vec![ratline1, ratline2], layer, options)?,
next_autoroute: Some(autorouter.autoroute_ratlines(vec![ratline2, ratline1], options)?), next_autoroute: Some(autorouter.autoroute_ratlines(
vec![ratline2, ratline1],
layer,
options,
)?),
ratline1, ratline1,
ratline2, ratline2,
total_length1: 0.0, total_length1: 0.0,

View File

@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
board::AccessMesadata, board::AccessMesadata,
layout::{via::ViaWeight, LayoutEdit}, layout::LayoutEdit,
router::ng, router::ng,
stepper::{Abort, Step}, stepper::{Abort, Step},
}; };
@ -25,11 +25,13 @@ use super::{
Autorouter, AutorouterOptions, Autorouter, AutorouterOptions,
}; };
type Type = PinSelection;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Command { pub enum Command {
Autoroute(PinSelection, AutorouterOptions), Autoroute {
pins: PinSelection,
active_layer: usize,
options: AutorouterOptions,
},
TopoAutoroute { TopoAutoroute {
selection: PinSelection, selection: PinSelection,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")] #[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
@ -37,9 +39,13 @@ pub enum Command {
active_layer: String, active_layer: String,
routed_band_width: f64, routed_band_width: f64,
}, },
PlaceVia(ViaWeight), PlaceVia(DotWeight),
RemoveBands(BandSelection), RemoveBands(BandSelection),
CompareDetours(Type, AutorouterOptions), CompareDetours {
pins: PinSelection,
active_layer: usize,
options: AutorouterOptions,
},
MeasureLength(BandSelection), MeasureLength(BandSelection),
} }

View File

@ -33,7 +33,6 @@ use super::{
execution::{Command, ExecutionStepper}, execution::{Command, ExecutionStepper},
history::{History, HistoryError}, history::{History, HistoryError},
measure_length::MeasureLengthExecutionStepper, measure_length::MeasureLengthExecutionStepper,
place_via::PlaceViaExecutionStepper,
remove_bands::RemoveBandsExecutionStepper, remove_bands::RemoveBandsExecutionStepper,
Autorouter, AutorouterError, Autorouter, AutorouterError,
}; };
@ -166,14 +165,18 @@ impl<M: AccessMesadata + Clone> Invoker<M> {
#[debug_requires(self.ongoing_command.is_none())] #[debug_requires(self.ongoing_command.is_none())]
fn dispatch_command(&mut self, command: &Command) -> Result<ExecutionStepper<M>, InvokerError> { fn dispatch_command(&mut self, command: &Command) -> Result<ExecutionStepper<M>, InvokerError> {
Ok(match command { Ok(match command {
Command::Autoroute(selection, options) => { Command::Autoroute {
let mut ratlines = self.autorouter.selected_ratlines(selection); pins,
active_layer,
options,
} => {
let mut ratlines = self.autorouter.selected_ratlines(pins);
if options.presort_by_pairwise_detours { if options.presort_by_pairwise_detours {
ratlines.sort_unstable_by(|a, b| { ratlines.sort_unstable_by(|a, b| {
let mut compare_detours = self let mut compare_detours = self
.autorouter .autorouter
.compare_detours_ratlines(*a, *b, *options) .compare_detours_ratlines(*a, *b, *active_layer, *options)
.unwrap(); .unwrap();
if let Ok((al, bl)) = compare_detours.finish(&mut self.autorouter) { if let Ok((al, bl)) = compare_detours.finish(&mut self.autorouter) {
PartialOrd::partial_cmp(&al, &bl).unwrap() PartialOrd::partial_cmp(&al, &bl).unwrap()
@ -183,7 +186,11 @@ impl<M: AccessMesadata + Clone> Invoker<M> {
}); });
} }
ExecutionStepper::Autoroute(self.autorouter.autoroute_ratlines(ratlines, *options)?) ExecutionStepper::Autoroute(self.autorouter.autoroute_ratlines(
ratlines,
*active_layer,
*options,
)?)
} }
Command::TopoAutoroute { Command::TopoAutoroute {
selection, selection,
@ -216,9 +223,15 @@ impl<M: AccessMesadata + Clone> Invoker<M> {
Command::RemoveBands(selection) => { Command::RemoveBands(selection) => {
ExecutionStepper::RemoveBands(self.autorouter.remove_bands(selection)?) ExecutionStepper::RemoveBands(self.autorouter.remove_bands(selection)?)
} }
Command::CompareDetours(selection, options) => ExecutionStepper::CompareDetours( Command::CompareDetours {
self.autorouter.compare_detours(selection, *options)?, pins,
), active_layer,
options,
} => ExecutionStepper::CompareDetours(self.autorouter.compare_detours(
pins,
*active_layer,
*options,
)?),
Command::MeasureLength(selection) => { Command::MeasureLength(selection) => {
ExecutionStepper::MeasureLength(self.autorouter.measure_length(selection)?) ExecutionStepper::MeasureLength(self.autorouter.measure_length(selection)?)
} }

View File

@ -6,21 +6,18 @@
//! the process of inserting a via with a specified weight and //! the process of inserting a via with a specified weight and
//! checks if the via has already been placed. //! checks if the via has already been placed.
use crate::{ use crate::{board::AccessMesadata, layout::LayoutEdit};
board::AccessMesadata,
layout::{via::ViaWeight, LayoutEdit},
};
use super::{invoker::GetDebugOverlayData, Autorouter, AutorouterError}; use super::{invoker::GetDebugOverlayData, Autorouter, AutorouterError};
#[derive(Debug)] #[derive(Debug)]
pub struct PlaceViaExecutionStepper { pub struct PlaceViaExecutionStepper {
weight: ViaWeight, weight: FixedDotWeight,
done: bool, done: bool,
} }
impl PlaceViaExecutionStepper { impl PlaceViaExecutionStepper {
pub fn new(weight: ViaWeight) -> Result<Self, AutorouterError> { pub fn new(weight: FixedDotWeight) -> Result<Self, AutorouterError> {
Ok(Self { Ok(Self {
weight, weight,
done: false, done: false,
@ -38,7 +35,7 @@ impl PlaceViaExecutionStepper {
autorouter autorouter
.board .board
.layout_mut() .layout_mut()
.add_via(&mut edit, self.weight)?; .add_fixed_dot(&mut edit, self.weight)?;
Ok(Some(edit)) Ok(Some(edit))
} else { } else {
Ok(None) Ok(None)

View File

@ -7,19 +7,20 @@ use std::ops::ControlFlow;
use geo::Point; use geo::Point;
use crate::{ use crate::{
autorouter::{Autorouter, AutorouterError, AutorouterOptions},
board::AccessMesadata, board::AccessMesadata,
drawing::{ drawing::{
band::BandTermsegIndex, band::BandTermsegIndex,
dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight}, dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight},
}, },
geometry::NodeMetadata,
graph::GetPetgraphIndex,
layout::LayoutEdit, layout::LayoutEdit,
math::Circle, math::Circle,
router::{RouteStepper, Router}, router::{RouteStepper, Router},
stepper::Step, stepper::Step,
}; };
use super::{Autorouter, AutorouterError, AutorouterOptions};
pub struct PointrouteExecutionStepper { pub struct PointrouteExecutionStepper {
route: RouteStepper, route: RouteStepper,
options: AutorouterOptions, options: AutorouterOptions,
@ -29,18 +30,28 @@ impl PointrouteExecutionStepper {
pub fn new( pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>, autorouter: &mut Autorouter<impl AccessMesadata>,
origin: FixedDotIndex, origin: FixedDotIndex,
layer: usize,
point: Point, point: Point,
options: AutorouterOptions, options: AutorouterOptions,
) -> Result<Self, AutorouterError> { ) -> Result<Self, AutorouterError> {
let destination = autorouter.board.add_fixed_dot_infringably( let destination = autorouter.board.add_fixed_dot_infringably(
&mut LayoutEdit::new(), &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 { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: point, pos: point,
r: options.router_options.routed_band_width / 2.0, r: options.router_options.routed_band_width / 2.0,
}, },
layer: 0,
maybe_net: None,
}), }),
None, None,
); );
@ -52,6 +63,7 @@ impl PointrouteExecutionStepper {
LayoutEdit::new(), LayoutEdit::new(),
origin, origin,
destination, destination,
layer,
options.router_options.routed_band_width, options.router_options.routed_band_width,
)?, )?,
options, options,

View File

@ -23,11 +23,11 @@ use crate::{
drawing::{ drawing::{
band::BandTermsegIndex, band::BandTermsegIndex,
dot::FixedDotIndex, dot::FixedDotIndex,
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules, rules::AccessRules,
}, },
geometry::shape::AccessShape, geometry::{shape::AccessShape, GetMetadata},
graph::{GenericIndex, GetPetgraphIndex, MakeRef}, graph::{GenericIndex, GetPetgraphIndex, MakeRef},
layout::{ layout::{
poly::{MakePolygon, PolyWeight}, poly::{MakePolygon, PolyWeight},
@ -110,7 +110,7 @@ impl Ratsnest {
if let PrimitiveIndex::FixedDot(dot) = node { if let PrimitiveIndex::FixedDot(dot) = node {
if layout.drawing().compounds(dot).next().is_none() { if layout.drawing().compounds(dot).next().is_none() {
handle_rvw( handle_rvw(
layout.drawing().primitive(dot).maybe_net(), layout.drawing().primitive(dot).metadata().maybe_net,
RatvertexIndex::FixedDot(dot), RatvertexIndex::FixedDot(dot),
node.primitive(layout.drawing()).shape().center(), node.primitive(layout.drawing()).shape().center(),
)?; )?;
@ -120,7 +120,11 @@ impl Ratsnest {
for poly in layout.layer_poly_nodes(layer) { for poly in layout.layer_poly_nodes(layer) {
handle_rvw( handle_rvw(
layout.drawing().compound_weight(poly.into()).maybe_net(), layout
.drawing()
.geometry()
.metadata(poly.petgraph_index())
.maybe_net,
RatvertexIndex::Poly(poly), RatvertexIndex::Poly(poly),
poly.ref_(layout).shape().center(), poly.ref_(layout).shape().center(),
)?; )?;

View File

@ -9,22 +9,17 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
board::{AccessMesadata, BandName, Board, ResolvedSelector}, board::{AccessMesadata, BandName, Board, ResolvedSelector},
drawing::{ drawing::{graph::PrimitiveIndex, Collect},
graph::{MakePrimitive, PrimitiveIndex},
Collect,
},
geometry::{ geometry::{
shape::{AccessShape, Shape}, shape::{AccessShape, Shape},
GenericNode, GetLayer, GenericNode,
}, },
graph::{GenericIndex, GetPetgraphIndex, MakeRef}, layout::NodeIndex,
layout::{poly::PolyWeight, CompoundWeight, NodeIndex},
}; };
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] #[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct PinSelector { pub struct PinSelector {
pub pin: String, pub pin: String,
pub layer: String,
} }
impl PinSelector { impl PinSelector {
@ -32,43 +27,8 @@ impl PinSelector {
board: &Board<impl AccessMesadata>, board: &Board<impl AccessMesadata>,
node: NodeIndex, node: NodeIndex,
) -> Option<PinSelector> { ) -> Option<PinSelector> {
let layer = match node { board.node_pinname(&node).map(|pinname| PinSelector {
NodeIndex::Primitive(primitive) => { pin: pinname.to_string(),
primitive.primitive(board.layout().drawing()).layer()
}
NodeIndex::Compound(compound) => {
if let CompoundWeight::Poly(..) = board.layout().drawing().compound_weight(compound)
{
GenericIndex::<PolyWeight>::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<impl AccessMesadata>,
pin: &str,
layer: usize,
) -> Option<PinSelector> {
Some(PinSelector {
pin: pin.to_string(),
layer: board.layout().rules().layer_layername(layer)?.to_string(),
}) })
} }
} }
@ -255,11 +215,10 @@ impl Selection {
self.band_selection.0.insert(x); self.band_selection.0.insert(x);
} }
} }
ResolvedSelector::Pin { pin_name, layer } => { ResolvedSelector::Pin { pin_name } => {
if let Some(x) = PinSelector::try_from_pin_and_layer_id(board, pin_name, layer) self.pin_selection.0.insert(PinSelector {
{ pin: pin_name.to_string(),
self.pin_selection.0.insert(x); });
}
} }
} }
} }

View File

@ -22,8 +22,8 @@ use crate::{
seg::{FixedSegIndex, FixedSegWeight, SegIndex, SegWeight}, seg::{FixedSegIndex, FixedSegWeight, SegIndex, SegWeight},
Collect, DrawingException, Collect, DrawingException,
}, },
geometry::{edit::ApplyGeometryEdit, GenericNode, GetLayer}, geometry::{edit::ApplyGeometryEdit, GenericNode, NodeMetadata},
graph::{GenericIndex, MakeRef}, graph::GenericIndex,
layout::{poly::PolyWeight, CompoundEntryLabel, CompoundWeight, Layout, LayoutEdit, NodeIndex}, layout::{poly::PolyWeight, CompoundEntryLabel, CompoundWeight, Layout, LayoutEdit, NodeIndex},
router::ng::EtchedPath, router::ng::EtchedPath,
}; };
@ -34,40 +34,30 @@ pub type BandName = planar_incr_embed::navmesh::OrderedPair<String>;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ResolvedSelector<'a> { pub enum ResolvedSelector<'a> {
Band { band_uid: BandUid }, Band { band_uid: BandUid },
Pin { pin_name: &'a str, layer: usize }, Pin { pin_name: &'a str },
} }
impl<'a> ResolvedSelector<'a> { impl<'a> ResolvedSelector<'a> {
pub fn try_from_node(board: &'a Board<impl AccessMesadata>, node: NodeIndex) -> Option<Self> { pub fn try_from_node(board: &'a Board<impl AccessMesadata>, node: NodeIndex) -> Option<Self> {
use crate::{drawing::graph::MakePrimitive, graph::GetPetgraphIndex}; let loose = match node {
NodeIndex::Primitive(primitive) => primitive.try_into().ok(),
let (layer, loose) = match node {
NodeIndex::Primitive(primitive) => (
primitive.primitive(board.layout().drawing()).layer(),
primitive.try_into().ok(),
),
NodeIndex::Compound(compound) => { NodeIndex::Compound(compound) => {
match board.layout().drawing().compound_weight(compound) { match board.layout().drawing().compound_weight(compound) {
CompoundWeight::Poly(..) => ( CompoundWeight::Poly(..) => None,
GenericIndex::<PolyWeight>::new(compound.petgraph_index())
.ref_(board.layout())
.layer(),
None,
),
_ => return None,
} }
} }
}; };
if let Some(pin_name) = board.node_pinname(&node) { board
Some(ResolvedSelector::Pin { pin_name, layer }) .node_pinname(&node)
} else { .map(|pin_name| ResolvedSelector::Pin { pin_name })
loose.and_then(|loose| { .or_else(|| {
Some(ResolvedSelector::Band { loose.and_then(|loose| {
band_uid: board.layout().drawing().loose_band_uid(loose).ok()?, Some(ResolvedSelector::Band {
band_uid: board.layout().drawing().loose_band_uid(loose).ok()?,
})
}) })
}) })
}
} }
} }
@ -110,10 +100,13 @@ impl<M: AccessMesadata> Board<M> {
pub fn add_fixed_dot_infringably( pub fn add_fixed_dot_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit, recorder: &mut LayoutEdit,
meta: NodeMetadata,
weight: FixedDotWeight, weight: FixedDotWeight,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) -> FixedDotIndex { ) -> 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 { if let Some(pin) = maybe_pin {
self.node_to_pinname self.node_to_pinname
@ -129,6 +122,7 @@ impl<M: AccessMesadata> Board<M> {
pub fn add_fixed_seg_infringably( pub fn add_fixed_seg_infringably(
&mut self, &mut self,
recorder: &mut LayoutEdit, recorder: &mut LayoutEdit,
meta: NodeMetadata,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
@ -136,7 +130,7 @@ impl<M: AccessMesadata> Board<M> {
) -> FixedSegIndex { ) -> FixedSegIndex {
let seg = self let seg = self
.layout .layout
.add_fixed_seg_infringably(recorder, from, to, weight); .add_fixed_seg_infringably(recorder, meta, from, to, weight);
if let Some(pin) = maybe_pin { if let Some(pin) = maybe_pin {
self.node_to_pinname self.node_to_pinname
@ -152,11 +146,14 @@ impl<M: AccessMesadata> Board<M> {
pub fn add_poly_with_nodes( pub fn add_poly_with_nodes(
&mut self, &mut self,
recorder: &mut LayoutEdit, recorder: &mut LayoutEdit,
meta: NodeMetadata,
weight: PolyWeight, weight: PolyWeight,
maybe_pin: Option<String>, maybe_pin: Option<String>,
nodes: &[PrimitiveIndex], nodes: &[PrimitiveIndex],
) -> GenericIndex<PolyWeight> { ) -> GenericIndex<PolyWeight> {
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 { if let Some(pin) = maybe_pin {
for i in nodes { for i in nodes {

View File

@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::{ use crate::{
geometry::{shape::MeasureLength, GetLayer}, geometry::{shape::MeasureLength, GetMetadata},
graph::MakeRef, graph::MakeRef,
}; };
@ -40,9 +40,11 @@ impl<'a, CW: 'a, Cel: 'a, R: 'a> BandRef<'a, CW, Cel, R> {
} }
} }
impl<CW: Clone, Cel: Copy, R: AccessRules> GetLayer for BandRef<'_, CW, Cel, R> { impl<CW: Clone, Cel: Copy, R: AccessRules> BandRef<'_, CW, Cel, R> {
fn layer(&self) -> usize { pub fn layer(&self) -> usize {
self.first_seg.primitive(self.drawing).layer() let meta = self.first_seg.primitive(self.drawing).metadata();
debug_assert_eq!(meta.from_layer, meta.to_layer);
meta.from_layer
} }
} }

View File

@ -6,12 +6,12 @@ use enum_dispatch::enum_dispatch;
use crate::{ use crate::{
drawing::{ drawing::{
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight},
primitive::{GenericPrimitive, Primitive}, primitive::{GenericPrimitive, Primitive},
rules::AccessRules, rules::AccessRules,
Drawing, Drawing,
}, },
geometry::{GetLayer, GetOffset, GetWidth, SetOffset}, geometry::{GetOffset, GetWidth, SetOffset},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
}; };
@ -45,7 +45,7 @@ impl TryFrom<PrimitiveIndex> for BendIndex {
} }
} }
#[enum_dispatch(GetOffset, SetOffset, GetWidth, GetLayer)] #[enum_dispatch(GetOffset, SetOffset, GetWidth)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum BendWeight { pub enum BendWeight {
Fixed(FixedBendWeight), Fixed(FixedBendWeight),
@ -109,20 +109,6 @@ impl SetOffset for LooseBendWeight {
pub struct GeneralBendWeight { pub struct GeneralBendWeight {
pub width: f64, pub width: f64,
pub offset: f64, pub offset: f64,
pub layer: usize,
pub maybe_net: Option<usize>,
}
impl GetLayer for GeneralBendWeight {
fn layer(&self) -> usize {
self.layer
}
}
impl GetMaybeNet for GeneralBendWeight {
fn maybe_net(&self) -> Option<usize> {
self.maybe_net
}
} }
impl GetOffset for GeneralBendWeight { impl GetOffset for GeneralBendWeight {

View File

@ -9,12 +9,12 @@ use petgraph::stable_graph::NodeIndex;
use crate::{ use crate::{
drawing::{ drawing::{
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight},
primitive::{GenericPrimitive, Primitive}, primitive::{GenericPrimitive, Primitive},
rules::AccessRules, rules::AccessRules,
Drawing, Drawing,
}, },
geometry::{GetLayer, GetSetPos, GetWidth}, geometry::{GetSetPos, GetWidth},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
math::Circle, math::Circle,
}; };
@ -47,7 +47,7 @@ impl TryFrom<PrimitiveIndex> for DotIndex {
} }
} }
#[enum_dispatch(GetSetPos, GetWidth, GetLayer)] #[enum_dispatch(GetSetPos, GetWidth)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum DotWeight { pub enum DotWeight {
Fixed(FixedDotWeight), Fixed(FixedDotWeight),
@ -104,20 +104,6 @@ impl GetSetPos for LooseDotWeight {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct GeneralDotWeight { pub struct GeneralDotWeight {
pub circle: Circle, pub circle: Circle,
pub layer: usize,
pub maybe_net: Option<usize>,
}
impl GetLayer for GeneralDotWeight {
fn layer(&self) -> usize {
self.layer
}
}
impl GetMaybeNet for GeneralDotWeight {
fn maybe_net(&self) -> Option<usize> {
self.maybe_net
}
} }
impl GetSetPos for GeneralDotWeight { impl GetSetPos for GeneralDotWeight {

View File

@ -18,7 +18,7 @@ use crate::{
collect::Collect, collect::Collect,
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
gear::{GearIndex, GetNextGear}, gear::{GearIndex, GetNextGear},
graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight},
guide::Guide, guide::Guide,
loose::{GetPrevNextLoose, Loose, LooseIndex}, loose::{GetPrevNextLoose, Loose, LooseIndex},
primitive::{ primitive::{
@ -36,7 +36,7 @@ use crate::{
recording_with_rtree::RecordingGeometryWithRtree, recording_with_rtree::RecordingGeometryWithRtree,
with_rtree::BboxedIndex, with_rtree::BboxedIndex,
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
GetLayer, GetOffset, GetSetPos, GetWidth, GetMetadata, GetOffset, GetSetPos, GetWidth, NodeMetadata,
}, },
graph::MakeRef, graph::MakeRef,
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
@ -297,10 +297,12 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn add_fixed_dot( pub fn add_fixed_dot(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
weight: FixedDotWeight, weight: FixedDotWeight,
) -> Result<FixedDotIndex, Infringement> { ) -> Result<FixedDotIndex, Infringement> {
self.add_dot_with_infringement_filtering( self.add_dot_with_infringement_filtering(
recorder, recorder,
meta,
weight, weight,
&|_drawing, _infringer, _infringee| true, &|_drawing, _infringer, _infringee| true,
) )
@ -318,23 +320,25 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn add_fixed_dot_infringably( pub fn add_fixed_dot_infringably(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
weight: FixedDotWeight, weight: FixedDotWeight,
) -> FixedDotIndex { ) -> 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_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()))] #[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<W: AccessDotWeight + Into<PrimitiveWeight> + GetLayer>( fn add_dot_with_infringement_filtering<W: AccessDotWeight + Into<PrimitiveWeight>>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
weight: W, weight: W,
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<GenericIndex<W>, Infringement> ) -> Result<GenericIndex<W>, Infringement>
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + 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)?; self.fail_and_remove_if_infringes_except(recorder, dot.into(), predicate)?;
Ok(dot) Ok(dot)
@ -346,12 +350,14 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn add_fixed_seg( pub fn add_fixed_seg(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> Result<FixedSegIndex, DrawingException> { ) -> Result<FixedSegIndex, DrawingException> {
self.add_seg_with_infringement_filtering( self.add_seg_with_infringement_filtering(
recorder, recorder,
meta,
from.into(), from.into(),
to.into(), to.into(),
weight, weight,
@ -364,11 +370,12 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn add_fixed_seg_infringably( pub fn add_fixed_seg_infringably(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> FixedSegIndex { ) -> 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))] #[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<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn add_lone_loose_seg( pub fn add_lone_loose_seg(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: LoneLooseSegWeight, weight: LoneLooseSegWeight,
) -> Result<LoneLooseSegIndex, DrawingException> { ) -> Result<LoneLooseSegIndex, DrawingException> {
let seg = self.add_seg_with_infringement_filtering( let seg = self.add_seg_with_infringement_filtering(
recorder, recorder,
meta,
from.into(), from.into(),
to.into(), to.into(),
weight, weight,
@ -399,12 +408,14 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn add_seq_loose_seg( pub fn add_seq_loose_seg(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: DotIndex, from: DotIndex,
to: LooseDotIndex, to: LooseDotIndex,
weight: SeqLooseSegWeight, weight: SeqLooseSegWeight,
) -> Result<SeqLooseSegIndex, DrawingException> { ) -> Result<SeqLooseSegIndex, DrawingException> {
let seg = self.add_seg_with_infringement_filtering( let seg = self.add_seg_with_infringement_filtering(
recorder, recorder,
meta,
from, from,
to.into(), to.into(),
weight, weight,
@ -429,9 +440,10 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
#[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_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().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()))] #[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<W: AccessSegWeight + Into<PrimitiveWeight> + GetLayer>( fn add_seg_with_infringement_filtering<W: AccessSegWeight + Into<PrimitiveWeight>>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: DotIndex, from: DotIndex,
to: DotIndex, to: DotIndex,
weight: W, weight: W,
@ -440,7 +452,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + 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)?; self.fail_and_remove_if_infringes_except(recorder, seg.into(), predicate)?;
// Raise a collision exception if the currently created cane's seg // Raise a collision exception if the currently created cane's seg
@ -469,8 +481,8 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
// Check whether the the seg is terminal, that is, whether at // Check whether the the seg is terminal, that is, whether at
// least one of its two joints is a fixed dot. // least one of its two joints is a fixed dot.
if matches!(from, DotIndex::Fixed(..)) || matches!(to, DotIndex::Fixed(..)) { if matches!(from, DotIndex::Fixed(..)) || matches!(to, DotIndex::Fixed(..)) {
collider.primitive(drawing).maybe_net() collider.primitive(drawing).metadata().maybe_net
!= collidee.primitive(drawing).maybe_net() != collidee.primitive(drawing).metadata().maybe_net
} else { } else {
// Cane is non-initial. // Cane is non-initial.
true true
@ -494,6 +506,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
fn add_loose_bend_with_infringement_filtering( fn add_loose_bend_with_infringement_filtering(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: LooseDotIndex, from: LooseDotIndex,
to: LooseDotIndex, to: LooseDotIndex,
around: GearIndex, around: GearIndex,
@ -502,15 +515,14 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
) -> Result<LooseBendIndex, DrawingException> { ) -> Result<LooseBendIndex, DrawingException> {
// It makes no sense to wrap something around or under one of its connectables. // It makes no sense to wrap something around or under one of its connectables.
// //
if let Some(net) = weight.maybe_net() { if let Some(net) = meta.maybe_net {
if let Some(around_net) = around.primitive(self).maybe_net() { if let Some(around_net) = around.primitive(self).metadata().maybe_net {
if net == around_net { if net == around_net {
return Err(AlreadyConnected(net, around.into()).into()); return Err(AlreadyConnected(net, around.into()).into());
} }
} }
//
if let Some(next_gear) = around.ref_(self).next_gear() { 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 { if net == next_gear_net {
return Err(AlreadyConnected(net, next_gear.into()).into()); return Err(AlreadyConnected(net, next_gear.into()).into());
} }
@ -522,6 +534,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
GearIndex::FixedDot(core) => self GearIndex::FixedDot(core) => self
.add_core_bend_with_infringement_filtering( .add_core_bend_with_infringement_filtering(
recorder, recorder,
meta,
from.into(), from.into(),
to.into(), to.into(),
core, core,
@ -532,6 +545,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
GearIndex::FixedBend(around) => self GearIndex::FixedBend(around) => self
.add_outer_bend_with_infringement_filtering( .add_outer_bend_with_infringement_filtering(
recorder, recorder,
meta,
from, from,
to, to,
around.into(), around.into(),
@ -542,6 +556,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
GearIndex::LooseBend(around) => self GearIndex::LooseBend(around) => self
.add_outer_bend_with_infringement_filtering( .add_outer_bend_with_infringement_filtering(
recorder, recorder,
meta,
from, from,
to, to,
around.into(), around.into(),
@ -556,11 +571,10 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
#[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().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_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()))] #[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< fn add_core_bend_with_infringement_filtering<W: AccessBendWeight + Into<PrimitiveWeight>>(
W: AccessBendWeight + Into<PrimitiveWeight> + GetLayer,
>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: DotIndex, from: DotIndex,
to: DotIndex, to: DotIndex,
core: FixedDotIndex, core: FixedDotIndex,
@ -570,9 +584,14 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
{ {
let bend = let bend = self.recording_geometry_with_rtree.add_bend(
self.recording_geometry_with_rtree recorder,
.add_bend(recorder, from, to, core.into(), weight); meta,
from,
to,
core.into(),
weight,
);
self.fail_and_remove_if_infringes_except(recorder, bend.into(), predicate)?; self.fail_and_remove_if_infringes_except(recorder, bend.into(), predicate)?;
Ok(bend) Ok(bend)
@ -585,6 +604,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
fn add_outer_bend_with_infringement_filtering( fn add_outer_bend_with_infringement_filtering(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: LooseDotIndex, from: LooseDotIndex,
to: LooseDotIndex, to: LooseDotIndex,
inner: BendIndex, inner: BendIndex,
@ -616,6 +636,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
let bend = self.recording_geometry_with_rtree.add_bend( let bend = self.recording_geometry_with_rtree.add_bend(
recorder, recorder,
meta,
from.into(), from.into(),
to.into(), to.into(),
core.into(), core.into(),
@ -659,6 +680,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn insert_cane( pub fn insert_cane(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: DotIndex, from: DotIndex,
around: GearIndex, around: GearIndex,
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
@ -669,6 +691,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
let maybe_next_gear = around.ref_(self).next_gear(); let maybe_next_gear = around.ref_(self).next_gear();
let cane = self.add_cane_with_infringement_filtering( let cane = self.add_cane_with_infringement_filtering(
recorder, recorder,
meta,
from, from,
around, around,
dot_weight, dot_weight,
@ -794,6 +817,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
pub fn add_cane( pub fn add_cane(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: DotIndex, from: DotIndex,
around: GearIndex, around: GearIndex,
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
@ -803,6 +827,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
self.add_cane_with_infringement_filtering( self.add_cane_with_infringement_filtering(
recorder, recorder,
meta,
from, from,
around, around,
dot_weight, dot_weight,
@ -820,6 +845,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
fn add_cane_with_infringement_filtering( fn add_cane_with_infringement_filtering(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: DotIndex, from: DotIndex,
around: GearIndex, around: GearIndex,
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
@ -828,13 +854,15 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
sense: RotationSense, sense: RotationSense,
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
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 // 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 let seg = self
.add_seg_with_infringement_filtering( .add_seg_with_infringement_filtering(
recorder, recorder,
meta,
from, from,
seg_to.into(), seg_to.into(),
seg_weight, seg_weight,
@ -855,6 +883,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
let bend = self let bend = self
.add_loose_bend_with_infringement_filtering( .add_loose_bend_with_infringement_filtering(
recorder, recorder,
meta,
bend_from, bend_from,
bend_to, bend_to,
around, around,
@ -1009,22 +1038,25 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> { impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
#[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().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()))] #[debug_ensures(self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))]
fn add_dot_infringably<W: AccessDotWeight + Into<PrimitiveWeight> + GetLayer>( fn add_dot_infringably<W: AccessDotWeight + Into<PrimitiveWeight>>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
weight: W, weight: W,
) -> GenericIndex<W> ) -> GenericIndex<W>
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + 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().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))] #[debug_ensures(self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count() + 2))]
fn add_seg_infringably<W: AccessSegWeight + Into<PrimitiveWeight> + GetLayer>( fn add_seg_infringably<W: AccessSegWeight + Into<PrimitiveWeight>>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
from: DotIndex, from: DotIndex,
to: DotIndex, to: DotIndex,
weight: W, weight: W,
@ -1033,16 +1065,17 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
GenericIndex<W>: Into<PrimitiveIndex>, GenericIndex<W>: Into<PrimitiveIndex>,
{ {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.add_seg(recorder, from, to, weight) .add_seg(recorder, meta, from, to, weight)
} }
pub fn add_compound( pub fn add_compound(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
meta: NodeMetadata,
weight: CW, weight: CW,
) -> GenericIndex<CW> { ) -> GenericIndex<CW> {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.add_compound(recorder, weight) .add_compound(recorder, meta, weight)
} }
pub fn remove_compound( pub fn remove_compound(
@ -1117,7 +1150,8 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
) -> impl Iterator<Item = GenericNode<PrimitiveIndex, GenericIndex<CW>>> + '_ { ) -> impl Iterator<Item = GenericNode<PrimitiveIndex, GenericIndex<CW>>> + '_ {
let limiting_shape = node.primitive(self).shape().inflate( let limiting_shape = node.primitive(self).shape().inflate(
node.primitive(self) node.primitive(self)
.maybe_net() .metadata()
.maybe_net
.map(|net| self.rules.largest_clearance(Some(net))) .map(|net| self.rules.largest_clearance(Some(net)))
.unwrap_or(0.0), .unwrap_or(0.0),
); );
@ -1125,7 +1159,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.rtree() .rtree()
.locate_in_envelope_intersecting( .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) .map(|wrapper| wrapper.data)
} }
@ -1167,7 +1201,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.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| { .filter_map(|wrapper| {
if let GenericNode::Primitive(collidee) = wrapper.data { if let GenericNode::Primitive(collidee) = wrapper.data {
Some(collidee) Some(collidee)
@ -1224,40 +1258,28 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
&self, &self,
index: GenericNode<PrimitiveIndex, GenericIndex<CW>>, index: GenericNode<PrimitiveIndex, GenericIndex<CW>>,
active_layer: usize, active_layer: usize,
) -> bool ) -> bool {
where self.recording_geometry_with_rtree
CW: super::graph::IsInLayer, .geometry()
{ .metadata(index)
match index { .is_in_layer(active_layer)
GenericNode::Primitive(primitive) => primitive.primitive(self).layer() == active_layer,
GenericNode::Compound(compound) => {
self.compound_weight(compound).is_in_layer(active_layer)
}
}
} }
pub fn is_node_in_any_layer_of( pub fn is_node_in_any_layer_of(
&self, &self,
index: GenericNode<PrimitiveIndex, GenericIndex<CW>>, index: GenericNode<PrimitiveIndex, GenericIndex<CW>>,
layers: &[bool], layers: &[bool],
) -> bool ) -> bool {
where self.recording_geometry_with_rtree
CW: IsInLayer, .geometry()
{ .metadata(index)
match index { .is_in_any_layer_of(layers)
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)
}
}
} }
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool { fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
if let (Some(node1_net), Some(node2_net)) = ( if let (Some(node1_net), Some(node2_net)) = (
node1.primitive(self).maybe_net(), node1.primitive(self).metadata().maybe_net,
node2.primitive(self).maybe_net(), node2.primitive(self).metadata().maybe_net,
) { ) {
node1_net == node2_net node1_net == node2_net
} else { } else {

View File

@ -5,10 +5,7 @@
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use petgraph::stable_graph::NodeIndex; use petgraph::stable_graph::NodeIndex;
use crate::{ use crate::graph::{GenericIndex, GetPetgraphIndex};
geometry::GetLayer,
graph::{GenericIndex, GetPetgraphIndex},
};
use super::{ use super::{
bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
@ -22,29 +19,6 @@ use super::{
Drawing, 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<T: GetLayer> 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<usize>;
}
#[enum_dispatch] #[enum_dispatch]
pub trait MakePrimitive { pub trait MakePrimitive {
fn primitive<'a, CW: Clone, Cel: Copy, R: AccessRules>( fn primitive<'a, CW: Clone, Cel: Copy, R: AccessRules>(
@ -55,18 +29,6 @@ pub trait MakePrimitive {
macro_rules! impl_weight_forward { macro_rules! impl_weight_forward {
($weight_struct:ty, $weight_variant:ident, $index_struct:ident) => { ($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<usize> {
self.0.maybe_net()
}
}
impl GetWidth for $weight_struct { impl GetWidth for $weight_struct {
fn width(&self) -> f64 { fn width(&self) -> f64 {
self.0.width() self.0.width()
@ -100,7 +62,7 @@ pub enum PrimitiveIndex {
LooseBend(LooseBendIndex), LooseBend(LooseBendIndex),
} }
#[enum_dispatch(GetWidth, GetLayer)] #[enum_dispatch(GetWidth)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum PrimitiveWeight { pub enum PrimitiveWeight {
FixedDot(FixedDotWeight), FixedDot(FixedDotWeight),

View File

@ -9,12 +9,15 @@ use crate::{
drawing::{ drawing::{
bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
graph::{GetMaybeNet, PrimitiveIndex, PrimitiveWeight}, graph::{PrimitiveIndex, PrimitiveWeight},
rules::{AccessRules, Conditions, GetConditions}, rules::{AccessRules, Conditions, GetConditions},
seg::{FixedSegWeight, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight}, seg::{FixedSegWeight, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight},
Drawing, Drawing,
}, },
geometry::{primitive::PrimitiveShape, GenericNode, GetLayer, GetOffset, GetWidth, Retag}, geometry::{
primitive::PrimitiveShape, GenericNode, GetMetadata, GetOffset, GetWidth, NodeMetadata,
Retag,
},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
}; };
@ -126,18 +129,6 @@ macro_rules! impl_primitive {
} }
} }
} }
impl<CW, Cel, R> GetLayer for $primitive_struct<'_, CW, Cel, R> {
fn layer(&self) -> usize {
self.weight().layer()
}
}
impl<CW, Cel, R> GetMaybeNet for $primitive_struct<'_, CW, Cel, R> {
fn maybe_net(&self) -> Option<usize> {
self.weight().maybe_net()
}
}
}; };
} }
@ -153,14 +144,7 @@ macro_rules! impl_loose_primitive {
}; };
} }
#[enum_dispatch( #[enum_dispatch(GetDrawing, GetMetadata, GetWidth, MakePrimitiveShape, GetLimbs)]
GetLayer,
GetMaybeNet,
GetWidth,
GetDrawing,
MakePrimitiveShape,
GetLimbs
)]
pub enum Primitive<'a, CW, Cel, R> { pub enum Primitive<'a, CW, Cel, R> {
FixedDot(FixedDot<'a, CW, Cel, R>), FixedDot(FixedDot<'a, CW, Cel, R>),
LooseDot(LooseDot<'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() .graph()
.node_weight(self.index.petgraph_index()) .node_weight(self.index.petgraph_index())
.unwrap() .unwrap()
.kind
{ {
*weight weight
} else { } else {
unreachable!() unreachable!()
} }
} }
} }
impl<W, CW, Cel, R> GetMetadata for GenericPrimitive<'_, W, CW, Cel, R> {
fn metadata(&self) -> NodeMetadata {
self.drawing
.geometry()
.graph()
.node_weight(self.index.petgraph_index())
.unwrap()
.meta
}
}
impl<W, CW, Cel, R> GetInterior<PrimitiveIndex> for GenericPrimitive<'_, W, CW, Cel, R> { impl<W, CW, Cel, R> GetInterior<PrimitiveIndex> for GenericPrimitive<'_, W, CW, Cel, R> {
fn interior(&self) -> Vec<PrimitiveIndex> { fn interior(&self) -> Vec<PrimitiveIndex> {
vec![self.tagged_weight().retag(self.index.petgraph_index())] 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> impl<'a, W, CW, Cel, R> GetConditions<'a> for &GenericPrimitive<'a, W, CW, Cel, R> {
where
GenericPrimitive<'a, W, CW, Cel, R>: GetMaybeNet,
{
fn conditions(self) -> Option<Conditions<'a>> { fn conditions(self) -> Option<Conditions<'a>> {
self.maybe_net().map(|net| Conditions { self.metadata().maybe_net.map(|net| Conditions {
net, net,
maybe_region: Some("A".into()), maybe_region: Some("A".into()),
maybe_layer: Some("F.Cu".into()), maybe_layer: Some("F.Cu".into()),

View File

@ -6,13 +6,13 @@ use enum_dispatch::enum_dispatch;
use crate::{ use crate::{
drawing::{ drawing::{
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, graph::{MakePrimitive, PrimitiveIndex, PrimitiveWeight},
loose::LooseIndex, loose::LooseIndex,
primitive::{GenericPrimitive, Primitive}, primitive::{GenericPrimitive, Primitive},
rules::AccessRules, rules::AccessRules,
Drawing, Drawing,
}, },
geometry::{GetLayer, GetWidth}, geometry::GetWidth,
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
}; };
@ -98,7 +98,7 @@ impl TryFrom<PrimitiveIndex> for SegIndex {
} }
} }
#[enum_dispatch(GetWidth, GetLayer)] #[enum_dispatch(GetWidth)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum SegWeight { pub enum SegWeight {
Fixed(FixedSegWeight), Fixed(FixedSegWeight),
@ -144,20 +144,6 @@ impl_weight_forward!(SeqLooseSegWeight, SeqLooseSeg, SeqLooseSegIndex);
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct GeneralSegWeight { pub struct GeneralSegWeight {
pub width: f64, pub width: f64,
pub layer: usize,
pub maybe_net: Option<usize>,
}
impl GetLayer for GeneralSegWeight {
fn layer(&self) -> usize {
self.layer
}
}
impl GetMaybeNet for GeneralSegWeight {
fn maybe_net(&self) -> Option<usize> {
self.maybe_net
}
} }
impl GetWidth for GeneralSegWeight { impl GetWidth for GeneralSegWeight {

View File

@ -2,13 +2,16 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::graph::{GenericIndex, GetPetgraphIndex}; use crate::{
geometry::NodeMetadata,
graph::{GenericIndex, GetPetgraphIndex},
};
pub trait ManageCompounds<CW: Clone> { pub trait ManageCompounds<CW: Clone> {
type GeneralIndex: Copy; type GeneralIndex: Copy;
type EntryLabel: Copy; type EntryLabel: Copy;
fn add_compound(&mut self, weight: CW) -> GenericIndex<CW>; fn add_compound(&mut self, meta: NodeMetadata, weight: CW) -> GenericIndex<CW>;
fn remove_compound(&mut self, compound: GenericIndex<CW>); fn remove_compound(&mut self, compound: GenericIndex<CW>);
fn add_to_compound<I>(&mut self, node: I, label: Self::EntryLabel, compound: GenericIndex<CW>) fn add_to_compound<I>(&mut self, node: I, label: Self::EntryLabel, compound: GenericIndex<CW>)
where where

View File

@ -6,12 +6,12 @@ use std::collections::{btree_map::Entry, BTreeMap};
use crate::graph::{GenericIndex, GetPetgraphIndex}; use crate::graph::{GenericIndex, GetPetgraphIndex};
use super::{AccessBendWeight, AccessDotWeight, AccessSegWeight, GetLayer}; use super::{AccessBendWeight, AccessDotWeight, AccessSegWeight, NodeMetadata};
pub trait ApplyGeometryEdit< pub trait ApplyGeometryEdit<
DW: AccessDotWeight + GetLayer, DW: AccessDotWeight,
SW: AccessSegWeight + GetLayer, SW: AccessSegWeight,
BW: AccessBendWeight + GetLayer, BW: AccessBendWeight,
CW: Clone, CW: Clone,
Cel: Copy, Cel: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy, PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy,
@ -25,17 +25,34 @@ pub trait ApplyGeometryEdit<
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI> { pub struct GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI> {
pub(super) dots: BTreeMap<DI, (Option<DW>, Option<DW>)>, pub(super) dots: BTreeMap<DI, (Option<(NodeMetadata, DW)>, Option<(NodeMetadata, DW)>)>,
pub(super) segs: BTreeMap<SI, (Option<((DI, DI), SW)>, Option<((DI, DI), SW)>)>, pub(super) segs: BTreeMap<
pub(super) bends: BTreeMap<BI, (Option<((DI, DI, DI), BW)>, Option<((DI, DI, DI), BW)>)>, SI,
pub(super) compounds: (
BTreeMap<GenericIndex<CW>, (Option<(Vec<(Cel, PI)>, CW)>, Option<(Vec<(Cel, PI)>, CW)>)>, 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<CW>,
(
Option<(NodeMetadata, Vec<(Cel, PI)>, CW)>,
Option<(NodeMetadata, Vec<(Cel, PI)>, CW)>,
),
>,
} }
impl< impl<
DW: AccessDotWeight + GetLayer, DW: AccessDotWeight,
SW: AccessSegWeight + GetLayer, SW: AccessSegWeight,
BW: AccessBendWeight + GetLayer, BW: AccessBendWeight,
CW: Clone, CW: Clone,
Cel: Copy, Cel: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy, PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy,

View File

@ -34,8 +34,8 @@ pub trait Retag {
} }
#[enum_dispatch] #[enum_dispatch]
pub trait GetLayer { pub trait GetMetadata {
fn layer(&self) -> usize; fn metadata(&self) -> NodeMetadata;
} }
#[enum_dispatch] #[enum_dispatch]
@ -67,7 +67,7 @@ pub enum GeometryLabel<Cel> {
Compound(Cel), 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<P, C> { pub enum GenericNode<P, C> {
Primitive(P), Primitive(P),
Compound(C), Compound(C),
@ -82,6 +82,47 @@ impl<P: GetPetgraphIndex, C: GetPetgraphIndex> 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<usize>,
}
impl NodeMetadata {
pub fn from_layer_and_net(layer: usize, maybe_net: Option<usize>) -> 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<P, C> {
pub meta: NodeMetadata,
pub kind: GenericNode<P, C>,
}
impl<P, C> GetMetadata for Node<P, C> {
#[inline(always)]
fn metadata(&self) -> NodeMetadata {
self.meta
}
}
pub trait AccessDotWeight: GetSetPos + GetWidth + Copy {} pub trait AccessDotWeight: GetSetPos + GetWidth + Copy {}
impl<T: GetSetPos + GetWidth + Copy> AccessDotWeight for T {} impl<T: GetSetPos + GetWidth + Copy> AccessDotWeight for T {}
@ -93,7 +134,7 @@ impl<T: SetOffset + GetWidth + Copy> AccessBendWeight for T {}
#[derive(Debug)] #[derive(Debug)]
pub struct Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> { pub struct Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> {
graph: StableDiGraph<GenericNode<PW, CW>, GeometryLabel<Cel>, usize>, graph: StableDiGraph<Node<PW, CW>, GeometryLabel<Cel>, usize>,
primitive_weight_marker: PhantomData<PW>, primitive_weight_marker: PhantomData<PW>,
dot_weight_marker: PhantomData<DW>, dot_weight_marker: PhantomData<DW>,
seg_weight_marker: PhantomData<SW>, seg_weight_marker: PhantomData<SW>,
@ -144,16 +185,21 @@ impl<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> Geometry<PW, DW, SW, BW, CW, Cel,
// field that actually contains data... // field that actually contains data...
#[inline(always)] #[inline(always)]
pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel<Cel>, usize> { pub fn graph(&self) -> &StableDiGraph<Node<PW, CW>, GeometryLabel<Cel>, usize> {
&self.graph &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<usize>) -> PW fn primitive_weight(&self, index: NodeIndex<usize>) -> PW
where where
PW: Copy, PW: Copy,
{ {
if let GenericNode::Primitive(weight) = self.graph.node_weight(index).unwrap() { if let GenericNode::Primitive(weight) = self.graph.node_weight(index).unwrap().kind {
*weight weight
} else { } else {
unreachable!() unreachable!()
} }
@ -173,27 +219,43 @@ impl<
BI: GetPetgraphIndex + Into<PI> + Copy, BI: GetPetgraphIndex + Into<PI> + Copy,
> Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> > Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
{ {
pub fn add_dot<W: AccessDotWeight + Into<PW>>(&mut self, weight: W) -> GenericIndex<W> { pub fn add_dot<W: AccessDotWeight + Into<PW>>(
GenericIndex::<W>::new(self.graph.add_node(GenericNode::Primitive(weight.into()))) &mut self,
meta: NodeMetadata,
weight: W,
) -> GenericIndex<W> {
GenericIndex::<W>::new(self.graph.add_node(Node {
meta,
kind: GenericNode::Primitive(weight.into()),
}))
} }
pub(super) fn add_dot_at_index<W: AccessDotWeight + Into<PW>>( pub(super) fn add_dot_at_index<W: AccessDotWeight + Into<PW>>(
&mut self, &mut self,
dot: GenericIndex<W>, dot: GenericIndex<W>,
meta: NodeMetadata,
weight: W, weight: W,
) { ) {
self.graph self.graph.update_node(
.update_node(dot.petgraph_index(), GenericNode::Primitive(weight.into())); dot.petgraph_index(),
Node {
meta,
kind: GenericNode::Primitive(weight.into()),
},
);
} }
pub fn add_seg<W: AccessSegWeight + Into<PW>>( pub fn add_seg<W: AccessSegWeight + Into<PW>>(
&mut self, &mut self,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
weight: W, weight: W,
) -> GenericIndex<W> { ) -> GenericIndex<W> {
let seg = let seg = GenericIndex::<W>::new(self.graph.add_node(Node {
GenericIndex::<W>::new(self.graph.add_node(GenericNode::Primitive(weight.into()))); meta,
kind: GenericNode::Primitive(weight.into()),
}));
self.init_seg_joints(seg, from, to); self.init_seg_joints(seg, from, to);
seg seg
} }
@ -201,12 +263,18 @@ impl<
pub(super) fn add_seg_at_index<W: AccessSegWeight + Into<PW>>( pub(super) fn add_seg_at_index<W: AccessSegWeight + Into<PW>>(
&mut self, &mut self,
seg: GenericIndex<W>, seg: GenericIndex<W>,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
weight: W, weight: W,
) { ) {
self.graph self.graph.update_node(
.update_node(seg.petgraph_index(), GenericNode::Primitive(weight.into())); seg.petgraph_index(),
Node {
meta,
kind: GenericNode::Primitive(weight.into()),
},
);
self.init_seg_joints(seg, from, to); self.init_seg_joints(seg, from, to);
} }
@ -249,13 +317,16 @@ impl<
pub fn add_bend<W: AccessBendWeight + Into<PW>>( pub fn add_bend<W: AccessBendWeight + Into<PW>>(
&mut self, &mut self,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
core: DI, core: DI,
weight: W, weight: W,
) -> GenericIndex<W> { ) -> GenericIndex<W> {
let bend = let bend = GenericIndex::<W>::new(self.graph.add_node(Node {
GenericIndex::<W>::new(self.graph.add_node(GenericNode::Primitive(weight.into()))); meta,
kind: GenericNode::Primitive(weight.into()),
}));
self.init_bend_joints_and_core(bend, from, to, core); self.init_bend_joints_and_core(bend, from, to, core);
bend bend
} }
@ -263,19 +334,35 @@ impl<
pub(super) fn add_bend_at_index<W: AccessBendWeight + Into<PW>>( pub(super) fn add_bend_at_index<W: AccessBendWeight + Into<PW>>(
&mut self, &mut self,
bend: GenericIndex<W>, bend: GenericIndex<W>,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
core: DI, core: DI,
weight: W, weight: W,
) { ) {
self.graph self.graph.update_node(
.update_node(bend.petgraph_index(), GenericNode::Primitive(weight.into())); bend.petgraph_index(),
Node {
meta,
kind: GenericNode::Primitive(weight.into()),
},
);
self.init_bend_joints_and_core(bend, from, to, core); self.init_bend_joints_and_core(bend, from, to, core);
} }
pub(super) fn add_compound_at_index(&mut self, compound: GenericIndex<CW>, weight: CW) { pub(super) fn add_compound_at_index(
self.graph &mut self,
.update_node(compound.petgraph_index(), GenericNode::Compound(weight)); compound: GenericIndex<CW>,
meta: NodeMetadata,
weight: CW,
) {
self.graph.update_node(
compound.petgraph_index(),
Node {
meta,
kind: GenericNode::Compound(weight),
},
);
} }
fn init_bend_joints_and_core<W: AccessBendWeight + Into<PW>>( fn init_bend_joints_and_core<W: AccessBendWeight + Into<PW>>(
@ -309,15 +396,19 @@ impl<
pub fn move_dot(&mut self, dot: DI, to: Point) { pub fn move_dot(&mut self, dot: DI, to: Point) {
let mut weight = self.dot_weight(dot); let mut weight = self.dot_weight(dot);
weight.set_pos(to); weight.set_pos(to);
*self.graph.node_weight_mut(dot.petgraph_index()).unwrap() = self.graph
GenericNode::Primitive(weight.into()); .node_weight_mut(dot.petgraph_index())
.unwrap()
.kind = GenericNode::Primitive(weight.into());
} }
pub fn shift_bend(&mut self, bend: BI, offset: f64) { pub fn shift_bend(&mut self, bend: BI, offset: f64) {
let mut weight = self.bend_weight(bend); let mut weight = self.bend_weight(bend);
weight.set_offset(offset); weight.set_offset(offset);
*self.graph.node_weight_mut(bend.petgraph_index()).unwrap() = self.graph
GenericNode::Primitive(weight.into()); .node_weight_mut(bend.petgraph_index())
.unwrap()
.kind = GenericNode::Primitive(weight.into());
} }
pub fn flip_bend(&mut self, bend: BI) { pub fn flip_bend(&mut self, bend: BI) {
@ -426,16 +517,6 @@ impl<
.unwrap_or_else(|_| unreachable!()) .unwrap_or_else(|_| unreachable!())
} }
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> &CW {
if let GenericNode::Compound(weight) =
self.graph.node_weight(compound.petgraph_index()).unwrap()
{
weight
} else {
unreachable!()
}
}
fn core_weight(&self, bend: BI) -> DW { fn core_weight(&self, bend: BI) -> DW {
self.graph self.graph
.edges_directed(bend.petgraph_index(), Outgoing) .edges_directed(bend.petgraph_index(), Outgoing)
@ -589,8 +670,11 @@ impl<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW: Clone, Cel: Copy, PI: Copy, D
type GeneralIndex = PI; type GeneralIndex = PI;
type EntryLabel = Cel; type EntryLabel = Cel;
fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> { fn add_compound(&mut self, meta: NodeMetadata, weight: CW) -> GenericIndex<CW> {
GenericIndex::<CW>::new(self.graph.add_node(GenericNode::Compound(weight))) GenericIndex::<CW>::new(self.graph.add_node(Node {
meta,
kind: GenericNode::Compound(weight),
}))
} }
fn remove_compound(&mut self, compound: GenericIndex<CW>) { fn remove_compound(&mut self, compound: GenericIndex<CW>) {
@ -609,8 +693,11 @@ impl<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW: Clone, Cel: Copy, PI: Copy, D
} }
fn compound_weight(&self, compound: GenericIndex<CW>) -> &CW { fn compound_weight(&self, compound: GenericIndex<CW>) -> &CW {
if let GenericNode::Compound(weight) = if let GenericNode::Compound(ref weight) = self
self.graph.node_weight(compound.petgraph_index()).unwrap() .graph
.node_weight(compound.petgraph_index())
.unwrap()
.kind
{ {
weight weight
} else { } else {

View File

@ -12,7 +12,7 @@ use rstar::{RTreeObject, AABB};
use crate::{ use crate::{
geometry::{ geometry::{
shape::{AccessShape, MeasureLength}, shape::{AccessShape, MeasureLength},
GetWidth, GetWidth, NodeMetadata,
}, },
math::{self, Circle}, 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); let envelope = self.bbox(margin);
AABB::from_corners( 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()[0],
envelope.upper()[1], 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)] #[enum_dispatch(AccessShape, AccessPrimitiveShape, GetWidth, MeasureLength)]

View File

@ -15,7 +15,7 @@ use super::{
edit::{ApplyGeometryEdit, GeometryEdit}, edit::{ApplyGeometryEdit, GeometryEdit},
with_rtree::{BboxedIndex, GeometryWithRtree}, with_rtree::{BboxedIndex, GeometryWithRtree},
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
GetLayer, GetWidth, Retag, GetWidth, Node, NodeMetadata, Retag,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -48,16 +48,16 @@ impl<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
*self.geometry_with_rtree.layer_count() *self.geometry_with_rtree.layer_count()
} }
pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel<Cel>, usize> { pub fn graph(&self) -> &StableDiGraph<Node<PW, CW>, GeometryLabel<Cel>, usize> {
self.geometry_with_rtree.graph() self.geometry_with_rtree.graph()
} }
} }
impl< impl<
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy, PW: GetWidth + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy,
DW: AccessDotWeight + Into<PW> + GetLayer, DW: AccessDotWeight + Into<PW>,
SW: AccessSegWeight + Into<PW> + GetLayer, SW: AccessSegWeight + Into<PW>,
BW: AccessBendWeight + Into<PW> + GetLayer, BW: AccessBendWeight + Into<PW>,
CW: Clone, CW: Clone,
Cel: Copy, Cel: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy, PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy,
@ -72,30 +72,35 @@ impl<
} }
} }
pub fn add_dot<W: AccessDotWeight + Into<PW> + GetLayer>( pub fn add_dot<W: AccessDotWeight + Into<PW>>(
&mut self, &mut self,
recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>, recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>,
meta: NodeMetadata,
weight: W, weight: W,
) -> GenericIndex<W> ) -> GenericIndex<W>
where where
GenericIndex<W>: Into<PI>, GenericIndex<W>: Into<PI>,
{ {
let dot = self.geometry_with_rtree.add_dot(weight); let dot = self.geometry_with_rtree.add_dot(meta, weight);
recorder.dots.insert( recorder.dots.insert(
Into::<PI>::into(dot) Into::<PI>::into(dot)
.try_into() .try_into()
.unwrap_or_else(|_| unreachable!()), .unwrap_or_else(|_| unreachable!()),
( (
None, None,
Some(weight.into().try_into().unwrap_or_else(|_| unreachable!())), Some((
meta,
weight.into().try_into().unwrap_or_else(|_| unreachable!()),
)),
), ),
); );
dot dot
} }
pub fn add_seg<W: AccessSegWeight + Into<PW> + GetLayer>( pub fn add_seg<W: AccessSegWeight + Into<PW>>(
&mut self, &mut self,
recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>, recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
weight: W, weight: W,
@ -103,7 +108,7 @@ impl<
where where
GenericIndex<W>: Into<PI>, GenericIndex<W>: Into<PI>,
{ {
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( recorder.segs.insert(
Into::<PI>::into(seg) Into::<PI>::into(seg)
.try_into() .try_into()
@ -111,6 +116,7 @@ impl<
( (
None, None,
Some(( Some((
meta,
(from, to), (from, to),
weight.into().try_into().unwrap_or_else(|_| unreachable!()), weight.into().try_into().unwrap_or_else(|_| unreachable!()),
)), )),
@ -119,9 +125,10 @@ impl<
seg seg
} }
pub fn add_bend<W: AccessBendWeight + Into<PW> + GetLayer>( pub fn add_bend<W: AccessBendWeight + Into<PW>>(
&mut self, &mut self,
recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>, recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
core: DI, core: DI,
@ -130,7 +137,9 @@ impl<
where where
GenericIndex<W>: Into<PI>, GenericIndex<W>: Into<PI>,
{ {
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( recorder.bends.insert(
Into::<PI>::into(bend) Into::<PI>::into(bend)
.try_into() .try_into()
@ -138,6 +147,7 @@ impl<
( (
None, None,
Some(( Some((
meta,
(from, to, core), (from, to, core),
weight.into().try_into().unwrap_or_else(|_| unreachable!()), weight.into().try_into().unwrap_or_else(|_| unreachable!()),
)), )),
@ -149,12 +159,13 @@ impl<
pub fn add_compound( pub fn add_compound(
&mut self, &mut self,
recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>, recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>,
meta: NodeMetadata,
weight: CW, weight: CW,
) -> GenericIndex<CW> { ) -> GenericIndex<CW> {
let compound = self.geometry_with_rtree.add_compound(weight.clone()); let compound = self.geometry_with_rtree.add_compound(meta, weight.clone());
recorder recorder
.compounds .compounds
.insert(compound, (None, Some((vec![], weight)))); .insert(compound, (None, Some((meta, vec![], weight))));
compound compound
} }
@ -166,6 +177,7 @@ impl<
compound: GenericIndex<CW>, compound: GenericIndex<CW>,
) { ) {
let geometry = self.geometry_with_rtree.geometry(); let geometry = self.geometry_with_rtree.geometry();
let meta = geometry.metadata(compound);
let old_members = geometry.compound_members(compound).collect(); let old_members = geometry.compound_members(compound).collect();
let old_weight = geometry.compound_weight(compound).clone(); let old_weight = geometry.compound_weight(compound).clone();
@ -179,8 +191,8 @@ impl<
recorder recorder
.compounds .compounds
.entry(compound) .entry(compound)
.or_insert((Some((old_members, old_weight)), None)) .or_insert((Some((meta, old_members, old_weight)), None))
.1 = Some((new_members, new_weight)); .1 = Some((meta, new_members, new_weight));
} }
pub fn remove_dot( pub fn remove_dot(
@ -188,9 +200,11 @@ impl<
recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>, recorder: &mut GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI>,
dot: DI, dot: DI,
) -> Result<(), ()> { ) -> 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)?; 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(()) Ok(())
} }
@ -200,10 +214,11 @@ impl<
seg: SI, seg: SI,
) { ) {
let geometry = self.geometry_with_rtree.geometry(); let geometry = self.geometry_with_rtree.geometry();
let meta = geometry.metadata(seg);
let weight = geometry.seg_weight(seg); let weight = geometry.seg_weight(seg);
let joints = geometry.seg_joints(seg); let joints = geometry.seg_joints(seg);
self.geometry_with_rtree.remove_seg(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( pub fn remove_bend(
@ -212,6 +227,7 @@ impl<
bend: BI, bend: BI,
) { ) {
let geometry = self.geometry_with_rtree.geometry(); let geometry = self.geometry_with_rtree.geometry();
let meta = geometry.metadata(bend);
let weight = geometry.bend_weight(bend); let weight = geometry.bend_weight(bend);
let joints = geometry.bend_joints(bend); let joints = geometry.bend_joints(bend);
let core = geometry.core(bend); let core = geometry.core(bend);
@ -219,7 +235,7 @@ impl<
edit_remove_from_map( edit_remove_from_map(
&mut recorder.bends, &mut recorder.bends,
bend, bend,
((joints.0, joints.1, core), weight), (meta, (joints.0, joints.1, core), weight),
); );
} }
@ -229,10 +245,11 @@ impl<
compound: GenericIndex<CW>, compound: GenericIndex<CW>,
) { ) {
let geometry = self.geometry_with_rtree.geometry(); let geometry = self.geometry_with_rtree.geometry();
let meta = geometry.metadata(compound);
let weight = geometry.compound_weight(compound).clone(); let weight = geometry.compound_weight(compound).clone();
let members = geometry.compound_members(compound).collect(); let members = geometry.compound_members(compound).collect();
self.geometry_with_rtree.remove_compound(compound); 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( pub fn move_dot(
@ -241,6 +258,7 @@ impl<
dot: DI, dot: DI,
to: Point, to: Point,
) { ) {
let meta = self.geometry_with_rtree.geometry().metadata(dot);
let old_weight = self.geometry_with_rtree.geometry().dot_weight(dot); let old_weight = self.geometry_with_rtree.geometry().dot_weight(dot);
self.geometry_with_rtree.move_dot(dot, to); self.geometry_with_rtree.move_dot(dot, to);
let new_weight = self.geometry_with_rtree.geometry().dot_weight(dot); let new_weight = self.geometry_with_rtree.geometry().dot_weight(dot);
@ -248,8 +266,8 @@ impl<
recorder recorder
.dots .dots
.entry(dot) .entry(dot)
.or_insert((Some(old_weight), None)) .or_insert((Some((meta, old_weight)), None))
.1 = Some(new_weight); .1 = Some((meta, new_weight));
} }
fn modify_bend<F>( fn modify_bend<F>(
@ -261,6 +279,7 @@ impl<
F: FnOnce(&mut GeometryWithRtree<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>, BI), F: FnOnce(&mut GeometryWithRtree<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>, BI),
{ {
let geometry = self.geometry_with_rtree.geometry(); let geometry = self.geometry_with_rtree.geometry();
let meta = geometry.metadata(bend);
let old_joints = geometry.bend_joints(bend); let old_joints = geometry.bend_joints(bend);
let old_core = geometry.core(bend); let old_core = geometry.core(bend);
let old_weight = geometry.bend_weight(bend); let old_weight = geometry.bend_weight(bend);
@ -276,10 +295,10 @@ impl<
.bends .bends
.entry(bend) .entry(bend)
.or_insert(( .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, 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( pub fn shift_bend(
@ -347,10 +366,10 @@ fn edit_remove_from_map<I: Eq + Ord, T>(
} }
impl< impl<
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy, PW: GetWidth + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy,
DW: AccessDotWeight + Into<PW> + GetLayer, DW: AccessDotWeight + Into<PW>,
SW: AccessSegWeight + Into<PW> + GetLayer, SW: AccessSegWeight + Into<PW>,
BW: AccessBendWeight + Into<PW> + GetLayer, BW: AccessBendWeight + Into<PW>,
CW: Clone, CW: Clone,
Cel: Copy, Cel: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy, PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Ord + Copy,
@ -386,29 +405,30 @@ impl<
} }
for (dot, (.., maybe_new_data)) in &edit.dots { for (dot, (.., maybe_new_data)) in &edit.dots {
if let Some(weight) = maybe_new_data { if let Some((meta, weight)) = maybe_new_data {
self.geometry_with_rtree.add_dot_at_index(*dot, *weight); self.geometry_with_rtree
.add_dot_at_index(*dot, *meta, *weight);
} }
} }
for (seg, (.., maybe_new_data)) in &edit.segs { 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 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 { 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 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 { 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 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 { for (entry_label, member) in members {
self.geometry_with_rtree.add_to_compound( self.geometry_with_rtree.add_to_compound(

View File

@ -13,7 +13,7 @@ use crate::{
compound::ManageCompounds, compound::ManageCompounds,
primitive::{AccessPrimitiveShape, PrimitiveShape}, primitive::{AccessPrimitiveShape, PrimitiveShape},
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
GetLayer, GetWidth, Retag, GetWidth, Node, NodeMetadata, Retag,
}, },
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
}; };
@ -60,7 +60,7 @@ impl<PW: Clone, DW, SW, BW, CW: Clone, Cel: Clone, PI: Clone, DI, SI, BI> Clone
impl<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> impl<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
GeometryWithRtree<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> GeometryWithRtree<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
{ {
pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel<Cel>, usize> { pub fn graph(&self) -> &StableDiGraph<Node<PW, CW>, GeometryLabel<Cel>, usize> {
self.geometry.graph() self.geometry.graph()
} }
} }
@ -68,10 +68,10 @@ impl<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
#[debug_invariant(self.test_envelopes())] #[debug_invariant(self.test_envelopes())]
#[debug_invariant(self.geometry.graph().node_count() == self.rtree.size())] #[debug_invariant(self.geometry.graph().node_count() == self.rtree.size())]
impl< impl<
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy, PW: GetWidth + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy,
DW: AccessDotWeight + Into<PW> + GetLayer, DW: AccessDotWeight + Into<PW>,
SW: AccessSegWeight + Into<PW> + GetLayer, SW: AccessSegWeight + Into<PW>,
BW: AccessBendWeight + Into<PW> + GetLayer, BW: AccessBendWeight + Into<PW>,
CW: Clone, CW: Clone,
Cel: Copy, Cel: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + PartialEq + Copy, PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + PartialEq + Copy,
@ -88,30 +88,33 @@ impl<
} }
} }
pub fn add_dot<W: AccessDotWeight + Into<PW> + GetLayer>( pub fn add_dot<W: AccessDotWeight + Into<PW>>(
&mut self, &mut self,
meta: NodeMetadata,
weight: W, weight: W,
) -> GenericIndex<W> ) -> GenericIndex<W>
where where
GenericIndex<W>: Into<PI>, GenericIndex<W>: Into<PI>,
{ {
let dot = self.geometry.add_dot(weight); let dot = self.geometry.add_dot(meta, weight);
self.init_dot_bbox(dot.into().try_into().unwrap_or_else(|_| unreachable!())); self.init_bbox(dot);
dot dot
} }
pub(super) fn add_dot_at_index<W: AccessDotWeight + Into<PW> + GetLayer>( pub(super) fn add_dot_at_index<W: AccessDotWeight + Into<PW>>(
&mut self, &mut self,
dot: DI, dot: DI,
meta: NodeMetadata,
weight: W, weight: W,
) { ) {
self.geometry self.geometry
.add_dot_at_index(GenericIndex::<W>::new(dot.petgraph_index()), weight); .add_dot_at_index(GenericIndex::<W>::new(dot.petgraph_index()), meta, weight);
self.init_dot_bbox(dot); self.init_bbox(dot);
} }
pub fn add_seg<W: AccessSegWeight + Into<PW> + GetLayer>( pub fn add_seg<W: AccessSegWeight + Into<PW>>(
&mut self, &mut self,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
weight: W, weight: W,
@ -119,29 +122,32 @@ impl<
where where
GenericIndex<W>: Into<PI>, GenericIndex<W>: Into<PI>,
{ {
let seg = self.geometry.add_seg(from, to, weight); let seg = self.geometry.add_seg(meta, from, to, weight);
self.init_seg_bbox(seg.into().try_into().unwrap_or_else(|_| unreachable!())); self.init_bbox(seg);
seg seg
} }
pub(super) fn add_seg_at_index<W: AccessSegWeight + Into<PW> + GetLayer>( pub(super) fn add_seg_at_index<W: AccessSegWeight + Into<PW>>(
&mut self, &mut self,
seg: SI, seg: SI,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
weight: W, weight: W,
) { ) {
self.geometry.add_seg_at_index( self.geometry.add_seg_at_index(
GenericIndex::<W>::new(seg.petgraph_index()), GenericIndex::<W>::new(seg.petgraph_index()),
meta,
from, from,
to, to,
weight, weight,
); );
self.init_seg_bbox(seg); self.init_bbox(seg);
} }
pub fn add_bend<W: AccessBendWeight + Into<PW> + GetLayer>( pub fn add_bend<W: AccessBendWeight + Into<PW>>(
&mut self, &mut self,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
core: DI, core: DI,
@ -150,14 +156,15 @@ impl<
where where
GenericIndex<W>: Into<PI>, GenericIndex<W>: Into<PI>,
{ {
let bend = self.geometry.add_bend(from, to, core, weight); let bend = self.geometry.add_bend(meta, from, to, core, weight);
self.init_bend_bbox(bend.into().try_into().unwrap_or_else(|_| unreachable!())); self.init_bbox(bend);
bend bend
} }
pub(super) fn add_bend_at_index<W: AccessBendWeight + Into<PW> + GetLayer>( pub(super) fn add_bend_at_index<W: AccessBendWeight + Into<PW>>(
&mut self, &mut self,
bend: BI, bend: BI,
meta: NodeMetadata,
from: DI, from: DI,
to: DI, to: DI,
core: DI, core: DI,
@ -165,17 +172,26 @@ impl<
) { ) {
self.geometry.add_bend_at_index( self.geometry.add_bend_at_index(
GenericIndex::<W>::new(bend.petgraph_index()), GenericIndex::<W>::new(bend.petgraph_index()),
meta,
from, from,
to, to,
core, core,
weight, weight,
); );
self.init_bend_bbox(bend); self.init_bbox(bend);
} }
pub(super) fn add_compound_at_index(&mut self, compound: GenericIndex<CW>, weight: CW) { pub(super) fn add_compound_at_index(
self.geometry &mut self,
.add_compound_at_index(GenericIndex::<CW>::new(compound.petgraph_index()), weight); compound: GenericIndex<CW>,
meta: NodeMetadata,
weight: CW,
) {
self.geometry.add_compound_at_index(
GenericIndex::<CW>::new(compound.petgraph_index()),
meta,
weight,
);
} }
pub fn add_to_compound<W>( pub fn add_to_compound<W>(
@ -199,18 +215,18 @@ impl<
return Err(()); return Err(());
} }
self.rtree.remove(&self.make_dot_bbox(dot)); self.rtree.remove(&self.make_bbox(dot.into()));
self.geometry.remove_primitive(dot.into()); self.geometry.remove_primitive(dot.into());
Ok(()) Ok(())
} }
pub fn remove_seg(&mut self, seg: SI) { 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()); self.geometry.remove_primitive(seg.into());
} }
pub fn remove_bend(&mut self, bend: BI) { 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()); self.geometry.remove_primitive(bend.into());
} }
@ -221,23 +237,23 @@ impl<
pub fn move_dot(&mut self, dot: DI, to: Point) { pub fn move_dot(&mut self, dot: DI, to: Point) {
for seg in self.geometry.joined_segs(dot) { 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) { 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.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) { 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) { 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; let mut rail = bend;
while let Some(outer) = self.geometry.outer(rail) { 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; 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.geometry.shift_bend(bend, offset);
self.rtree.insert(self.make_bend_bbox(bend)); self.rtree.insert(self.make_bbox(bend.into()));
rail = bend; rail = bend;
while let Some(outer) = self.geometry.outer(rail) { 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; rail = outer;
} }
} }
@ -270,28 +286,28 @@ impl<
let mut rail = bend; let mut rail = bend;
while let Some(outer) = self.geometry.outer(rail) { 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; 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.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; rail = bend;
while let Some(outer) = self.geometry.outer(rail) { 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; rail = outer;
} }
} }
} }
impl< impl<
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy, PW: GetWidth + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy,
DW: AccessDotWeight + Into<PW> + GetLayer, DW: AccessDotWeight + Into<PW>,
SW: AccessSegWeight + Into<PW> + GetLayer, SW: AccessSegWeight + Into<PW>,
BW: AccessBendWeight + Into<PW> + GetLayer, BW: AccessBendWeight + Into<PW>,
CW: Clone, CW: Clone,
Cel: Copy, Cel: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + PartialEq + Copy, PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + PartialEq + Copy,
@ -300,60 +316,17 @@ impl<
BI: GetPetgraphIndex + Into<PI> + Copy, BI: GetPetgraphIndex + Into<PI> + Copy,
> GeometryWithRtree<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> > GeometryWithRtree<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
{ {
fn init_dot_bbox(&mut self, dot: DI) { fn init_bbox(&mut self, primitive: impl Into<PI>) {
self.rtree.insert(self.make_dot_bbox(dot)); self.rtree.insert(self.make_bbox(primitive.into()));
}
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 make_bbox(&self, primitive: PI) -> BboxedIndex<GenericNode<PI, GenericIndex<CW>>> { fn make_bbox(&self, primitive: PI) -> BboxedIndex<GenericNode<PI, GenericIndex<CW>>> {
if let Ok(dot) = <PI as TryInto<DI>>::try_into(primitive) {
self.make_dot_bbox(dot)
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(primitive) {
self.make_seg_bbox(seg)
} else if let Ok(bend) = <PI as TryInto<BI>>::try_into(primitive) {
self.make_bend_bbox(bend)
} else {
unreachable!();
}
}
fn make_dot_bbox(&self, dot: DI) -> BboxedIndex<GenericNode<PI, GenericIndex<CW>>> {
BboxedIndex::new( BboxedIndex::new(
Bbox::new( Bbox::new(
self.geometry self.shape(primitive)
.dot_shape(dot) .envelope_3d_from_meta(0.0, self.metadata(primitive)),
.envelope_3d(0.0, self.layer(dot.into())),
), ),
GenericNode::Primitive(dot.into()), GenericNode::Primitive(primitive),
)
}
fn make_seg_bbox(&self, seg: SI) -> BboxedIndex<GenericNode<PI, GenericIndex<CW>>> {
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<GenericNode<PI, GenericIndex<CW>>> {
BboxedIndex::new(
Bbox::new(
self.geometry
.bend_shape(bend)
.envelope_3d(0.0, self.layer(bend.into())),
),
GenericNode::Primitive(bend.into()),
) )
} }
@ -384,16 +357,8 @@ impl<
} }
} }
fn layer(&self, primitive: PI) -> usize { pub fn metadata(&self, node: impl GetPetgraphIndex) -> NodeMetadata {
if let Ok(dot) = <PI as TryInto<DI>>::try_into(primitive) { self.geometry.metadata(node)
self.geometry.dot_weight(dot).layer()
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(primitive) {
self.geometry.seg_weight(seg).layer()
} else if let Ok(bend) = <PI as TryInto<BI>>::try_into(primitive) {
self.geometry.bend_weight(bend).layer()
} else {
unreachable!();
}
} }
fn test_envelopes(&self) -> bool { fn test_envelopes(&self) -> bool {
@ -403,24 +368,24 @@ impl<
return false; return false;
}; };
let shape = self.shape(primitive_node); let shape = self.shape(primitive_node);
let layer = self.layer(primitive_node); let metadata = self.metadata(primitive_node);
let wrapper = BboxedIndex::new( 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), GenericNode::Primitive(primitive_node),
); );
!self !self
.rtree .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) .any(|w| *w == wrapper)
}) })
} }
} }
impl< impl<
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy, PW: GetWidth + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<Index = PI> + Copy,
DW: AccessDotWeight + Into<PW> + GetLayer, DW: AccessDotWeight + Into<PW>,
SW: AccessSegWeight + Into<PW> + GetLayer, SW: AccessSegWeight + Into<PW>,
BW: AccessBendWeight + Into<PW> + GetLayer, BW: AccessBendWeight + Into<PW>,
CW: Clone, CW: Clone,
Cel: Copy, Cel: Copy,
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + PartialEq + Copy, PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + PartialEq + Copy,
@ -432,8 +397,8 @@ impl<
type GeneralIndex = PI; type GeneralIndex = PI;
type EntryLabel = Cel; type EntryLabel = Cel;
fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> { fn add_compound(&mut self, meta: NodeMetadata, weight: CW) -> GenericIndex<CW> {
let compound = self.geometry.add_compound(weight); let compound = self.geometry.add_compound(meta, weight);
self.rtree.insert(self.make_compound_bbox(compound)); self.rtree.insert(self.make_compound_bbox(compound));
compound compound
} }

View File

@ -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<PrimitiveIndex, GenericIndex<CompoundWeight>>;
pub type LayoutEdit = DrawingEdit<CompoundWeight, CompoundEntryLabel>;
#[derive(Clone, Debug, Getters)]
/// Structure for managing the Layout design
pub struct Layout<R> {
pub(super) drawing: Drawing<CompoundWeight, CompoundEntryLabel, R>,
}
impl<R> Layout<R> {
pub fn new(drawing: Drawing<CompoundWeight, CompoundEntryLabel, R>) -> Self {
Self { drawing }
}
}
impl<R: AccessRules> Layout<R> {
/// 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<Cane, DrawingException> {
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<GenericIndex<ViaWeight>, 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::<ViaWeight>::new(compound.petgraph_index()))
}
pub fn add_fixed_dot(
&mut self,
recorder: &mut LayoutEdit,
weight: FixedDotWeight,
) -> Result<FixedDotIndex, Infringement> {
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<FixedSegIndex, DrawingException> {
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<LoneLooseSegIndex, DrawingException> {
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<SeqLooseSegIndex, DrawingException> {
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<PolyWeight> {
GenericIndex::<PolyWeight>::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<PolyWeight>, 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<Item = GenericIndex<PolyWeight>> + '_ {
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::<PolyWeight>::new(compound.petgraph_index()));
}
}
None
})
}
pub fn layer_poly_nodes(
&self,
layer: usize,
) -> impl Iterator<Item = GenericIndex<PolyWeight>> + '_ {
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::<PolyWeight>::new(compound.petgraph_index()));
}
}
None
})
}
pub fn poly_members(
&self,
poly: GenericIndex<PolyWeight>,
) -> impl Iterator<Item = (CompoundEntryLabel, PrimitiveIndex)> + '_ {
self.drawing
.geometry()
.compound_members(GenericIndex::new(poly.petgraph_index()))
}
fn compound_shape(&self, compound: GenericIndex<CompoundWeight>) -> Shape {
match self.drawing.compound_weight(compound) {
CompoundWeight::Poly(_) => GenericIndex::<PolyWeight>::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<R: AccessRules>(
drawing: &Drawing<CompoundWeight, CompoundEntryLabel, R>,
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::<PolyWeight>::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<ViaWeight>) -> Via<R> {
Via::new(index, self.drawing())
}
}
impl<R: AccessRules>
ApplyGeometryEdit<
DotWeight,
SegWeight,
BendWeight,
CompoundWeight,
CompoundEntryLabel,
PrimitiveIndex,
DotIndex,
SegIndex,
BendIndex,
> for Layout<R>
{
fn apply(&mut self, edit: &LayoutEdit) {
self.drawing.apply(edit);
}
}

View File

@ -1,12 +1,345 @@
// SPDX-FileCopyrightText: 2024 Topola contributors // SPDX-FileCopyrightText: 2024 Topola contributors
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
//! Layout module for handling board geometry. //! Layout module for handling board geometry.
mod collect_bands; mod collect_bands;
mod layout;
pub mod poly; 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<PrimitiveIndex, GenericIndex<CompoundWeight>>;
pub type LayoutEdit = DrawingEdit<CompoundWeight, CompoundEntryLabel>;
#[derive(Clone, Debug, Getters)]
/// Structure for managing the Layout design
pub struct Layout<R> {
pub(super) drawing: Drawing<CompoundWeight, CompoundEntryLabel, R>,
}
impl<R> Layout<R> {
pub fn new(drawing: Drawing<CompoundWeight, CompoundEntryLabel, R>) -> Self {
Self { drawing }
}
}
impl<R: AccessRules> Layout<R> {
/// 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<Cane, DrawingException> {
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<FixedDotIndex, Infringement> {
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<FixedSegIndex, DrawingException> {
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<LoneLooseSegIndex, DrawingException> {
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<SeqLooseSegIndex, DrawingException> {
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<PolyWeight> {
GenericIndex::<PolyWeight>::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<PolyWeight>, 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<Item = GenericIndex<PolyWeight>> + '_ {
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::<PolyWeight>::new(compound.petgraph_index()));
}
None
})
}
pub fn layer_poly_nodes(
&self,
layer: usize,
) -> impl Iterator<Item = GenericIndex<PolyWeight>> + '_ {
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::<PolyWeight>::new(compound.petgraph_index()));
}
None
})
}
pub fn poly_members(
&self,
poly: GenericIndex<PolyWeight>,
) -> impl Iterator<Item = (CompoundEntryLabel, PrimitiveIndex)> + '_ {
self.drawing
.geometry()
.compound_members(GenericIndex::new(poly.petgraph_index()))
}
fn compound_shape(&self, compound: GenericIndex<CompoundWeight>) -> Shape {
match self.drawing.compound_weight(compound) {
CompoundWeight::Poly(_) => GenericIndex::<PolyWeight>::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<R: AccessRules>(
drawing: &Drawing<CompoundWeight, CompoundEntryLabel, R>,
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::<PolyWeight>::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<R: AccessRules>
ApplyGeometryEdit<
DotWeight,
SegWeight,
BendWeight,
CompoundWeight,
CompoundEntryLabel,
PrimitiveIndex,
DotIndex,
SegIndex,
BendIndex,
> for Layout<R>
{
fn apply(&mut self, edit: &LayoutEdit) {
self.drawing.apply(edit);
}
}

View File

@ -14,13 +14,13 @@ use geo::{
use crate::{ use crate::{
drawing::{ drawing::{
dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight}, dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight},
graph::{GetMaybeNet, PrimitiveIndex}, graph::PrimitiveIndex,
primitive::GetLimbs, primitive::GetLimbs,
rules::AccessRules, rules::AccessRules,
seg::SegIndex, seg::SegIndex,
Drawing, Drawing,
}, },
geometry::{compound::ManageCompounds, GetLayer, GetSetPos}, geometry::{compound::ManageCompounds, GetMetadata, GetSetPos, NodeMetadata},
graph::{GenericIndex, GetPetgraphIndex, MakeRef}, graph::{GenericIndex, GetPetgraphIndex, MakeRef},
layout::{CompoundEntryLabel, CompoundWeight, Layout, LayoutEdit}, layout::{CompoundEntryLabel, CompoundWeight, Layout, LayoutEdit},
math::Circle, math::Circle,
@ -49,8 +49,7 @@ pub(super) fn add_poly_with_nodes_intern<R: AccessRules>(
recorder: &mut LayoutEdit, recorder: &mut LayoutEdit,
poly: GenericIndex<PolyWeight>, poly: GenericIndex<PolyWeight>,
nodes: &[PrimitiveIndex], nodes: &[PrimitiveIndex],
layer: usize, meta: NodeMetadata,
maybe_net: Option<usize>,
) -> FixedDotIndex { ) -> FixedDotIndex {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Rto { struct Rto {
@ -99,13 +98,12 @@ pub(super) fn add_poly_with_nodes_intern<R: AccessRules>(
let apex = layout.add_fixed_dot_infringably( let apex = layout.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: shape.centroid().unwrap(), pos: shape.centroid().unwrap(),
r: 100.0, r: 100.0,
}, },
layer,
maybe_net,
}), }),
); );
@ -180,19 +178,9 @@ impl<'a, R> PolyRef<'a, R> {
} }
} }
impl<R> GetLayer for PolyRef<'_, R> { impl<R> GetMetadata for PolyRef<'_, R> {
fn layer(&self) -> usize { fn metadata(&self) -> NodeMetadata {
if let CompoundWeight::Poly(weight) = self.drawing.compound_weight(self.index.into()) { self.drawing.geometry().metadata(self.index)
weight.layer()
} else {
unreachable!();
}
}
}
impl<R> GetMaybeNet for PolyRef<'_, R> {
fn maybe_net(&self) -> Option<usize> {
self.drawing.compound_weight(self.index.into()).maybe_net()
} }
} }
@ -221,11 +209,10 @@ impl<R> MakePolygon for PolyRef<'_, R> {
} }
} }
#[enum_dispatch(GetLayer, GetMaybeNet)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum PolyWeight { pub enum PolyWeight {
Solid(SolidPolyWeight), Solid,
Pour(PourPolyWeight), Pour,
} }
impl From<GenericIndex<PolyWeight>> for GenericIndex<CompoundWeight> { impl From<GenericIndex<PolyWeight>> for GenericIndex<CompoundWeight> {
@ -233,51 +220,3 @@ impl From<GenericIndex<PolyWeight>> for GenericIndex<CompoundWeight> {
GenericIndex::<CompoundWeight>::new(poly.petgraph_index()) GenericIndex::<CompoundWeight>::new(poly.petgraph_index())
} }
} }
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SolidPolyWeight {
pub layer: usize,
pub maybe_net: Option<usize>,
}
impl GetLayer for SolidPolyWeight {
fn layer(&self) -> usize {
self.layer
}
}
impl GetMaybeNet for SolidPolyWeight {
fn maybe_net(&self) -> Option<usize> {
self.maybe_net
}
}
impl From<GenericIndex<SolidPolyWeight>> for GenericIndex<CompoundWeight> {
fn from(poly: GenericIndex<SolidPolyWeight>) -> Self {
GenericIndex::<CompoundWeight>::new(poly.petgraph_index())
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PourPolyWeight {
pub layer: usize,
pub maybe_net: Option<usize>,
}
impl GetLayer for PourPolyWeight {
fn layer(&self) -> usize {
self.layer
}
}
impl GetMaybeNet for PourPolyWeight {
fn maybe_net(&self) -> Option<usize> {
self.maybe_net
}
}
impl From<GenericIndex<PourPolyWeight>> for GenericIndex<CompoundWeight> {
fn from(poly: GenericIndex<PourPolyWeight>) -> Self {
GenericIndex::<CompoundWeight>::new(poly.petgraph_index())
}
}

View File

@ -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<ViaWeight>,
drawing: &'a Drawing<CompoundWeight, CompoundEntryLabel, R>,
}
impl<'a, R> Via<'a, R> {
pub fn new(
index: GenericIndex<ViaWeight>,
drawing: &'a Drawing<CompoundWeight, CompoundEntryLabel, R>,
) -> Self {
Self { index, drawing }
}
}
impl<R: AccessRules> GetMaybeNet for Via<'_, R> {
fn maybe_net(&self) -> Option<usize> {
self.drawing.compound_weight(self.index.into()).maybe_net()
}
}
impl<R: AccessRules> 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<usize>,
}
impl From<GenericIndex<ViaWeight>> for GenericIndex<CompoundWeight> {
fn from(via: GenericIndex<ViaWeight>) -> Self {
GenericIndex::<CompoundWeight>::new(via.petgraph_index())
}
}
impl GetMaybeNet for ViaWeight {
fn maybe_net(&self) -> Option<usize> {
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()
}
}

View File

@ -14,14 +14,14 @@ use crate::{
bend::{BendIndex, GeneralBendWeight, LooseBendWeight}, bend::{BendIndex, GeneralBendWeight, LooseBendWeight},
dot::{DotIndex, FixedDotIndex, GeneralDotWeight, LooseDotIndex, LooseDotWeight}, dot::{DotIndex, FixedDotIndex, GeneralDotWeight, LooseDotIndex, LooseDotWeight},
gear::GearIndex, gear::GearIndex,
graph::{GetMaybeNet, MakePrimitive}, graph::MakePrimitive,
head::{CaneHead, GetFace, Head}, head::{CaneHead, GetFace, Head},
primitive::GetOtherJoint, primitive::GetOtherJoint,
rules::AccessRules, rules::AccessRules,
seg::{GeneralSegWeight, LoneLooseSegWeight, SeqLooseSegWeight}, seg::{GeneralSegWeight, LoneLooseSegWeight, SeqLooseSegWeight},
DrawingException, Guide, Infringement, DrawingException, Guide, Infringement,
}, },
geometry::{GetLayer, GetSetPos}, geometry::{GetMetadata, GetSetPos},
layout::{Layout, LayoutEdit}, layout::{Layout, LayoutEdit},
math::{Circle, NoTangents, RotationSense}, math::{Circle, NoTangents, RotationSense},
}; };
@ -87,11 +87,7 @@ impl<R: AccessRules> Draw for Layout<R> {
.drawing() .drawing()
.head_into_dot_segment(&head, into, width) .head_into_dot_segment(&head, into, width)
.map_err(Into::<DrawException>::into)?; .map_err(Into::<DrawException>::into)?;
let meta = head.face().primitive(self.drawing()).metadata();
let (layer, maybe_net) = {
let face = head.face().primitive(self.drawing());
(face.layer(), face.maybe_net())
};
self.extend_head( self.extend_head(
recorder, recorder,
@ -101,25 +97,19 @@ impl<R: AccessRules> Draw for Layout<R> {
DotIndex::Fixed(dot) => this DotIndex::Fixed(dot) => this
.add_lone_loose_seg( .add_lone_loose_seg(
recorder, recorder,
meta,
dot, dot,
into, into,
LoneLooseSegWeight(GeneralSegWeight { LoneLooseSegWeight(GeneralSegWeight { width }),
width,
layer,
maybe_net,
}),
) )
.map(BandTermsegIndex::Lone), .map(BandTermsegIndex::Lone),
DotIndex::Loose(dot) => this DotIndex::Loose(dot) => this
.add_seq_loose_seg( .add_seq_loose_seg(
recorder, recorder,
meta,
into.into(), into.into(),
dot, dot,
SeqLooseSegWeight(GeneralSegWeight { SeqLooseSegWeight(GeneralSegWeight { width }),
width,
layer,
maybe_net,
}),
) )
.map(BandTermsegIndex::Seq), .map(BandTermsegIndex::Seq),
}, },
@ -284,10 +274,10 @@ impl<R: AccessRules> DrawPrivate for Layout<R> {
width: f64, width: f64,
offset: f64, offset: f64,
) -> Result<CaneHead, DrawingException> { ) -> Result<CaneHead, DrawingException> {
let layer = head.face().primitive(self.drawing()).layer(); let meta = head.face().primitive(self.drawing()).metadata();
let maybe_net = head.face().primitive(self.drawing()).maybe_net();
let cane = self.insert_cane( let cane = self.insert_cane(
recorder, recorder,
meta,
head.face(), head.face(),
around, around,
LooseDotWeight(GeneralDotWeight { LooseDotWeight(GeneralDotWeight {
@ -295,20 +285,9 @@ impl<R: AccessRules> DrawPrivate for Layout<R> {
pos: to, pos: to,
r: width / 2.0, 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, sense,
)?; )?;
Ok(CaneHead { Ok(CaneHead {

View File

@ -24,11 +24,11 @@ use crate::{
dot::FixedDotIndex, dot::FixedDotIndex,
gear::{GearIndex, GetNextGear}, gear::{GearIndex, GetNextGear},
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex}, graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex},
primitive::Primitive, primitive::{MakePrimitiveShape, Primitive},
rules::AccessRules, rules::AccessRules,
Drawing, Drawing,
}, },
geometry::GetLayer, geometry::shape::AccessShape,
graph::{GetPetgraphIndex, MakeRef}, graph::{GetPetgraphIndex, MakeRef},
layout::Layout, layout::Layout,
math::RotationSense, math::RotationSense,
@ -116,6 +116,12 @@ pub struct NavnodeWeight {
pub enum NavmeshError { pub enum NavmeshError {
#[error("failed to insert vertex in navmesh")] #[error("failed to insert vertex in navmesh")]
Insertion(#[from] InsertionError), Insertion(#[from] InsertionError),
#[error("a selected pin is not in layer")]
NotInLayer(usize),
#[error("pins are in different networks")]
DifferentNetworks(Option<usize>, Option<usize>),
} }
/// The navmesh holds the entire Topola's search space represented as a graph. /// The navmesh holds the entire Topola's search space represented as a graph.
@ -147,9 +153,10 @@ impl Navmesh {
layout: &Layout<impl AccessRules>, layout: &Layout<impl AccessRules>,
origin: FixedDotIndex, origin: FixedDotIndex,
destination: FixedDotIndex, destination: FixedDotIndex,
layer: usize,
options: RouterOptions, options: RouterOptions,
) -> Result<Self, NavmeshError> { ) -> Result<Self, NavmeshError> {
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) Self::new_from_prenavmesh(layout, prenavmesh, origin, destination, options)
} }

View File

@ -131,6 +131,7 @@ impl Prenavmesh {
layout: &Layout<impl AccessRules>, layout: &Layout<impl AccessRules>,
origin: FixedDotIndex, origin: FixedDotIndex,
destination: FixedDotIndex, destination: FixedDotIndex,
layer: usize,
_options: RouterOptions, _options: RouterOptions,
) -> Result<Self, NavmeshError> { ) -> Result<Self, NavmeshError> {
let mut this = Self { let mut this = Self {
@ -138,13 +139,26 @@ impl Prenavmesh {
constraints: vec![], constraints: vec![],
}; };
let layer = layout.drawing().primitive(origin).layer(); let meta_origin = layout.drawing().geometry().metadata(origin);
let maybe_net = layout.drawing().primitive(origin).maybe_net(); 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) { for node in layout.drawing().layer_primitive_nodes(layer) {
let primitive = node.primitive(layout.drawing()); 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() if node == origin.into()
|| node == destination.into() || node == destination.into()
|| Some(primitive_net) != maybe_net || Some(primitive_net) != maybe_net
@ -176,8 +190,9 @@ impl Prenavmesh {
for node in layout.drawing().layer_primitive_nodes(layer) { for node in layout.drawing().layer_primitive_nodes(layer) {
let primitive = node.primitive(layout.drawing()); 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() if node == origin.into()
|| node == destination.into() || node == destination.into()
|| Some(primitive_net) != maybe_net || Some(primitive_net) != maybe_net

View File

@ -36,9 +36,10 @@ impl RouteStepper {
recorder: LayoutEdit, recorder: LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
layer: usize,
width: f64, width: f64,
) -> Result<Self, NavmeshError> { ) -> Result<Self, NavmeshError> {
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)) Ok(Self::new_from_navmesh(router, recorder, navmesh, width))
} }

View File

@ -152,9 +152,10 @@ impl<'a, R: AccessRules> Router<'a, R> {
recorder: LayoutEdit, recorder: LayoutEdit,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
layer: usize,
width: f64, width: f64,
) -> Result<RouteStepper, NavmeshError> { ) -> Result<RouteStepper, NavmeshError> {
RouteStepper::new(self, recorder, from, to, width) RouteStepper::new(self, recorder, from, to, layer, width)
} }
pub fn layout_mut(&mut self) -> &mut Layout<R> { pub fn layout_mut(&mut self) -> &mut Layout<R> {

View File

@ -14,13 +14,13 @@ use crate::{
board::{AccessMesadata, Board}, board::{AccessMesadata, Board},
drawing::{ drawing::{
dot::{FixedDotWeight, GeneralDotWeight}, dot::{FixedDotWeight, GeneralDotWeight},
graph::{GetMaybeNet, MakePrimitive}, graph::MakePrimitive,
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
seg::{FixedSegWeight, GeneralSegWeight}, seg::{FixedSegWeight, GeneralSegWeight},
Drawing, Drawing,
}, },
geometry::{primitive::PrimitiveShape, GetLayer, GetWidth}, geometry::{primitive::PrimitiveShape, GetMetadata, GetWidth, NodeMetadata},
layout::{poly::SolidPolyWeight, Layout, LayoutEdit}, layout::{poly::PolyWeight, Layout, LayoutEdit},
math::{Circle, PointWithRotation}, math::{Circle, PointWithRotation},
specctra::{ specctra::{
mesadata::SpecctraMesadata, mesadata::SpecctraMesadata,
@ -77,78 +77,77 @@ impl SpecctraDesign {
let mut net_outs = BTreeMap::<usize, structure::NetOut>::new(); let mut net_outs = BTreeMap::<usize, structure::NetOut>::new();
for index in drawing.primitive_nodes() { for index in drawing.primitive_nodes() {
let primitive = index.primitive(drawing); let primitive = index.primitive(drawing);
let meta = primitive.metadata();
if let Some(net) = primitive.maybe_net() { let Some(net) = meta.maybe_net else {
let coords = match primitive.shape() { continue;
PrimitiveShape::Seg(seg) => { };
vec![
structure::Point {
x: seg.from.x(),
y: seg.from.y(),
},
structure::Point {
x: seg.to.x(),
y: seg.to.y(),
},
]
}
PrimitiveShape::Bend(bend) => { // object spans multiple layers
// Since general circle arcs don't seem to be supported // TODO: these are Vias
// we're downgrading each one to a chain of straight if meta.from_layer != meta.to_layer {
// line segments. continue;
// 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);
} }
let layer = meta.from_layer;
let coords: Vec<structure::Point> = 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 { let ses = structure::SesFile {
@ -249,8 +248,7 @@ impl SpecctraDesign {
place.point_with_rotation(), place.point_with_rotation(),
pin.point_with_rotation(), pin.point_with_rotation(),
circle.diameter / 2.0, circle.diameter / 2.0,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
Some(pinname.clone()), Some(pinname.clone()),
) )
} }
@ -265,8 +263,7 @@ impl SpecctraDesign {
rect.y1, rect.y1,
rect.x2, rect.x2,
rect.y2, rect.y2,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
Some(pinname.clone()), Some(pinname.clone()),
) )
} }
@ -279,8 +276,7 @@ impl SpecctraDesign {
pin.point_with_rotation(), pin.point_with_rotation(),
&path.coords, &path.coords,
path.width, path.width,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
Some(pinname.clone()), Some(pinname.clone()),
) )
} }
@ -293,8 +289,7 @@ impl SpecctraDesign {
pin.point_with_rotation(), pin.point_with_rotation(),
&polygon.coords, &polygon.coords,
polygon.width, polygon.width,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
Some(pinname.clone()), Some(pinname.clone()),
) )
} }
@ -325,8 +320,7 @@ impl SpecctraDesign {
PointWithRotation::from_xy(via.x, via.y), PointWithRotation::from_xy(via.x, via.y),
PointWithRotation::default(), PointWithRotation::default(),
circle.diameter / 2.0, circle.diameter / 2.0,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
None, None,
) )
} }
@ -341,8 +335,7 @@ impl SpecctraDesign {
rect.y1, rect.y1,
rect.x2, rect.x2,
rect.y2, rect.y2,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
None, None,
) )
} }
@ -355,8 +348,7 @@ impl SpecctraDesign {
PointWithRotation::default(), PointWithRotation::default(),
&path.coords, &path.coords,
path.width, path.width,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
None, None,
) )
} }
@ -369,8 +361,7 @@ impl SpecctraDesign {
PointWithRotation::default(), PointWithRotation::default(),
&polygon.coords, &polygon.coords,
polygon.width, polygon.width,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
None, None,
) )
} }
@ -394,8 +385,7 @@ impl SpecctraDesign {
PointWithRotation::default(), PointWithRotation::default(),
&wire.path.coords, &wire.path.coords,
wire.path.width, wire.path.width,
layer, NodeMetadata::from_layer_and_net(layer, net),
net,
None, None,
); );
} }
@ -429,8 +419,7 @@ impl SpecctraDesign {
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
r: f64, r: f64,
layer: usize, meta: NodeMetadata,
maybe_net: Option<usize>,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) { ) {
let circle = Circle { let circle = Circle {
@ -440,11 +429,8 @@ impl SpecctraDesign {
board.add_fixed_dot_infringably( board.add_fixed_dot_infringably(
recorder, recorder,
FixedDotWeight(GeneralDotWeight { meta,
circle, FixedDotWeight(GeneralDotWeight { circle }),
layer,
maybe_net,
}),
maybe_pin, maybe_pin,
); );
} }
@ -458,108 +444,92 @@ impl SpecctraDesign {
y1: f64, y1: f64,
x2: f64, x2: f64,
y2: f64, y2: f64,
layer: usize, meta: NodeMetadata,
maybe_net: Option<usize>,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) { ) {
// Corners. // Corners.
let dot_1_1 = board.add_fixed_dot_infringably( let dot_1_1 = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x1, y1), pos: Self::pos(place, pin, x1, y1),
r: 0.5, r: 0.5,
}, },
layer,
maybe_net,
}), }),
None, None,
); );
let dot_2_1 = board.add_fixed_dot_infringably( let dot_2_1 = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x2, y1), pos: Self::pos(place, pin, x2, y1),
r: 0.5, r: 0.5,
}, },
layer,
maybe_net,
}), }),
None, None,
); );
let dot_2_2 = board.add_fixed_dot_infringably( let dot_2_2 = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x2, y2), pos: Self::pos(place, pin, x2, y2),
r: 0.5, r: 0.5,
}, },
layer,
maybe_net,
}), }),
None, None,
); );
let dot_1_2 = board.add_fixed_dot_infringably( let dot_1_2 = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, x1, y2), pos: Self::pos(place, pin, x1, y2),
r: 0.5, r: 0.5,
}, },
layer,
maybe_net,
}), }),
None, None,
); );
// Sides. // Sides.
let seg1 = board.add_fixed_seg_infringably( let seg1 = board.add_fixed_seg_infringably(
recorder, recorder,
meta,
dot_1_1, dot_1_1,
dot_2_1, dot_2_1,
FixedSegWeight(GeneralSegWeight { FixedSegWeight(GeneralSegWeight { width: 1.0 }),
width: 1.0,
layer,
maybe_net,
}),
None, None,
); );
let seg2 = board.add_fixed_seg_infringably( let seg2 = board.add_fixed_seg_infringably(
recorder, recorder,
meta,
dot_2_1, dot_2_1,
dot_2_2, dot_2_2,
FixedSegWeight(GeneralSegWeight { FixedSegWeight(GeneralSegWeight { width: 1.0 }),
width: 1.0,
layer,
maybe_net,
}),
None, None,
); );
let seg3 = board.add_fixed_seg_infringably( let seg3 = board.add_fixed_seg_infringably(
recorder, recorder,
meta,
dot_2_2, dot_2_2,
dot_1_2, dot_1_2,
FixedSegWeight(GeneralSegWeight { FixedSegWeight(GeneralSegWeight { width: 1.0 }),
width: 1.0,
layer,
maybe_net,
}),
None, None,
); );
let seg4 = board.add_fixed_seg_infringably( let seg4 = board.add_fixed_seg_infringably(
recorder, recorder,
meta,
dot_1_2, dot_1_2,
dot_1_1, dot_1_1,
FixedSegWeight(GeneralSegWeight { FixedSegWeight(GeneralSegWeight { width: 1.0 }),
width: 1.0,
layer,
maybe_net,
}),
None, None,
); );
board.add_poly_with_nodes( board.add_poly_with_nodes(
recorder, recorder,
SolidPolyWeight { layer, maybe_net }.into(), meta,
PolyWeight::Solid.into(),
maybe_pin, maybe_pin,
&[ &[
dot_1_1.into(), dot_1_1.into(),
@ -581,21 +551,19 @@ impl SpecctraDesign {
pin: PointWithRotation, pin: PointWithRotation,
coords: &[structure::Point], coords: &[structure::Point],
width: f64, width: f64,
layer: usize, meta: NodeMetadata,
maybe_net: Option<usize>,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) { ) {
// add the first coordinate in the wire path as a dot and save its index // 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_pos = Self::pos(place, pin, coords[0].x, coords[0].y);
let mut prev_index = board.add_fixed_dot_infringably( let mut prev_index = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: prev_pos, pos: prev_pos,
r: width / 2.0, r: width / 2.0,
}, },
layer,
maybe_net,
}), }),
maybe_pin.clone(), maybe_pin.clone(),
); );
@ -610,13 +578,12 @@ impl SpecctraDesign {
let index = board.add_fixed_dot_infringably( let index = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos, pos,
r: width / 2.0, r: width / 2.0,
}, },
layer,
maybe_net,
}), }),
maybe_pin.clone(), maybe_pin.clone(),
); );
@ -624,13 +591,10 @@ impl SpecctraDesign {
// add a seg between the current and previous coords // add a seg between the current and previous coords
let _ = board.add_fixed_seg_infringably( let _ = board.add_fixed_seg_infringably(
recorder, recorder,
meta,
prev_index, prev_index,
index, index,
FixedSegWeight(GeneralSegWeight { FixedSegWeight(GeneralSegWeight { width }),
width,
layer,
maybe_net,
}),
maybe_pin.clone(), maybe_pin.clone(),
); );
@ -646,8 +610,7 @@ impl SpecctraDesign {
pin: PointWithRotation, pin: PointWithRotation,
mut coords: &[structure::Point], mut coords: &[structure::Point],
width: f64, width: f64,
layer: usize, meta: NodeMetadata,
maybe_net: Option<usize>,
maybe_pin: Option<String>, maybe_pin: Option<String>,
) { ) {
let mut nodes = Vec::with_capacity(coords.len() * 2 - 1); 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 // add the first coordinate in the wire path as a dot and save its index
let first_index = board.add_fixed_dot_infringably( let first_index = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, coords[0].x, coords[0].y), pos: Self::pos(place, pin, coords[0].x, coords[0].y),
r: width / 2.0, r: width / 2.0,
}, },
layer,
maybe_net,
}), }),
None, None,
); );
@ -674,23 +636,18 @@ impl SpecctraDesign {
coords = &coords[..coords.len() - 1]; coords = &coords[..coords.len() - 1];
} }
let seg_weight = FixedSegWeight(GeneralSegWeight { let seg_weight = FixedSegWeight(GeneralSegWeight { width });
width,
layer,
maybe_net,
});
// iterate through path coords starting from the second // iterate through path coords starting from the second
for coord in &coords[1..] { for coord in &coords[1..] {
let index = board.add_fixed_dot_infringably( let index = board.add_fixed_dot_infringably(
recorder, recorder,
meta,
FixedDotWeight(GeneralDotWeight { FixedDotWeight(GeneralDotWeight {
circle: Circle { circle: Circle {
pos: Self::pos(place, pin, coord.x, coord.y), pos: Self::pos(place, pin, coord.x, coord.y),
r: width / 2.0, r: width / 2.0,
}, },
layer,
maybe_net,
}), }),
None, None,
); );
@ -699,7 +656,7 @@ impl SpecctraDesign {
// add a seg between the current and previous coords // add a seg between the current and previous coords
nodes.push( nodes.push(
board 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(), .into(),
); );
@ -709,13 +666,21 @@ impl SpecctraDesign {
// add a seg between the last and first coords // add a seg between the last and first coords
nodes.push( nodes.push(
board 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(), .into(),
); );
board.add_poly_with_nodes( board.add_poly_with_nodes(
recorder, recorder,
SolidPolyWeight { layer, maybe_net }.into(), meta,
PolyWeight::Solid.into(),
maybe_pin, maybe_pin,
&nodes[..], &nodes[..],
); );

View File

@ -12,8 +12,7 @@ use topola::{
Autorouter, Autorouter,
}, },
board::{AccessMesadata, Board}, board::{AccessMesadata, Board},
drawing::graph::GetMaybeNet, geometry::{shape::MeasureLength, GenericNode, GetMetadata},
geometry::{shape::MeasureLength, GenericNode, GetLayer},
graph::{GetPetgraphIndex, MakeRef}, graph::{GetPetgraphIndex, MakeRef},
layout::LayoutEdit, layout::LayoutEdit,
router::{navmesh::Navmesh, RouterOptions}, router::{navmesh::Navmesh, RouterOptions},
@ -74,6 +73,7 @@ pub fn assert_navnode_count(
autorouter: &mut Autorouter<SpecctraMesadata>, autorouter: &mut Autorouter<SpecctraMesadata>,
origin_pin: &str, origin_pin: &str,
destination_pin: &str, destination_pin: &str,
layer: usize,
expected_count: usize, expected_count: usize,
) { ) {
let (origin, destination) = autorouter let (origin, destination) = autorouter
@ -104,6 +104,7 @@ pub fn assert_navnode_count(
autorouter.board().layout(), autorouter.board().layout(),
origin, origin,
destination, destination,
layer,
RouterOptions { RouterOptions {
wrap_around_bands: true, wrap_around_bands: true,
squeeze_through_under_bends: false, squeeze_through_under_bends: false,
@ -119,56 +120,23 @@ pub fn assert_single_layer_groundless_autoroute(
layername: &str, layername: &str,
) { ) {
let unionfind = unionfind(autorouter); 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() { for ratline in autorouter.ratsnest().graph().edge_indices() {
let (origin_dot, destination_dot) = autorouter.ratline_endpoints(ratline); let (origin_dot, destination_dot) = autorouter.ratline_endpoints(ratline);
let origin_layer = autorouter assert!(drawing.primitive(origin_dot).metadata().is_in_layer(layer));
.board() assert!(drawing
.layout()
.drawing()
.primitive(origin_dot)
.layer();
let destination_layer = autorouter
.board()
.layout()
.drawing()
.primitive(destination_dot) .primitive(destination_dot)
.layer(); .metadata()
.is_in_layer(layer));
if let (Some(origin_layername), Some(destination_layername)) = ( let origin_net = drawing.primitive(origin_dot).metadata().maybe_net;
autorouter let destination_net = drawing.primitive(destination_dot).metadata().maybe_net;
.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();
assert_eq!(origin_net, destination_net); assert_eq!(origin_net, destination_net);
let net = origin_net.unwrap(); let net = origin_net.unwrap();

View File

@ -5,7 +5,6 @@
use topola::{ use topola::{
autorouter::{execution::Command, invoker::InvokerError, AutorouterError}, autorouter::{execution::Command, invoker::InvokerError, AutorouterError},
board::AccessMesadata, board::AccessMesadata,
layout::via::ViaWeight,
math::Circle, math::Circle,
}; };

View File

@ -3,12 +3,9 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use topola::{ use topola::{
autorouter::{ drawing::dot::{GeneralDotWeight, LooseDotWeight},
execution::Command, geometry::NodeMetadata,
invoker::{Invoker, InvokerError}, layout::LayoutEdit,
AutorouterError,
},
layout::via::ViaWeight,
math::Circle, math::Circle,
}; };
@ -63,22 +60,25 @@ fn test_tht_diode_bridge_rectifier() {
//common::assert_number_of_conncomps(&mut autorouter, 4); //common::assert_number_of_conncomps(&mut autorouter, 4);
common::assert_band_length(autorouter.board(), "J2-2", "D4-2", 15906.760439007436, 0.01); common::assert_band_length(autorouter.board(), "J2-2", "D4-2", 15906.760439007436, 0.01);
let mut invoker = Invoker::new(autorouter); let result = autorouter
let result = invoker.execute(Command::PlaceVia(ViaWeight { .board()
from_layer: 0, .layout()
to_layer: 1, .drawing()
circle: Circle { .add_dot_with_infringement_filtering(
pos: [0.0, 0.0].into(), &mut LayoutEdit::new(),
r: 200000.0, NodeMetadata {
}, from_layer: 0,
maybe_net: Some(1234), to_layer: 1,
})); maybe_net: Some(1234),
assert!(matches!( },
result, LooseDotWeight(GeneralDotWeight {
Err(InvokerError::Autorouter(AutorouterError::CouldNotPlaceVia( circle: Circle {
.. pos: [0.0, 0.0].into(),
))) r: 200000.0,
)); },
}),
);
assert!(matches!(result, Err(_)));
} }
#[test] #[test]