mirror of https://codeberg.org/topola/topola.git
refactor: replace multiple custom Recording* structures with single generic Recording<'a, T> struct
This commit is contained in:
parent
26631ed6cd
commit
a911c0cddf
|
|
@ -12,6 +12,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},
|
||||||
|
geometry::edit::Recordable,
|
||||||
layout::{via::ViaWeight, LayoutEdit},
|
layout::{via::ViaWeight, LayoutEdit},
|
||||||
router::{astar::AstarError, navmesh::NavmeshError, RouterOptions},
|
router::{astar::AstarError, navmesh::NavmeshError, RouterOptions},
|
||||||
triangulation::GetTrianvertexNodeIndex,
|
triangulation::GetTrianvertexNodeIndex,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
board::mesadata::AccessMesadata,
|
board::mesadata::AccessMesadata,
|
||||||
drawing::graph::PrimitiveIndex,
|
drawing::graph::PrimitiveIndex,
|
||||||
geometry::primitive::PrimitiveShape,
|
geometry::{edit::Recordable, primitive::PrimitiveShape},
|
||||||
layout::{via::ViaWeight, LayoutEdit},
|
layout::{via::ViaWeight, LayoutEdit},
|
||||||
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
board::mesadata::AccessMesadata,
|
board::mesadata::AccessMesadata,
|
||||||
drawing::graph::PrimitiveIndex,
|
drawing::graph::PrimitiveIndex,
|
||||||
geometry::primitive::PrimitiveShape,
|
geometry::{edit::Recordable, primitive::PrimitiveShape},
|
||||||
layout::LayoutEdit,
|
layout::LayoutEdit,
|
||||||
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
router::{navcord::NavcordStepper, navmesh::Navmesh},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,11 @@ use crate::{
|
||||||
graph::{GetLayer, GetMaybeNet, PrimitiveIndex, PrimitiveWeight},
|
graph::{GetLayer, GetMaybeNet, PrimitiveIndex, PrimitiveWeight},
|
||||||
seg::{FixedSegIndex, FixedSegWeight, SegIndex, SegWeight},
|
seg::{FixedSegIndex, FixedSegWeight, SegIndex, SegWeight},
|
||||||
},
|
},
|
||||||
geometry::{edit::ApplyGeometryEdit, shape::AccessShape, GenericNode},
|
geometry::{
|
||||||
|
edit::{ApplyGeometryEdit, Recordable},
|
||||||
|
shape::AccessShape,
|
||||||
|
GenericNode,
|
||||||
|
},
|
||||||
graph::GenericIndex,
|
graph::GenericIndex,
|
||||||
layout::{
|
layout::{
|
||||||
poly::{GetMaybeApex, MakePolyShape, PolyWeight},
|
poly::{GetMaybeApex, MakePolyShape, PolyWeight},
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,9 @@ use thiserror::Error;
|
||||||
|
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
compound::ManageCompounds,
|
compound::ManageCompounds,
|
||||||
edit::{ApplyGeometryEdit, GeometryEdit},
|
edit::{ApplyGeometryEdit, GeometryEdit, Recordable, Recording},
|
||||||
primitive::{AccessPrimitiveShape, PrimitiveShape},
|
primitive::{AccessPrimitiveShape, PrimitiveShape},
|
||||||
recording_with_rtree::RecordingGeometryWithRtree,
|
with_rtree::{BboxedIndex, GeometryWithRtree},
|
||||||
with_rtree::BboxedIndex,
|
|
||||||
with_rtree::GeometryWithRtree,
|
|
||||||
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
||||||
GetOffset, GetPos, GetWidth,
|
GetOffset, GetPos, GetWidth,
|
||||||
};
|
};
|
||||||
|
|
@ -100,12 +98,18 @@ pub struct Drawing<CW, R> {
|
||||||
rules: R,
|
rules: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RecordingDrawing<'a, CW, R> {
|
impl<CW: Copy, R> Recordable for Drawing<CW, R> {
|
||||||
pub drawing: &'a mut Drawing<CW, R>,
|
type PW = PrimitiveWeight;
|
||||||
pub recorder: &'a mut DrawingEdit<CW>,
|
type DW = DotWeight;
|
||||||
|
type SW = SegWeight;
|
||||||
|
type BW = BendWeight;
|
||||||
|
type CW = CW;
|
||||||
|
type PI = PrimitiveIndex;
|
||||||
|
type DI = DotIndex;
|
||||||
|
type SI = SegIndex;
|
||||||
|
type BI = BendIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_invariant(self.test_if_looses_dont_infringe_each_other())]
|
|
||||||
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 {
|
||||||
|
|
@ -114,17 +118,6 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn recording<'a>(
|
|
||||||
&'a mut self,
|
|
||||||
recorder: &'a mut DrawingEdit<CW>,
|
|
||||||
) -> RecordingDrawing<'a, CW, R> {
|
|
||||||
RecordingDrawing {
|
|
||||||
drawing: self,
|
|
||||||
recorder,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn graph(
|
fn graph(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -317,6 +310,8 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
self.geometry_with_rtree.graph().node_count()
|
self.geometry_with_rtree.graph().node_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used for constraints checking on nightly Rust
|
||||||
|
#[allow(unused)]
|
||||||
fn test_if_looses_dont_infringe_each_other(&self) -> bool {
|
fn test_if_looses_dont_infringe_each_other(&self) -> bool {
|
||||||
!self
|
!self
|
||||||
.primitive_nodes()
|
.primitive_nodes()
|
||||||
|
|
@ -359,24 +354,33 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
impl<CW: Copy, R: AccessRules> Recording<'_, Drawing<CW, R>> {
|
||||||
fn recording_geometry_with_rtree(
|
fn recording_geometry_with_rtree(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> RecordingGeometryWithRtree<
|
) -> Recording<
|
||||||
'_,
|
'_,
|
||||||
PrimitiveWeight,
|
GeometryWithRtree<
|
||||||
DotWeight,
|
PrimitiveWeight,
|
||||||
SegWeight,
|
DotWeight,
|
||||||
BendWeight,
|
SegWeight,
|
||||||
CW,
|
BendWeight,
|
||||||
PrimitiveIndex,
|
CW,
|
||||||
DotIndex,
|
PrimitiveIndex,
|
||||||
SegIndex,
|
DotIndex,
|
||||||
BendIndex,
|
SegIndex,
|
||||||
|
BendIndex,
|
||||||
|
>,
|
||||||
> {
|
> {
|
||||||
self.drawing.geometry_with_rtree.recording(self.recorder)
|
self.inner.geometry_with_rtree.recording(self.recorder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rules_mut(&mut self) -> &mut R {
|
||||||
|
&mut self.inner.rules
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_invariant(self.inner.test_if_looses_dont_infringe_each_other())]
|
||||||
|
impl<CW: Copy, R: AccessRules> Recording<'_, Drawing<CW, R>> {
|
||||||
pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> {
|
pub fn remove_band(&mut self, band: BandTermsegIndex) -> Result<(), DrawingException> {
|
||||||
match band {
|
match band {
|
||||||
BandTermsegIndex::Straight(seg) => {
|
BandTermsegIndex::Straight(seg) => {
|
||||||
|
|
@ -406,16 +410,16 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
LooseIndex::Bend(bend) => {
|
LooseIndex::Bend(bend) => {
|
||||||
bends.push(bend);
|
bends.push(bend);
|
||||||
|
|
||||||
if let Some(outer) = self.drawing.primitive(bend).outer() {
|
if let Some(outer) = self.inner.primitive(bend).outer() {
|
||||||
outers.push(outer);
|
outers.push(outer);
|
||||||
self.reattach_bend(outer, self.drawing.primitive(bend).inner());
|
self.reattach_bend(outer, self.inner.primitive(bend).inner());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let prev_prev = prev;
|
let prev_prev = prev;
|
||||||
prev = maybe_loose;
|
prev = maybe_loose;
|
||||||
maybe_loose = self.drawing.loose(loose).next_loose(prev_prev);
|
maybe_loose = self.inner.loose(loose).next_loose(prev_prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
for bend in bends {
|
for bend in bends {
|
||||||
|
|
@ -443,27 +447,27 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> {
|
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> {
|
||||||
self.add_dot_with_infringables(weight, Some(&[]))
|
self.add_dot_with_infringables(weight, Some(&[]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count() - 1))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count() - 1))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn remove_fixed_dot(&mut self, dot: FixedDotIndex) {
|
pub fn remove_fixed_dot(&mut self, dot: FixedDotIndex) {
|
||||||
self.recording_geometry_with_rtree().remove_dot(dot.into());
|
self.recording_geometry_with_rtree().remove_dot(dot.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex {
|
pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex {
|
||||||
self.add_dot_infringably(weight)
|
self.add_dot_infringably(weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.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,
|
||||||
weight: W,
|
weight: W,
|
||||||
|
|
@ -478,9 +482,9 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(dot)
|
Ok(dot)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn add_fixed_seg(
|
pub fn add_fixed_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
|
|
@ -490,8 +494,8 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
self.add_seg_with_infringables(from.into(), to.into(), weight, Some(&[]))
|
self.add_seg_with_infringables(from.into(), to.into(), weight, Some(&[]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 2))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 2))]
|
||||||
pub fn add_fixed_seg_infringably(
|
pub fn add_fixed_seg_infringably(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
|
|
@ -501,10 +505,10 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
self.add_seg_infringably(from.into(), to.into(), weight)
|
self.add_seg_infringably(from.into(), to.into(), weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 2))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 2))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn add_lone_loose_seg(
|
pub fn add_lone_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: FixedDotIndex,
|
from: FixedDotIndex,
|
||||||
|
|
@ -515,10 +519,10 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(seg)
|
Ok(seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 2))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 2))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn add_seq_loose_seg(
|
pub fn add_seq_loose_seg(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -529,10 +533,10 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(seg)
|
Ok(seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() >= old(self.drawing.graph().edge_count() + 2))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() >= old(self.inner.graph().edge_count() + 2))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.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,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -549,11 +553,11 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(seg)
|
Ok(seg)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 3)
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 3)
|
||||||
|| self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 4))]
|
|| self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
fn add_loose_bend_with_infringables(
|
fn add_loose_bend_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: LooseDotIndex,
|
from: LooseDotIndex,
|
||||||
|
|
@ -565,14 +569,14 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
// It makes no sense to wrap something around or under one of its connectables.
|
// It makes no sense to wrap something around or under one of its connectables.
|
||||||
//
|
//
|
||||||
if let Some(net) = weight.maybe_net {
|
if let Some(net) = weight.maybe_net {
|
||||||
if let Some(around_net) = around.primitive(self.drawing).maybe_net() {
|
if let Some(around_net) = around.primitive(self.inner).maybe_net() {
|
||||||
if net == around_net {
|
if net == around_net {
|
||||||
return Err(AlreadyConnected(net, around.into()).into());
|
return Err(AlreadyConnected(net, around.into()).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
if let Some(next_gear) = around.ref_(self.drawing).next_gear() {
|
if let Some(next_gear) = around.ref_(self.inner).next_gear() {
|
||||||
if let Some(next_gear_net) = next_gear.primitive(self.drawing).maybe_net() {
|
if let Some(next_gear_net) = next_gear.primitive(self.inner).maybe_net() {
|
||||||
if net == next_gear_net {
|
if net == next_gear_net {
|
||||||
return Err(AlreadyConnected(net, next_gear.into()).into());
|
return Err(AlreadyConnected(net, next_gear.into()).into());
|
||||||
}
|
}
|
||||||
|
|
@ -593,10 +597,10 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 3))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 3))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.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,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -616,10 +620,10 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(bend)
|
Ok(bend)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
fn add_outer_bend_with_infringables(
|
fn add_outer_bend_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: LooseDotIndex,
|
from: LooseDotIndex,
|
||||||
|
|
@ -629,15 +633,15 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<GenericIndex<LooseBendWeight>, Infringement> {
|
) -> Result<GenericIndex<LooseBendWeight>, Infringement> {
|
||||||
let core = *self
|
let core = *self
|
||||||
.drawing
|
.inner
|
||||||
.graph()
|
.graph()
|
||||||
.neighbors(inner.petgraph_index())
|
.neighbors(inner.petgraph_index())
|
||||||
.filter(|ni| {
|
.filter(|ni| {
|
||||||
matches!(
|
matches!(
|
||||||
self.drawing
|
self.inner
|
||||||
.graph()
|
.graph()
|
||||||
.edge_weight(
|
.edge_weight(
|
||||||
self.drawing
|
self.inner
|
||||||
.graph()
|
.graph()
|
||||||
.find_edge(inner.petgraph_index(), *ni)
|
.find_edge(inner.petgraph_index(), *ni)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -664,25 +668,25 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(bend)
|
Ok(bend)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn flip_bend(&mut self, bend: FixedBendIndex) {
|
pub fn flip_bend(&mut self, bend: FixedBendIndex) {
|
||||||
self.recording_geometry_with_rtree().flip_bend(bend.into());
|
self.recording_geometry_with_rtree().flip_bend(bend.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count())
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count())
|
||||||
|| self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() - 1)
|
|| self.inner.graph().edge_count() == old(self.inner.graph().edge_count() - 1)
|
||||||
|| self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 1))]
|
|| self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 1))]
|
||||||
fn reattach_bend(&mut self, bend: LooseBendIndex, maybe_new_inner: Option<LooseBendIndex>) {
|
fn reattach_bend(&mut self, bend: LooseBendIndex, maybe_new_inner: Option<LooseBendIndex>) {
|
||||||
self.recording_geometry_with_rtree()
|
self.recording_geometry_with_rtree()
|
||||||
.reattach_bend(bend.into(), maybe_new_inner.map(Into::into));
|
.reattach_bend(bend.into(), maybe_new_inner.map(Into::into));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() >= old(self.drawing.graph().edge_count() + 5))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() >= old(self.inner.graph().edge_count() + 5))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn insert_cane(
|
pub fn insert_cane(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -692,7 +696,7 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
bend_weight: LooseBendWeight,
|
bend_weight: LooseBendWeight,
|
||||||
cw: bool,
|
cw: bool,
|
||||||
) -> Result<Cane, DrawingException> {
|
) -> Result<Cane, DrawingException> {
|
||||||
let maybe_next_gear = around.ref_(self.drawing).next_gear();
|
let maybe_next_gear = around.ref_(self.inner).next_gear();
|
||||||
let cane = self.add_cane_with_infringables(
|
let cane = self.add_cane_with_infringables(
|
||||||
from,
|
from,
|
||||||
around,
|
around,
|
||||||
|
|
@ -707,16 +711,16 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
self.reattach_bend(next_gear, Some(cane.bend));
|
self.reattach_bend(next_gear, Some(cane.bend));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(outer) = self.drawing.primitive(cane.bend).outer() {
|
if let Some(outer) = self.inner.primitive(cane.bend).outer() {
|
||||||
self.update_this_and_outward_bows(outer).inspect_err(|_| {
|
self.update_this_and_outward_bows(outer).inspect_err(|_| {
|
||||||
let joint = self.drawing.primitive(cane.bend).other_joint(cane.dot);
|
let joint = self.inner.primitive(cane.bend).other_joint(cane.dot);
|
||||||
self.remove_cane(&cane, joint);
|
self.remove_cane(&cane, joint);
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Segs must not cross.
|
// Segs must not cross.
|
||||||
if let Some(collision) = self.drawing.detect_collision(cane.seg.into()) {
|
if let Some(collision) = self.inner.detect_collision(cane.seg.into()) {
|
||||||
let joint = self.drawing.primitive(cane.bend).other_joint(cane.dot);
|
let joint = self.inner.primitive(cane.bend).other_joint(cane.dot);
|
||||||
self.remove_cane(&cane, joint);
|
self.remove_cane(&cane, joint);
|
||||||
Err(collision.into())
|
Err(collision.into())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -724,8 +728,8 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
fn update_this_and_outward_bows(
|
fn update_this_and_outward_bows(
|
||||||
&mut self,
|
&mut self,
|
||||||
around: LooseBendIndex,
|
around: LooseBendIndex,
|
||||||
|
|
@ -734,10 +738,10 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
let mut maybe_rail = Some(around);
|
let mut maybe_rail = Some(around);
|
||||||
|
|
||||||
while let Some(rail) = maybe_rail {
|
while let Some(rail) = maybe_rail {
|
||||||
let rail_primitive = self.drawing.primitive(rail);
|
let rail_primitive = self.inner.primitive(rail);
|
||||||
let joints = rail_primitive.joints();
|
let joints = rail_primitive.joints();
|
||||||
|
|
||||||
let guide = Guide::new(self.drawing);
|
let guide = Guide::new(self.inner);
|
||||||
let from_head = guide.rear_head(joints.1);
|
let from_head = guide.rear_head(joints.1);
|
||||||
let to_head = guide.rear_head(joints.0);
|
let to_head = guide.rear_head(joints.0);
|
||||||
|
|
||||||
|
|
@ -747,7 +751,7 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
&from_head,
|
&from_head,
|
||||||
inner.into(),
|
inner.into(),
|
||||||
true,
|
true,
|
||||||
self.drawing.primitive(rail).width(),
|
self.inner.primitive(rail).width(),
|
||||||
)?
|
)?
|
||||||
.end_point();
|
.end_point();
|
||||||
let to = guide
|
let to = guide
|
||||||
|
|
@ -755,30 +759,30 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
&to_head,
|
&to_head,
|
||||||
inner.into(),
|
inner.into(),
|
||||||
false,
|
false,
|
||||||
self.drawing.primitive(rail).width(),
|
self.inner.primitive(rail).width(),
|
||||||
)?
|
)?
|
||||||
.end_point();
|
.end_point();
|
||||||
let offset = guide.head_around_bend_offset(
|
let offset = guide.head_around_bend_offset(
|
||||||
&from_head,
|
&from_head,
|
||||||
inner.into(),
|
inner.into(),
|
||||||
self.drawing.primitive(rail).width(),
|
self.inner.primitive(rail).width(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
joints.0.into(),
|
joints.0.into(),
|
||||||
from,
|
from,
|
||||||
Some(&self.drawing.collect().bend_outer_bows(rail)),
|
Some(&self.inner.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
joints.1.into(),
|
joints.1.into(),
|
||||||
to,
|
to,
|
||||||
Some(&self.drawing.collect().bend_outer_bows(rail)),
|
Some(&self.inner.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.shift_bend_with_infringables(
|
self.shift_bend_with_infringables(
|
||||||
rail.into(),
|
rail.into(),
|
||||||
offset,
|
offset,
|
||||||
Some(&self.drawing.collect().bend_outer_bows(rail)),
|
Some(&self.inner.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Update offsets in case the rule conditions changed.
|
// Update offsets in case the rule conditions changed.
|
||||||
|
|
@ -789,7 +793,7 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
&from_head,
|
&from_head,
|
||||||
core.into(),
|
core.into(),
|
||||||
true,
|
true,
|
||||||
self.drawing.primitive(rail).width(),
|
self.inner.primitive(rail).width(),
|
||||||
)?
|
)?
|
||||||
.end_point();
|
.end_point();
|
||||||
let to = guide
|
let to = guide
|
||||||
|
|
@ -797,43 +801,43 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
&to_head,
|
&to_head,
|
||||||
core.into(),
|
core.into(),
|
||||||
false,
|
false,
|
||||||
self.drawing.primitive(rail).width(),
|
self.inner.primitive(rail).width(),
|
||||||
)?
|
)?
|
||||||
.end_point();
|
.end_point();
|
||||||
let offset = guide.head_around_dot_offset(
|
let offset = guide.head_around_dot_offset(
|
||||||
&from_head,
|
&from_head,
|
||||||
core.into(),
|
core.into(),
|
||||||
self.drawing.primitive(rail).width(),
|
self.inner.primitive(rail).width(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
joints.0.into(),
|
joints.0.into(),
|
||||||
from,
|
from,
|
||||||
Some(&self.drawing.collect().bend_outer_bows(rail)),
|
Some(&self.inner.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
self.move_dot_with_infringables(
|
self.move_dot_with_infringables(
|
||||||
joints.1.into(),
|
joints.1.into(),
|
||||||
to,
|
to,
|
||||||
Some(&self.drawing.collect().bend_outer_bows(rail)),
|
Some(&self.inner.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.shift_bend_with_infringables(
|
self.shift_bend_with_infringables(
|
||||||
rail.into(),
|
rail.into(),
|
||||||
offset,
|
offset,
|
||||||
Some(&self.drawing.collect().bend_outer_bows(rail)),
|
Some(&self.inner.collect().bend_outer_bows(rail)),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_rail = self.drawing.primitive(rail).outer();
|
maybe_rail = self.inner.primitive(rail).outer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() >= old(self.drawing.graph().edge_count() + 5))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() >= old(self.inner.graph().edge_count() + 5))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn add_cane(
|
pub fn add_cane(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -854,10 +858,10 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() >= old(self.drawing.graph().edge_count() + 5))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() >= old(self.inner.graph().edge_count() + 5))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
fn add_cane_with_infringables(
|
fn add_cane_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -902,13 +906,13 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count() - 4))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count() - 4))]
|
||||||
pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) {
|
pub fn remove_cane(&mut self, cane: &Cane, face: LooseDotIndex) {
|
||||||
let maybe_outer = self.drawing.primitive(cane.bend).outer();
|
let maybe_outer = self.inner.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.drawing.primitive(cane.bend).inner());
|
self.reattach_bend(outer, self.inner.primitive(cane.bend).inner());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.recording_geometry_with_rtree()
|
self.recording_geometry_with_rtree()
|
||||||
|
|
@ -928,8 +932,8 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
pub fn move_dot(&mut self, dot: DotIndex, to: Point) -> Result<(), Infringement> {
|
pub fn move_dot(&mut self, 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(dot, to, Some(&[])),
|
||||||
|
|
@ -937,20 +941,19 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
fn move_dot_with_infringables(
|
fn move_dot_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
dot: DotIndex,
|
dot: DotIndex,
|
||||||
to: Point,
|
to: Point,
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<(), Infringement> {
|
) -> Result<(), Infringement> {
|
||||||
let old_pos = self.drawing.geometry().dot_weight(dot).pos();
|
let old_pos = self.inner.geometry().dot_weight(dot).pos();
|
||||||
self.recording_geometry_with_rtree().move_dot(dot, to);
|
self.recording_geometry_with_rtree().move_dot(dot, to);
|
||||||
|
|
||||||
for limb in dot.primitive(self.drawing).limbs() {
|
for limb in dot.primitive(self.inner).limbs() {
|
||||||
if let Some(infringement) = self.drawing.detect_infringement_except(limb, infringables)
|
if let Some(infringement) = self.inner.detect_infringement_except(limb, infringables) {
|
||||||
{
|
|
||||||
// Restore original state.
|
// Restore original state.
|
||||||
self.recording_geometry_with_rtree().move_dot(dot, old_pos);
|
self.recording_geometry_with_rtree().move_dot(dot, old_pos);
|
||||||
return Err(infringement);
|
return Err(infringement);
|
||||||
|
|
@ -958,7 +961,7 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(infringement) = self
|
if let Some(infringement) = self
|
||||||
.drawing
|
.inner
|
||||||
.detect_infringement_except(dot.into(), infringables)
|
.detect_infringement_except(dot.into(), infringables)
|
||||||
{
|
{
|
||||||
// Restore original state.
|
// Restore original state.
|
||||||
|
|
@ -969,20 +972,20 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
fn shift_bend_with_infringables(
|
fn shift_bend_with_infringables(
|
||||||
&mut self,
|
&mut self,
|
||||||
bend: BendIndex,
|
bend: BendIndex,
|
||||||
offset: f64,
|
offset: f64,
|
||||||
infringables: Option<&[PrimitiveIndex]>,
|
infringables: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<(), Infringement> {
|
) -> Result<(), Infringement> {
|
||||||
let old_offset = self.drawing.geometry().bend_weight(bend).offset();
|
let old_offset = self.inner.geometry().bend_weight(bend).offset();
|
||||||
self.recording_geometry_with_rtree()
|
self.recording_geometry_with_rtree()
|
||||||
.shift_bend(bend, offset);
|
.shift_bend(bend, offset);
|
||||||
|
|
||||||
if let Some(infringement) = self
|
if let Some(infringement) = self
|
||||||
.drawing
|
.inner
|
||||||
.detect_infringement_except(bend.into(), infringables)
|
.detect_infringement_except(bend.into(), infringables)
|
||||||
{
|
{
|
||||||
// Restore original state.
|
// Restore original state.
|
||||||
|
|
@ -994,8 +997,8 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
fn add_dot_infringably<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
|
fn add_dot_infringably<W: AccessDotWeight<PrimitiveWeight> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
weight: W,
|
weight: W,
|
||||||
|
|
@ -1006,8 +1009,8 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
self.recording_geometry_with_rtree().add_dot(weight)
|
self.recording_geometry_with_rtree().add_dot(weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(self.drawing.graph().node_count() == old(self.drawing.graph().node_count() + 1))]
|
#[debug_ensures(self.inner.graph().node_count() == old(self.inner.graph().node_count() + 1))]
|
||||||
#[debug_ensures(self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count() + 2))]
|
#[debug_ensures(self.inner.graph().edge_count() == old(self.inner.graph().edge_count() + 2))]
|
||||||
fn add_seg_infringably<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
|
fn add_seg_infringably<W: AccessSegWeight<PrimitiveWeight> + GetLayer>(
|
||||||
&mut self,
|
&mut self,
|
||||||
from: DotIndex,
|
from: DotIndex,
|
||||||
|
|
@ -1035,15 +1038,15 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
.add_to_compound(primitive, compound);
|
.add_to_compound(primitive, compound);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count()))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().node_count() == old(self.inner.graph().node_count()))]
|
||||||
#[debug_ensures(ret.is_ok() -> self.drawing.graph().edge_count() == old(self.drawing.graph().edge_count()))]
|
#[debug_ensures(ret.is_ok() -> self.inner.graph().edge_count() == old(self.inner.graph().edge_count()))]
|
||||||
#[debug_ensures(ret.is_err() -> self.drawing.graph().node_count() == old(self.drawing.graph().node_count() - 1))]
|
#[debug_ensures(ret.is_err() -> self.inner.graph().node_count() == old(self.inner.graph().node_count() - 1))]
|
||||||
fn fail_and_remove_if_infringes_except(
|
fn fail_and_remove_if_infringes_except(
|
||||||
&mut self,
|
&mut self,
|
||||||
node: PrimitiveIndex,
|
node: PrimitiveIndex,
|
||||||
maybe_except: Option<&[PrimitiveIndex]>,
|
maybe_except: Option<&[PrimitiveIndex]>,
|
||||||
) -> Result<(), Infringement> {
|
) -> Result<(), Infringement> {
|
||||||
if let Some(infringement) = self.drawing.detect_infringement_except(node, maybe_except) {
|
if let Some(infringement) = self.inner.detect_infringement_except(node, maybe_except) {
|
||||||
let mut recording_geometry_with_rtree = self.recording_geometry_with_rtree();
|
let mut recording_geometry_with_rtree = self.recording_geometry_with_rtree();
|
||||||
if let Ok(dot) = node.try_into() {
|
if let Ok(dot) = node.try_into() {
|
||||||
recording_geometry_with_rtree.remove_dot(dot);
|
recording_geometry_with_rtree.remove_dot(dot);
|
||||||
|
|
@ -1056,10 +1059,6 @@ impl<CW: Copy, R: AccessRules> RecordingDrawing<'_, CW, R> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rules_mut(&mut self) -> &mut R {
|
|
||||||
&mut self.drawing.rules
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CW: Copy, R: AccessRules>
|
impl<CW: Copy, R: AccessRules>
|
||||||
|
|
@ -1075,27 +1074,8 @@ impl<CW: Copy, R: AccessRules>
|
||||||
BendIndex,
|
BendIndex,
|
||||||
> for Drawing<CW, R>
|
> for Drawing<CW, R>
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline(always)]
|
||||||
fn apply(&mut self, edit: &DrawingEdit<CW>) {
|
fn apply(&mut self, edit: &DrawingEdit<CW>) {
|
||||||
self.geometry_with_rtree.apply(edit);
|
self.geometry_with_rtree.apply(edit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CW: Copy, R: AccessRules>
|
|
||||||
ApplyGeometryEdit<
|
|
||||||
PrimitiveWeight,
|
|
||||||
DotWeight,
|
|
||||||
SegWeight,
|
|
||||||
BendWeight,
|
|
||||||
CW,
|
|
||||||
PrimitiveIndex,
|
|
||||||
DotIndex,
|
|
||||||
SegIndex,
|
|
||||||
BendIndex,
|
|
||||||
> for RecordingDrawing<'_, CW, R>
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn apply(&mut self, edit: &DrawingEdit<CW>) {
|
|
||||||
self.drawing.geometry_with_rtree.apply(edit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
use std::{collections::HashMap, hash::Hash, marker::PhantomData};
|
use std::{collections::HashMap, hash::Hash, marker::PhantomData};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -87,3 +88,142 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Recordable {
|
||||||
|
type PW: GetWidth
|
||||||
|
+ GetLayer
|
||||||
|
+ TryInto<Self::DW>
|
||||||
|
+ TryInto<Self::SW>
|
||||||
|
+ TryInto<Self::BW>
|
||||||
|
+ Retag<Self::PI>
|
||||||
|
+ Copy;
|
||||||
|
type DW: AccessDotWeight<Self::PW> + GetLayer;
|
||||||
|
type SW: AccessSegWeight<Self::PW> + GetLayer;
|
||||||
|
type BW: AccessBendWeight<Self::PW> + GetLayer;
|
||||||
|
type CW: Copy;
|
||||||
|
type PI: GetPetgraphIndex
|
||||||
|
+ TryInto<Self::DI>
|
||||||
|
+ TryInto<Self::SI>
|
||||||
|
+ TryInto<Self::BI>
|
||||||
|
+ Copy
|
||||||
|
+ Eq
|
||||||
|
+ Hash;
|
||||||
|
type DI: GetPetgraphIndex + Into<Self::PI> + Copy + Eq + Hash;
|
||||||
|
type SI: GetPetgraphIndex + Into<Self::PI> + Copy + Eq + Hash;
|
||||||
|
type BI: GetPetgraphIndex + Into<Self::PI> + Copy + Eq + Hash;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn recording<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
recorder: &'a mut GeometryEdit<
|
||||||
|
Self::PW,
|
||||||
|
Self::DW,
|
||||||
|
Self::SW,
|
||||||
|
Self::BW,
|
||||||
|
Self::CW,
|
||||||
|
Self::PI,
|
||||||
|
Self::DI,
|
||||||
|
Self::SI,
|
||||||
|
Self::BI,
|
||||||
|
>,
|
||||||
|
) -> Recording<'a, Self> {
|
||||||
|
Recording {
|
||||||
|
inner: self,
|
||||||
|
recorder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RecordingEdit<T: Recordable + ?Sized> = GeometryEdit<
|
||||||
|
<T as Recordable>::PW,
|
||||||
|
<T as Recordable>::DW,
|
||||||
|
<T as Recordable>::SW,
|
||||||
|
<T as Recordable>::BW,
|
||||||
|
<T as Recordable>::CW,
|
||||||
|
<T as Recordable>::PI,
|
||||||
|
<T as Recordable>::DI,
|
||||||
|
<T as Recordable>::SI,
|
||||||
|
<T as Recordable>::BI,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub struct Recording<'a, T: Recordable + ?Sized> {
|
||||||
|
pub inner: &'a mut T,
|
||||||
|
pub recorder: &'a mut RecordingEdit<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> fmt::Debug for Recording<'a, T>
|
||||||
|
where
|
||||||
|
T: Recordable + fmt::Debug + ?Sized,
|
||||||
|
<T as Recordable>::PW: fmt::Debug,
|
||||||
|
<T as Recordable>::DW: fmt::Debug,
|
||||||
|
<T as Recordable>::SW: fmt::Debug,
|
||||||
|
<T as Recordable>::BW: fmt::Debug,
|
||||||
|
<T as Recordable>::CW: fmt::Debug,
|
||||||
|
<T as Recordable>::PI: fmt::Debug,
|
||||||
|
<T as Recordable>::DI: fmt::Debug,
|
||||||
|
<T as Recordable>::SI: fmt::Debug,
|
||||||
|
<T as Recordable>::BI: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Recording")
|
||||||
|
.field("inner", &self.inner)
|
||||||
|
.field("recorder", &self.recorder)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is a hack, but it allows us to not needing as much boilerplate for delegations
|
||||||
|
impl<'a, T: Recordable + ?Sized> core::ops::Deref for Recording<'a, T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &T {
|
||||||
|
self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T>
|
||||||
|
ApplyGeometryEdit<
|
||||||
|
<T as Recordable>::PW,
|
||||||
|
<T as Recordable>::DW,
|
||||||
|
<T as Recordable>::SW,
|
||||||
|
<T as Recordable>::BW,
|
||||||
|
<T as Recordable>::CW,
|
||||||
|
<T as Recordable>::PI,
|
||||||
|
<T as Recordable>::DI,
|
||||||
|
<T as Recordable>::SI,
|
||||||
|
<T as Recordable>::BI,
|
||||||
|
> for Recording<'a, T>
|
||||||
|
where
|
||||||
|
T: Recordable
|
||||||
|
+ ?Sized
|
||||||
|
+ ApplyGeometryEdit<
|
||||||
|
<T as Recordable>::PW,
|
||||||
|
<T as Recordable>::DW,
|
||||||
|
<T as Recordable>::SW,
|
||||||
|
<T as Recordable>::BW,
|
||||||
|
<T as Recordable>::CW,
|
||||||
|
<T as Recordable>::PI,
|
||||||
|
<T as Recordable>::DI,
|
||||||
|
<T as Recordable>::SI,
|
||||||
|
<T as Recordable>::BI,
|
||||||
|
>,
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn apply(
|
||||||
|
&mut self,
|
||||||
|
edit: &GeometryEdit<
|
||||||
|
<T as Recordable>::PW,
|
||||||
|
<T as Recordable>::DW,
|
||||||
|
<T as Recordable>::SW,
|
||||||
|
<T as Recordable>::BW,
|
||||||
|
<T as Recordable>::CW,
|
||||||
|
<T as Recordable>::PI,
|
||||||
|
<T as Recordable>::DI,
|
||||||
|
<T as Recordable>::SI,
|
||||||
|
<T as Recordable>::BI,
|
||||||
|
>,
|
||||||
|
) {
|
||||||
|
self.inner.apply(edit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,18 +16,12 @@ use crate::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
compound::ManageCompounds,
|
compound::ManageCompounds,
|
||||||
edit::{ApplyGeometryEdit, GeometryEdit},
|
edit::{GeometryEdit, Recording},
|
||||||
with_rtree::{BboxedIndex, GeometryWithRtree},
|
with_rtree::{BboxedIndex, GeometryWithRtree},
|
||||||
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
||||||
GetWidth,
|
GetWidth,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RecordingGeometryWithRtree<'a, PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
|
||||||
pub geometry_with_rtree: &'a mut GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
|
||||||
pub recorder: &'a mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
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,
|
||||||
|
|
@ -38,13 +32,13 @@ impl<
|
||||||
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||||
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||||
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||||
> RecordingGeometryWithRtree<'_, PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
> Recording<'_, GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>>
|
||||||
{
|
{
|
||||||
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(&mut self, weight: W) -> GenericIndex<W>
|
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(&mut self, weight: W) -> GenericIndex<W>
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PI>,
|
GenericIndex<W>: Into<PI>,
|
||||||
{
|
{
|
||||||
let dot = self.geometry_with_rtree.add_dot(weight);
|
let dot = self.inner.add_dot(weight);
|
||||||
self.recorder.dots.insert(
|
self.recorder.dots.insert(
|
||||||
Into::<PI>::into(dot)
|
Into::<PI>::into(dot)
|
||||||
.try_into()
|
.try_into()
|
||||||
|
|
@ -66,7 +60,7 @@ impl<
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PI>,
|
GenericIndex<W>: Into<PI>,
|
||||||
{
|
{
|
||||||
let seg = self.geometry_with_rtree.add_seg(from, to, weight);
|
let seg = self.inner.add_seg(from, to, weight);
|
||||||
self.recorder.segs.insert(
|
self.recorder.segs.insert(
|
||||||
Into::<PI>::into(seg)
|
Into::<PI>::into(seg)
|
||||||
.try_into()
|
.try_into()
|
||||||
|
|
@ -92,7 +86,7 @@ impl<
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PI>,
|
GenericIndex<W>: Into<PI>,
|
||||||
{
|
{
|
||||||
let bend = self.geometry_with_rtree.add_bend(from, to, core, weight);
|
let bend = self.inner.add_bend(from, to, core, weight);
|
||||||
self.recorder.bends.insert(
|
self.recorder.bends.insert(
|
||||||
Into::<PI>::into(bend)
|
Into::<PI>::into(bend)
|
||||||
.try_into()
|
.try_into()
|
||||||
|
|
@ -109,7 +103,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> {
|
pub fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> {
|
||||||
let compound = self.geometry_with_rtree.add_compound(weight);
|
let compound = self.inner.add_compound(weight);
|
||||||
self.recorder
|
self.recorder
|
||||||
.compounds
|
.compounds
|
||||||
.insert(compound, (None, Some((vec![], weight))));
|
.insert(compound, (None, Some((vec![], weight))));
|
||||||
|
|
@ -117,14 +111,13 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_to_compound<W>(&mut self, primitive: GenericIndex<W>, compound: GenericIndex<CW>) {
|
pub fn add_to_compound<W>(&mut self, primitive: GenericIndex<W>, compound: GenericIndex<CW>) {
|
||||||
let geometry = self.geometry_with_rtree.geometry();
|
let geometry = self.inner.geometry();
|
||||||
let old_members = geometry.compound_members(compound).collect();
|
let old_members = geometry.compound_members(compound).collect();
|
||||||
let old_weight = geometry.compound_weight(compound);
|
let old_weight = geometry.compound_weight(compound);
|
||||||
|
|
||||||
self.geometry_with_rtree
|
self.inner.add_to_compound(primitive, compound);
|
||||||
.add_to_compound(primitive, compound);
|
|
||||||
|
|
||||||
let geometry = self.geometry_with_rtree.geometry();
|
let geometry = self.inner.geometry();
|
||||||
let new_members = geometry.compound_members(compound).collect();
|
let new_members = geometry.compound_members(compound).collect();
|
||||||
let new_weight = geometry.compound_weight(compound);
|
let new_weight = geometry.compound_weight(compound);
|
||||||
|
|
||||||
|
|
@ -136,26 +129,26 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_dot(&mut self, dot: DI) -> Result<(), ()> {
|
pub fn remove_dot(&mut self, dot: DI) -> Result<(), ()> {
|
||||||
let weight = self.geometry_with_rtree.geometry().dot_weight(dot);
|
let weight = self.inner.geometry().dot_weight(dot);
|
||||||
self.geometry_with_rtree.remove_dot(dot)?;
|
self.inner.remove_dot(dot)?;
|
||||||
edit_remove_from_map(&mut self.recorder.dots, dot, weight);
|
edit_remove_from_map(&mut self.recorder.dots, dot, weight);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_seg(&mut self, seg: SI) {
|
pub fn remove_seg(&mut self, seg: SI) {
|
||||||
let geometry = self.geometry_with_rtree.geometry();
|
let geometry = self.inner.geometry();
|
||||||
let weight = geometry.seg_weight(seg);
|
let weight = geometry.seg_weight(seg);
|
||||||
let joints = geometry.seg_joints(seg);
|
let joints = geometry.seg_joints(seg);
|
||||||
self.geometry_with_rtree.remove_seg(seg);
|
self.inner.remove_seg(seg);
|
||||||
edit_remove_from_map(&mut self.recorder.segs, seg, (joints, weight));
|
edit_remove_from_map(&mut self.recorder.segs, seg, (joints, weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_bend(&mut self, bend: BI) {
|
pub fn remove_bend(&mut self, bend: BI) {
|
||||||
let geometry = self.geometry_with_rtree.geometry();
|
let geometry = self.inner.geometry();
|
||||||
let weight = geometry.bend_weight(bend);
|
let weight = geometry.bend_weight(bend);
|
||||||
let joints = geometry.bend_joints(bend);
|
let joints = geometry.bend_joints(bend);
|
||||||
let core = geometry.core(bend);
|
let core = geometry.core(bend);
|
||||||
self.geometry_with_rtree.remove_bend(bend);
|
self.inner.remove_bend(bend);
|
||||||
edit_remove_from_map(
|
edit_remove_from_map(
|
||||||
&mut self.recorder.bends,
|
&mut self.recorder.bends,
|
||||||
bend,
|
bend,
|
||||||
|
|
@ -164,17 +157,17 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_compound(&mut self, compound: GenericIndex<CW>) {
|
pub fn remove_compound(&mut self, compound: GenericIndex<CW>) {
|
||||||
let geometry = self.geometry_with_rtree.geometry();
|
let geometry = self.inner.geometry();
|
||||||
let weight = geometry.compound_weight(compound);
|
let weight = geometry.compound_weight(compound);
|
||||||
let members = geometry.compound_members(compound).collect();
|
let members = geometry.compound_members(compound).collect();
|
||||||
self.geometry_with_rtree.remove_compound(compound);
|
self.inner.remove_compound(compound);
|
||||||
edit_remove_from_map(&mut self.recorder.compounds, compound, (members, weight));
|
edit_remove_from_map(&mut self.recorder.compounds, compound, (members, weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_dot(&mut self, dot: DI, to: Point) {
|
pub fn move_dot(&mut self, dot: DI, to: Point) {
|
||||||
let old_weight = self.geometry_with_rtree.geometry().dot_weight(dot);
|
let old_weight = self.inner.geometry().dot_weight(dot);
|
||||||
self.geometry_with_rtree.move_dot(dot, to);
|
self.inner.move_dot(dot, to);
|
||||||
let new_weight = self.geometry_with_rtree.geometry().dot_weight(dot);
|
let new_weight = self.inner.geometry().dot_weight(dot);
|
||||||
|
|
||||||
self.recorder
|
self.recorder
|
||||||
.dots
|
.dots
|
||||||
|
|
@ -187,14 +180,14 @@ impl<
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>, BI),
|
F: FnOnce(&mut GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>, BI),
|
||||||
{
|
{
|
||||||
let geometry = self.geometry_with_rtree.geometry();
|
let geometry = self.inner.geometry();
|
||||||
let old_joints = geometry.bend_joints(bend);
|
let old_joints = geometry.bend_joints(bend);
|
||||||
let old_core = geometry.core(bend);
|
let old_core = geometry.core(bend);
|
||||||
let old_weight = geometry.bend_weight(bend);
|
let old_weight = geometry.bend_weight(bend);
|
||||||
|
|
||||||
f(&mut self.geometry_with_rtree, bend);
|
f(&mut self.inner, bend);
|
||||||
|
|
||||||
let geometry = self.geometry_with_rtree.geometry();
|
let geometry = self.inner.geometry();
|
||||||
let new_joints = geometry.bend_joints(bend);
|
let new_joints = geometry.bend_joints(bend);
|
||||||
let new_core = geometry.core(bend);
|
let new_core = geometry.core(bend);
|
||||||
let new_weight = geometry.bend_weight(bend);
|
let new_weight = geometry.bend_weight(bend);
|
||||||
|
|
@ -228,14 +221,14 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
|
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
|
||||||
self.geometry_with_rtree.compound_weight(compound)
|
self.inner.compound_weight(compound)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compounds<'a, W: 'a>(
|
pub fn compounds<'a, W: 'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
node: GenericIndex<W>,
|
node: GenericIndex<W>,
|
||||||
) -> impl Iterator<Item = GenericIndex<CW>> + 'a {
|
) -> impl Iterator<Item = GenericIndex<CW>> + 'a {
|
||||||
self.geometry_with_rtree.compounds(node)
|
self.inner.compounds(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recorder(&self) -> &GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
pub fn recorder(&self) -> &GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
||||||
|
|
@ -243,19 +236,19 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn geometry(&self) -> &Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
pub fn geometry(&self) -> &Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
||||||
self.geometry_with_rtree.geometry()
|
self.inner.geometry()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PI, GenericIndex<CW>>>> {
|
pub fn rtree(&self) -> &RTree<BboxedIndex<GenericNode<PI, GenericIndex<CW>>>> {
|
||||||
self.geometry_with_rtree.rtree()
|
self.inner.rtree()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layer_count(&self) -> usize {
|
pub fn layer_count(&self) -> usize {
|
||||||
*self.geometry_with_rtree.layer_count()
|
*self.inner.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.inner.graph()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,22 +273,3 @@ fn edit_remove_from_map<I, T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
> ApplyGeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
|
||||||
for RecordingGeometryWithRtree<'_, PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
|
||||||
{
|
|
||||||
#[inline(always)]
|
|
||||||
fn apply(&mut self, edit: &GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>) {
|
|
||||||
self.geometry_with_rtree.apply(edit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use contracts_try::debug_invariant;
|
use contracts_try::debug_invariant;
|
||||||
use core::hash::Hash;
|
use core::{cmp::Eq, hash::Hash};
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
use petgraph::stable_graph::StableDiGraph;
|
use petgraph::stable_graph::StableDiGraph;
|
||||||
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
drawing::graph::{GetLayer, Retag},
|
drawing::graph::{GetLayer, Retag},
|
||||||
geometry::{
|
geometry::{
|
||||||
compound::ManageCompounds,
|
compound::ManageCompounds,
|
||||||
edit::{ApplyGeometryEdit, GeometryEdit},
|
edit::{ApplyGeometryEdit, GeometryEdit, Recordable},
|
||||||
primitive::{AccessPrimitiveShape, PrimitiveShape},
|
primitive::{AccessPrimitiveShape, PrimitiveShape},
|
||||||
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
||||||
GetWidth,
|
GetWidth,
|
||||||
|
|
@ -48,6 +48,29 @@ pub struct GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI> {
|
||||||
layer_count: usize,
|
layer_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> + Copy + Eq + Hash,
|
||||||
|
DI: GetPetgraphIndex + Into<PI> + Copy + Eq + Hash,
|
||||||
|
SI: GetPetgraphIndex + Into<PI> + Copy + Eq + Hash,
|
||||||
|
BI: GetPetgraphIndex + Into<PI> + Copy + Eq + Hash,
|
||||||
|
> Recordable for GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
||||||
|
{
|
||||||
|
type PW = PW;
|
||||||
|
type DW = DW;
|
||||||
|
type SW = SW;
|
||||||
|
type BW = BW;
|
||||||
|
type CW = CW;
|
||||||
|
type PI = PI;
|
||||||
|
type DI = DI;
|
||||||
|
type SI = SI;
|
||||||
|
type BI = BI;
|
||||||
|
}
|
||||||
|
|
||||||
#[debug_invariant(self.test_envelopes())]
|
#[debug_invariant(self.test_envelopes())]
|
||||||
#[debug_invariant(self.geometry.graph().node_count() == self.rtree.size())]
|
#[debug_invariant(self.geometry.graph().node_count() == self.rtree.size())]
|
||||||
impl<
|
impl<
|
||||||
|
|
@ -70,28 +93,6 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn recording<'a>(
|
|
||||||
&'a mut self,
|
|
||||||
recorder: &'a mut super::edit::GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
|
||||||
) -> super::recording_with_rtree::RecordingGeometryWithRtree<
|
|
||||||
'a,
|
|
||||||
PW,
|
|
||||||
DW,
|
|
||||||
SW,
|
|
||||||
BW,
|
|
||||||
CW,
|
|
||||||
PI,
|
|
||||||
DI,
|
|
||||||
SI,
|
|
||||||
BI,
|
|
||||||
> {
|
|
||||||
super::recording_with_rtree::RecordingGeometryWithRtree {
|
|
||||||
geometry_with_rtree: self,
|
|
||||||
recorder,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(&mut self, weight: W) -> GenericIndex<W>
|
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(&mut self, weight: W) -> GenericIndex<W>
|
||||||
where
|
where
|
||||||
GenericIndex<W>: Into<PI>,
|
GenericIndex<W>: Into<PI>,
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,13 @@ use crate::{
|
||||||
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
|
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
|
||||||
SegWeight, SeqLooseSegIndex, SeqLooseSegWeight,
|
SegWeight, SeqLooseSegIndex, SeqLooseSegWeight,
|
||||||
},
|
},
|
||||||
Drawing, DrawingEdit, DrawingException, Infringement, RecordingDrawing,
|
Drawing, DrawingEdit, DrawingException, Infringement,
|
||||||
|
},
|
||||||
|
geometry::{
|
||||||
|
edit::{ApplyGeometryEdit, Recordable, Recording},
|
||||||
|
shape::Shape,
|
||||||
|
GenericNode,
|
||||||
},
|
},
|
||||||
geometry::{edit::ApplyGeometryEdit, shape::Shape, GenericNode},
|
|
||||||
graph::{GenericIndex, GetPetgraphIndex},
|
graph::{GenericIndex, GetPetgraphIndex},
|
||||||
layout::{
|
layout::{
|
||||||
poly::{MakePolyShape, Poly, PolyWeight},
|
poly::{MakePolyShape, Poly, PolyWeight},
|
||||||
|
|
@ -53,24 +57,23 @@ pub struct Layout<R> {
|
||||||
drawing: Drawing<CompoundWeight, R>,
|
drawing: Drawing<CompoundWeight, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RecordingLayout<'a, R> {
|
|
||||||
pub layout: &'a mut Layout<R>,
|
|
||||||
pub recorder: &'a mut LayoutEdit,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> Layout<R> {
|
impl<R> Layout<R> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(drawing: Drawing<CompoundWeight, R>) -> Self {
|
pub fn new(drawing: Drawing<CompoundWeight, R>) -> Self {
|
||||||
Self { drawing }
|
Self { drawing }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
impl<R> Recordable for Layout<R> {
|
||||||
pub fn recording<'a>(&'a mut self, recorder: &'a mut LayoutEdit) -> RecordingLayout<'a, R> {
|
type PW = PrimitiveWeight;
|
||||||
RecordingLayout {
|
type DW = DotWeight;
|
||||||
layout: self,
|
type SW = SegWeight;
|
||||||
recorder,
|
type BW = BendWeight;
|
||||||
}
|
type CW = CompoundWeight;
|
||||||
}
|
type PI = PrimitiveIndex;
|
||||||
|
type DI = DotIndex;
|
||||||
|
type SI = SegIndex;
|
||||||
|
type BI = BendIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: AccessRules> Layout<R> {
|
impl<R: AccessRules> Layout<R> {
|
||||||
|
|
@ -205,22 +208,13 @@ impl<R: AccessRules> Layout<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a hack, but it allows us to not needing as much boilerplate for delegations
|
impl<R: AccessRules> Recording<'_, Layout<R>> {
|
||||||
impl<R> core::ops::Deref for RecordingLayout<'_, R> {
|
fn recording_drawing(&mut self) -> Recording<'_, Drawing<CompoundWeight, R>> {
|
||||||
type Target = Layout<R>;
|
self.inner.drawing.recording(self.recorder)
|
||||||
|
|
||||||
fn deref(&self) -> &Layout<R> {
|
|
||||||
self.layout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: AccessRules> RecordingLayout<'_, R> {
|
|
||||||
fn recording_drawing(&mut self) -> RecordingDrawing<'_, CompoundWeight, R> {
|
|
||||||
self.layout.drawing.recording(self.recorder)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rules_mut(&mut self) -> &mut R {
|
pub fn rules_mut(&mut self) -> &mut R {
|
||||||
self.layout.drawing.rules_mut()
|
self.inner.drawing.rules_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert [`Cane`] object into the [`Layout`]
|
/// Insert [`Cane`] object into the [`Layout`]
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ use crate::{
|
||||||
dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight},
|
dot::{DotIndex, FixedDotIndex, LooseDotIndex, LooseDotWeight},
|
||||||
gear::GearIndex,
|
gear::GearIndex,
|
||||||
graph::{GetLayer, GetMaybeNet, MakePrimitive},
|
graph::{GetLayer, GetMaybeNet, MakePrimitive},
|
||||||
guide::Guide,
|
|
||||||
head::{CaneHead, GetFace, Head},
|
head::{CaneHead, GetFace, Head},
|
||||||
primitive::GetOtherJoint,
|
primitive::GetOtherJoint,
|
||||||
rules::AccessRules,
|
rules::AccessRules,
|
||||||
seg::{LoneLooseSegWeight, SeqLooseSegWeight},
|
seg::{LoneLooseSegWeight, SeqLooseSegWeight},
|
||||||
Drawing, DrawingException, Infringement,
|
DrawingException, Infringement,
|
||||||
},
|
},
|
||||||
layout::{CompoundWeight, Layout, LayoutEdit, RecordingLayout},
|
geometry::edit::Recording,
|
||||||
|
layout::Layout,
|
||||||
math::{Circle, NoTangents},
|
math::{Circle, NoTangents},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ pub trait Draw {
|
||||||
fn undo_cane(&mut self, head: CaneHead) -> Option<Head>;
|
fn undo_cane(&mut self, head: CaneHead) -> Option<Head>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: AccessRules> Draw for RecordingLayout<'a, R> {
|
impl<'a, R: AccessRules> Draw for Recording<'a, Layout<R>> {
|
||||||
fn start(&mut self, from: LooseDotIndex) -> Head {
|
fn start(&mut self, from: LooseDotIndex) -> Head {
|
||||||
self.guide().cane_head(from).into()
|
self.guide().cane_head(from).into()
|
||||||
}
|
}
|
||||||
|
|
@ -188,7 +188,7 @@ impl<'a, R: AccessRules> Draw for RecordingLayout<'a, R> {
|
||||||
#[debug_ensures(ret.is_ok() -> this.drawing().node_count() == old(this.drawing().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> this.drawing().node_count() == old(this.drawing().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> this.drawing().node_count() == old(this.drawing().node_count()))]
|
#[debug_ensures(ret.is_err() -> this.drawing().node_count() == old(this.drawing().node_count()))]
|
||||||
fn cane_around<R: AccessRules>(
|
fn cane_around<R: AccessRules>(
|
||||||
this: &mut RecordingLayout<'_, R>,
|
this: &mut Recording<'_, Layout<R>>,
|
||||||
head: Head,
|
head: Head,
|
||||||
around: GearIndex,
|
around: GearIndex,
|
||||||
from: Point,
|
from: Point,
|
||||||
|
|
@ -203,7 +203,7 @@ fn cane_around<R: AccessRules>(
|
||||||
|
|
||||||
#[debug_ensures(this.drawing().node_count() == old(this.drawing().node_count()))]
|
#[debug_ensures(this.drawing().node_count() == old(this.drawing().node_count()))]
|
||||||
fn extend_head<R: AccessRules>(
|
fn extend_head<R: AccessRules>(
|
||||||
this: &mut RecordingLayout<'_, R>,
|
this: &mut Recording<'_, Layout<R>>,
|
||||||
head: Head,
|
head: Head,
|
||||||
to: Point,
|
to: Point,
|
||||||
) -> Result<Head, Infringement> {
|
) -> Result<Head, Infringement> {
|
||||||
|
|
@ -218,7 +218,7 @@ fn extend_head<R: AccessRules>(
|
||||||
#[debug_ensures(ret.is_ok() -> this.drawing().node_count() == old(this.drawing().node_count() + 4))]
|
#[debug_ensures(ret.is_ok() -> this.drawing().node_count() == old(this.drawing().node_count() + 4))]
|
||||||
#[debug_ensures(ret.is_err() -> this.drawing().node_count() == old(this.drawing().node_count()))]
|
#[debug_ensures(ret.is_err() -> this.drawing().node_count() == old(this.drawing().node_count()))]
|
||||||
fn cane<R: AccessRules>(
|
fn cane<R: AccessRules>(
|
||||||
this: &mut RecordingLayout<'_, R>,
|
this: &mut Recording<'_, Layout<R>>,
|
||||||
head: Head,
|
head: Head,
|
||||||
around: GearIndex,
|
around: GearIndex,
|
||||||
to: Point,
|
to: Point,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use crate::{
|
||||||
head::{BareHead, CaneHead, Head},
|
head::{BareHead, CaneHead, Head},
|
||||||
rules::AccessRules,
|
rules::AccessRules,
|
||||||
},
|
},
|
||||||
|
geometry::edit::Recordable,
|
||||||
layout::LayoutEdit,
|
layout::LayoutEdit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing::{band::BandTermsegIndex, dot::FixedDotIndex, rules::AccessRules},
|
drawing::{band::BandTermsegIndex, dot::FixedDotIndex, rules::AccessRules},
|
||||||
|
geometry::edit::Recordable,
|
||||||
layout::{Layout, LayoutEdit},
|
layout::{Layout, LayoutEdit},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue