mirror of https://codeberg.org/topola/topola.git
feat(board,layout,drawing): implement edit recording
Not stored in the undo/redo objects yet.
This commit is contained in:
parent
ad1b43b806
commit
d6fe67a373
|
|
@ -2,6 +2,7 @@ use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use topola::autorouter::invoker::Invoker;
|
use topola::autorouter::invoker::Invoker;
|
||||||
use topola::autorouter::Autorouter;
|
use topola::autorouter::Autorouter;
|
||||||
|
use topola::layout::LayoutEdit;
|
||||||
use topola::specctra::design::SpecctraDesign;
|
use topola::specctra::design::SpecctraDesign;
|
||||||
|
|
||||||
fn main() -> Result<(), std::io::Error> {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
|
|
@ -9,7 +10,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let design_bufread = BufReader::new(design_file);
|
let design_bufread = BufReader::new(design_file);
|
||||||
|
|
||||||
let design = SpecctraDesign::load(design_bufread).unwrap();
|
let design = SpecctraDesign::load(design_bufread).unwrap();
|
||||||
let board = design.make_board();
|
let board = design.make_board(&mut LayoutEdit::new());
|
||||||
|
|
||||||
let invoker = Invoker::new(Autorouter::new(board).unwrap());
|
let invoker = Invoker::new(Autorouter::new(board).unwrap());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use thiserror::Error;
|
||||||
use crate::{
|
use crate::{
|
||||||
board::{mesadata::AccessMesadata, Board},
|
board::{mesadata::AccessMesadata, Board},
|
||||||
drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement},
|
drawing::{band::BandTermsegIndex, dot::FixedDotIndex, Infringement},
|
||||||
layout::via::ViaWeight,
|
layout::{via::ViaWeight, LayoutEdit},
|
||||||
router::{astar::AstarError, navmesh::NavmeshError, RouterOptions},
|
router::{astar::AstarError, navmesh::NavmeshError, RouterOptions},
|
||||||
triangulation::GetTrianvertexNodeIndex,
|
triangulation::GetTrianvertexNodeIndex,
|
||||||
};
|
};
|
||||||
|
|
@ -73,7 +73,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
||||||
.node_index()
|
.node_index()
|
||||||
{
|
{
|
||||||
RatvertexIndex::FixedDot(dot) => dot,
|
RatvertexIndex::FixedDot(dot) => dot,
|
||||||
RatvertexIndex::Poly(poly) => self.board.poly_apex(poly),
|
RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
|
||||||
};
|
};
|
||||||
|
|
||||||
PointrouteExecutionStepper::new(self, origin_dot, point, options)
|
PointrouteExecutionStepper::new(self, origin_dot, point, options)
|
||||||
|
|
@ -82,7 +82,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
||||||
pub fn undo_pointroute(&mut self, band: BandTermsegIndex) -> Result<(), AutorouterError> {
|
pub fn undo_pointroute(&mut self, band: BandTermsegIndex) -> Result<(), AutorouterError> {
|
||||||
self.board
|
self.board
|
||||||
.layout_mut()
|
.layout_mut()
|
||||||
.remove_band(band)
|
.remove_band(&mut LayoutEdit::new(), band)
|
||||||
.map_err(|_| AutorouterError::CouldNotRemoveBand(band))
|
.map_err(|_| AutorouterError::CouldNotRemoveBand(band))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.board
|
self.board
|
||||||
.layout_mut()
|
.layout_mut()
|
||||||
.remove_band(band)
|
.remove_band(&mut LayoutEdit::new(), band)
|
||||||
.map_err(|_| AutorouterError::CouldNotRemoveBand(band))?;
|
.map_err(|_| AutorouterError::CouldNotRemoveBand(band))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,7 +191,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
||||||
.node_index()
|
.node_index()
|
||||||
{
|
{
|
||||||
RatvertexIndex::FixedDot(dot) => dot,
|
RatvertexIndex::FixedDot(dot) => dot,
|
||||||
RatvertexIndex::Poly(poly) => self.board.poly_apex(poly),
|
RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
|
||||||
};
|
};
|
||||||
|
|
||||||
let target_dot = match self
|
let target_dot = match self
|
||||||
|
|
@ -202,7 +202,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
||||||
.node_index()
|
.node_index()
|
||||||
{
|
{
|
||||||
RatvertexIndex::FixedDot(dot) => dot,
|
RatvertexIndex::FixedDot(dot) => dot,
|
||||||
RatvertexIndex::Poly(poly) => self.board.poly_apex(poly),
|
RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
|
||||||
};
|
};
|
||||||
|
|
||||||
(source_dot, target_dot)
|
(source_dot, target_dot)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
board::mesadata::AccessMesadata,
|
board::mesadata::AccessMesadata,
|
||||||
drawing::graph::PrimitiveIndex,
|
drawing::graph::PrimitiveIndex,
|
||||||
geometry::primitive::PrimitiveShape,
|
geometry::primitive::PrimitiveShape,
|
||||||
layout::via::ViaWeight,
|
layout::{via::ViaWeight, LayoutEdit},
|
||||||
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -35,7 +35,10 @@ impl PlaceViaExecutionStepper {
|
||||||
) -> Result<(), AutorouterError> {
|
) -> Result<(), AutorouterError> {
|
||||||
if !self.done {
|
if !self.done {
|
||||||
self.done = true;
|
self.done = true;
|
||||||
autorouter.board.layout_mut().add_via(self.weight)?;
|
autorouter
|
||||||
|
.board
|
||||||
|
.layout_mut()
|
||||||
|
.add_via(&mut LayoutEdit::new(), self.weight)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use crate::{
|
||||||
band::BandTermsegIndex,
|
band::BandTermsegIndex,
|
||||||
dot::{FixedDotIndex, FixedDotWeight},
|
dot::{FixedDotIndex, FixedDotWeight},
|
||||||
},
|
},
|
||||||
|
layout::LayoutEdit,
|
||||||
math::Circle,
|
math::Circle,
|
||||||
router::{route::RouteStepper, Router},
|
router::{route::RouteStepper, Router},
|
||||||
stepper::Step,
|
stepper::Step,
|
||||||
|
|
@ -29,6 +30,7 @@ impl PointrouteExecutionStepper {
|
||||||
options: AutorouterOptions,
|
options: AutorouterOptions,
|
||||||
) -> Result<Self, AutorouterError> {
|
) -> Result<Self, AutorouterError> {
|
||||||
let destination = autorouter.board.add_fixed_dot_infringably(
|
let destination = autorouter.board.add_fixed_dot_infringably(
|
||||||
|
&mut LayoutEdit::new(),
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: point,
|
pos: point,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
board::mesadata::AccessMesadata,
|
board::mesadata::AccessMesadata,
|
||||||
drawing::graph::PrimitiveIndex,
|
drawing::graph::PrimitiveIndex,
|
||||||
geometry::primitive::PrimitiveShape,
|
geometry::primitive::PrimitiveShape,
|
||||||
|
layout::LayoutEdit,
|
||||||
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -36,7 +37,10 @@ impl RemoveBandsExecutionStepper {
|
||||||
|
|
||||||
for selector in self.selection.selectors() {
|
for selector in self.selection.selectors() {
|
||||||
let band = autorouter.board.bandname_band(&selector.band).unwrap().0;
|
let band = autorouter.board.bandname_band(&selector.band).unwrap().0;
|
||||||
autorouter.board.layout_mut().remove_band(band);
|
autorouter
|
||||||
|
.board
|
||||||
|
.layout_mut()
|
||||||
|
.remove_band(&mut LayoutEdit::new(), band);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use topola::{
|
||||||
activity::{ActivityContext, ActivityStepperWithStatus, InteractiveInput},
|
activity::{ActivityContext, ActivityStepperWithStatus, InteractiveInput},
|
||||||
Interactor,
|
Interactor,
|
||||||
},
|
},
|
||||||
|
layout::LayoutEdit,
|
||||||
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
||||||
stepper::Step,
|
stepper::Step,
|
||||||
};
|
};
|
||||||
|
|
@ -30,7 +31,7 @@ pub struct Workspace {
|
||||||
|
|
||||||
impl Workspace {
|
impl Workspace {
|
||||||
pub fn new(design: SpecctraDesign, tr: &Translator) -> Result<Self, String> {
|
pub fn new(design: SpecctraDesign, tr: &Translator) -> Result<Self, String> {
|
||||||
let board = design.make_board();
|
let board = design.make_board(&mut LayoutEdit::new());
|
||||||
let layers = Layers::new(&board);
|
let layers = Layers::new(&board);
|
||||||
let overlay = Overlay::new(&board).map_err(|err| {
|
let overlay = Overlay::new(&board).map_err(|err| {
|
||||||
format!(
|
format!(
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use topola::autorouter::invoker::Invoker;
|
||||||
use topola::autorouter::selection::PinSelection;
|
use topola::autorouter::selection::PinSelection;
|
||||||
use topola::autorouter::Autorouter;
|
use topola::autorouter::Autorouter;
|
||||||
use topola::autorouter::AutorouterOptions;
|
use topola::autorouter::AutorouterOptions;
|
||||||
|
use topola::layout::LayoutEdit;
|
||||||
use topola::router::RouterOptions;
|
use topola::router::RouterOptions;
|
||||||
use topola::specctra::design::SpecctraDesign;
|
use topola::specctra::design::SpecctraDesign;
|
||||||
|
|
||||||
|
|
@ -19,7 +20,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let mut design_bufread = BufReader::new(design_file);
|
let mut design_bufread = BufReader::new(design_file);
|
||||||
|
|
||||||
let design = SpecctraDesign::load(design_bufread).unwrap();
|
let design = SpecctraDesign::load(design_bufread).unwrap();
|
||||||
let board = design.make_board();
|
let board = design.make_board(&mut LayoutEdit::new());
|
||||||
|
|
||||||
let history = if let Some(commands_filename) = args.commands {
|
let history = if let Some(commands_filename) = args.commands {
|
||||||
let command_file = File::open(commands_filename)?;
|
let command_file = File::open(commands_filename)?;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
graph::GenericIndex,
|
graph::GenericIndex,
|
||||||
layout::{
|
layout::{
|
||||||
poly::{GetMaybeApex, MakePolyShape, PolyWeight},
|
poly::{GetMaybeApex, MakePolyShape, PolyWeight},
|
||||||
Layout, NodeIndex,
|
Layout, LayoutEdit, NodeIndex,
|
||||||
},
|
},
|
||||||
math::Circle,
|
math::Circle,
|
||||||
};
|
};
|
||||||
|
|
@ -67,10 +67,11 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
/// Inserts the dot into the layout and, if a pin name is provided, maps it to the created dot's node.
|
/// Inserts the dot into the layout and, if a pin name is provided, maps it to the created dot's node.
|
||||||
pub fn add_fixed_dot_infringably(
|
pub fn add_fixed_dot_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
weight: FixedDotWeight,
|
weight: FixedDotWeight,
|
||||||
maybe_pin: Option<String>,
|
maybe_pin: Option<String>,
|
||||||
) -> FixedDotIndex {
|
) -> FixedDotIndex {
|
||||||
let dot = self.layout.add_fixed_dot_infringably(weight);
|
let dot = self.layout.add_fixed_dot_infringably(recorder, weight);
|
||||||
|
|
||||||
if let Some(ref pin) = maybe_pin {
|
if let Some(ref pin) = maybe_pin {
|
||||||
self.node_to_pinname
|
self.node_to_pinname
|
||||||
|
|
@ -85,10 +86,13 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
/// Adds the segment to the layout and maps the pin name to the created segment if provided.
|
/// Adds the segment to the layout and maps the pin name to the created segment if provided.
|
||||||
pub fn add_poly_fixed_dot_infringably(
|
pub fn add_poly_fixed_dot_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
weight: FixedDotWeight,
|
weight: FixedDotWeight,
|
||||||
poly: GenericIndex<PolyWeight>,
|
poly: GenericIndex<PolyWeight>,
|
||||||
) -> FixedDotIndex {
|
) -> FixedDotIndex {
|
||||||
let dot = self.layout.add_poly_fixed_dot_infringably(weight, poly);
|
let dot = self
|
||||||
|
.layout
|
||||||
|
.add_poly_fixed_dot_infringably(recorder, weight, poly);
|
||||||
|
|
||||||
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
|
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
|
||||||
self.node_to_pinname
|
self.node_to_pinname
|
||||||
|
|
@ -103,12 +107,15 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
/// Adds the segment to the layout and updates the internal mapping if necessary.
|
/// Adds the segment to the layout and updates the internal mapping if necessary.
|
||||||
pub fn add_fixed_seg_infringably(
|
pub fn add_fixed_seg_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
maybe_pin: Option<String>,
|
maybe_pin: Option<String>,
|
||||||
) -> FixedSegIndex {
|
) -> FixedSegIndex {
|
||||||
let seg = self.layout.add_fixed_seg_infringably(from, to, weight);
|
let seg = self
|
||||||
|
.layout
|
||||||
|
.add_fixed_seg_infringably(recorder, from, to, weight);
|
||||||
|
|
||||||
if let Some(pin) = maybe_pin {
|
if let Some(pin) = maybe_pin {
|
||||||
self.node_to_pinname
|
self.node_to_pinname
|
||||||
|
|
@ -123,6 +130,7 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
/// Adds the segment to the layout and updates the internal mapping if necessary.
|
/// Adds the segment to the layout and updates the internal mapping if necessary.
|
||||||
pub fn add_poly_fixed_seg_infringably(
|
pub fn add_poly_fixed_seg_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
|
|
@ -130,7 +138,7 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
) -> FixedSegIndex {
|
) -> FixedSegIndex {
|
||||||
let seg = self
|
let seg = self
|
||||||
.layout
|
.layout
|
||||||
.add_poly_fixed_seg_infringably(from, to, weight, poly);
|
.add_poly_fixed_seg_infringably(recorder, from, to, weight, poly);
|
||||||
|
|
||||||
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
|
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
|
||||||
self.node_to_pinname
|
self.node_to_pinname
|
||||||
|
|
@ -145,10 +153,11 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
/// Inserts the polygon into the layout and, if a pin name is provided, maps it to the created polygon's node.
|
/// Inserts the polygon into the layout and, if a pin name is provided, maps it to the created polygon's node.
|
||||||
pub fn add_poly(
|
pub fn add_poly(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
weight: PolyWeight,
|
weight: PolyWeight,
|
||||||
maybe_pin: Option<String>,
|
maybe_pin: Option<String>,
|
||||||
) -> GenericIndex<PolyWeight> {
|
) -> GenericIndex<PolyWeight> {
|
||||||
let poly = self.layout.add_poly(weight);
|
let poly = self.layout.add_poly(recorder, weight);
|
||||||
|
|
||||||
if let Some(pin) = maybe_pin {
|
if let Some(pin) = maybe_pin {
|
||||||
self.node_to_pinname
|
self.node_to_pinname
|
||||||
|
|
@ -161,11 +170,16 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
/// Retrieves or creates the apex (top point) of a polygon in the layout.
|
/// Retrieves or creates the apex (top point) of a polygon in the layout.
|
||||||
///
|
///
|
||||||
/// If the polygon already has an apex, returns it. Otherwise, creates and returns a new fixed dot as the apex.
|
/// If the polygon already has an apex, returns it. Otherwise, creates and returns a new fixed dot as the apex.
|
||||||
pub fn poly_apex(&mut self, poly: GenericIndex<PolyWeight>) -> FixedDotIndex {
|
pub fn poly_apex(
|
||||||
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
|
poly: GenericIndex<PolyWeight>,
|
||||||
|
) -> FixedDotIndex {
|
||||||
if let Some(apex) = self.layout.poly(poly).maybe_apex() {
|
if let Some(apex) = self.layout.poly(poly).maybe_apex() {
|
||||||
apex
|
apex
|
||||||
} else {
|
} else {
|
||||||
self.add_poly_fixed_dot_infringably(
|
self.add_poly_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: self.layout.poly(poly).shape().center(),
|
pos: self.layout.poly(poly).shape().center(),
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum BendIndex {
|
pub enum BendIndex {
|
||||||
Fixed(FixedBendIndex),
|
Fixed(FixedBendIndex),
|
||||||
Loose(LooseBendIndex),
|
Loose(LooseBendIndex),
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum DotIndex {
|
pub enum DotIndex {
|
||||||
Fixed(FixedDotIndex),
|
Fixed(FixedDotIndex),
|
||||||
Loose(LooseDotIndex),
|
Loose(LooseDotIndex),
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ use rstar::{RTree, AABB};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
compound::ManageCompounds,
|
|
||||||
primitive::{AccessPrimitiveShape, PrimitiveShape},
|
primitive::{AccessPrimitiveShape, PrimitiveShape},
|
||||||
with_rtree::{BboxedIndex, GeometryWithRtree},
|
recording_with_rtree::{GeometryEdit, RecordingGeometryWithRtree},
|
||||||
|
with_rtree::BboxedIndex,
|
||||||
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
||||||
GetOffset, GetPos, GetWidth,
|
GetOffset, GetPos, GetWidth,
|
||||||
};
|
};
|
||||||
|
|
@ -65,9 +65,21 @@ pub struct Collision(pub PrimitiveShape, pub PrimitiveIndex);
|
||||||
#[error("{1:?} is already connected to net {0}")]
|
#[error("{1:?} is already connected to net {0}")]
|
||||||
pub struct AlreadyConnected(pub usize, pub PrimitiveIndex);
|
pub struct AlreadyConnected(pub usize, pub PrimitiveIndex);
|
||||||
|
|
||||||
|
pub type DrawingEdit<CW: Copy> = GeometryEdit<
|
||||||
|
PrimitiveWeight,
|
||||||
|
DotWeight,
|
||||||
|
SegWeight,
|
||||||
|
BendWeight,
|
||||||
|
CW,
|
||||||
|
PrimitiveIndex,
|
||||||
|
DotIndex,
|
||||||
|
SegIndex,
|
||||||
|
BendIndex,
|
||||||
|
>;
|
||||||
|
|
||||||
#[derive(Debug, Getters)]
|
#[derive(Debug, Getters)]
|
||||||
pub struct Drawing<CW: Copy, R: AccessRules> {
|
pub struct Drawing<CW: Copy, R: AccessRules> {
|
||||||
geometry_with_rtree: GeometryWithRtree<
|
recording_geometry_with_rtree: RecordingGeometryWithRtree<
|
||||||
PrimitiveWeight,
|
PrimitiveWeight,
|
||||||
DotWeight,
|
DotWeight,
|
||||||
SegWeight,
|
SegWeight,
|
||||||
|
|
@ -85,15 +97,20 @@ pub struct Drawing<CW: Copy, R: AccessRules> {
|
||||||
impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
pub fn new(rules: R, layer_count: usize) -> Self {
|
pub fn new(rules: R, layer_count: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
geometry_with_rtree: GeometryWithRtree::new(layer_count),
|
recording_geometry_with_rtree: RecordingGeometryWithRtree::new(layer_count),
|
||||||
rules,
|
rules,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> {
|
pub fn remove_band(
|
||||||
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
|
band: BandTermsegIndex,
|
||||||
|
) -> Result<(), DrawingException> {
|
||||||
match band {
|
match band {
|
||||||
BandTermsegIndex::Straight(seg) => {
|
BandTermsegIndex::Straight(seg) => {
|
||||||
self.geometry_with_rtree.remove_seg(seg.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_seg(recorder, seg.into());
|
||||||
}
|
}
|
||||||
BandTermsegIndex::Bended(first_loose_seg) => {
|
BandTermsegIndex::Bended(first_loose_seg) => {
|
||||||
let mut dots = vec![];
|
let mut dots = vec![];
|
||||||
|
|
@ -110,7 +127,8 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
dots.push(dot);
|
dots.push(dot);
|
||||||
}
|
}
|
||||||
LooseIndex::LoneSeg(seg) => {
|
LooseIndex::LoneSeg(seg) => {
|
||||||
self.geometry_with_rtree.remove_seg(seg.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_seg(recorder, seg.into());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LooseIndex::SeqSeg(seg) => {
|
LooseIndex::SeqSeg(seg) => {
|
||||||
|
|
@ -121,7 +139,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
|
|
||||||
if let Some(outer) = self.primitive(bend).outer() {
|
if let Some(outer) = self.primitive(bend).outer() {
|
||||||
outers.push(outer);
|
outers.push(outer);
|
||||||
self.reattach_bend(outer, self.primitive(bend).inner());
|
self.reattach_bend(recorder, outer, self.primitive(bend).inner());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -132,22 +150,25 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for bend in bends {
|
for bend in bends {
|
||||||
self.geometry_with_rtree.remove_bend(bend.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_bend(recorder, bend.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
for seg in segs {
|
for seg in segs {
|
||||||
self.geometry_with_rtree.remove_seg(seg.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_seg(recorder, seg.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must remove the dots only after the segs and bends because we need dots to calculate
|
// We must remove the dots only after the segs and bends because we need dots to calculate
|
||||||
// the shapes, which we first need unchanged to remove the segs and bends from the R-tree.
|
// the shapes, which we first need unchanged to remove the segs and bends from the R-tree.
|
||||||
|
|
||||||
for dot in dots {
|
for dot in dots {
|
||||||
self.geometry_with_rtree.remove_dot(dot.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_dot(recorder, dot.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
for outer in outers {
|
for outer in outers {
|
||||||
self.update_this_and_outward_bows(outer)?;
|
self.update_this_and_outward_bows(recorder, outer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -158,34 +179,44 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> {
|
pub fn add_fixed_dot(
|
||||||
self.add_dot_with_infringables(weight, Some(&[]))
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
|
weight: FixedDotWeight,
|
||||||
|
) -> Result<FixedDotIndex, Infringement> {
|
||||||
|
self.add_dot_with_infringables(recorder, weight, Some(&[]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn remove_fixed_dot(&mut self, dot: FixedDotIndex) {
|
pub fn remove_fixed_dot(&mut self, recorder: &mut DrawingEdit<CW>, dot: FixedDotIndex) {
|
||||||
self.geometry_with_rtree.remove_dot(dot.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_dot(recorder, dot.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex {
|
pub fn add_fixed_dot_infringably(
|
||||||
self.add_dot_infringably(weight)
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
|
weight: FixedDotWeight,
|
||||||
|
) -> FixedDotIndex {
|
||||||
|
self.add_dot_infringably(recorder, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
fn add_dot_with_infringables<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
|
fn add_dot_with_infringables<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
weight: W,
|
weight: W,
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<GenericIndex<W>, Infringement>
|
) -> Result<GenericIndex<W>, Infringement>
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
||||||
{
|
{
|
||||||
let dot = self.add_dot_infringably(weight);
|
let dot = self.add_dot_infringably(recorder, weight);
|
||||||
self.fail_and_remove_if_infringes_except(dot.into(), infringables)?;
|
self.fail_and_remove_if_infringes_except(recorder, dot.into(), infringables)?;
|
||||||
|
|
||||||
Ok(dot)
|
Ok(dot)
|
||||||
}
|
}
|
||||||
|
|
@ -195,22 +226,24 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn add_fixed_seg(
|
pub fn add_fixed_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
) -> Result<FixedSegIndex, Infringement> {
|
) -> Result<FixedSegIndex, Infringement> {
|
||||||
self.add_seg_with_infringables(from.into(), to.into(), weight, Some(&[]))
|
self.add_seg_with_infringables(recorder, from.into(), to.into(), weight, Some(&[]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))]
|
||||||
pub fn add_fixed_seg_infringably(
|
pub fn add_fixed_seg_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
) -> FixedSegIndex {
|
) -> FixedSegIndex {
|
||||||
self.add_seg_infringably(from.into(), to.into(), weight)
|
self.add_seg_infringably(recorder, from.into(), to.into(), weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
||||||
|
|
@ -219,11 +252,13 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn add_lone_loose_seg(
|
pub fn add_lone_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: LoneLooseSegWeight,
|
weight: LoneLooseSegWeight,
|
||||||
) -> Result<LoneLooseSegIndex, Infringement> {
|
) -> Result<LoneLooseSegIndex, Infringement> {
|
||||||
let seg = self.add_seg_with_infringables(from.into(), to.into(), weight, Some(&[]))?;
|
let seg =
|
||||||
|
self.add_seg_with_infringables(recorder, from.into(), to.into(), weight, Some(&[]))?;
|
||||||
Ok(seg)
|
Ok(seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,11 +268,12 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn add_seq_loose_seg(
|
pub fn add_seq_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
to: LooseDotIndex,
|
to: LooseDotIndex,
|
||||||
weight: SeqLooseSegWeight,
|
weight: SeqLooseSegWeight,
|
||||||
) -> Result<SeqLooseSegIndex, Infringement> {
|
) -> Result<SeqLooseSegIndex, Infringement> {
|
||||||
let seg = self.add_seg_with_infringables(from, to.into(), weight, Some(&[]))?;
|
let seg = self.add_seg_with_infringables(recorder, from, to.into(), weight, Some(&[]))?;
|
||||||
Ok(seg)
|
Ok(seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,6 +283,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn add_seg_with_infringables<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
|
fn add_seg_with_infringables<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
to: DotIndex,
|
to: DotIndex,
|
||||||
weight: W,
|
weight: W,
|
||||||
|
|
@ -255,8 +292,8 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
||||||
{
|
{
|
||||||
let seg = self.add_seg_infringably(from, to, weight);
|
let seg = self.add_seg_infringably(recorder, from, to, weight);
|
||||||
self.fail_and_remove_if_infringes_except(seg.into(), infringables)?;
|
self.fail_and_remove_if_infringes_except(recorder, seg.into(), infringables)?;
|
||||||
|
|
||||||
Ok(seg)
|
Ok(seg)
|
||||||
}
|
}
|
||||||
|
|
@ -268,6 +305,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn add_loose_bend_with_infringables(
|
fn add_loose_bend_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: LooseDotIndex,
|
from: LooseDotIndex,
|
||||||
to: LooseDotIndex,
|
to: LooseDotIndex,
|
||||||
around: GearIndex,
|
around: GearIndex,
|
||||||
|
|
@ -294,13 +332,34 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
|
|
||||||
match around {
|
match around {
|
||||||
GearIndex::FixedDot(core) => self
|
GearIndex::FixedDot(core) => self
|
||||||
.add_core_bend_with_infringables(from.into(), to.into(), core, weight, infringables)
|
.add_core_bend_with_infringables(
|
||||||
|
recorder,
|
||||||
|
from.into(),
|
||||||
|
to.into(),
|
||||||
|
core,
|
||||||
|
weight,
|
||||||
|
infringables,
|
||||||
|
)
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
GearIndex::FixedBend(around) => self
|
GearIndex::FixedBend(around) => self
|
||||||
.add_outer_bend_with_infringables(from, to, around.into(), weight, infringables)
|
.add_outer_bend_with_infringables(
|
||||||
|
recorder,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
around.into(),
|
||||||
|
weight,
|
||||||
|
infringables,
|
||||||
|
)
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
GearIndex::LooseBend(around) => self
|
GearIndex::LooseBend(around) => self
|
||||||
.add_outer_bend_with_infringables(from, to, around.into(), weight, infringables)
|
.add_outer_bend_with_infringables(
|
||||||
|
recorder,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
around.into(),
|
||||||
|
weight,
|
||||||
|
infringables,
|
||||||
|
)
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -311,6 +370,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn add_core_bend_with_infringables<W: AccessBendWeight<PrimitiveWeight> + GetLayer>(
|
fn add_core_bend_with_infringables<W: AccessBendWeight<PrimitiveWeight> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
to: DotIndex,
|
to: DotIndex,
|
||||||
core: FixedDotIndex,
|
core: FixedDotIndex,
|
||||||
|
|
@ -320,11 +380,11 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
||||||
{
|
{
|
||||||
let bend = self
|
let bend =
|
||||||
.geometry_with_rtree
|
self.recording_geometry_with_rtree
|
||||||
.add_bend(from, to, core.into(), weight);
|
.add_bend(recorder, from, to, core.into(), weight);
|
||||||
|
|
||||||
self.fail_and_remove_if_infringes_except(bend.into(), infringables)?;
|
self.fail_and_remove_if_infringes_except(recorder, bend.into(), infringables)?;
|
||||||
Ok(bend)
|
Ok(bend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,6 +394,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn add_outer_bend_with_infringables(
|
fn add_outer_bend_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: LooseDotIndex,
|
from: LooseDotIndex,
|
||||||
to: LooseDotIndex,
|
to: LooseDotIndex,
|
||||||
inner: BendIndex,
|
inner: BendIndex,
|
||||||
|
|
@ -341,15 +402,15 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<GenericIndex<LooseBendWeight>, Infringement> {
|
) -> Result<GenericIndex<LooseBendWeight>, Infringement> {
|
||||||
let core = *self
|
let core = *self
|
||||||
.geometry_with_rtree
|
.recording_geometry_with_rtree
|
||||||
.graph()
|
.graph()
|
||||||
.neighbors(inner.petgraph_index())
|
.neighbors(inner.petgraph_index())
|
||||||
.filter(|ni| {
|
.filter(|ni| {
|
||||||
matches!(
|
matches!(
|
||||||
self.geometry_with_rtree
|
self.recording_geometry_with_rtree
|
||||||
.graph()
|
.graph()
|
||||||
.edge_weight(
|
.edge_weight(
|
||||||
self.geometry_with_rtree
|
self.recording_geometry_with_rtree
|
||||||
.graph()
|
.graph()
|
||||||
.find_edge(inner.petgraph_index(), *ni)
|
.find_edge(inner.petgraph_index(), *ni)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -363,29 +424,42 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
.first()
|
.first()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let bend = self
|
let bend = self.recording_geometry_with_rtree.add_bend(
|
||||||
.geometry_with_rtree
|
recorder,
|
||||||
.add_bend(from.into(), to.into(), core.into(), weight);
|
from.into(),
|
||||||
self.geometry_with_rtree
|
to.into(),
|
||||||
.reattach_bend(bend.into(), Some(inner));
|
core.into(),
|
||||||
|
weight,
|
||||||
|
);
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.reattach_bend(recorder, bend.into(), Some(inner));
|
||||||
|
|
||||||
self.fail_and_remove_if_infringes_except(bend.into(), infringables)?;
|
self.fail_and_remove_if_infringes_except(recorder, bend.into(), infringables)?;
|
||||||
Ok(bend)
|
Ok(bend)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn flip_bend(&mut self, bend: FixedBendIndex) {
|
pub fn flip_bend(&mut self, recorder: &mut DrawingEdit<CW>, bend: FixedBendIndex) {
|
||||||
self.geometry_with_rtree.flip_bend(bend.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.flip_bend(recorder, bend.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count())
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count())
|
||||||
|| self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() - 1)
|
|| self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() - 1)
|
||||||
|| self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 1))]
|
|| self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 1))]
|
||||||
fn reattach_bend(&mut self, bend: LooseBendIndex, maybe_new_inner: Option<LooseBendIndex>) {
|
fn reattach_bend(
|
||||||
self.geometry_with_rtree
|
&mut self,
|
||||||
.reattach_bend(bend.into(), maybe_new_inner.map(Into::into));
|
recorder: &mut DrawingEdit<CW>,
|
||||||
|
bend: LooseBendIndex,
|
||||||
|
maybe_new_inner: Option<LooseBendIndex>,
|
||||||
|
) {
|
||||||
|
self.recording_geometry_with_rtree.reattach_bend(
|
||||||
|
recorder,
|
||||||
|
bend.into(),
|
||||||
|
maybe_new_inner.map(Into::into),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 4))]
|
||||||
|
|
@ -394,6 +468,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn insert_cane(
|
pub fn insert_cane(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
around: GearIndex,
|
around: GearIndex,
|
||||||
dot_weight: LooseDotWeight,
|
dot_weight: LooseDotWeight,
|
||||||
|
|
@ -403,6 +478,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
) -> Result<Cane, DrawingException> {
|
) -> Result<Cane, DrawingException> {
|
||||||
let maybe_next_gear = around.ref_(self).next_gear();
|
let maybe_next_gear = around.ref_(self).next_gear();
|
||||||
let cane = self.add_cane_with_infringables(
|
let cane = self.add_cane_with_infringables(
|
||||||
|
recorder,
|
||||||
from,
|
from,
|
||||||
around,
|
around,
|
||||||
dot_weight,
|
dot_weight,
|
||||||
|
|
@ -413,13 +489,14 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(next_gear) = maybe_next_gear {
|
if let Some(next_gear) = maybe_next_gear {
|
||||||
self.reattach_bend(next_gear, Some(cane.bend));
|
self.reattach_bend(recorder, next_gear, Some(cane.bend));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(outer) = self.primitive(cane.bend).outer() {
|
if let Some(outer) = self.primitive(cane.bend).outer() {
|
||||||
self.update_this_and_outward_bows(outer).map_err(|err| {
|
self.update_this_and_outward_bows(recorder, outer)
|
||||||
|
.map_err(|err| {
|
||||||
let joint = self.primitive(cane.bend).other_joint(cane.dot);
|
let joint = self.primitive(cane.bend).other_joint(cane.dot);
|
||||||
self.remove_cane(&cane, joint);
|
self.remove_cane(recorder, &cane, joint);
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
@ -427,7 +504,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
// Segs must not cross.
|
// Segs must not cross.
|
||||||
if let Some(collision) = self.detect_collision(cane.seg.into()) {
|
if let Some(collision) = self.detect_collision(cane.seg.into()) {
|
||||||
let joint = self.primitive(cane.bend).other_joint(cane.dot);
|
let joint = self.primitive(cane.bend).other_joint(cane.dot);
|
||||||
self.remove_cane(&cane, joint);
|
self.remove_cane(recorder, &cane, joint);
|
||||||
Err(collision.into())
|
Err(collision.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(cane)
|
Ok(cane)
|
||||||
|
|
@ -438,6 +515,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn update_this_and_outward_bows(
|
fn update_this_and_outward_bows(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
around: LooseBendIndex,
|
around: LooseBendIndex,
|
||||||
) -> Result<(), DrawingException> {
|
) -> Result<(), DrawingException> {
|
||||||
// FIXME: Fail gracefully on infringement.
|
// FIXME: Fail gracefully on infringement.
|
||||||
|
|
@ -475,17 +553,20 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
|
recorder,
|
||||||
joints.0.into(),
|
joints.0.into(),
|
||||||
from,
|
from,
|
||||||
Some(&self.collect().bend_outer_bows(rail)),
|
Some(&self.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
|
recorder,
|
||||||
joints.1.into(),
|
joints.1.into(),
|
||||||
to,
|
to,
|
||||||
Some(&self.collect().bend_outer_bows(rail)),
|
Some(&self.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.shift_bend_with_infringables(
|
self.shift_bend_with_infringables(
|
||||||
|
recorder,
|
||||||
rail.into(),
|
rail.into(),
|
||||||
offset,
|
offset,
|
||||||
Some(&self.collect().bend_outer_bows(rail)),
|
Some(&self.collect().bend_outer_bows(rail)),
|
||||||
|
|
@ -517,17 +598,20 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
|
recorder,
|
||||||
joints.0.into(),
|
joints.0.into(),
|
||||||
from,
|
from,
|
||||||
Some(&self.collect().bend_outer_bows(rail)),
|
Some(&self.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
|
recorder,
|
||||||
joints.1.into(),
|
joints.1.into(),
|
||||||
to,
|
to,
|
||||||
Some(&self.collect().bend_outer_bows(rail)),
|
Some(&self.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.shift_bend_with_infringables(
|
self.shift_bend_with_infringables(
|
||||||
|
recorder,
|
||||||
rail.into(),
|
rail.into(),
|
||||||
offset,
|
offset,
|
||||||
Some(&self.collect().bend_outer_bows(rail)),
|
Some(&self.collect().bend_outer_bows(rail)),
|
||||||
|
|
@ -546,6 +630,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn add_cane(
|
pub fn add_cane(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
around: GearIndex,
|
around: GearIndex,
|
||||||
dot_weight: LooseDotWeight,
|
dot_weight: LooseDotWeight,
|
||||||
|
|
@ -554,6 +639,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
cw: bool,
|
cw: bool,
|
||||||
) -> Result<Cane, DrawingException> {
|
) -> Result<Cane, DrawingException> {
|
||||||
self.add_cane_with_infringables(
|
self.add_cane_with_infringables(
|
||||||
|
recorder,
|
||||||
from,
|
from,
|
||||||
around,
|
around,
|
||||||
dot_weight,
|
dot_weight,
|
||||||
|
|
@ -570,6 +656,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn add_cane_with_infringables(
|
fn add_cane_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
around: GearIndex,
|
around: GearIndex,
|
||||||
dot_weight: LooseDotWeight,
|
dot_weight: LooseDotWeight,
|
||||||
|
|
@ -578,30 +665,43 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
cw: bool,
|
cw: bool,
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<Cane, DrawingException> {
|
) -> Result<Cane, DrawingException> {
|
||||||
let seg_to = self.add_dot_with_infringables(dot_weight, infringables)?;
|
let seg_to = self.add_dot_with_infringables(recorder, dot_weight, infringables)?;
|
||||||
let seg = self
|
let seg = self
|
||||||
.add_seg_with_infringables(from, seg_to.into(), seg_weight, infringables)
|
.add_seg_with_infringables(recorder, from, seg_to.into(), seg_weight, infringables)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
self.geometry_with_rtree.remove_dot(seg_to.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_dot(recorder, seg_to.into());
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let to = self
|
let to = self
|
||||||
.add_dot_with_infringables(dot_weight, infringables)
|
.add_dot_with_infringables(recorder, dot_weight, infringables)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
self.geometry_with_rtree.remove_seg(seg.into());
|
self.recording_geometry_with_rtree
|
||||||
self.geometry_with_rtree.remove_dot(seg_to.into());
|
.remove_seg(recorder, seg.into());
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_dot(recorder, seg_to.into());
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) };
|
let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) };
|
||||||
|
|
||||||
let bend = self
|
let bend = self
|
||||||
.add_loose_bend_with_infringables(bend_from, bend_to, around, bend_weight, infringables)
|
.add_loose_bend_with_infringables(
|
||||||
|
recorder,
|
||||||
|
bend_from,
|
||||||
|
bend_to,
|
||||||
|
around,
|
||||||
|
bend_weight,
|
||||||
|
infringables,
|
||||||
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
self.geometry_with_rtree.remove_dot(to.into());
|
self.recording_geometry_with_rtree
|
||||||
self.geometry_with_rtree.remove_seg(seg.into());
|
.remove_dot(recorder, to.into());
|
||||||
self.geometry_with_rtree.remove_dot(seg_to.into());
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_seg(recorder, seg.into());
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_dot(recorder, seg_to.into());
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|
@ -613,25 +713,34 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 4))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 4))]
|
||||||
pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) {
|
pub fn remove_cane(
|
||||||
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
|
cane: &Cane,
|
||||||
|
face: LooseDotIndex,
|
||||||
|
) {
|
||||||
let maybe_outer = self.primitive(cane.bend).outer();
|
let maybe_outer = self.primitive(cane.bend).outer();
|
||||||
|
|
||||||
// Removing a loose bend affects its outer bends.
|
// Removing a loose bend affects its outer bends.
|
||||||
if let Some(outer) = maybe_outer {
|
if let Some(outer) = maybe_outer {
|
||||||
self.reattach_bend(outer, self.primitive(cane.bend).inner());
|
self.reattach_bend(recorder, outer, self.primitive(cane.bend).inner());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.geometry_with_rtree.remove_bend(cane.bend.into());
|
self.recording_geometry_with_rtree
|
||||||
self.geometry_with_rtree.remove_seg(cane.seg.into());
|
.remove_bend(recorder, cane.bend.into());
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_seg(recorder, cane.seg.into());
|
||||||
|
|
||||||
// We must remove the dots only after the segs and bends because we need dots to calculate
|
// We must remove the dots only after the segs and bends because we need dots to calculate
|
||||||
// the shapes, which we first need unchanged to remove the segs and bends from the R-tree.
|
// the shapes, which we first need unchanged to remove the segs and bends from the R-tree.
|
||||||
|
|
||||||
self.geometry_with_rtree.remove_dot(face.into());
|
self.recording_geometry_with_rtree
|
||||||
self.geometry_with_rtree.remove_dot(cane.dot.into());
|
.remove_dot(recorder, face.into());
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_dot(recorder, cane.dot.into());
|
||||||
|
|
||||||
if let Some(outer) = maybe_outer {
|
if let Some(outer) = maybe_outer {
|
||||||
self.update_this_and_outward_bows(outer).unwrap(); // Must never fail.
|
self.update_this_and_outward_bows(recorder, outer).unwrap(); // Must never fail.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -641,10 +750,15 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> {
|
pub fn move_dot(
|
||||||
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
|
dot: DotIndex,
|
||||||
|
to: Point,
|
||||||
|
) -> Result<(), Infringement> {
|
||||||
match dot {
|
match dot {
|
||||||
DotIndex::Fixed(..) => self.move_dot_with_infringables(dot, to, Some(&[])),
|
DotIndex::Fixed(..) => self.move_dot_with_infringables(recorder, dot, to, Some(&[])),
|
||||||
DotIndex::Loose(..) => self.move_dot_with_infringables(dot, to, Some(&[])),
|
DotIndex::Loose(..) => self.move_dot_with_infringables(recorder, dot, to, Some(&[])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -652,24 +766,32 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn move_dot_with_infringables(
|
fn move_dot_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
dot: DotIndex,
|
dot: DotIndex,
|
||||||
to: Point,
|
to: Point,
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<(), Infringement> {
|
) -> Result<(), Infringement> {
|
||||||
let old_pos = self.geometry_with_rtree.geometry().dot_weight(dot).pos();
|
let old_pos = self
|
||||||
self.geometry_with_rtree.move_dot(dot, to);
|
.recording_geometry_with_rtree
|
||||||
|
.geometry()
|
||||||
|
.dot_weight(dot)
|
||||||
|
.pos();
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.move_dot(recorder, dot, to);
|
||||||
|
|
||||||
for limb in dot.primitive(self).limbs() {
|
for limb in dot.primitive(self).limbs() {
|
||||||
if let Some(infringement) = self.detect_infringement_except(limb, infringables) {
|
if let Some(infringement) = self.detect_infringement_except(limb, infringables) {
|
||||||
// Restore original state.
|
// Restore original state.
|
||||||
self.geometry_with_rtree.move_dot(dot, old_pos);
|
self.recording_geometry_with_rtree
|
||||||
|
.move_dot(recorder, dot, old_pos);
|
||||||
return Err(infringement);
|
return Err(infringement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) {
|
if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) {
|
||||||
// Restore original state.
|
// Restore original state.
|
||||||
self.geometry_with_rtree.move_dot(dot, old_pos);
|
self.recording_geometry_with_rtree
|
||||||
|
.move_dot(recorder, dot, old_pos);
|
||||||
return Err(infringement);
|
return Err(infringement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -680,20 +802,23 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn shift_bend_with_infringables(
|
fn shift_bend_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
bend: BendIndex,
|
bend: BendIndex,
|
||||||
offset: f64,
|
offset: f64,
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<(), Infringement> {
|
) -> Result<(), Infringement> {
|
||||||
let old_offset = self
|
let old_offset = self
|
||||||
.geometry_with_rtree
|
.recording_geometry_with_rtree
|
||||||
.geometry()
|
.geometry()
|
||||||
.bend_weight(bend)
|
.bend_weight(bend)
|
||||||
.offset();
|
.offset();
|
||||||
self.geometry_with_rtree.shift_bend(bend, offset);
|
self.recording_geometry_with_rtree
|
||||||
|
.shift_bend(recorder, bend, offset);
|
||||||
|
|
||||||
if let Some(infringement) = self.detect_infringement_except(bend.into(), infringables) {
|
if let Some(infringement) = self.detect_infringement_except(bend.into(), infringables) {
|
||||||
// Restore original state.
|
// Restore original state.
|
||||||
self.geometry_with_rtree.shift_bend(bend, old_offset);
|
self.recording_geometry_with_rtree
|
||||||
|
.shift_bend(recorder, bend, old_offset);
|
||||||
return Err(infringement);
|
return Err(infringement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -703,7 +828,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
fn detect_collision(&self, node: PrimitiveIndex) -> Option<Collision> {
|
fn detect_collision(&self, node: PrimitiveIndex) -> Option<Collision> {
|
||||||
let shape = node.primitive(self).shape();
|
let shape = node.primitive(self).shape();
|
||||||
|
|
||||||
self.geometry_with_rtree
|
self.recording_geometry_with_rtree
|
||||||
.rtree()
|
.rtree()
|
||||||
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
|
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
|
||||||
.filter_map(|wrapper| {
|
.filter_map(|wrapper| {
|
||||||
|
|
@ -724,18 +849,20 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
fn add_dot_infringably<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
|
fn add_dot_infringably<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
weight: W,
|
weight: W,
|
||||||
) -> GenericIndex<W>
|
) -> GenericIndex<W>
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
GenericIndex<W>: Into<PrimitiveIndex> + Copy,
|
||||||
{
|
{
|
||||||
self.geometry_with_rtree.add_dot(weight)
|
self.recording_geometry_with_rtree.add_dot(recorder, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count() + 2))]
|
||||||
fn add_seg_infringably<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
|
fn add_seg_infringably<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
to: DotIndex,
|
to: DotIndex,
|
||||||
weight: W,
|
weight: W,
|
||||||
|
|
@ -743,7 +870,28 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PrimitiveIndex>,
|
GenericIndex<W>: Into<PrimitiveIndex>,
|
||||||
{
|
{
|
||||||
self.geometry_with_rtree.add_seg(from, to, weight)
|
self.recording_geometry_with_rtree
|
||||||
|
.add_seg(recorder, from, to, weight)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_compound(&mut self, recorder: &mut DrawingEdit<CW>, weight: CW) -> GenericIndex<CW> {
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.add_compound(recorder, weight)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_compound(&mut self, recorder: &mut DrawingEdit<CW>, compound: GenericIndex<CW>) {
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_compound(recorder, compound);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_to_compound<W>(
|
||||||
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
|
primitive: GenericIndex<W>,
|
||||||
|
compound: GenericIndex<CW>,
|
||||||
|
) {
|
||||||
|
self.recording_geometry_with_rtree
|
||||||
|
.add_to_compound(recorder, primitive, compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(ret.is_ok() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
|
|
@ -751,16 +899,18 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))]
|
#[debug_ensures(ret.is_err() -> self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))]
|
||||||
fn fail_and_remove_if_infringes_except(
|
fn fail_and_remove_if_infringes_except(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut DrawingEdit<CW>,
|
||||||
node: PrimitiveIndex,
|
node: PrimitiveIndex,
|
||||||
maybe_except: Option<&[PrimitiveIndex]>,
|
maybe_except: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<(), Infringement> {
|
) -> Result<(), Infringement> {
|
||||||
if let Some(infringement) = self.detect_infringement_except(node, maybe_except) {
|
if let Some(infringement) = self.detect_infringement_except(node, maybe_except) {
|
||||||
if let Ok(dot) = node.try_into() {
|
if let Ok(dot) = node.try_into() {
|
||||||
self.geometry_with_rtree.remove_dot(dot);
|
self.recording_geometry_with_rtree.remove_dot(recorder, dot);
|
||||||
} else if let Ok(seg) = node.try_into() {
|
} else if let Ok(seg) = node.try_into() {
|
||||||
self.geometry_with_rtree.remove_seg(seg);
|
self.recording_geometry_with_rtree.remove_seg(recorder, seg);
|
||||||
} else if let Ok(bend) = node.try_into() {
|
} else if let Ok(bend) = node.try_into() {
|
||||||
self.geometry_with_rtree.remove_bend(bend);
|
self.recording_geometry_with_rtree
|
||||||
|
.remove_bend(recorder, bend);
|
||||||
}
|
}
|
||||||
return Err(infringement);
|
return Err(infringement);
|
||||||
}
|
}
|
||||||
|
|
@ -799,7 +949,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
.unwrap_or(0.0),
|
.unwrap_or(0.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.geometry_with_rtree
|
self.recording_geometry_with_rtree
|
||||||
.rtree()
|
.rtree()
|
||||||
.locate_in_envelope_intersecting(
|
.locate_in_envelope_intersecting(
|
||||||
&limiting_shape.envelope_3d(0.0, node.primitive(self).layer()),
|
&limiting_shape.envelope_3d(0.0, node.primitive(self).layer()),
|
||||||
|
|
@ -832,7 +982,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primitive_nodes(&self) -> impl Iterator<Item = PrimitiveIndex> + '_ {
|
pub fn primitive_nodes(&self) -> impl Iterator<Item = PrimitiveIndex> + '_ {
|
||||||
self.geometry_with_rtree
|
self.recording_geometry_with_rtree
|
||||||
.rtree()
|
.rtree()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|wrapper| {
|
.filter_map(|wrapper| {
|
||||||
|
|
@ -845,7 +995,7 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layer_primitive_nodes(&self, layer: usize) -> impl Iterator<Item = PrimitiveIndex> + '_ {
|
pub fn layer_primitive_nodes(&self, layer: usize) -> impl Iterator<Item = PrimitiveIndex> + '_ {
|
||||||
self.geometry_with_rtree
|
self.recording_geometry_with_rtree
|
||||||
.rtree()
|
.rtree()
|
||||||
.locate_in_envelope_intersecting(&AABB::from_corners(
|
.locate_in_envelope_intersecting(&AABB::from_corners(
|
||||||
[-f64::INFINITY, -f64::INFINITY, layer as f64],
|
[-f64::INFINITY, -f64::INFINITY, layer as f64],
|
||||||
|
|
@ -860,6 +1010,17 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
|
||||||
|
self.recording_geometry_with_rtree.compound_weight(compound)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compounds<'a, W: 'a>(
|
||||||
|
&'a self,
|
||||||
|
node: GenericIndex<W>,
|
||||||
|
) -> impl Iterator<Item = GenericIndex<CW>> + 'a {
|
||||||
|
self.recording_geometry_with_rtree.compounds(node)
|
||||||
|
}
|
||||||
|
|
||||||
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
|
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
|
||||||
if let (Some(node1_net_id), Some(node2_net_id)) = (
|
if let (Some(node1_net_id), Some(node2_net_id)) = (
|
||||||
node1.primitive(self).maybe_net(),
|
node1.primitive(self).maybe_net(),
|
||||||
|
|
@ -884,11 +1045,11 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
SegIndex,
|
SegIndex,
|
||||||
BendIndex,
|
BendIndex,
|
||||||
> {
|
> {
|
||||||
self.geometry_with_rtree.geometry()
|
self.recording_geometry_with_rtree.geometry()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PrimitiveIndex, GenericIndex<CW>>>> {
|
pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PrimitiveIndex, GenericIndex<CW>>>> {
|
||||||
self.geometry_with_rtree.rtree()
|
self.recording_geometry_with_rtree.rtree()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
|
|
@ -914,11 +1075,11 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layer_count(&self) -> usize {
|
pub fn layer_count(&self) -> usize {
|
||||||
*self.geometry_with_rtree.layer_count()
|
self.recording_geometry_with_rtree.layer_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node_count(&self) -> usize {
|
pub fn node_count(&self) -> usize {
|
||||||
self.geometry_with_rtree.graph().node_count()
|
self.recording_geometry_with_rtree.graph().node_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_if_looses_dont_infringe_each_other(&self) -> bool {
|
fn test_if_looses_dont_infringe_each_other(&self) -> bool {
|
||||||
|
|
@ -958,26 +1119,3 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CW: Copy, R: AccessRules> ManageCompounds<CW, GenericIndex<CW>> for Drawing<CW, R> {
|
|
||||||
fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> {
|
|
||||||
self.geometry_with_rtree.add_compound(weight)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_compound(&mut self, compound: GenericIndex<CW>) {
|
|
||||||
self.geometry_with_rtree.remove_compound(compound);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_to_compound<W>(&mut self, primitive: GenericIndex<W>, compound: GenericIndex<CW>) {
|
|
||||||
self.geometry_with_rtree
|
|
||||||
.add_to_compound(primitive, compound);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
|
|
||||||
self.geometry_with_rtree.compound_weight(compound)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compounds<W>(&self, node: GenericIndex<W>) -> impl Iterator<Item = GenericIndex<CW>> {
|
|
||||||
self.geometry_with_rtree.compounds(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum SegIndex {
|
pub enum SegIndex {
|
||||||
Fixed(FixedSegIndex),
|
Fixed(FixedSegIndex),
|
||||||
LoneLoose(LoneLooseSegIndex),
|
LoneLoose(LoneLooseSegIndex),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use std::{collections::HashMap, hash::Hash, marker::PhantomData};
|
||||||
|
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
use petgraph::stable_graph::StableDiGraph;
|
use petgraph::stable_graph::StableDiGraph;
|
||||||
|
use rstar::RTree;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing::graph::{GetLayer, Retag},
|
drawing::graph::{GetLayer, Retag},
|
||||||
|
|
@ -9,10 +10,13 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
compound::ManageCompounds, with_rtree::GeometryWithRtree, AccessBendWeight, AccessDotWeight,
|
compound::ManageCompounds,
|
||||||
AccessSegWeight, GenericNode, GeometryLabel, GetWidth,
|
with_rtree::{BboxedIndex, GeometryWithRtree},
|
||||||
|
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
||||||
|
GetWidth,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct GeometryEdit<
|
pub struct GeometryEdit<
|
||||||
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||||
DW: AccessDotWeight<PW> + GetLayer,
|
DW: AccessDotWeight<PW> + GetLayer,
|
||||||
|
|
@ -31,6 +35,30 @@ pub struct GeometryEdit<
|
||||||
primitive_weight_marker: PhantomData<PW>,
|
primitive_weight_marker: PhantomData<PW>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||||
|
DW: AccessDotWeight<PW> + GetLayer,
|
||||||
|
SW: AccessSegWeight<PW> + GetLayer,
|
||||||
|
BW: AccessBendWeight<PW> + GetLayer,
|
||||||
|
CW: Copy,
|
||||||
|
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Hash + Copy,
|
||||||
|
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||||
|
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||||
|
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||||
|
> GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
||||||
|
{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
dots: HashMap::new(),
|
||||||
|
segs: HashMap::new(),
|
||||||
|
bends: HashMap::new(),
|
||||||
|
compounds: HashMap::new(),
|
||||||
|
primitive_weight_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct RecordingGeometryWithRtree<
|
pub struct RecordingGeometryWithRtree<
|
||||||
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||||
DW: AccessDotWeight<PW> + GetLayer,
|
DW: AccessDotWeight<PW> + GetLayer,
|
||||||
|
|
@ -57,6 +85,14 @@ impl<
|
||||||
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||||
> RecordingGeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
> RecordingGeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
||||||
{
|
{
|
||||||
|
pub fn new(layer_count: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
geometry_with_rtree: GeometryWithRtree::<PW, DW, SW, BW, CW, PI, DI, SI, BI>::new(
|
||||||
|
layer_count,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(
|
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||||
|
|
@ -349,6 +385,18 @@ impl<
|
||||||
self.geometry_with_rtree.compounds(node)
|
self.geometry_with_rtree.compounds(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn geometry(&self) -> &Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
||||||
|
self.geometry_with_rtree.geometry()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PI, GenericIndex<CW>>>> {
|
||||||
|
self.geometry_with_rtree.rtree()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn layer_count(&self) -> usize {
|
||||||
|
*self.geometry_with_rtree.layer_count()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel, usize> {
|
pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel, usize> {
|
||||||
self.geometry_with_rtree.graph()
|
self.geometry_with_rtree.graph()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ use crate::{
|
||||||
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex,
|
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex,
|
||||||
SeqLooseSegWeight,
|
SeqLooseSegWeight,
|
||||||
},
|
},
|
||||||
Drawing, DrawingException, Infringement,
|
Drawing, DrawingEdit, DrawingException, Infringement,
|
||||||
},
|
},
|
||||||
geometry::{compound::ManageCompounds, GenericNode},
|
geometry::GenericNode,
|
||||||
graph::{GenericIndex, GetPetgraphIndex},
|
graph::{GenericIndex, GetPetgraphIndex},
|
||||||
layout::{
|
layout::{
|
||||||
poly::{Poly, PolyWeight},
|
poly::{Poly, PolyWeight},
|
||||||
|
|
@ -39,6 +39,7 @@ pub enum CompoundWeight {
|
||||||
|
|
||||||
/// The alias to differ node types
|
/// The alias to differ node types
|
||||||
pub type NodeIndex = GenericNode<PrimitiveIndex, GenericIndex<CompoundWeight>>;
|
pub type NodeIndex = GenericNode<PrimitiveIndex, GenericIndex<CompoundWeight>>;
|
||||||
|
pub type LayoutEdit = DrawingEdit<CompoundWeight>;
|
||||||
|
|
||||||
#[derive(Debug, Getters)]
|
#[derive(Debug, Getters)]
|
||||||
/// Structure for managing the Layout design
|
/// Structure for managing the Layout design
|
||||||
|
|
@ -54,6 +55,7 @@ impl<R: AccessRules> Layout<R> {
|
||||||
/// Insert [`Cane`] object into the [`Layout`]
|
/// Insert [`Cane`] object into the [`Layout`]
|
||||||
pub fn insert_cane(
|
pub fn insert_cane(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
around: GearIndex,
|
around: GearIndex,
|
||||||
dot_weight: LooseDotWeight,
|
dot_weight: LooseDotWeight,
|
||||||
|
|
@ -61,39 +63,53 @@ impl<R: AccessRules> Layout<R> {
|
||||||
bend_weight: LooseBendWeight,
|
bend_weight: LooseBendWeight,
|
||||||
cw: bool,
|
cw: bool,
|
||||||
) -> Result<Cane, DrawingException> {
|
) -> Result<Cane, DrawingException> {
|
||||||
self.drawing
|
self.drawing.insert_cane(
|
||||||
.insert_cane(from, around, dot_weight, seg_weight, bend_weight, cw)
|
recorder,
|
||||||
|
from,
|
||||||
|
around,
|
||||||
|
dot_weight,
|
||||||
|
seg_weight,
|
||||||
|
bend_weight,
|
||||||
|
cw,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove [`Cane`] object from the [`Layout`]
|
/// Remove [`Cane`] object from the [`Layout`]
|
||||||
pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) {
|
pub fn remove_cane(&mut self, recorder: &mut LayoutEdit, cane: &Cane, face: LooseDotIndex) {
|
||||||
self.drawing.remove_cane(cane, face)
|
self.drawing.remove_cane(recorder, cane, face)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.node_count() == old(self.drawing.node_count()) + weight.to_layer - weight.from_layer + 2)]
|
#[debug_ensures(ret.is_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()))]
|
#[debug_ensures(ret.is_err() -> self.drawing.node_count() == old(self.drawing.node_count()))]
|
||||||
/// Insert [`Via`] into the [`Layout`]
|
/// Insert [`Via`] into the [`Layout`]
|
||||||
pub fn add_via(&mut self, weight: ViaWeight) -> Result<GenericIndex<ViaWeight>, Infringement> {
|
pub fn add_via(
|
||||||
let compound = self.drawing.add_compound(weight.into());
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
|
weight: ViaWeight,
|
||||||
|
) -> Result<GenericIndex<ViaWeight>, Infringement> {
|
||||||
|
let compound = self.drawing.add_compound(recorder, weight.into());
|
||||||
let mut dots = vec![];
|
let mut dots = vec![];
|
||||||
|
|
||||||
for layer in weight.from_layer..=weight.to_layer {
|
for layer in weight.from_layer..=weight.to_layer {
|
||||||
match self.drawing.add_fixed_dot(FixedDotWeight {
|
match self.drawing.add_fixed_dot(
|
||||||
|
recorder,
|
||||||
|
FixedDotWeight {
|
||||||
circle: weight.circle,
|
circle: weight.circle,
|
||||||
layer,
|
layer,
|
||||||
maybe_net: weight.maybe_net,
|
maybe_net: weight.maybe_net,
|
||||||
}) {
|
},
|
||||||
|
) {
|
||||||
Ok(dot) => {
|
Ok(dot) => {
|
||||||
self.drawing.add_to_compound(dot, compound);
|
self.drawing.add_to_compound(recorder, dot, compound);
|
||||||
dots.push(dot);
|
dots.push(dot);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// Remove inserted dots.
|
// Remove inserted dots.
|
||||||
|
|
||||||
self.drawing.remove_compound(compound);
|
self.drawing.remove_compound(recorder, compound);
|
||||||
|
|
||||||
for dot in dots.iter().rev() {
|
for dot in dots.iter().rev() {
|
||||||
self.drawing.remove_fixed_dot(*dot);
|
self.drawing.remove_fixed_dot(recorder, *dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
|
|
@ -104,24 +120,32 @@ impl<R: AccessRules> Layout<R> {
|
||||||
Ok(GenericIndex::<ViaWeight>::new(compound.petgraph_index()))
|
Ok(GenericIndex::<ViaWeight>::new(compound.petgraph_index()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_fixed_dot(
|
||||||
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> {
|
&mut self,
|
||||||
self.drawing.add_fixed_dot(weight)
|
recorder: &mut LayoutEdit,
|
||||||
|
weight: FixedDotWeight,
|
||||||
|
) -> Result<FixedDotIndex, Infringement> {
|
||||||
|
self.drawing.add_fixed_dot(recorder, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex {
|
pub fn add_fixed_dot_infringably(
|
||||||
self.drawing.add_fixed_dot_infringably(weight)
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
|
weight: FixedDotWeight,
|
||||||
|
) -> FixedDotIndex {
|
||||||
|
self.drawing.add_fixed_dot_infringably(recorder, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_poly_fixed_dot(
|
pub fn add_poly_fixed_dot(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
weight: FixedDotWeight,
|
weight: FixedDotWeight,
|
||||||
poly: GenericIndex<PolyWeight>,
|
poly: GenericIndex<PolyWeight>,
|
||||||
) -> Result<FixedDotIndex, Infringement> {
|
) -> Result<FixedDotIndex, Infringement> {
|
||||||
let maybe_dot = self.drawing.add_fixed_dot(weight);
|
let maybe_dot = self.drawing.add_fixed_dot(recorder, weight);
|
||||||
|
|
||||||
if let Ok(dot) = maybe_dot {
|
if let Ok(dot) = maybe_dot {
|
||||||
self.drawing.add_to_compound(dot, poly.into());
|
self.drawing.add_to_compound(recorder, dot, poly.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_dot
|
maybe_dot
|
||||||
|
|
@ -129,43 +153,48 @@ impl<R: AccessRules> Layout<R> {
|
||||||
|
|
||||||
pub fn add_poly_fixed_dot_infringably(
|
pub fn add_poly_fixed_dot_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
weight: FixedDotWeight,
|
weight: FixedDotWeight,
|
||||||
poly: GenericIndex<PolyWeight>,
|
poly: GenericIndex<PolyWeight>,
|
||||||
) -> FixedDotIndex {
|
) -> FixedDotIndex {
|
||||||
let dot = self.drawing.add_fixed_dot_infringably(weight);
|
let dot = self.drawing.add_fixed_dot_infringably(recorder, weight);
|
||||||
self.drawing.add_to_compound(dot, poly.into());
|
self.drawing.add_to_compound(recorder, dot, poly.into());
|
||||||
dot
|
dot
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_fixed_seg(
|
pub fn add_fixed_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
) -> Result<FixedSegIndex, Infringement> {
|
) -> Result<FixedSegIndex, Infringement> {
|
||||||
self.drawing.add_fixed_seg(from, to, weight)
|
self.drawing.add_fixed_seg(recorder, from, to, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_fixed_seg_infringably(
|
pub fn add_fixed_seg_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
) -> FixedSegIndex {
|
) -> FixedSegIndex {
|
||||||
self.drawing.add_fixed_seg_infringably(from, to, weight)
|
self.drawing
|
||||||
|
.add_fixed_seg_infringably(recorder, from, to, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_poly_fixed_seg(
|
pub fn add_poly_fixed_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
poly: GenericIndex<PolyWeight>,
|
poly: GenericIndex<PolyWeight>,
|
||||||
) -> Result<FixedSegIndex, Infringement> {
|
) -> Result<FixedSegIndex, Infringement> {
|
||||||
let maybe_seg = self.add_fixed_seg(from, to, weight);
|
let maybe_seg = self.add_fixed_seg(recorder, from, to, weight);
|
||||||
|
|
||||||
if let Ok(seg) = maybe_seg {
|
if let Ok(seg) = maybe_seg {
|
||||||
self.drawing.add_to_compound(seg, poly.into());
|
self.drawing.add_to_compound(recorder, seg, poly.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_seg
|
maybe_seg
|
||||||
|
|
@ -173,48 +202,64 @@ impl<R: AccessRules> Layout<R> {
|
||||||
|
|
||||||
pub fn add_poly_fixed_seg_infringably(
|
pub fn add_poly_fixed_seg_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: FixedSegWeight,
|
weight: FixedSegWeight,
|
||||||
poly: GenericIndex<PolyWeight>,
|
poly: GenericIndex<PolyWeight>,
|
||||||
) -> FixedSegIndex {
|
) -> FixedSegIndex {
|
||||||
let seg = self.add_fixed_seg_infringably(from, to, weight);
|
let seg = self.add_fixed_seg_infringably(recorder, from, to, weight);
|
||||||
self.drawing.add_to_compound(seg, poly.into());
|
self.drawing.add_to_compound(recorder, seg, poly.into());
|
||||||
seg
|
seg
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_lone_loose_seg(
|
pub fn add_lone_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
to: FixedDotIndex,
|
to: FixedDotIndex,
|
||||||
weight: LoneLooseSegWeight,
|
weight: LoneLooseSegWeight,
|
||||||
) -> Result<LoneLooseSegIndex, Infringement> {
|
) -> Result<LoneLooseSegIndex, Infringement> {
|
||||||
self.drawing.add_lone_loose_seg(from, to, weight)
|
self.drawing.add_lone_loose_seg(recorder, from, to, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_seq_loose_seg(
|
pub fn add_seq_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
to: LooseDotIndex,
|
to: LooseDotIndex,
|
||||||
weight: SeqLooseSegWeight,
|
weight: SeqLooseSegWeight,
|
||||||
) -> Result<SeqLooseSegIndex, Infringement> {
|
) -> Result<SeqLooseSegIndex, Infringement> {
|
||||||
self.drawing.add_seq_loose_seg(from, to, weight)
|
self.drawing.add_seq_loose_seg(recorder, from, to, weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> {
|
pub fn move_dot(
|
||||||
self.drawing.move_dot(dot, to)
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
|
dot: DotIndex,
|
||||||
|
to: Point,
|
||||||
|
) -> Result<(), Infringement> {
|
||||||
|
self.drawing.move_dot(recorder, dot, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_poly(&mut self, weight: PolyWeight) -> GenericIndex<PolyWeight> {
|
pub fn add_poly(
|
||||||
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
|
weight: PolyWeight,
|
||||||
|
) -> GenericIndex<PolyWeight> {
|
||||||
GenericIndex::<PolyWeight>::new(
|
GenericIndex::<PolyWeight>::new(
|
||||||
self.drawing
|
self.drawing
|
||||||
.add_compound(CompoundWeight::Poly(weight))
|
.add_compound(recorder, CompoundWeight::Poly(weight))
|
||||||
.petgraph_index(),
|
.petgraph_index(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> {
|
pub fn remove_band(
|
||||||
self.drawing.remove_band(band)
|
&mut self,
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
|
band: BandTermsegIndex,
|
||||||
|
) -> Result<(), DrawingException> {
|
||||||
|
self.drawing.remove_band(recorder, band)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn polys<W: 'static>(
|
pub fn polys<W: 'static>(
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
rules::AccessRules,
|
rules::AccessRules,
|
||||||
seg::SegIndex,
|
seg::SegIndex,
|
||||||
},
|
},
|
||||||
geometry::{compound::ManageCompounds, poly::PolyShape, GetPos},
|
geometry::{poly::PolyShape, GetPos},
|
||||||
graph::{GenericIndex, GetPetgraphIndex},
|
graph::{GenericIndex, GetPetgraphIndex},
|
||||||
layout::{CompoundWeight, Layout},
|
layout::{CompoundWeight, Layout},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing::{graph::GetMaybeNet, primitive::MakePrimitiveShape, rules::AccessRules},
|
drawing::{graph::GetMaybeNet, primitive::MakePrimitiveShape, rules::AccessRules},
|
||||||
geometry::{
|
geometry::primitive::{DotShape, PrimitiveShape},
|
||||||
compound::ManageCompounds,
|
|
||||||
primitive::{DotShape, PrimitiveShape},
|
|
||||||
},
|
|
||||||
graph::{GenericIndex, GetPetgraphIndex},
|
graph::{GenericIndex, GetPetgraphIndex},
|
||||||
layout::{CompoundWeight, Layout},
|
layout::{CompoundWeight, Layout},
|
||||||
math::Circle,
|
math::Circle,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
seg::{LoneLooseSegWeight, SeqLooseSegWeight},
|
seg::{LoneLooseSegWeight, SeqLooseSegWeight},
|
||||||
DrawingException, Infringement,
|
DrawingException, Infringement,
|
||||||
},
|
},
|
||||||
layout::Layout,
|
layout::{Layout, LayoutEdit},
|
||||||
math::{Circle, NoTangents},
|
math::{Circle, NoTangents},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -66,6 +66,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
|
||||||
DotIndex::Fixed(dot) => BandTermsegIndex::Straight(
|
DotIndex::Fixed(dot) => BandTermsegIndex::Straight(
|
||||||
self.layout
|
self.layout
|
||||||
.add_lone_loose_seg(
|
.add_lone_loose_seg(
|
||||||
|
&mut LayoutEdit::new(),
|
||||||
dot,
|
dot,
|
||||||
into,
|
into,
|
||||||
LoneLooseSegWeight {
|
LoneLooseSegWeight {
|
||||||
|
|
@ -79,6 +80,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
|
||||||
DotIndex::Loose(dot) => BandTermsegIndex::Bended(
|
DotIndex::Loose(dot) => BandTermsegIndex::Bended(
|
||||||
self.layout
|
self.layout
|
||||||
.add_seq_loose_seg(
|
.add_seq_loose_seg(
|
||||||
|
&mut LayoutEdit::new(),
|
||||||
into.into(),
|
into.into(),
|
||||||
dot,
|
dot,
|
||||||
SeqLooseSegWeight {
|
SeqLooseSegWeight {
|
||||||
|
|
@ -164,7 +166,8 @@ impl<'a, R: AccessRules> Draw<'a, R> {
|
||||||
#[debug_ensures(self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))]
|
#[debug_ensures(self.layout.drawing().node_count() == old(self.layout.drawing().node_count()))]
|
||||||
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, Infringement> {
|
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, Infringement> {
|
||||||
if let Head::Cane(head) = head {
|
if let Head::Cane(head) = head {
|
||||||
self.layout.move_dot(head.face.into(), to)?;
|
self.layout
|
||||||
|
.move_dot(&mut LayoutEdit::new(), head.face.into(), to)?;
|
||||||
Ok(Head::Cane(head))
|
Ok(Head::Cane(head))
|
||||||
} else {
|
} else {
|
||||||
Ok(head)
|
Ok(head)
|
||||||
|
|
@ -185,6 +188,7 @@ impl<'a, R: AccessRules> Draw<'a, R> {
|
||||||
let layer = head.face().primitive(self.layout.drawing()).layer();
|
let layer = head.face().primitive(self.layout.drawing()).layer();
|
||||||
let maybe_net = head.face().primitive(self.layout.drawing()).maybe_net();
|
let maybe_net = head.face().primitive(self.layout.drawing()).maybe_net();
|
||||||
let cane = self.layout.insert_cane(
|
let cane = self.layout.insert_cane(
|
||||||
|
&mut LayoutEdit::new(),
|
||||||
head.face(),
|
head.face(),
|
||||||
around,
|
around,
|
||||||
LooseDotWeight {
|
LooseDotWeight {
|
||||||
|
|
@ -227,7 +231,8 @@ impl<'a, R: AccessRules> Draw<'a, R> {
|
||||||
.primitive(head.cane.seg)
|
.primitive(head.cane.seg)
|
||||||
.other_joint(head.cane.dot.into());
|
.other_joint(head.cane.dot.into());
|
||||||
|
|
||||||
self.layout.remove_cane(&head.cane, head.face);
|
self.layout
|
||||||
|
.remove_cane(&mut LayoutEdit::new(), &head.cane, head.face);
|
||||||
Some(self.guide().head(prev_dot))
|
Some(self.guide().head(prev_dot))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
Drawing,
|
Drawing,
|
||||||
},
|
},
|
||||||
geometry::{primitive::PrimitiveShape, GetWidth},
|
geometry::{primitive::PrimitiveShape, GetWidth},
|
||||||
layout::{poly::SolidPolyWeight, Layout},
|
layout::{poly::SolidPolyWeight, Layout, LayoutEdit},
|
||||||
math::{Circle, PointWithRotation},
|
math::{Circle, PointWithRotation},
|
||||||
specctra::{
|
specctra::{
|
||||||
mesadata::SpecctraMesadata,
|
mesadata::SpecctraMesadata,
|
||||||
|
|
@ -185,7 +185,7 @@ impl SpecctraDesign {
|
||||||
/// which is used for layout and routing operations. The board is initialized with [`SpecctraMesadata`],
|
/// which is used for layout and routing operations. The board is initialized with [`SpecctraMesadata`],
|
||||||
/// which includes layer and net mappings, and is populated with components, pins, vias, and wires
|
/// which includes layer and net mappings, and is populated with components, pins, vias, and wires
|
||||||
/// from the PCB definition.
|
/// from the PCB definition.
|
||||||
pub fn make_board(&self) -> Board<SpecctraMesadata> {
|
pub fn make_board(&self, recorder: &mut LayoutEdit) -> Board<SpecctraMesadata> {
|
||||||
let mesadata = SpecctraMesadata::from_pcb(&self.pcb);
|
let mesadata = SpecctraMesadata::from_pcb(&self.pcb);
|
||||||
let mut board = Board::new(Layout::new(Drawing::new(
|
let mut board = Board::new(Layout::new(Drawing::new(
|
||||||
mesadata,
|
mesadata,
|
||||||
|
|
@ -210,11 +210,7 @@ impl SpecctraDesign {
|
||||||
net_pin_assignments.pins.as_ref().and_then(|pins| {
|
net_pin_assignments.pins.as_ref().and_then(|pins| {
|
||||||
// take the list of pins
|
// take the list of pins
|
||||||
// and for each pin output (pin name, net id)
|
// and for each pin output (pin name, net id)
|
||||||
Some(pins
|
Some(pins.names.iter().map(move |pinname| (pinname.clone(), net)))
|
||||||
.names
|
|
||||||
.iter()
|
|
||||||
.map(move |pinname| (pinname.clone(), net))
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
// flatten the nested iters into a single stream of tuples
|
// flatten the nested iters into a single stream of tuples
|
||||||
|
|
@ -248,6 +244,7 @@ impl SpecctraDesign {
|
||||||
Shape::Circle(circle) => {
|
Shape::Circle(circle) => {
|
||||||
let layer = get_layer(&board, &circle.layer);
|
let layer = get_layer(&board, &circle.layer);
|
||||||
Self::add_circle(
|
Self::add_circle(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
place.point_with_rotation(),
|
place.point_with_rotation(),
|
||||||
pin.point_with_rotation(),
|
pin.point_with_rotation(),
|
||||||
|
|
@ -260,6 +257,7 @@ impl SpecctraDesign {
|
||||||
Shape::Rect(rect) => {
|
Shape::Rect(rect) => {
|
||||||
let layer = get_layer(&board, &rect.layer);
|
let layer = get_layer(&board, &rect.layer);
|
||||||
Self::add_rect(
|
Self::add_rect(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
place.point_with_rotation(),
|
place.point_with_rotation(),
|
||||||
pin.point_with_rotation(),
|
pin.point_with_rotation(),
|
||||||
|
|
@ -275,6 +273,7 @@ impl SpecctraDesign {
|
||||||
Shape::Path(path) => {
|
Shape::Path(path) => {
|
||||||
let layer = get_layer(&board, &path.layer);
|
let layer = get_layer(&board, &path.layer);
|
||||||
Self::add_path(
|
Self::add_path(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
place.point_with_rotation(),
|
place.point_with_rotation(),
|
||||||
pin.point_with_rotation(),
|
pin.point_with_rotation(),
|
||||||
|
|
@ -288,6 +287,7 @@ impl SpecctraDesign {
|
||||||
Shape::Polygon(polygon) => {
|
Shape::Polygon(polygon) => {
|
||||||
let layer = get_layer(&board, &polygon.layer);
|
let layer = get_layer(&board, &polygon.layer);
|
||||||
Self::add_polygon(
|
Self::add_polygon(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
place.point_with_rotation(),
|
place.point_with_rotation(),
|
||||||
pin.point_with_rotation(),
|
pin.point_with_rotation(),
|
||||||
|
|
@ -305,11 +305,7 @@ impl SpecctraDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
for via in &self.pcb.wiring.vias {
|
for via in &self.pcb.wiring.vias {
|
||||||
let net = board
|
let net = board.layout().drawing().rules().netname_net(&via.net);
|
||||||
.layout()
|
|
||||||
.drawing()
|
|
||||||
.rules()
|
|
||||||
.netname_net(&via.net);
|
|
||||||
|
|
||||||
let padstack = self.pcb.library.find_padstack_by_name(&via.name).unwrap();
|
let padstack = self.pcb.library.find_padstack_by_name(&via.name).unwrap();
|
||||||
|
|
||||||
|
|
@ -322,6 +318,7 @@ impl SpecctraDesign {
|
||||||
Shape::Circle(circle) => {
|
Shape::Circle(circle) => {
|
||||||
let layer = get_layer(&board, &circle.layer);
|
let layer = get_layer(&board, &circle.layer);
|
||||||
Self::add_circle(
|
Self::add_circle(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
// TODO: refactor?
|
// TODO: refactor?
|
||||||
// should this call take PointWithRotation?
|
// should this call take PointWithRotation?
|
||||||
|
|
@ -336,6 +333,7 @@ impl SpecctraDesign {
|
||||||
Shape::Rect(rect) => {
|
Shape::Rect(rect) => {
|
||||||
let layer = get_layer(&board, &rect.layer);
|
let layer = get_layer(&board, &rect.layer);
|
||||||
Self::add_rect(
|
Self::add_rect(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
PointWithRotation::from_xy(via.x, via.y),
|
PointWithRotation::from_xy(via.x, via.y),
|
||||||
PointWithRotation::default(),
|
PointWithRotation::default(),
|
||||||
|
|
@ -351,6 +349,7 @@ impl SpecctraDesign {
|
||||||
Shape::Path(path) => {
|
Shape::Path(path) => {
|
||||||
let layer = get_layer(&board, &path.layer);
|
let layer = get_layer(&board, &path.layer);
|
||||||
Self::add_path(
|
Self::add_path(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
PointWithRotation::from_xy(via.x, via.y),
|
PointWithRotation::from_xy(via.x, via.y),
|
||||||
PointWithRotation::default(),
|
PointWithRotation::default(),
|
||||||
|
|
@ -364,6 +363,7 @@ impl SpecctraDesign {
|
||||||
Shape::Polygon(polygon) => {
|
Shape::Polygon(polygon) => {
|
||||||
let layer = get_layer(&board, &polygon.layer);
|
let layer = get_layer(&board, &polygon.layer);
|
||||||
Self::add_polygon(
|
Self::add_polygon(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
PointWithRotation::from_xy(via.x, via.y),
|
PointWithRotation::from_xy(via.x, via.y),
|
||||||
PointWithRotation::default(),
|
PointWithRotation::default(),
|
||||||
|
|
@ -385,13 +385,10 @@ impl SpecctraDesign {
|
||||||
.rules()
|
.rules()
|
||||||
.layername_layer(&wire.path.layer)
|
.layername_layer(&wire.path.layer)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let net = board
|
let net = board.layout().drawing().rules().netname_net(&wire.net);
|
||||||
.layout()
|
|
||||||
.drawing()
|
|
||||||
.rules()
|
|
||||||
.netname_net(&wire.net);
|
|
||||||
|
|
||||||
Self::add_path(
|
Self::add_path(
|
||||||
|
recorder,
|
||||||
&mut board,
|
&mut board,
|
||||||
PointWithRotation::default(),
|
PointWithRotation::default(),
|
||||||
PointWithRotation::default(),
|
PointWithRotation::default(),
|
||||||
|
|
@ -427,6 +424,7 @@ impl SpecctraDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_circle(
|
fn add_circle(
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
board: &mut Board<SpecctraMesadata>,
|
board: &mut Board<SpecctraMesadata>,
|
||||||
place: PointWithRotation,
|
place: PointWithRotation,
|
||||||
pin: PointWithRotation,
|
pin: PointWithRotation,
|
||||||
|
|
@ -441,6 +439,7 @@ impl SpecctraDesign {
|
||||||
};
|
};
|
||||||
|
|
||||||
board.add_fixed_dot_infringably(
|
board.add_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle,
|
circle,
|
||||||
layer,
|
layer,
|
||||||
|
|
@ -451,6 +450,7 @@ impl SpecctraDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_rect(
|
fn add_rect(
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
board: &mut Board<SpecctraMesadata>,
|
board: &mut Board<SpecctraMesadata>,
|
||||||
place: PointWithRotation,
|
place: PointWithRotation,
|
||||||
pin: PointWithRotation,
|
pin: PointWithRotation,
|
||||||
|
|
@ -463,16 +463,14 @@ impl SpecctraDesign {
|
||||||
maybe_pin: Option<String>,
|
maybe_pin: Option<String>,
|
||||||
) {
|
) {
|
||||||
let poly = board.add_poly(
|
let poly = board.add_poly(
|
||||||
SolidPolyWeight {
|
recorder,
|
||||||
layer,
|
SolidPolyWeight { layer, maybe_net }.into(),
|
||||||
maybe_net,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
maybe_pin.clone(),
|
maybe_pin.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Corners.
|
// Corners.
|
||||||
let dot_1_1 = board.add_poly_fixed_dot_infringably(
|
let dot_1_1 = board.add_poly_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place, pin, x1, y1),
|
pos: Self::pos(place, pin, x1, y1),
|
||||||
|
|
@ -484,6 +482,7 @@ impl SpecctraDesign {
|
||||||
poly,
|
poly,
|
||||||
);
|
);
|
||||||
let dot_2_1 = board.add_poly_fixed_dot_infringably(
|
let dot_2_1 = board.add_poly_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place, pin, x2, y1),
|
pos: Self::pos(place, pin, x2, y1),
|
||||||
|
|
@ -495,6 +494,7 @@ impl SpecctraDesign {
|
||||||
poly,
|
poly,
|
||||||
);
|
);
|
||||||
let dot_2_2 = board.add_poly_fixed_dot_infringably(
|
let dot_2_2 = board.add_poly_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place, pin, x2, y2),
|
pos: Self::pos(place, pin, x2, y2),
|
||||||
|
|
@ -506,6 +506,7 @@ impl SpecctraDesign {
|
||||||
poly,
|
poly,
|
||||||
);
|
);
|
||||||
let dot_1_2 = board.add_poly_fixed_dot_infringably(
|
let dot_1_2 = board.add_poly_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place, pin, x1, y2),
|
pos: Self::pos(place, pin, x1, y2),
|
||||||
|
|
@ -518,6 +519,7 @@ impl SpecctraDesign {
|
||||||
);
|
);
|
||||||
// Sides.
|
// Sides.
|
||||||
board.add_poly_fixed_seg_infringably(
|
board.add_poly_fixed_seg_infringably(
|
||||||
|
recorder,
|
||||||
dot_1_1,
|
dot_1_1,
|
||||||
dot_2_1,
|
dot_2_1,
|
||||||
FixedSegWeight {
|
FixedSegWeight {
|
||||||
|
|
@ -528,6 +530,7 @@ impl SpecctraDesign {
|
||||||
poly,
|
poly,
|
||||||
);
|
);
|
||||||
board.add_poly_fixed_seg_infringably(
|
board.add_poly_fixed_seg_infringably(
|
||||||
|
recorder,
|
||||||
dot_2_1,
|
dot_2_1,
|
||||||
dot_2_2,
|
dot_2_2,
|
||||||
FixedSegWeight {
|
FixedSegWeight {
|
||||||
|
|
@ -538,6 +541,7 @@ impl SpecctraDesign {
|
||||||
poly,
|
poly,
|
||||||
);
|
);
|
||||||
board.add_poly_fixed_seg_infringably(
|
board.add_poly_fixed_seg_infringably(
|
||||||
|
recorder,
|
||||||
dot_2_2,
|
dot_2_2,
|
||||||
dot_1_2,
|
dot_1_2,
|
||||||
FixedSegWeight {
|
FixedSegWeight {
|
||||||
|
|
@ -548,6 +552,7 @@ impl SpecctraDesign {
|
||||||
poly,
|
poly,
|
||||||
);
|
);
|
||||||
board.add_poly_fixed_seg_infringably(
|
board.add_poly_fixed_seg_infringably(
|
||||||
|
recorder,
|
||||||
dot_1_2,
|
dot_1_2,
|
||||||
dot_1_1,
|
dot_1_1,
|
||||||
FixedSegWeight {
|
FixedSegWeight {
|
||||||
|
|
@ -560,6 +565,7 @@ impl SpecctraDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_path(
|
fn add_path(
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
board: &mut Board<SpecctraMesadata>,
|
board: &mut Board<SpecctraMesadata>,
|
||||||
place: PointWithRotation,
|
place: PointWithRotation,
|
||||||
pin: PointWithRotation,
|
pin: PointWithRotation,
|
||||||
|
|
@ -572,6 +578,7 @@ impl SpecctraDesign {
|
||||||
// add the first coordinate in the wire path as a dot and save its index
|
// add the first coordinate in the wire path as a dot and save its index
|
||||||
let mut prev_pos = Self::pos(place, pin, coords[0].x, coords[0].y);
|
let mut prev_pos = Self::pos(place, pin, coords[0].x, coords[0].y);
|
||||||
let mut prev_index = board.add_fixed_dot_infringably(
|
let mut prev_index = board.add_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: prev_pos,
|
pos: prev_pos,
|
||||||
|
|
@ -592,6 +599,7 @@ impl SpecctraDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = board.add_fixed_dot_infringably(
|
let index = board.add_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos,
|
pos,
|
||||||
|
|
@ -605,6 +613,7 @@ impl SpecctraDesign {
|
||||||
|
|
||||||
// add a seg between the current and previous coords
|
// add a seg between the current and previous coords
|
||||||
let _ = board.add_fixed_seg_infringably(
|
let _ = board.add_fixed_seg_infringably(
|
||||||
|
recorder,
|
||||||
prev_index,
|
prev_index,
|
||||||
index,
|
index,
|
||||||
FixedSegWeight {
|
FixedSegWeight {
|
||||||
|
|
@ -621,6 +630,7 @@ impl SpecctraDesign {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_polygon(
|
fn add_polygon(
|
||||||
|
recorder: &mut LayoutEdit,
|
||||||
board: &mut Board<SpecctraMesadata>,
|
board: &mut Board<SpecctraMesadata>,
|
||||||
place: PointWithRotation,
|
place: PointWithRotation,
|
||||||
pin: PointWithRotation,
|
pin: PointWithRotation,
|
||||||
|
|
@ -631,16 +641,14 @@ impl SpecctraDesign {
|
||||||
maybe_pin: Option<String>,
|
maybe_pin: Option<String>,
|
||||||
) {
|
) {
|
||||||
let poly = board.add_poly(
|
let poly = board.add_poly(
|
||||||
SolidPolyWeight {
|
recorder,
|
||||||
layer,
|
SolidPolyWeight { layer, maybe_net }.into(),
|
||||||
maybe_net,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
maybe_pin.clone(),
|
maybe_pin.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// add the first coordinate in the wire path as a dot and save its index
|
// add the first coordinate in the wire path as a dot and save its index
|
||||||
let mut prev_index = board.add_poly_fixed_dot_infringably(
|
let mut prev_index = board.add_poly_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place, pin, coords[0].x, coords[0].y),
|
pos: Self::pos(place, pin, coords[0].x, coords[0].y),
|
||||||
|
|
@ -657,6 +665,7 @@ impl SpecctraDesign {
|
||||||
// iterate through path coords starting from the second
|
// iterate through path coords starting from the second
|
||||||
for coord in coords.iter().skip(1) {
|
for coord in coords.iter().skip(1) {
|
||||||
let index = board.add_poly_fixed_dot_infringably(
|
let index = board.add_poly_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
FixedDotWeight {
|
FixedDotWeight {
|
||||||
circle: Circle {
|
circle: Circle {
|
||||||
pos: Self::pos(place, pin, coord.x, coord.y),
|
pos: Self::pos(place, pin, coord.x, coord.y),
|
||||||
|
|
@ -671,6 +680,7 @@ impl SpecctraDesign {
|
||||||
|
|
||||||
// add a seg between the current and previous coords
|
// add a seg between the current and previous coords
|
||||||
let _ = board.add_poly_fixed_seg_infringably(
|
let _ = board.add_poly_fixed_seg_infringably(
|
||||||
|
recorder,
|
||||||
prev_index,
|
prev_index,
|
||||||
index,
|
index,
|
||||||
FixedSegWeight {
|
FixedSegWeight {
|
||||||
|
|
|
||||||
|
|
@ -86,11 +86,7 @@ impl SpecctraMesadata {
|
||||||
.classes
|
.classes
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|class| &class.nets)
|
.flat_map(|class| &class.nets)
|
||||||
.chain(
|
.chain(pcb.network.nets.iter().map(|net| &net.name))
|
||||||
pcb.network.nets
|
|
||||||
.iter()
|
|
||||||
.map(|net| &net.name)
|
|
||||||
)
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(net, netname)| (net, netname.clone())),
|
.map(|(net, netname)| (net, netname.clone())),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use topola::{
|
||||||
drawing::graph::{GetLayer, GetMaybeNet},
|
drawing::graph::{GetLayer, GetMaybeNet},
|
||||||
geometry::shape::MeasureLength,
|
geometry::shape::MeasureLength,
|
||||||
graph::{GetPetgraphIndex, MakeRef},
|
graph::{GetPetgraphIndex, MakeRef},
|
||||||
|
layout::LayoutEdit,
|
||||||
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -18,7 +19,8 @@ pub fn load_design_and_assert(filename: &str) -> Invoker<SpecctraMesadata> {
|
||||||
let design_file = File::open(filename).unwrap();
|
let design_file = File::open(filename).unwrap();
|
||||||
let design_bufread = BufReader::new(design_file);
|
let design_bufread = BufReader::new(design_file);
|
||||||
let design = SpecctraDesign::load(design_bufread).unwrap();
|
let design = SpecctraDesign::load(design_bufread).unwrap();
|
||||||
let mut invoker = Invoker::new(Autorouter::new(design.make_board()).unwrap());
|
let mut invoker =
|
||||||
|
Invoker::new(Autorouter::new(design.make_board(&mut LayoutEdit::new())).unwrap());
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
invoker.undo(),
|
invoker.undo(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue