diff --git a/crates/topola-egui/src/viewport.rs b/crates/topola-egui/src/viewport.rs index 9062715..0c7e5bc 100644 --- a/crates/topola-egui/src/viewport.rs +++ b/crates/topola-egui/src/viewport.rs @@ -21,7 +21,7 @@ use topola::{ geometry::{shape::AccessShape, GenericNode}, graph::MakeRef, layout::{poly::MakePolygon, via::ViaWeight}, - math::Circle, + math::{Circle, RotationSense}, }; use crate::{config::Config, menu_bar::MenuBar, painter::Painter, workspace::Workspace}; @@ -213,23 +213,25 @@ impl Viewport { .shape() .center(); - if let Some(from_cw) = - navmesh.node_weight(edge.source()).unwrap().maybe_cw + if let Some(from_sense) = + navmesh.node_weight(edge.source()).unwrap().maybe_sense { - if from_cw { - from -= [0.0, 150.0].into(); - } else { - from += [0.0, 150.0].into(); - } + from += match from_sense { + RotationSense::Counterclockwise => { + [0.0, 150.0].into() + } + RotationSense::Clockwise => [-0.0, -150.0].into(), + }; } - if let Some(to_cw) = - navmesh.node_weight(edge.target()).unwrap().maybe_cw + if let Some(to_sense) = + navmesh.node_weight(edge.target()).unwrap().maybe_sense { - if to_cw { - to -= [0.0, 150.0].into(); - } else { - to += [0.0, 150.0].into(); + to += match to_sense { + RotationSense::Counterclockwise => { + [0.0, 150.0].into() + } + RotationSense::Clockwise => [-0.0, -150.0].into(), } } diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs index 6ffa7aa..87833ef 100644 --- a/src/drawing/drawing.rs +++ b/src/drawing/drawing.rs @@ -10,14 +10,6 @@ use core::fmt; use rstar::{RTree, AABB}; use thiserror::Error; -use crate::geometry::{ - edit::{ApplyGeometryEdit, GeometryEdit}, - primitive::{AccessPrimitiveShape, PrimitiveShape}, - recording_with_rtree::RecordingGeometryWithRtree, - with_rtree::BboxedIndex, - AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, - GetLayer, GetOffset, GetSetPos, GetWidth, -}; use crate::graph::{GenericIndex, GetPetgraphIndex}; use crate::math::NoTangents; use crate::{ @@ -42,6 +34,17 @@ use crate::{ }, graph::MakeRef, }; +use crate::{ + geometry::{ + edit::{ApplyGeometryEdit, GeometryEdit}, + primitive::{AccessPrimitiveShape, PrimitiveShape}, + recording_with_rtree::RecordingGeometryWithRtree, + with_rtree::BboxedIndex, + AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, + GetLayer, GetOffset, GetSetPos, GetWidth, + }, + math::RotationSense, +}; #[derive(Clone, Copy, Error)] pub enum DrawingException { @@ -498,7 +501,7 @@ impl Drawing { dot_weight: LooseDotWeight, seg_weight: SeqLooseSegWeight, bend_weight: LooseBendWeight, - cw: bool, + sense: RotationSense, ) -> Result { let maybe_next_gear = around.ref_(self).next_gear(); let cane = self.add_cane_with_infringables( @@ -508,7 +511,7 @@ impl Drawing { dot_weight, seg_weight, bend_weight, - cw, + sense, Some(&[]), )?; @@ -551,14 +554,34 @@ impl Drawing { let (from, to, offset) = if let Some(inner) = rail_primitive.inner() { let inner = inner.into(); - let from = self.head_around_bend_segment(&from_head, inner, true, width)?; - let to = self.head_around_bend_segment(&to_head, inner, false, width)?; + let from = self.head_around_bend_segment( + &from_head, + inner, + RotationSense::Clockwise, + width, + )?; + let to = self.head_around_bend_segment( + &to_head, + inner, + RotationSense::Counterclockwise, + width, + )?; let offset = self.head_around_bend_offset(&from_head, inner, width); (from, to, offset) } else { let core = rail_primitive.core().into(); - let from = self.head_around_dot_segment(&from_head, core, true, width)?; - let to = self.head_around_dot_segment(&to_head, core, false, width)?; + let from = self.head_around_dot_segment( + &from_head, + core, + RotationSense::Clockwise, + width, + )?; + let to = self.head_around_dot_segment( + &to_head, + core, + RotationSense::Counterclockwise, + width, + )?; let offset = self.head_around_dot_offset(&from_head, core, width); (from, to, offset) }; @@ -621,7 +644,7 @@ impl Drawing { dot_weight: LooseDotWeight, seg_weight: SeqLooseSegWeight, bend_weight: LooseBendWeight, - cw: bool, + sense: RotationSense, ) -> Result { self.add_cane_with_infringables( recorder, @@ -630,7 +653,7 @@ impl Drawing { dot_weight, seg_weight, bend_weight, - cw, + sense, Some(&[]), ) } @@ -647,7 +670,7 @@ impl Drawing { dot_weight: LooseDotWeight, seg_weight: SeqLooseSegWeight, bend_weight: LooseBendWeight, - cw: bool, + sense: RotationSense, infringables: Option<&[PrimitiveIndex]>, ) -> Result { let seg_to = self.add_dot_with_infringables(recorder, dot_weight, infringables)?; @@ -667,7 +690,10 @@ impl Drawing { .remove_dot(recorder, seg_to.into()); })?; - let (bend_from, bend_to) = if cw { (to, seg_to) } else { (seg_to, to) }; + let (bend_from, bend_to) = match sense { + RotationSense::Counterclockwise => (seg_to, to), + RotationSense::Clockwise => (to, seg_to), + }; let bend = self .add_loose_bend_with_infringables( diff --git a/src/drawing/guide.rs b/src/drawing/guide.rs index 492f356..05101cc 100644 --- a/src/drawing/guide.rs +++ b/src/drawing/guide.rs @@ -9,7 +9,7 @@ use crate::{ primitive::{AccessPrimitiveShape, PrimitiveShape}, shape::AccessShape, }, - math::{self, Circle, NoTangents}, + math::{self, Circle, NoTangents, RotationSense}, }; use super::{ @@ -41,7 +41,7 @@ pub trait Guide { &self, head: &Head, around: DotIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result; @@ -58,13 +58,13 @@ pub trait Guide { &self, head: &Head, around: BendIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result; fn head_around_bend_offset(&self, head: &Head, around: BendIndex, _width: f64) -> f64; - fn head_cw(&self, head: &Head) -> Option; + fn head_sense(&self, head: &Head) -> Option; fn cane_head(&self, face: LooseDotIndex) -> CaneHead; @@ -86,8 +86,8 @@ impl Guide for Drawing { r: 0.0, }; - let from_cw = self.head_cw(head); - math::tangent_segment(from_circle, from_cw, to_circle, None) + let from_sense = self.head_sense(head); + math::tangent_segment(from_circle, from_sense, to_circle, None) } fn head_around_dot_segments( @@ -100,9 +100,9 @@ impl Guide for Drawing { let to_circle = self.dot_circle(around, width, self.conditions(head.face().into()).as_ref()); - let from_cw = self.head_cw(head); + let from_sense = self.head_sense(head); let tangents: Vec = - math::tangent_segments(from_circle, from_cw, to_circle, None)?.collect(); + math::tangent_segments(from_circle, from_sense, to_circle, None)?.collect(); Ok((tangents[0], tangents[1])) } @@ -110,15 +110,15 @@ impl Guide for Drawing { &self, head: &Head, around: DotIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result { let from_circle = self.head_circle(head, width); let to_circle = self.dot_circle(around, width, self.conditions(head.face().into()).as_ref()); - let from_cw = self.head_cw(head); - math::tangent_segment(from_circle, from_cw, to_circle, Some(cw)) + let from_sense = self.head_sense(head); + math::tangent_segment(from_circle, from_sense, to_circle, Some(sense)) } fn head_around_dot_offset(&self, head: &Head, around: DotIndex, _width: f64) -> f64 { @@ -138,9 +138,9 @@ impl Guide for Drawing { let to_circle = self.bend_circle(around, width, self.conditions(head.face().into()).as_ref()); - let from_cw = self.head_cw(head); + let from_sense = self.head_sense(head); let tangents: Vec = - math::tangent_segments(from_circle, from_cw, to_circle, None)?.collect(); + math::tangent_segments(from_circle, from_sense, to_circle, None)?.collect(); Ok((tangents[0], tangents[1])) } @@ -148,15 +148,15 @@ impl Guide for Drawing { &self, head: &Head, around: BendIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result { let from_circle = self.head_circle(head, width); let to_circle = self.bend_circle(around, width, self.conditions(head.face().into()).as_ref()); - let from_cw = self.head_cw(head); - math::tangent_segment(from_circle, from_cw, to_circle, Some(cw)) + let from_sense = self.head_sense(head); + math::tangent_segment(from_circle, from_sense, to_circle, Some(sense)) } fn head_around_bend_offset(&self, head: &Head, around: BendIndex, _width: f64) -> f64 { @@ -166,14 +166,14 @@ impl Guide for Drawing { ) } - fn head_cw(&self, head: &Head) -> Option { + fn head_sense(&self, head: &Head) -> Option { if let Head::Cane(head) = head { let joints = self.primitive(head.cane.bend).joints(); if head.face() == joints.0.into() { - Some(false) + Some(RotationSense::Counterclockwise) } else { - Some(true) + Some(RotationSense::Clockwise) } } else { None diff --git a/src/layout/layout.rs b/src/layout/layout.rs index f99bab3..9e98797 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -39,7 +39,7 @@ use crate::{ poly::{is_apex, MakePolygon, PolyWeight}, via::{Via, ViaWeight}, }, - math::{Circle, LineIntersection, NormalLine}, + math::{Circle, LineIntersection, NormalLine, RotationSense}, }; /// Represents a weight for various compounds @@ -78,7 +78,7 @@ impl Layout { dot_weight: LooseDotWeight, seg_weight: SeqLooseSegWeight, bend_weight: LooseBendWeight, - cw: bool, + sense: RotationSense, ) -> Result { self.drawing.insert_cane( recorder, @@ -87,7 +87,7 @@ impl Layout { dot_weight, seg_weight, bend_weight, - cw, + sense, ) } diff --git a/src/math/mod.rs b/src/math/mod.rs index b164608..cffa601 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -9,6 +9,12 @@ pub use specctra_core::math::{Circle, PointWithRotation}; mod tangents; pub use tangents::*; +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum RotationSense { + Counterclockwise, + Clockwise, +} + #[derive(Clone, Copy, Debug, PartialEq)] pub enum LineIntersection { Empty, diff --git a/src/math/tangents.rs b/src/math/tangents.rs index ee4e0f5..3b6f237 100644 --- a/src/math/tangents.rs +++ b/src/math/tangents.rs @@ -6,7 +6,7 @@ use geo::{geometry::Point, Line}; use specctra_core::math::Circle; use thiserror::Error; -use super::{seq_perp_dot_product, NormalLine}; +use super::{seq_perp_dot_product, NormalLine, RotationSense}; #[derive(Error, Debug, Clone, Copy, PartialEq)] #[error("no tangents for {0:?} and {1:?}")] // TODO add real error message @@ -84,27 +84,31 @@ fn tangent_point_pairs( pub fn tangent_segments( circle1: Circle, - cw1: Option, + maybe_sense1: Option, circle2: Circle, - cw2: Option, + maybe_sense2: Option, ) -> Result, NoTangents> { Ok(tangent_point_pairs(circle1, circle2)? .into_iter() .filter_map(move |tangent_point_pair| { - if let Some(cw1) = cw1 { + if let Some(sense1) = maybe_sense1 { let cross1 = seq_perp_dot_product(tangent_point_pair.0, tangent_point_pair.1, circle1.pos); - if (cw1 && cross1 <= 0.0) || (!cw1 && cross1 >= 0.0) { + if (sense1 == RotationSense::Clockwise && cross1 <= 0.0) + || (sense1 == RotationSense::Counterclockwise && cross1 >= 0.0) + { return None; } } - if let Some(cw2) = cw2 { + if let Some(sense2) = maybe_sense2 { let cross2 = seq_perp_dot_product(tangent_point_pair.0, tangent_point_pair.1, circle2.pos); - if (cw2 && cross2 >= 0.0) || (!cw2 && cross2 <= 0.0) { + if (sense2 == RotationSense::Clockwise && cross2 >= 0.0) + || (sense2 == RotationSense::Counterclockwise && cross2 <= 0.0) + { return None; } } @@ -115,11 +119,13 @@ pub fn tangent_segments( pub fn tangent_segment( circle1: Circle, - cw1: Option, + maybe_sense1: Option, circle2: Circle, - cw2: Option, + maybe_sense2: Option, ) -> Result { - Ok(tangent_segments(circle1, cw1, circle2, cw2)? - .next() - .unwrap()) + Ok( + tangent_segments(circle1, maybe_sense1, circle2, maybe_sense2)? + .next() + .unwrap(), + ) } diff --git a/src/router/draw.rs b/src/router/draw.rs index 8729e64..e39d661 100644 --- a/src/router/draw.rs +++ b/src/router/draw.rs @@ -23,7 +23,7 @@ use crate::{ }, geometry::GetLayer, layout::{Layout, LayoutEdit}, - math::{Circle, NoTangents}, + math::{Circle, NoTangents, RotationSense}, }; #[derive(Error, Debug, Clone, Copy)] @@ -53,7 +53,7 @@ pub trait Draw { recorder: &mut LayoutEdit, head: Head, around: FixedDotIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result; @@ -62,7 +62,7 @@ pub trait Draw { recorder: &mut LayoutEdit, head: Head, around: BendIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result; @@ -130,12 +130,12 @@ impl Draw for Layout { recorder: &mut LayoutEdit, head: Head, around: FixedDotIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result { let tangent = self .drawing() - .head_around_dot_segment(&head, around.into(), cw, width)?; + .head_around_dot_segment(&head, around.into(), sense, width)?; let offset = self .drawing() .head_around_dot_offset(&head, around.into(), width); @@ -145,7 +145,7 @@ impl Draw for Layout { around.into(), tangent.start_point(), tangent.end_point(), - cw, + sense, width, offset, ) @@ -159,12 +159,12 @@ impl Draw for Layout { recorder: &mut LayoutEdit, head: Head, around: BendIndex, - cw: bool, + sense: RotationSense, width: f64, ) -> Result { let tangent = self .drawing() - .head_around_bend_segment(&head, around, cw, width)?; + .head_around_bend_segment(&head, around, sense, width)?; let offset = self.drawing().head_around_bend_offset(&head, around, width); self.cane_around( @@ -173,7 +173,7 @@ impl Draw for Layout { around.into(), tangent.start_point(), tangent.end_point(), - cw, + sense, width, offset, ) @@ -203,7 +203,7 @@ trait DrawPrivate { around: GearIndex, from: Point, to: Point, - cw: bool, + sense: RotationSense, width: f64, offset: f64, ) -> Result; @@ -221,7 +221,7 @@ trait DrawPrivate { head: Head, around: GearIndex, to: Point, - cw: bool, + sense: RotationSense, width: f64, offset: f64, ) -> Result; @@ -239,12 +239,12 @@ impl DrawPrivate for Layout { around: GearIndex, from: Point, to: Point, - cw: bool, + sense: RotationSense, width: f64, offset: f64, ) -> Result { let head = self.extend_head(recorder, head, from)?; - self.cane(recorder, head, around, to, cw, width, offset) + self.cane(recorder, head, around, to, sense, width, offset) } #[debug_ensures(self.drawing().node_count() == old(self.drawing().node_count()))] @@ -270,7 +270,7 @@ impl DrawPrivate for Layout { head: Head, around: GearIndex, to: Point, - cw: bool, + sense: RotationSense, width: f64, offset: f64, ) -> Result { @@ -299,7 +299,7 @@ impl DrawPrivate for Layout { layer, maybe_net, }), - cw, + sense, )?; Ok(CaneHead { face: self.drawing().primitive(cane.bend).other_joint(cane.dot), diff --git a/src/router/navcord.rs b/src/router/navcord.rs index 4986508..d0a34b4 100644 --- a/src/router/navcord.rs +++ b/src/router/navcord.rs @@ -60,20 +60,28 @@ impl NavcordStepper { around: NavvertexIndex, ) -> Result { let around_node_weight = navmesh.node_weight(around).unwrap(); - let cw = around_node_weight - .maybe_cw + let sense = around_node_weight + .maybe_sense .ok_or(NavcorderException::CannotWrap)?; match around_node_weight.node { BinavvertexNodeIndex::FixedDot(dot) => { - layout.cane_around_dot(&mut self.recorder, head, dot, cw, self.width) - } - BinavvertexNodeIndex::FixedBend(fixed_bend) => { - layout.cane_around_bend(&mut self.recorder, head, fixed_bend.into(), cw, self.width) - } - BinavvertexNodeIndex::LooseBend(loose_bend) => { - layout.cane_around_bend(&mut self.recorder, head, loose_bend.into(), cw, self.width) + layout.cane_around_dot(&mut self.recorder, head, dot, sense, self.width) } + BinavvertexNodeIndex::FixedBend(fixed_bend) => layout.cane_around_bend( + &mut self.recorder, + head, + fixed_bend.into(), + sense, + self.width, + ), + BinavvertexNodeIndex::LooseBend(loose_bend) => layout.cane_around_bend( + &mut self.recorder, + head, + loose_bend.into(), + sense, + self.width, + ), } .map_err(NavcorderException::CannotDraw) } diff --git a/src/router/navmesh.rs b/src/router/navmesh.rs index a00df94..e07a333 100644 --- a/src/router/navmesh.rs +++ b/src/router/navmesh.rs @@ -31,6 +31,7 @@ use crate::{ geometry::{shape::AccessShape, GetLayer}, graph::{GetPetgraphIndex, MakeRef}, layout::Layout, + math::RotationSense, router::astar::MakeEdgeRef, triangulation::{GetTrianvertexNodeIndex, Triangulation}, }; @@ -136,7 +137,7 @@ pub struct NavvertexWeight { /// one is clockwise (`Some(true)`), the other counterclockwise (`Some(false)`). /// The origin and destination nodes however have /// only one corresponding navmesh vertex each (`None`). - pub maybe_cw: Option, + pub maybe_sense: Option, } #[derive(Error, Debug, Clone)] @@ -222,7 +223,7 @@ impl Navmesh { if trianvertex == origin.into() { let navvertex = graph.add_node(NavvertexWeight { node: trianvertex.into(), - maybe_cw: None, + maybe_sense: None, }); origin_navvertex = Some(navvertex); @@ -230,7 +231,7 @@ impl Navmesh { } else if trianvertex == destination.into() { let navvertex = graph.add_node(NavvertexWeight { node: trianvertex.into(), - maybe_cw: None, + maybe_sense: None, }); destination_navvertex = Some(navvertex); @@ -313,12 +314,12 @@ impl Navmesh { ) { let navvertex1 = graph.add_node(NavvertexWeight { node, - maybe_cw: Some(false), + maybe_sense: Some(RotationSense::Counterclockwise), }); let navvertex2 = graph.add_node(NavvertexWeight { node, - maybe_cw: Some(true), + maybe_sense: Some(RotationSense::Clockwise), }); map.get_mut(&trianvertex)