feat: use topola-rules / put 'AccessRules' into separate crate

This commit is contained in:
Ellen Emilia Anna Zscheile 2025-01-31 14:13:28 +01:00
parent 67c4933b09
commit 910ab5b76a
34 changed files with 317 additions and 118 deletions

1
.gitignore vendored
View File

@ -28,6 +28,7 @@ fp-info-cache
# Lockfiles # Lockfiles
*.lck *.lck
.#*
# ---> Topola # ---> Topola
*.ses *.ses

View File

@ -13,6 +13,7 @@ geo-types.workspace = true
serde.workspace = true serde.workspace = true
specctra_derive.path = "../specctra_derive" specctra_derive.path = "../specctra_derive"
thiserror.workspace = true thiserror.workspace = true
topola-rules.path = "../topola-rules"
utf8-chars = "3.0" utf8-chars = "3.0"
[dependencies.rstar] [dependencies.rstar]

View File

@ -8,7 +8,7 @@ pub mod error;
pub mod math; pub mod math;
pub mod mesadata; pub mod mesadata;
pub mod read; pub mod read;
pub mod rules; pub use topola_rules as rules;
pub mod structure; pub mod structure;
pub mod write; pub mod write;

View File

@ -9,7 +9,7 @@ use bimap::BiBTreeMap;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use crate::{ use crate::{
rules::{AccessRules, Conditions}, rules::{AccessRules, Conditions, OrderedPair},
structure::Pcb, structure::Pcb,
}; };
@ -17,7 +17,7 @@ use crate::{
/// ///
/// This trait implements generic function for accessing or modifying different /// This trait implements generic function for accessing or modifying different
/// compounds of board parts like nets or layers /// compounds of board parts like nets or layers
pub trait AccessMesadata: AccessRules { pub trait AccessMesadata: AccessRules<Scalar = f64, ObjectKind = ()> {
/// Renames a layer based on its index. /// Renames a layer based on its index.
fn bename_layer(&mut self, layer: usize, layername: String); fn bename_layer(&mut self, layer: usize, layername: String);
@ -178,19 +178,16 @@ impl SpecctraMesadata {
} }
impl AccessRules for SpecctraMesadata { impl AccessRules for SpecctraMesadata {
fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64 { type Scalar = f64;
let (Some(net1), Some(net2)) = (conditions1.maybe_net, conditions2.maybe_net) else { type ObjectKind = ();
return 0.0;
};
let clr1 = self.get_rule(net1).clearance; fn clearance(&self, conditions: OrderedPair<&Conditions<'_, ()>>) -> f64 {
let clr2 = self.get_rule(net2).clearance; let (conditions1, conditions2) = conditions.into();
if clr1 > clr2 { let clr1 = self.get_rule(conditions1.net).clearance;
clr1 let clr2 = self.get_rule(conditions2.net).clearance;
} else {
clr2 f64::max(clr1, clr2)
}
} }
fn largest_clearance(&self, _maybe_net: Option<usize>) -> f64 { fn largest_clearance(&self, _maybe_net: Option<usize>) -> f64 {

View File

@ -1,19 +0,0 @@
// SPDX-FileCopyrightText: 2024 Topola contributors
//
// SPDX-License-Identifier: MIT
pub trait GetConditions {
fn conditions(&self) -> Conditions;
}
#[derive(Debug, Default)]
pub struct Conditions {
pub maybe_net: Option<usize>,
pub maybe_region: Option<String>,
pub maybe_layer: Option<String>,
}
pub trait AccessRules {
fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64;
fn largest_clearance(&self, net: Option<usize>) -> f64;
}

View File

@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2024 Topola contributors
#
# SPDX-License-Identifier: MIT OR Apache-2.0
[package]
name = "topola-rules"
version = "0.1.1"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://codeberg.org/topola/topola"
[package.metadata.docs.rs]
features = ["serde"]
[dependencies]
[dependencies.serde]
version = "1.0"
features = ["derive", "alloc"]
default-features = false
optional = true

View File

@ -0,0 +1,3 @@
# topola-rules
Generic design rules/clearance handling.

View File

@ -0,0 +1,163 @@
// SPDX-FileCopyrightText: 2025 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0
//
//! Generic design rules/clearance handling.
#![no_std]
extern crate alloc;
use alloc::borrow::Cow;
use core::ops;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(from = "(T, T)", into = "(T, T)"))]
#[cfg_attr(
feature = "serde",
serde(bound(
deserialize = "T: serde::Deserialize<'de> + Ord",
serialize = "T: serde::Serialize + Clone"
))
)]
pub struct OrderedPair<T>(T, T);
impl<T> ops::Index<bool> for OrderedPair<T> {
type Output = T;
#[inline]
fn index(&self, index: bool) -> &T {
if index { &self.1 } else { &self.0 }
}
}
impl<T: Ord> From<(T, T)> for OrderedPair<T> {
fn from(mut x: (T, T)) -> Self {
if x.0 > x.1 {
core::mem::swap(&mut x.0, &mut x.1);
}
let (a, b) = x;
Self(a, b)
}
}
impl<T> From<OrderedPair<T>> for (T, T) {
#[inline(always)]
fn from(OrderedPair(a, b): OrderedPair<T>) -> (T, T) {
(a, b)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Conditions<'a, K> {
pub net: usize,
#[cfg_attr(feature = "serde", serde(borrow))]
pub maybe_region: Option<Cow<'a, str>>,
#[cfg_attr(feature = "serde", serde(borrow))]
pub maybe_layer: Option<Cow<'a, str>>,
pub kind: K,
}
impl<K: Copy> Conditions<'_, K> {
#[inline]
pub fn ref_(&self) -> Conditions<'_, K> {
Conditions {
net: self.net,
maybe_region: self.maybe_region.as_ref().map(|i| Cow::Borrowed(&**i)),
maybe_layer: self.maybe_layer.as_ref().map(|i| Cow::Borrowed(&**i)),
kind: self.kind,
}
}
}
pub trait GetConditions<'a>: Sized {
type ObjectKind: Copy + Eq;
#[inline(always)]
fn conditions(self) -> Option<Conditions<'a, Self::ObjectKind>> {
None
}
}
impl<'a, K: Copy + Eq> GetConditions<'a> for &'a Conditions<'_, K> {
type ObjectKind = K;
#[inline]
fn conditions(self) -> Option<Conditions<'a, K>> {
Some(self.ref_())
}
}
impl<'a, T: Copy + GetConditions<'a>> GetConditions<'a> for &T {
type ObjectKind = <T as GetConditions<'a>>::ObjectKind;
#[inline(always)]
fn conditions(self) -> Option<Conditions<'a, <T as GetConditions<'a>>::ObjectKind>> {
T::conditions(*self)
}
}
pub trait GetWidth {
type Scalar: Copy;
fn width(&self) -> Self::Scalar;
}
impl<T: GetWidth> GetWidth for &T {
type Scalar = <T as GetWidth>::Scalar;
#[inline(always)]
fn width(&self) -> <T as GetWidth>::Scalar {
T::width(*self)
}
}
pub trait AccessRules {
type Scalar: Copy + core::ops::Add<Output = Self::Scalar> + core::iter::Sum;
type ObjectKind: Copy + Eq;
fn clearance(&self, conditions: OrderedPair<&Conditions<'_, Self::ObjectKind>>)
-> Self::Scalar;
fn largest_clearance(&self, maybe_net: Option<usize>) -> Self::Scalar;
}
impl<T: AccessRules + Copy> AccessRules for &T {
type Scalar = <T as AccessRules>::Scalar;
type ObjectKind = <T as AccessRules>::ObjectKind;
#[inline(always)]
fn clearance(
&self,
conditions: OrderedPair<&Conditions<'_, <T as AccessRules>::ObjectKind>>,
) -> <T as AccessRules>::Scalar {
T::clearance(*self, conditions)
}
#[inline(always)]
fn largest_clearance(&self, maybe_net: Option<usize>) -> <T as AccessRules>::Scalar {
T::largest_clearance(*self, maybe_net)
}
}
impl<T: AccessRules + ?Sized> AccessRules for alloc::sync::Arc<T> {
type Scalar = <T as AccessRules>::Scalar;
type ObjectKind = <T as AccessRules>::ObjectKind;
#[inline(always)]
fn clearance(
&self,
conditions: OrderedPair<&Conditions<'_, <T as AccessRules>::ObjectKind>>,
) -> <T as AccessRules>::Scalar {
T::clearance(self, conditions)
}
#[inline(always)]
fn largest_clearance(&self, maybe_net: Option<usize>) -> <T as AccessRules>::Scalar {
T::largest_clearance(self, maybe_net)
}
}

View File

@ -25,7 +25,7 @@ use crate::{
dot::FixedDotIndex, dot::FixedDotIndex,
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex}, graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules, AccessRules,
}, },
geometry::shape::AccessShape, geometry::shape::AccessShape,
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},

