mirror of https://codeberg.org/topola/topola.git
Add `Guide` struct to generate guide curves
This commit is contained in:
parent
356154c914
commit
bbbd2f57fe
|
|
@ -0,0 +1,116 @@
|
||||||
|
use geo::Line;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
graph::{BendIndex, DotIndex},
|
||||||
|
layout::Head,
|
||||||
|
math::{self, Circle},
|
||||||
|
mesh::Mesh,
|
||||||
|
rules::{Conditions, Rules},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Guide<'a, 'b> {
|
||||||
|
mesh: &'a Mesh,
|
||||||
|
rules: &'a Rules,
|
||||||
|
conditions: &'b Conditions,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Guide<'a, 'b> {
|
||||||
|
pub fn new(mesh: &'a Mesh, rules: &'a Rules, conditions: &'b Conditions) -> Self {
|
||||||
|
Self {
|
||||||
|
mesh,
|
||||||
|
rules,
|
||||||
|
conditions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn head_into_dot_segment(&self, head: &Head, into: DotIndex, width: f64) -> Line {
|
||||||
|
let from_circle = self.head_circle(&head, width);
|
||||||
|
let to_circle = Circle {
|
||||||
|
pos: self.mesh.primitive(into).weight().circle.pos,
|
||||||
|
r: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let from_cw = self.head_cw(&head);
|
||||||
|
math::tangent_segment(from_circle, from_cw, to_circle, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn head_around_bend_segment(
|
||||||
|
&self,
|
||||||
|
head: &Head,
|
||||||
|
around: BendIndex,
|
||||||
|
cw: bool,
|
||||||
|
width: f64,
|
||||||
|
) -> Line {
|
||||||
|
let from_circle = self.head_circle(&head, width);
|
||||||
|
let to_circle = self.bend_circle(around, width);
|
||||||
|
|
||||||
|
let from_cw = self.head_cw(&head);
|
||||||
|
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn head_around_dot_segment(
|
||||||
|
&self,
|
||||||
|
head: &Head,
|
||||||
|
around: DotIndex,
|
||||||
|
cw: bool,
|
||||||
|
width: f64,
|
||||||
|
) -> Line {
|
||||||
|
let from_circle = self.head_circle(&head, width);
|
||||||
|
let to_circle = self.dot_circle(around, width + 5.0);
|
||||||
|
|
||||||
|
let from_cw = self.head_cw(&head);
|
||||||
|
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn head_cw(&self, head: &Head) -> Option<bool> {
|
||||||
|
match head.bend {
|
||||||
|
Some(bend) => Some(self.mesh.primitive(bend).weight().cw),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn head_circle(&self, head: &Head, width: f64) -> Circle {
|
||||||
|
let maybe_bend = head.bend;
|
||||||
|
|
||||||
|
let conditions = Conditions {
|
||||||
|
lower_net: None,
|
||||||
|
higher_net: None,
|
||||||
|
layer: None,
|
||||||
|
zone: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match maybe_bend {
|
||||||
|
Some(bend) => {
|
||||||
|
if let Some(inner) = self.mesh.primitive(bend).inner() {
|
||||||
|
self.bend_circle(inner, width)
|
||||||
|
} else {
|
||||||
|
self.dot_circle(self.mesh.primitive(bend).core().unwrap(), width + 5.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Circle {
|
||||||
|
pos: self.mesh.primitive(head.dot).weight().circle.pos,
|
||||||
|
r: 0.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bend_circle(&self, bend: BendIndex, width: f64) -> Circle {
|
||||||
|
let mut circle = self
|
||||||
|
.mesh
|
||||||
|
.primitive(bend)
|
||||||
|
.shape()
|
||||||
|
.as_bend()
|
||||||
|
.unwrap()
|
||||||
|
.circle();
|
||||||
|
circle.r += self.rules.ruleset(&self.conditions).clearance.min + 10.0;
|
||||||
|
circle
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dot_circle(&self, dot: DotIndex, width: f64) -> Circle {
|
||||||
|
let circle = self.mesh.primitive(dot).weight().circle;
|
||||||
|
Circle {
|
||||||
|
pos: circle.pos,
|
||||||
|
r: circle.r + width + self.rules.ruleset(self.conditions).clearance.min,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
184
src/layout.rs
184
src/layout.rs
|
|
@ -4,6 +4,7 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use crate::graph::{BendIndex, DotIndex, Path, SegIndex, TaggedIndex};
|
use crate::graph::{BendIndex, DotIndex, Path, SegIndex, TaggedIndex};
|
||||||
use crate::graph::{BendWeight, DotWeight, SegWeight, TaggedWeight};
|
use crate::graph::{BendWeight, DotWeight, SegWeight, TaggedWeight};
|
||||||
|
use crate::guide::Guide;
|
||||||
use crate::math;
|
use crate::math;
|
||||||
use crate::math::Circle;
|
use crate::math::Circle;
|
||||||
use crate::mesh::Mesh;
|
use crate::mesh::Mesh;
|
||||||
|
|
@ -35,34 +36,20 @@ impl Layout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn route_finish(&mut self, head: Head, to: DotIndex, width: f64) -> Result<(), ()> {
|
pub fn route_finish(&mut self, head: Head, into: DotIndex, width: f64) -> Result<(), ()> {
|
||||||
if let Some(bend) = self.mesh.primitive(to).bend() {
|
if let Some(bend) = self.mesh.primitive(into).bend() {
|
||||||
self.route_finish_in_bend(head, bend, to, width)
|
self.route_finish_in_bend(head, bend, into, width)
|
||||||
} else {
|
} else {
|
||||||
self.route_finish_in_dot(head, to, width)
|
self.route_finish_in_dot(head, into, width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn route_finish_in_dot(&mut self, head: Head, to: DotIndex, width: f64) -> Result<(), ()> {
|
fn route_finish_in_dot(&mut self, head: Head, into: DotIndex, width: f64) -> Result<(), ()> {
|
||||||
let from_circle = self.head_guidecircle(&head, width);
|
let tangent = self
|
||||||
|
.guide(&Default::default())
|
||||||
let conditions = Conditions {
|
.head_into_dot_segment(&head, into, width);
|
||||||
lower_net: None,
|
let head = self.extend_head(head, tangent.start_point())?;
|
||||||
higher_net: None,
|
self.add_seg(head.dot, into, width)?;
|
||||||
layer: None,
|
|
||||||
zone: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let to_circle = Circle {
|
|
||||||
pos: self.mesh.primitive(to).weight().circle.pos,
|
|
||||||
r: 0.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let from_cw = self.head_cw(&head);
|
|
||||||
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, None);
|
|
||||||
|
|
||||||
let head = self.extend_head(head, tangent_points.0)?;
|
|
||||||
self.add_seg(head.dot, to, width)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,28 +60,17 @@ impl Layout {
|
||||||
to: DotIndex,
|
to: DotIndex,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let from_circle = self.head_guidecircle(&head, width);
|
|
||||||
|
|
||||||
let conditions = Conditions {
|
|
||||||
lower_net: None,
|
|
||||||
higher_net: None,
|
|
||||||
layer: None,
|
|
||||||
zone: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let to_circle = self.bend_circle(to_bend, width);
|
|
||||||
let from_cw = self.head_cw(&head);
|
|
||||||
|
|
||||||
let to_head = Head {
|
let to_head = Head {
|
||||||
bend: Some(to_bend),
|
bend: Some(to_bend),
|
||||||
dot: to,
|
dot: to,
|
||||||
};
|
};
|
||||||
let to_cw = self.head_cw(&to_head);
|
let to_cw = self.guide(&Default::default()).head_cw(&to_head).unwrap();
|
||||||
|
let tangent = self
|
||||||
|
.guide(&Default::default())
|
||||||
|
.head_around_bend_segment(&head, to_bend, to_cw, width);
|
||||||
|
let head = self.extend_head(head, tangent.start_point())?;
|
||||||
|
|
||||||
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, to_cw);
|
let to_head = self.extend_head(to_head, tangent.end_point())?;
|
||||||
let head = self.extend_head(head, tangent_points.0)?;
|
|
||||||
|
|
||||||
let to_head = self.extend_head(to_head, tangent_points.1)?;
|
|
||||||
self.add_seg(head.dot, to, width)?;
|
self.add_seg(head.dot, to, width)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -121,22 +97,18 @@ impl Layout {
|
||||||
cw: bool,
|
cw: bool,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<Head, ()> {
|
) -> Result<Head, ()> {
|
||||||
let from_circle = self.head_guidecircle(&head, width);
|
let tangent = self
|
||||||
|
.guide(&Default::default())
|
||||||
|
.head_around_dot_segment(&head, around, cw, width);
|
||||||
|
|
||||||
let conditions = Conditions {
|
let head = self.extend_head(head, tangent.start_point())?;
|
||||||
lower_net: None,
|
self.route_seg_bend(
|
||||||
higher_net: None,
|
head,
|
||||||
layer: None,
|
TaggedIndex::Dot(around),
|
||||||
zone: None,
|
tangent.end_point(),
|
||||||
};
|
cw,
|
||||||
|
width,
|
||||||
let to_circle = self.dot_guidecircle(around, width + 5.0, conditions);
|
)
|
||||||
|
|
||||||
let from_cw = self.head_cw(&head);
|
|
||||||
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw));
|
|
||||||
|
|
||||||
let head = self.extend_head(head, tangent_points.0)?;
|
|
||||||
self.route_seg_bend(head, TaggedIndex::Dot(around), tangent_points.1, cw, width)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shove_around_bend(
|
pub fn shove_around_bend(
|
||||||
|
|
@ -161,22 +133,18 @@ impl Layout {
|
||||||
cw: bool,
|
cw: bool,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<Head, ()> {
|
) -> Result<Head, ()> {
|
||||||
let from_circle = self.head_guidecircle(&head, width);
|
let tangent = self
|
||||||
|
.guide(&Default::default())
|
||||||
|
.head_around_bend_segment(&head, around, cw, width);
|
||||||
|
|
||||||
let conditions = Conditions {
|
let head = self.extend_head(head, tangent.start_point())?;
|
||||||
lower_net: None,
|
self.route_seg_bend(
|
||||||
higher_net: None,
|
head,
|
||||||
layer: None,
|
TaggedIndex::Bend(around),
|
||||||
zone: None,
|
tangent.end_point(),
|
||||||
};
|
cw,
|
||||||
|
width,
|
||||||
let to_circle = self.bend_guidecircle(around, width, conditions);
|
)
|
||||||
|
|
||||||
let from_cw = self.head_cw(&head);
|
|
||||||
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw));
|
|
||||||
|
|
||||||
let head = self.extend_head(head, tangent_points.0)?;
|
|
||||||
self.route_seg_bend(head, TaggedIndex::Bend(around), tangent_points.1, cw, width)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn route_seg_bend(
|
fn route_seg_bend(
|
||||||
|
|
@ -301,76 +269,6 @@ impl Layout {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn head_guidecircle(&self, head: &Head, width: f64) -> Circle {
|
|
||||||
let maybe_bend = head.bend;
|
|
||||||
|
|
||||||
let conditions = Conditions {
|
|
||||||
lower_net: None,
|
|
||||||
higher_net: None,
|
|
||||||
layer: None,
|
|
||||||
zone: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
match maybe_bend {
|
|
||||||
Some(bend) => {
|
|
||||||
if let Some(inner) = self.mesh.primitive(bend).inner() {
|
|
||||||
self.bend_guidecircle(inner, width, conditions)
|
|
||||||
} else {
|
|
||||||
self.dot_guidecircle(
|
|
||||||
self.mesh.primitive(bend).core().unwrap(),
|
|
||||||
width + 5.0,
|
|
||||||
conditions,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Circle {
|
|
||||||
pos: self.mesh.primitive(head.dot).weight().circle.pos,
|
|
||||||
r: 0.0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn head_cw(&self, head: &Head) -> Option<bool> {
|
|
||||||
match head.bend {
|
|
||||||
Some(bend) => Some(self.mesh.primitive(bend).weight().cw),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dot_guidecircle(&self, dot: DotIndex, width: f64, conditions: Conditions) -> Circle {
|
|
||||||
let circle = self.mesh.primitive(dot).weight().circle;
|
|
||||||
Circle {
|
|
||||||
pos: circle.pos,
|
|
||||||
r: circle.r + width + self.rules.ruleset(conditions).clearance.min,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bend_circle(&self, bend: BendIndex, width: f64) -> Circle {
|
|
||||||
let mut r = 0.0;
|
|
||||||
let mut layer = bend;
|
|
||||||
|
|
||||||
while let Some(inner) = self.mesh.primitive(layer).inner() {
|
|
||||||
r += 5.0 + self.mesh.primitive(inner).shape().width();
|
|
||||||
layer = inner;
|
|
||||||
}
|
|
||||||
|
|
||||||
let core_circle = self
|
|
||||||
.mesh
|
|
||||||
.primitive(self.mesh.primitive(bend).core().unwrap())
|
|
||||||
.weight()
|
|
||||||
.circle;
|
|
||||||
Circle {
|
|
||||||
pos: core_circle.pos,
|
|
||||||
r: core_circle.r + r + width + 5.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bend_guidecircle(&self, bend: BendIndex, width: f64, conditions: Conditions) -> Circle {
|
|
||||||
let mut circle = self.bend_circle(bend, width);
|
|
||||||
circle.r += self.rules.ruleset(conditions).clearance.min + 10.0;
|
|
||||||
circle
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> {
|
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> {
|
||||||
if let Some(..) = head.bend {
|
if let Some(..) = head.bend {
|
||||||
self.extend_head_bend(head, to)
|
self.extend_head_bend(head, to)
|
||||||
|
|
@ -413,4 +311,8 @@ impl Layout {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn guide<'a>(&'a self, conditions: &'a Conditions) -> Guide {
|
||||||
|
Guide::new(&self.mesh, &self.rules, conditions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ macro_rules! dbg_dot {
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod graph;
|
mod graph;
|
||||||
mod bow;
|
mod bow;
|
||||||
|
mod guide;
|
||||||
mod layout;
|
mod layout;
|
||||||
mod math;
|
mod math;
|
||||||
mod mesh;
|
mod mesh;
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ fn cast_point_to_canonical_line(pt: Point, line: CanonicalLine) -> Point {
|
||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] {
|
fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] {
|
||||||
let tgs = _tangents(circle1, circle2);
|
let tgs = _tangents(circle1, circle2);
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|
@ -92,12 +92,12 @@ pub fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point);
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tangent_point_pair(
|
pub fn tangent_segment(
|
||||||
circle1: Circle,
|
circle1: Circle,
|
||||||
cw1: Option<bool>,
|
cw1: Option<bool>,
|
||||||
circle2: Circle,
|
circle2: Circle,
|
||||||
cw2: Option<bool>,
|
cw2: Option<bool>,
|
||||||
) -> (Point, Point) {
|
) -> Line {
|
||||||
let tangent_point_pairs = tangent_point_pairs(circle1, circle2);
|
let tangent_point_pairs = tangent_point_pairs(circle1, circle2);
|
||||||
|
|
||||||
for tangent_point_pair in tangent_point_pairs {
|
for tangent_point_pair in tangent_point_pairs {
|
||||||
|
|
@ -117,7 +117,7 @@ pub fn tangent_point_pair(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tangent_point_pair;
|
return Line::new(tangent_point_pair.0, tangent_point_pair.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
|
|
||||||
|
|
@ -239,15 +239,6 @@ impl Mesh {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn triangulate(&mut self) {
|
fn triangulate(&mut self) {
|
||||||
/*for edge_index in self.graph.edge_indices() {
|
|
||||||
if *self.graph.edge_weight(edge_index).unwrap() == Label::Peer {
|
|
||||||
self.graph.remove_edge(edge_index);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
/*for (edge_index, edge) in self.graph.raw_edges().iter().enumerate() {
|
|
||||||
self.graph.remove_edge(edge_index);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let peer_edge_indices: Vec<EdgeIndex<usize>> = self
|
let peer_edge_indices: Vec<EdgeIndex<usize>> = self
|
||||||
.graph
|
.graph
|
||||||
.edge_indices()
|
.edge_indices()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub struct Conditions {
|
pub struct Conditions {
|
||||||
pub lower_net: Option<i64>,
|
pub lower_net: Option<i64>,
|
||||||
pub higher_net: Option<i64>,
|
pub higher_net: Option<i64>,
|
||||||
|
|
@ -40,7 +40,7 @@ impl Rules {
|
||||||
me
|
me
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ruleset(&self, conditions: Conditions) -> &Ruleset {
|
pub fn ruleset(&self, conditions: &Conditions) -> &Ruleset {
|
||||||
let priority = conditions.priority();
|
let priority = conditions.priority();
|
||||||
|
|
||||||
for index in (1..(priority + 1)).rev() {
|
for index in (1..(priority + 1)).rev() {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use enum_as_inner::EnumAsInner;
|
||||||
use geo::{point, polygon, EuclideanDistance, Intersects, Point, Polygon, Rotate};
|
use geo::{point, polygon, EuclideanDistance, Intersects, Point, Polygon, Rotate};
|
||||||
use rstar::{RTreeObject, AABB};
|
use rstar::{RTreeObject, AABB};
|
||||||
|
|
||||||
|
|
@ -69,7 +70,7 @@ impl BendShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, EnumAsInner, PartialEq)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
// Intentionally in different order to reorder `self.intersects(...)` properly.
|
// Intentionally in different order to reorder `self.intersects(...)` properly.
|
||||||
Dot(DotShape),
|
Dot(DotShape),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue