Implement bending on bends

There's some ugly constants added here and there, will clean this up
later.
This commit is contained in:
Mikolaj Wielgus 2023-07-12 11:15:54 +02:00
parent dfcfc99413
commit 0770917a41
6 changed files with 197 additions and 58 deletions

View File

@ -29,9 +29,8 @@ impl Layout {
}
}
pub fn route_around(&mut self, from: DotIndex, around: DotIndex, cw: bool, width: f64) -> DotIndex {
pub fn route_around_dot(&mut self, from: DotIndex, around: DotIndex, cw: bool, width: f64) -> DotIndex {
let from_circle = self.head_guidecircle(from, width);
let around_circle = self.mesh.weight(Index::Dot(around)).as_dot().unwrap().circle;
let conditions = Conditions {
lower_net: None,
@ -40,21 +39,32 @@ impl Layout {
zone: None,
};
let to_circle = self.circle_shell(around_circle, width + 5.0, conditions);
let maybe_bend = self.mesh.bend(from);
let from_cw = match maybe_bend {
Some(bend) => Some(self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw),
None => None,
};
let to_circle = self.dot_guidecircle(around, width + 5.0, conditions);
let from_cw = self.mesh.cw(Index::Dot(from));
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw));
if maybe_bend.is_some() {
self.stretch_head_bend(from, tangent_points.0);
self.extend_head(from, tangent_points.0);
self.route_seg_bend(from, Index::Dot(around), tangent_points.1, cw, width)
}
self.route_seg_bend(from, around, tangent_points.1, cw, width)
pub fn route_around_bend(&mut self, from: DotIndex, around: BendIndex, cw: bool, width: f64) -> DotIndex {
let from_circle = self.head_guidecircle(from, width);
let conditions = Conditions {
lower_net: None,
higher_net: None,
layer: None,
zone: None,
};
let to_circle = self.bend_guidecircle(around, width, conditions);
let from_cw = self.mesh.cw(Index::Dot(from));
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw));
self.extend_head(from, tangent_points.0);
self.route_seg_bend(from, Index::Bend(around), tangent_points.1, cw, width)
}
pub fn route_to(&mut self, from: DotIndex, to: DotIndex, width: f64) -> DotIndex {
@ -72,29 +82,27 @@ impl Layout {
r: 0.0,
};
let maybe_bend = self.mesh.bend(from);
let from_cw = match maybe_bend {
Some(bend) => Some(self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw),
None => None,
};
let from_cw = self.mesh.cw(Index::Dot(from));
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, None);
if maybe_bend.is_some() {
self.stretch_head_bend(from, tangent_points.0);
}
self.extend_head(from, tangent_points.0);
self.add_seg(from, to, width);
to
}
fn route_seg_bend(&mut self, from: DotIndex, around: DotIndex, to: Point, cw: bool, width: f64) -> DotIndex {
fn route_seg_bend(&mut self, from: DotIndex, around: Index, to: Point, cw: bool, width: f64) -> DotIndex {
let bend_from = self.route_seg(from, to, width);
let bend_to = self.add_dot(*self.mesh.primitive(Index::Dot(bend_from)).weight.as_dot().unwrap());
let from_primitive = self.mesh.primitive(Index::Dot(from));
let net = from_primitive.weight.as_dot().unwrap().net;
let bend = self.mesh.add_bend(bend_from, bend_to, BendWeight {net, around, cw});
let mut layer = around;
while let Index::Bend(..) = layer {
layer = self.mesh.weight(layer).as_bend().unwrap().around;
}
let center = *layer.as_dot().unwrap();
let bend = self.mesh.add_bend(bend_from, bend_to, BendWeight {net, around, center, cw});
bend_to
}
@ -125,8 +133,12 @@ impl Layout {
match maybe_bend {
Some(bend) => {
let head_around = self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().around;
let circle = self.mesh.weight(Index::Dot(head_around)).as_dot().unwrap().circle;
self.circle_shell(circle, width + 5.0, conditions)
match self.mesh.weight(head_around) {
Weight::Dot(..) => self.dot_guidecircle(*head_around.as_dot().unwrap(), width + 5.0, conditions),
Weight::Bend(..) => self.bend_guidecircle(*head_around.as_bend().unwrap(), width, conditions),
Weight::Seg(..) => unreachable!(),
}
},
None => Circle {
pos: self.mesh.weight(Index::Dot(head)).as_dot().unwrap().circle.pos,
@ -135,14 +147,42 @@ impl Layout {
}
}
fn circle_shell(&self, circle: Circle, width: f64, conditions: Conditions) -> Circle {
fn dot_guidecircle(&self, dot: DotIndex, width: f64, conditions: Conditions) -> Circle {
let circle = self.mesh.weight(Index::Dot(dot)).as_dot().unwrap().circle;
Circle {
pos: circle.pos,
r: circle.r + width + self.rules.ruleset(conditions).clearance.min,
}
}
fn stretch_head_bend(&mut self, dot: DotIndex, to: Point) {
fn bend_guidecircle(&self, bend: BendIndex, width: f64, conditions: Conditions) -> Circle {
let mut layer = Index::Bend(bend);
let mut r = width + self.rules.ruleset(conditions).clearance.min;
while let Index::Bend(..) = layer {
layer = self.mesh.weight(layer).as_bend().unwrap().around;
r += 5.0 + self.mesh.primitive(layer).width();
}
let circle = self.primitive(layer).weight.as_dot().unwrap().circle;
Circle {
pos: circle.pos,
r: circle.r - 5.0 + r,
}
}
fn extend_head(&mut self, from: DotIndex, to: Point) {
if let Some(..) = self.mesh.bend(from) {
self.extend_head_bend(from, to);
} else {
// No assertion for now because we temporarily use floats.
//println!("{:?} {:?}", self.mesh.weight(Index::Dot(from)).as_dot().unwrap().circle.pos, to);
//assert!(self.mesh.weight(Index::Dot(from)).as_dot().unwrap().circle.pos == to);
}
}
fn extend_head_bend(&mut self, dot: DotIndex, to: Point) {
let bend = self.mesh.bend(dot).unwrap();
let dot_weight = *self.mesh.weight(Index::Dot(dot)).as_dot().unwrap();
let bend_weight = *self.mesh.weight(Index::Bend(bend)).as_bend().unwrap();
@ -186,4 +226,8 @@ impl Layout {
pub fn primitive(&self, index: Index) -> Primitive {
return self.mesh.primitive(index);
}
pub fn bend(&self, index: DotIndex) -> Option<BendIndex> {
return self.mesh.bend(index);
}
}

View File

@ -40,7 +40,7 @@ fn main() {
let mut i = 0;
let mut layout = Layout::new();
let index = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (150.5, 80.5).into(), r: 8.0}});
/*let index = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (150.5, 80.5).into(), r: 8.0}});
//layout.route_seg(index, Point {x: 400.5, y: 350.5}, 6.0);
let index2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (180.5, 150.5).into(), r: 8.0}});
@ -51,11 +51,37 @@ fn main() {
let barrier2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (190.5, 250.5).into(), r: 8.0}});
layout.add_seg(index3, barrier2, 16.0);
let index4 = layout.route_around(index, index2, true, 5.0);
let index5 = layout.route_around(index4, index3, false, 5.0);
let index4 = layout.route_around_dot(index, index2, true, 5.0);
let index5 = layout.route_around_dot(index4, index3, false, 5.0);
let index6 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (140.5, 300.5).into(), r: 8.0}});
let index7 = layout.route_to(index5, index6, 5.0);
let index7 = layout.route_to(index5, index6, 5.0);*/
let dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 150.5).into(), r: 8.0}});
let dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (130.5, 150.5).into(), r: 8.0}});
let dot3 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (160.5, 150.5).into(), r: 8.0}});
let obstacle_dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (220.5, 250.5).into(), r: 8.0}});
let obstacle_dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 250.5).into(), r: 8.0}});
layout.add_seg(obstacle_dot1, obstacle_dot2, 16.0);
let dot4 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (200.5, 350.5).into(), r: 8.0}});
let dot5 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (220.5, 380.5).into(), r: 8.0}});
let dot6 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (290.5, 380.5).into(), r: 8.0}});
let index3_1 = layout.route_around_dot(dot3, obstacle_dot1, true, 5.0);
let index3_2 = layout.route_to(index3_1, dot4, 5.0);
let index2_1 = layout.route_around_dot(dot2, dot3, true, 5.0);
let index2_2 = layout.route_around_bend(index2_1, layout.bend(index3_1).unwrap(), true, 5.0);
let index2_3 = layout.route_to(index2_2, dot5, 5.0);
let index1_1 = layout.route_around_bend(dot1, layout.bend(index2_1).unwrap(), true, 5.0);
let index1_2 = layout.route_around_bend(index1_1, layout.bend(index2_2).unwrap(), true, 5.0);
let index1_3 = layout.route_to(index1_2, dot6, 5.0);
//
//layout.route_around_bend(dot1, layout.bend(index2).unwrap(), true, 5.0);
'running: loop {
i = (i + 1) % 255;
@ -91,11 +117,12 @@ fn main() {
Color::RGB(200, 52, 52));
},
Weight::Bend(bend) => {
let circle = primitive.circle().unwrap();
let dot_neighbor_weights = primitive.dot_neighbor_weights;
let around_circle = primitive.around_weight.unwrap().circle;
//let around_circle = primitive.around_weight.unwrap().circle;
let delta1 = dot_neighbor_weights[0].circle.pos - around_circle.pos;
let delta2 = dot_neighbor_weights[1].circle.pos - around_circle.pos;
let delta1 = dot_neighbor_weights[0].circle.pos - circle.pos;
let delta2 = dot_neighbor_weights[1].circle.pos - circle.pos;
let mut angle1 = delta1.y().atan2(delta1.x());
let mut angle2 = delta2.y().atan2(delta2.x());
@ -106,9 +133,12 @@ fn main() {
for d in -3..3 {
let _ = canvas.arc(
around_circle.pos.x() as i16,
around_circle.pos.y() as i16,
(primitive.around_weight.unwrap().circle.r + 10.0 + (d as f64)) as i16,
//around_circle.pos.x() as i16,
//around_circle.pos.y() as i16,
circle.pos.x() as i16,
circle.pos.y() as i16,
//(primitive.around_weight.unwrap().circle.r + 10.0 + (d as f64)) as i16,
(circle.r + (d as f64)) as i16,
angle1.to_degrees() as i16,
angle2.to_degrees() as i16,
Color::RGB(200, 52, 52));

View File

@ -1,14 +1,14 @@
use std::ops::Sub;
use geo::geometry::Point;
#[derive(Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Line {
pub a: f64,
pub b: f64,
pub c: f64,
}
#[derive(Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Circle {
pub pos: Point,
pub r: f64,

View File

@ -11,7 +11,7 @@ pub type DotIndex = NodeIndex<u32>;
pub type SegIndex = EdgeIndex<u32>;
pub type BendIndex = EdgeIndex<u32>;
#[derive(EnumAsInner, Copy, Clone, PartialEq)]
#[derive(Debug, EnumAsInner, Copy, Clone, PartialEq)]
pub enum Index {
Dot(DotIndex),
Seg(SegIndex),
@ -88,7 +88,19 @@ impl Mesh {
.map(|index| *self.weight(index).as_dot().unwrap())
.collect(),
around_weight: match index {
Index::Bend(bend_index) => Some(*self.weight(Index::Dot((*self.weight(index).as_bend().unwrap()).around)).as_dot().unwrap()),
Index::Bend(bend_index) => {
Some(self.weight((*self.weight(index).as_bend().unwrap()).around))
},
_ => None,
},
center: match index {
Index::Bend(bend_index) => {
let mut layer = index;
while let Index::Bend(..) = layer {
layer = self.weight(layer).as_bend().unwrap().around;
}
Some(self.weight(layer).as_dot().unwrap().circle.pos)
},
_ => None,
}
}
@ -105,14 +117,43 @@ impl Mesh {
}
}
pub fn bend(&self, index: NodeIndex) -> Option<BendIndex> {
let edges: Vec<EdgeIndex<u32>> = self.graph.edges(index).map(|r| r.id()).collect();
pub fn cw(&self, index: Index) -> Option<bool> {
match index {
Index::Dot(node_index) => {
let maybe_bend = self.bend(node_index);
match maybe_bend {
Some(bend) => Some(self.weight(Index::Bend(bend)).as_bend().unwrap().cw),
None => None,
}
}
Index::Seg(edge_index) => None,
Index::Bend(edge_index) => Some(self.weight(index).as_bend().unwrap().cw),
}
}
if edges.len() != 1 {
pub fn bend(&self, index: DotIndex) -> Option<BendIndex> {
//let edges: Vec<EdgeIndex<u32>> = self.graph.edges(index).map(|r| r.id()).collect();
let bends: Vec<EdgeIndex<u32>> = self.graph.edges(index)
.filter_map(|r| match self.weight(Index::Bend(r.id())) {
Weight::Bend(..) => Some(r.id()),
_ => None,
})
.collect();
if bends.len() != 1 {
return None;
}
return Some(edges[0]);
Some(bends[0])
/*if edges.len() == 0 {
return None;
}*/
/*if edges[0]
Some(edges[0])*/
//None
}
pub fn weight(&self, index: Index) -> Weight {

View File

@ -1,12 +1,14 @@
use geo::{Point, EuclideanDistance};
use rstar::{RTreeObject, AABB};
use crate::weight::{Weight, DotWeight};
use crate::{weight::{Weight, DotWeight}, math::Circle};
#[derive(PartialEq)]
pub struct Primitive {
pub weight: Weight,
pub dot_neighbor_weights: Vec<DotWeight>,
pub around_weight: Option<DotWeight>,
pub around_weight: Option<Weight>,
pub center: Option<Point>,
}
impl Primitive {
@ -23,16 +25,37 @@ impl Primitive {
let points: Vec<[f64; 2]> = self.dot_neighbor_weights.iter()
.map(|neighbor| [neighbor.circle.pos.x(), neighbor.circle.pos.y()])
.collect();
return AABB::<[f64; 2]>::from_points(&points);
},
}
}
/*pub fn weight(&self) -> Weight {
pub fn circle(&self) -> Option<Circle> {
match self.weight {
Weight::Dot(dot) => Some(dot.circle),
Weight::Seg(seg) => None,
Weight::Bend(bend) => {
let r = self.dot_neighbor_weights[0].circle.pos.euclidean_distance(&self.center.unwrap());
Some(Circle {
pos: self.center.unwrap(),
r,
})
}
}
}
pub fn width(&self) -> f64 {
match self.weight {
Weight::Dot(dot) => dot.circle.r * 2.0,
Weight::Seg(seg) => seg.width,
Weight::Bend(bend) => self.dot_neighbor_weights[0].circle.r * 2.0,
}
}
pub fn weight(&self) -> Weight {
return self.weight;
}*/
}
}
impl RTreeObject for Primitive {

View File

@ -1,26 +1,27 @@
use enum_as_inner::EnumAsInner;
use crate::{math::Circle, mesh::DotIndex};
use crate::{math::Circle, mesh::{Index, DotIndex}};
#[derive(Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DotWeight {
pub net: i32,
pub circle: Circle,
}
#[derive(Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BendWeight {
pub net: i32,
pub around: DotIndex,
pub around: Index,
pub center: DotIndex,
pub cw: bool,
}
#[derive(Clone, Copy, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SegWeight {
pub net: i32,
pub width: f64,
}
#[derive(EnumAsInner, Clone, Copy, PartialEq)]
#[derive(Debug, EnumAsInner, Clone, Copy, PartialEq)]
pub enum Weight {
Dot(DotWeight),
Seg(SegWeight),