View File

@ -15,9 +15,8 @@ use super::{
graph::MakePrimitive, graph::MakePrimitive,
loose::{GetPrevNextLoose, LooseIndex}, loose::{GetPrevNextLoose, LooseIndex},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules,
seg::{LoneLooseSegIndex, SeqLooseSegIndex}, seg::{LoneLooseSegIndex, SeqLooseSegIndex},
Drawing, AccessRules, Drawing,
}; };
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]

View File

@ -8,8 +8,7 @@ use crate::{
drawing::{ drawing::{
graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight, Retag}, graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight, Retag},
primitive::{GenericPrimitive, Primitive}, primitive::{GenericPrimitive, Primitive},
rules::AccessRules, AccessRules, Drawing,
Drawing,
}, },
geometry::{GetOffset, GetWidth, SetOffset}, geometry::{GetOffset, GetWidth, SetOffset},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},

View File

@ -7,9 +7,8 @@ use super::{
dot::LooseDotIndex, dot::LooseDotIndex,
graph::PrimitiveIndex, graph::PrimitiveIndex,
primitive::{GetInterior, GetJoints, GetOtherJoint, LooseBend, LooseDot}, primitive::{GetInterior, GetJoints, GetOtherJoint, LooseBend, LooseDot},
rules::AccessRules,
seg::SeqLooseSegIndex, seg::SeqLooseSegIndex,
Drawing, AccessRules, Drawing,
}; };
/// A cane is a sequence consisting of a seg followed by a dot followed by a /// A cane is a sequence consisting of a seg followed by a dot followed by a

