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