View File

@ -11,8 +11,7 @@ use super::{
graph::PrimitiveIndex, graph::PrimitiveIndex,
loose::{GetPrevNextLoose, LooseIndex}, loose::{GetPrevNextLoose, LooseIndex},
primitive::{GetInnerOuter, GetJoints}, primitive::{GetInnerOuter, GetJoints},
rules::AccessRules, AccessRules, Drawing,
Drawing,
}; };
pub trait Collect { pub trait Collect {

View File

@ -11,8 +11,7 @@ use crate::{
drawing::{ drawing::{
graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight, Retag}, graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight, Retag},
primitive::{GenericPrimitive, Primitive}, primitive::{GenericPrimitive, Primitive},
rules::AccessRules, AccessRules, Drawing,
Drawing,
}, },
geometry::{GetSetPos, GetWidth}, geometry::{GetSetPos, GetWidth},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},

View File

@ -36,11 +36,12 @@ use crate::{
GenericPrimitive, GetCore, GetInnerOuter, GetJoints, GetLimbs, GetOtherJoint, GenericPrimitive, GetCore, GetInnerOuter, GetJoints, GetLimbs, GetOtherJoint,
MakePrimitiveShape, MakePrimitiveShape,
}, },
rules::{AccessRules, GetConditions}, rules::GetConditions,
seg::{ seg::{
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
SegWeight, SeqLooseSegIndex, SeqLooseSegWeight, SegWeight, SeqLooseSegIndex, SeqLooseSegWeight,
}, },
AccessRules,
}, },
graph::MakeRef, graph::MakeRef,
}; };
@ -982,8 +983,12 @@ impl<CW: Copy, R: AccessRules> Drawing<CW, R> {
let epsilon = 1.0; let epsilon = 1.0;
inflated_shape = node.primitive(self).shape().inflate( inflated_shape = node.primitive(self).shape().inflate(
(self.rules.clearance(&conditions, &infringee_conditions) - epsilon) match (&conditions, infringee_conditions) {
.clamp(0.0, f64::INFINITY), (None, _) | (_, None) => 0.0,
(Some(lhs), Some(rhs)) => (self.rules.clearance((lhs, &rhs).into())
- epsilon)
.clamp(0.0, f64::INFINITY),
},
); );
inflated_shape inflated_shape

View File

@ -11,8 +11,7 @@ use crate::{
dot::FixedDotIndex, dot::FixedDotIndex,
graph::{MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
primitive::{FixedBend, FixedDot, GetFirstGear, GetInnerOuter, LooseBend, Primitive}, primitive::{FixedBend, FixedDot, GetFirstGear, GetInnerOuter, LooseBend, Primitive},
rules::AccessRules, AccessRules, Drawing,
Drawing,
}, },
graph::{GetPetgraphIndex, MakeRef}, graph::{GetPetgraphIndex, MakeRef},
}; };

View File

@ -11,11 +11,11 @@ use super::{
bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
dot::{FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, dot::{FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
primitive::Primitive, primitive::Primitive,
rules::AccessRules,
seg::{ seg::{
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex,
SeqLooseSegWeight, SeqLooseSegWeight,
}, },
AccessRules,
}; };
#[enum_dispatch] #[enum_dispatch]

View File

@ -18,8 +18,8 @@ use super::{
graph::{MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
head::{BareHead, CaneHead, GetFace, Head}, head::{BareHead, CaneHead, GetFace, Head},
primitive::{GetCore, GetInnerOuter, GetJoints, GetOtherJoint, GetWeight, MakePrimitiveShape}, primitive::{GetCore, GetInnerOuter, GetJoints, GetOtherJoint, GetWeight, MakePrimitiveShape},
rules::{AccessRules, Conditions, GetConditions}, rules::{Conditions, GetConditions},
Drawing, AccessRules, Drawing,
}; };
pub trait Guide { pub trait Guide {
@ -97,7 +97,8 @@ impl<CW: Copy, R: AccessRules> Guide for Drawing<CW, R> {
width: f64, width: f64,
) -> Result<(Line, Line), NoTangents> { ) -> Result<(Line, Line), NoTangents> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width, &self.conditions(head.face().into())); let to_circle =
self.dot_circle(around, width, self.conditions(head.face().into()).as_ref());
let from_cw = self.head_cw(head); let from_cw = self.head_cw(head);
let tangents: Vec<Line> = let tangents: Vec<Line> =
@ -113,16 +114,17 @@ impl<CW: Copy, R: AccessRules> Guide for Drawing<CW, R> {
width: f64, width: f64,
) -> Result<Line, NoTangents> { ) -> Result<Line, NoTangents> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width, &self.conditions(head.face().into())); let to_circle =
self.dot_circle(around, width, self.conditions(head.face().into()).as_ref());
let from_cw = self.head_cw(head); let from_cw = self.head_cw(head);
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw)) math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
} }
fn head_around_dot_offset(&self, head: &Head, around: DotIndex, _width: f64) -> f64 { fn head_around_dot_offset(&self, head: &Head, around: DotIndex, _width: f64) -> f64 {
self.rules().clearance( self.clearance(
&self.conditions(around.into()), self.conditions(around.into()).as_ref(),
&self.conditions(head.face().into()), self.conditions(head.face().into()).as_ref(),
) )
} }
@ -133,7 +135,8 @@ impl<CW: Copy, R: AccessRules> Guide for Drawing<CW, R> {
width: f64, width: f64,
) -> Result<(Line, Line), NoTangents> { ) -> Result<(Line, Line), NoTangents> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width, &self.conditions(head.face().into())); let to_circle =
self.bend_circle(around, width, self.conditions(head.face().into()).as_ref());
let from_cw = self.head_cw(head); let from_cw = self.head_cw(head);
let tangents: Vec<Line> = let tangents: Vec<Line> =
@ -149,16 +152,17 @@ impl<CW: Copy, R: AccessRules> Guide for Drawing<CW, R> {
width: f64, width: f64,
) -> Result<Line, NoTangents> { ) -> Result<Line, NoTangents> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width, &self.conditions(head.face().into())); let to_circle =
self.bend_circle(around, width, self.conditions(head.face().into()).as_ref());
let from_cw = self.head_cw(head); let from_cw = self.head_cw(head);
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw)) math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
} }
fn head_around_bend_offset(&self, head: &Head, around: BendIndex, _width: f64) -> f64 { fn head_around_bend_offset(&self, head: &Head, around: BendIndex, _width: f64) -> f64 {
self.rules().clearance( self.clearance(
&self.conditions(head.face().into()), self.conditions(head.face().into()).as_ref(),
&self.conditions(around.into()), self.conditions(around.into()).as_ref(),
) )
} }
@ -196,18 +200,37 @@ impl<CW: Copy, R: AccessRules> Guide for Drawing<CW, R> {
} }
trait GuidePrivate { trait GuidePrivate {
fn clearance(&self, lhs: Option<&Conditions<'_, ()>>, rhs: Option<&Conditions<'_, ()>>) -> f64;
fn head_circle(&self, head: &Head, width: f64) -> Circle; fn head_circle(&self, head: &Head, width: f64) -> Circle;
fn bend_circle(&self, bend: BendIndex, width: f64, guide_conditions: &Conditions) -> Circle; fn bend_circle(
&self,
bend: BendIndex,
width: f64,
guide_conditions: Option<&Conditions<'_, ()>>,
) -> Circle;
fn dot_circle(&self, dot: DotIndex, width: f64, guide_conditions: &Conditions) -> Circle; fn dot_circle(
&self,
dot: DotIndex,
width: f64,
guide_conditions: Option<&Conditions<'_, ()>>,
) -> Circle;
fn rear(&self, head: CaneHead) -> DotIndex; fn rear(&self, head: CaneHead) -> DotIndex;
fn conditions(&self, node: PrimitiveIndex) -> Conditions; fn conditions(&self, node: PrimitiveIndex) -> Option<Conditions<'_, ()>>;
} }
impl<CW: Copy, R: AccessRules> GuidePrivate for Drawing<CW, R> { impl<CW: Copy, R: AccessRules> GuidePrivate for Drawing<CW, R> {
fn clearance(&self, lhs: Option<&Conditions<'_, ()>>, rhs: Option<&Conditions<'_, ()>>) -> f64 {
match (lhs, rhs) {
(None, _) | (_, None) => 0.0,
(Some(lhs), Some(rhs)) => self.rules().clearance((lhs, rhs).into()),
}
}
fn head_circle(&self, head: &Head, width: f64) -> Circle { fn head_circle(&self, head: &Head, width: f64) -> Circle {
match *head { match *head {
Head::Bare(head) => Circle { Head::Bare(head) => Circle {
@ -216,19 +239,28 @@ impl<CW: Copy, R: AccessRules> GuidePrivate for Drawing<CW, R> {
}, },
Head::Cane(head) => { Head::Cane(head) => {
if let Some(inner) = self.primitive(head.cane.bend).inner() { if let Some(inner) = self.primitive(head.cane.bend).inner() {
self.bend_circle(inner.into(), width, &self.conditions(head.face().into())) self.bend_circle(
inner.into(),
width,
self.conditions(head.face().into()).as_ref(),
)
} else { } else {
self.dot_circle( self.dot_circle(
self.primitive(head.cane.bend).core().into(), self.primitive(head.cane.bend).core().into(),
width, width,
&self.conditions(head.face().into()), self.conditions(head.face().into()).as_ref(),
) )
} }
} }
} }
} }
fn bend_circle(&self, bend: BendIndex, width: f64, guide_conditions: &Conditions) -> Circle { fn bend_circle(
&self,
bend: BendIndex,
width: f64,
guide_conditions: Option<&Conditions<'_, ()>>,
) -> Circle {
let outer_circle = match bend.primitive(self).shape() { let outer_circle = match bend.primitive(self).shape() {
PrimitiveShape::Bend(shape) => shape.outer_circle(), PrimitiveShape::Bend(shape) => shape.outer_circle(),
_ => unreachable!(), _ => unreachable!(),
@ -238,21 +270,22 @@ impl<CW: Copy, R: AccessRules> GuidePrivate for Drawing<CW, R> {
pos: outer_circle.pos, pos: outer_circle.pos,
r: outer_circle.r r: outer_circle.r
+ width / 2.0 + width / 2.0
+ self + self.clearance(self.conditions(bend.into()).as_ref(), guide_conditions),
.rules()
.clearance(&self.conditions(bend.into()), guide_conditions),
} }
} }
fn dot_circle(&self, dot: DotIndex, width: f64, guide_conditions: &Conditions) -> Circle { fn dot_circle(
&self,
dot: DotIndex,
width: f64,
guide_conditions: Option<&Conditions<'_, ()>>,
) -> Circle {
let shape = dot.primitive(self).shape(); let shape = dot.primitive(self).shape();
Circle { Circle {
pos: shape.center(), pos: shape.center(),
r: shape.width() / 2.0 r: shape.width() / 2.0
+ width / 2.0 + width / 2.0
+ self + self.clearance(self.conditions(dot.into()).as_ref(), guide_conditions),
.rules()
.clearance(&self.conditions(dot.into()), guide_conditions),
} }
} }
@ -261,7 +294,7 @@ impl<CW: Copy, R: AccessRules> GuidePrivate for Drawing<CW, R> {
.other_joint(head.cane.dot.into()) .other_joint(head.cane.dot.into())
} }
fn conditions(&self, node: PrimitiveIndex) -> Conditions { fn conditions(&self, node: PrimitiveIndex) -> Option<Conditions<'_, ()>> {
node.primitive(self).conditions() node.primitive(self).conditions()
} }
} }

View File

@ -10,8 +10,7 @@ use super::{
cane::Cane, cane::Cane,
dot::{DotIndex, FixedDotIndex, LooseDotIndex}, dot::{DotIndex, FixedDotIndex, LooseDotIndex},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules, AccessRules, Drawing,
Drawing,
}; };
#[enum_dispatch] #[enum_dispatch]

View File

@ -13,12 +13,11 @@ use crate::{
graph::{MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
primitive::{GetJoints, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg}, primitive::{GetJoints, LoneLooseSeg, LooseBend, LooseDot, Primitive, SeqLooseSeg},
seg::{LoneLooseSegIndex, SeqLooseSegIndex}, seg::{LoneLooseSegIndex, SeqLooseSegIndex},
AccessRules,
}, },
graph::GetPetgraphIndex, graph::GetPetgraphIndex,
}; };
use super::rules::AccessRules;
#[enum_dispatch] #[enum_dispatch]
pub trait GetPrevNextLoose { pub trait GetPrevNextLoose {
fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex>; fn next_loose(&self, maybe_prev: Option<LooseIndex>) -> Option<LooseIndex>;

View File

@ -15,6 +15,7 @@ mod guide;
pub mod head; pub mod head;
pub mod loose; pub mod loose;
pub mod primitive; pub mod primitive;
pub use crate::specctra::AccessRules;
pub use specctra_core::rules; pub use specctra_core::rules;
pub mod seg; pub mod seg;

View File

@ -11,13 +11,13 @@ use crate::{
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
graph::{GetLayer, GetMaybeNet, PrimitiveIndex, PrimitiveWeight, Retag}, graph::{GetLayer, GetMaybeNet, PrimitiveIndex, PrimitiveWeight, Retag},
seg::{FixedSegWeight, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight}, seg::{FixedSegWeight, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight},
Drawing, AccessRules, Drawing,
}, },
geometry::{primitive::PrimitiveShape, GenericNode, GetOffset, GetWidth}, geometry::{primitive::PrimitiveShape, GenericNode, GetOffset, GetWidth},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
}; };
use specctra_core::rules::{AccessRules, Conditions, GetConditions}; use specctra_core::rules::{Conditions, GetConditions};
#[enum_dispatch] #[enum_dispatch]
pub trait GetDrawing<'a, R: AccessRules> { pub trait GetDrawing<'a, R: AccessRules> {
@ -171,16 +171,20 @@ pub enum Primitive<'a, CW: Copy, R: AccessRules> {
LooseBend(LooseBend<'a, CW, R>), LooseBend(LooseBend<'a, CW, R>),
} }
impl<'a, CW: Copy, R: AccessRules> specctra_core::rules::GetConditions for Primitive<'a, CW, R> { impl<'a, CW: Copy, R: AccessRules> specctra_core::rules::GetConditions<'a>
fn conditions(&self) -> specctra_core::rules::Conditions { for &Primitive<'a, CW, R>
{
type ObjectKind = ();
fn conditions(self) -> Option<specctra_core::rules::Conditions<'a, ()>> {
match self { match self {
Self::FixedDot(x) => x.conditions(), Primitive::FixedDot(x) => x.conditions(),
Self::LooseDot(x) => x.conditions(), Primitive::LooseDot(x) => x.conditions(),
Self::FixedSeg(x) => x.conditions(), Primitive::FixedSeg(x) => x.conditions(),
Self::LoneLooseSeg(x) => x.conditions(), Primitive::LoneLooseSeg(x) => x.conditions(),
Self::SeqLooseSeg(x) => x.conditions(), Primitive::SeqLooseSeg(x) => x.conditions(),
Self::FixedBend(x) => x.conditions(), Primitive::FixedBend(x) => x.conditions(),
Self::LooseBend(x) => x.conditions(), Primitive::LooseBend(x) => x.conditions(),
} }
} }
} }
@ -244,16 +248,19 @@ where
} }
} }
impl<'a, W, CW: Copy, R: AccessRules> GetConditions for GenericPrimitive<'a, W, CW, R> impl<'a, W, CW: Copy, R: AccessRules> GetConditions<'a> for &GenericPrimitive<'a, W, CW, R>
where where
GenericPrimitive<'a, W, CW, R>: GetMaybeNet, GenericPrimitive<'a, W, CW, R>: GetMaybeNet,
{ {
fn conditions(&self) -> Conditions { type ObjectKind = ();
Conditions {
maybe_net: self.maybe_net(), fn conditions(self) -> Option<Conditions<'a, ()>> {
maybe_region: Some("A".to_string()), self.maybe_net().map(|net| Conditions {
maybe_layer: Some("F.Cu".to_string()), net,
} maybe_region: Some("A".into()),
maybe_layer: Some("F.Cu".into()),
kind: (),
})
} }
} }

View File

@ -8,8 +8,7 @@ use crate::{
drawing::{ drawing::{
graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight, Retag}, graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex, PrimitiveWeight, Retag},
primitive::{GenericPrimitive, Primitive}, primitive::{GenericPrimitive, Primitive},
rules::AccessRules, AccessRules, Drawing,
Drawing,
}, },
geometry::GetWidth, geometry::GetWidth,
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},

View File

@ -18,8 +18,8 @@ use crate::{
dot::DotWeight, dot::DotWeight,
graph::{PrimitiveWeight, Retag}, graph::{PrimitiveWeight, Retag},
primitive::Primitive, primitive::Primitive,
rules::AccessRules,
seg::SegWeight, seg::SegWeight,
AccessRules,
}, },
geometry::{ geometry::{
compound::ManageCompounds, compound::ManageCompounds,

View File

@ -16,12 +16,11 @@ use crate::{
gear::GearIndex, gear::GearIndex,
graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules,
seg::{ seg::{
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex, FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
SegWeight, SeqLooseSegIndex, SeqLooseSegWeight, SegWeight, SeqLooseSegIndex, SeqLooseSegWeight,
}, },
Cane, Drawing, DrawingEdit, DrawingException, Infringement, AccessRules, Cane, Drawing, DrawingEdit, DrawingException, Infringement,
}, },
geometry::{edit::ApplyGeometryEdit, shape::Shape, GenericNode}, geometry::{edit::ApplyGeometryEdit, shape::Shape, GenericNode},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},

View File

@ -13,9 +13,8 @@ use crate::{
dot::FixedDotIndex, dot::FixedDotIndex,
graph::{GetLayer, GetMaybeNet, PrimitiveIndex}, graph::{GetLayer, GetMaybeNet, PrimitiveIndex},
primitive::GetLimbs, primitive::GetLimbs,
rules::AccessRules,
seg::SegIndex, seg::SegIndex,
Drawing, AccessRules, Drawing,
}, },
geometry::GetSetPos, geometry::GetSetPos,
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},

View File

@ -10,8 +10,7 @@ use crate::{
drawing::{ drawing::{
graph::{GetMaybeNet, IsInLayer}, graph::{GetMaybeNet, IsInLayer},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules, AccessRules, Drawing,
Drawing,
}, },
geometry::primitive::{DotShape, PrimitiveShape}, geometry::primitive::{DotShape, PrimitiveShape},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},

View File

@ -17,9 +17,8 @@ use crate::{
graph::{GetLayer, GetMaybeNet, MakePrimitive}, graph::{GetLayer, GetMaybeNet, MakePrimitive},
head::{CaneHead, GetFace, Head}, head::{CaneHead, GetFace, Head},
primitive::GetOtherJoint, primitive::GetOtherJoint,
rules::AccessRules,
seg::{LoneLooseSegWeight, SeqLooseSegWeight}, seg::{LoneLooseSegWeight, SeqLooseSegWeight},
DrawingException, Guide, Infringement, AccessRules, DrawingException, Guide, Infringement,
}, },
layout::{Layout, LayoutEdit}, layout::{Layout, LayoutEdit},
math::{Circle, NoTangents}, math::{Circle, NoTangents},

View File

@ -11,7 +11,7 @@ use crate::{
dot::FixedDotIndex, dot::FixedDotIndex,
graph::PrimitiveIndex, graph::PrimitiveIndex,
head::{BareHead, CaneHead, Head}, head::{BareHead, CaneHead, Head},
rules::AccessRules, AccessRules,
}, },
layout::{Layout, LayoutEdit}, layout::{Layout, LayoutEdit},
}; };

View File

@ -6,7 +6,7 @@ use contracts_try::{debug_ensures, debug_requires};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
drawing::{band::BandTermsegIndex, dot::FixedDotIndex, rules::AccessRules}, drawing::{band::BandTermsegIndex, dot::FixedDotIndex, AccessRules},
layout::{Layout, LayoutEdit}, layout::{Layout, LayoutEdit},
}; };

View File

@ -25,8 +25,7 @@ use crate::{
gear::{GearIndex, GetNextGear}, gear::{GearIndex, GetNextGear},
graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex}, graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex},
primitive::{MakePrimitiveShape, Primitive}, primitive::{MakePrimitiveShape, Primitive},
rules::AccessRules, AccessRules, Drawing,
Drawing,
}, },
geometry::shape::AccessShape, geometry::shape::AccessShape,
graph::{GetPetgraphIndex, MakeRef}, graph::{GetPetgraphIndex, MakeRef},

View File

@ -7,9 +7,7 @@ use std::ops::ControlFlow;
use derive_getters::{Dissolve, Getters}; use derive_getters::{Dissolve, Getters};
use crate::{ use crate::{
drawing::{ drawing::{band::BandTermsegIndex, dot::FixedDotIndex, graph::PrimitiveIndex, AccessRules},
band::BandTermsegIndex, dot::FixedDotIndex, graph::PrimitiveIndex, rules::AccessRules,
},
geometry::primitive::PrimitiveShape, geometry::primitive::PrimitiveShape,
layout::LayoutEdit, layout::LayoutEdit,
router::{ router::{

View File

@ -14,8 +14,7 @@ use crate::{
graph::{MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
head::GetFace, head::GetFace,
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::AccessRules, AccessRules, Collision, DrawingException, Guide, Infringement,
Collision, DrawingException, Guide, Infringement,
}, },
geometry::{ geometry::{
primitive::PrimitiveShape, primitive::PrimitiveShape,

View File

@ -11,4 +11,7 @@ pub use specctra_core::error::{ParseError, ParseErrorContext};
pub use specctra_core::mesadata; pub use specctra_core::mesadata;
use specctra_core::*; use specctra_core::*;
pub trait AccessRules: specctra_core::rules::AccessRules<Scalar = f64, ObjectKind = ()> {}
impl<T> AccessRules for T where T: specctra_core::rules::AccessRules<Scalar = f64, ObjectKind = ()> {}
pub mod design; pub mod design;