overlay,egui: impl. incomplete ratsnest generation and drawing

For now only doing Delaunay triangulation, then applying minimum
spanning tree (without properly working edge ordering yet).
This commit is contained in:
Mikolaj Wielgus 2024-04-21 19:51:47 +02:00
parent 8ac63ea6d1
commit 8d59242f3f
9 changed files with 193 additions and 81 deletions

View File

@ -1,5 +1,6 @@
use futures::executor;
use geo::point;
use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use std::{
future::Future,
sync::mpsc::{channel, Receiver, Sender},
@ -10,7 +11,7 @@ use topola::{
dsn::{design::DsnDesign, rules::DsnRules},
geometry::{
compound::CompoundManagerTrait,
primitive::{BendShape, DotShape, PrimitiveShape, SegShape},
primitive::{BendShape, DotShape, PrimitiveShape, PrimitiveShapeTrait, SegShape},
GenericNode,
},
layout::{zone::MakePolyShape, Layout},
@ -25,13 +26,13 @@ use crate::painter::Painter;
#[serde(default)]
pub struct App {
#[serde(skip)]
overlay: Overlay,
maybe_overlay: Option<Overlay>,
#[serde(skip)]
text_channel: (Sender<String>, Receiver<String>),
#[serde(skip)]
layout: Option<Layout<DsnRules>>,
maybe_layout: Option<Layout<DsnRules>>,
#[serde(skip)]
from_rect: egui::emath::Rect,
@ -40,9 +41,9 @@ pub struct App {
impl Default for App {
fn default() -> Self {
Self {
overlay: Overlay::new(),
maybe_overlay: None,
text_channel: channel(),
layout: None,
maybe_layout: None,
from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0),
}
}
@ -71,12 +72,16 @@ impl eframe::App for App {
if cfg!(target_arch = "wasm32") {
if let Ok(file_contents) = self.text_channel.1.try_recv() {
let design = DsnDesign::load_from_string(file_contents).unwrap();
self.layout = Some(design.make_layout());
let layout = design.make_layout();
self.maybe_overlay = Some(Overlay::new(&layout).unwrap());
self.maybe_layout = Some(layout);
}
} else {
if let Ok(path) = self.text_channel.1.try_recv() {
let design = DsnDesign::load_from_file(&path).unwrap();
self.layout = Some(design.make_layout());
let layout = design.make_layout();
self.maybe_overlay = Some(Overlay::new(&layout).unwrap());
self.maybe_layout = Some(layout);
}
}
@ -144,9 +149,10 @@ impl eframe::App for App {
let transform = egui::emath::RectTransform::from_to(self.from_rect, viewport_rect);
let mut painter = Painter::new(ui, transform);
if let Some(layout) = &self.layout {
if let (Some(layout), Some(overlay)) = (&self.maybe_layout, &mut self.maybe_overlay)
{
if ctx.input(|i| i.pointer.any_click()) {
self.overlay.click(
overlay.click(
layout,
point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
);
@ -155,8 +161,7 @@ impl eframe::App for App {
for primitive in layout.drawing().layer_primitive_nodes(1) {
let shape = primitive.primitive(layout.drawing()).shape();
let color = if self
.overlay
let color = if overlay
.selection()
.contains(&GenericNode::Primitive(primitive))
{
@ -168,11 +173,7 @@ impl eframe::App for App {
}
for zone in layout.layer_zones(1) {
let color = if self
.overlay
.selection()
.contains(&GenericNode::Compound(zone))
{
let color = if overlay.selection().contains(&GenericNode::Compound(zone)) {
egui::Color32::from_rgb(100, 100, 255)
} else {
egui::Color32::from_rgb(52, 52, 200)
@ -189,8 +190,7 @@ impl eframe::App for App {
for primitive in layout.drawing().layer_primitive_nodes(0) {
let shape = primitive.primitive(layout.drawing()).shape();
let color = if self
.overlay
let color = if overlay
.selection()
.contains(&GenericNode::Primitive(primitive))
{
@ -202,11 +202,7 @@ impl eframe::App for App {
}
for zone in layout.layer_zones(0) {
let color = if self
.overlay
.selection()
.contains(&GenericNode::Compound(zone))
{
let color = if overlay.selection().contains(&GenericNode::Compound(zone)) {
egui::Color32::from_rgb(255, 100, 100)
} else {
egui::Color32::from_rgb(200, 52, 52)
@ -219,6 +215,24 @@ impl eframe::App for App {
color,
)
}
for edge in overlay.ratsnest().graph().edge_references() {
let from = overlay
.ratsnest()
.graph()
.node_weight(edge.source())
.unwrap()
.pos;
let to = overlay
.ratsnest()
.graph()
.node_weight(edge.target())
.unwrap()
.pos;
painter.paint_edge(from, to, egui::Color32::from_rgb(90, 90, 200));
}
//unreachable!();
}
})
});

View File

@ -70,6 +70,14 @@ impl<'a> Painter<'a> {
}
pub fn paint_edge(&mut self, from: Point, to: Point, color: Color32) {
//
self.ui.painter().add(epaint::Shape::line_segment(
[
self.transform
.transform_pos([from.x() as f32, -from.y() as f32].into()),
self.transform
.transform_pos([to.x() as f32, -to.y() as f32].into()),
],
Stroke::new(1.0, color),
));
}
}

View File

@ -24,7 +24,7 @@ use topola::dsn::design::DsnDesign;
use topola::geometry::primitive::{PrimitiveShape, PrimitiveShapeTrait};
use topola::layout::connectivity::BandIndex;
use topola::layout::Layout;
use topola::mesh::{Mesh, MeshEdgeReference, VertexIndex};
use topola::navmesh::{Navmesh, NavmeshEdgeReference, VertexIndex};
use topola::router::RouterObserverTrait;
use sdl2::event::Event;
@ -87,12 +87,12 @@ struct EmptyRouterObserver;
impl<R: RulesTrait> RouterObserverTrait<R> for EmptyRouterObserver {
fn on_rework(&mut self, _tracer: &Tracer<R>, _trace: &Trace) {}
fn before_probe(&mut self, _tracer: &Tracer<R>, _trace: &Trace, _edge: MeshEdgeReference) {}
fn before_probe(&mut self, _tracer: &Tracer<R>, _trace: &Trace, _edge: NavmeshEdgeReference) {}
fn on_probe(
&mut self,
_tracer: &Tracer<R>,
_trace: &Trace,
_edge: MeshEdgeReference,
_edge: NavmeshEdgeReference,
_result: Result<(), DrawException>,
) {
}
@ -135,7 +135,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
self.view,
RouterOrLayout::Layout(tracer.layout.drawing()),
None,
Some(tracer.mesh.clone()),
Some(tracer.navmesh.clone()),
&trace.path,
&[],
&[],
@ -143,7 +143,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
);
}
fn before_probe(&mut self, tracer: &Tracer<R>, trace: &Trace, edge: MeshEdgeReference) {
fn before_probe(&mut self, tracer: &Tracer<R>, trace: &Trace, edge: NavmeshEdgeReference) {
let mut path = trace.path.clone();
path.push(edge.target());
render_times(
@ -154,7 +154,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
self.view,
RouterOrLayout::Layout(tracer.layout.drawing()),
None,
Some(tracer.mesh.clone()),
Some(tracer.navmesh.clone()),
&path,
&[],
&[],
@ -166,7 +166,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
&mut self,
tracer: &Tracer<R>,
trace: &Trace,
_edge: MeshEdgeReference,
_edge: NavmeshEdgeReference,
result: Result<(), DrawException>,
) {
let (ghosts, highlighteds, delay) = match result {
@ -186,7 +186,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
self.view,
RouterOrLayout::Layout(tracer.layout.drawing()),
None,
Some(tracer.mesh.clone()),
Some(tracer.navmesh.clone()),
&trace.path,
&ghosts,
&highlighteds,
@ -324,7 +324,7 @@ fn render_times(
view: &mut View,
mut router_or_layout: RouterOrLayout<impl RulesTrait>,
maybe_band: Option<BandIndex>,
mut maybe_mesh: Option<Mesh>,
mut maybe_navmesh: Option<Navmesh>,
path: &[VertexIndex],
ghosts: &[PrimitiveShape],
highlighteds: &[PrimitiveIndex],
@ -389,7 +389,7 @@ fn render_times(
),
)
.ok();
maybe_mesh = None;
maybe_navmesh = None;
}
router.layout.drawing()
@ -440,8 +440,8 @@ fn render_times(
painter.paint_shape(&ghost, ColorU::new(75, 75, 150, 255), view.zoom);
}
if let Some(ref mesh) = maybe_mesh {
for edge in mesh.edge_references() {
if let Some(ref navmesh) = maybe_navmesh {
for edge in navmesh.edge_references() {
let to = edge.source().primitive(drawing).shape().center();
let from = edge.target().primitive(drawing).shape().center();

View File

@ -1,3 +1,4 @@
mod overlay;
pub mod ratsnest;
pub use overlay::*;

View File

@ -2,10 +2,11 @@ use std::collections::HashSet;
use geo::Point;
use rstar::AABB;
use spade::InsertionError;
use crate::{
drawing::{
graph::{GetLayer, MakePrimitive, PrimitiveIndex},
graph::{GetLayer, MakePrimitive},
primitive::MakePrimitiveShape,
rules::RulesTrait,
},
@ -13,24 +14,23 @@ use crate::{
compound::CompoundManagerTrait,
shape::{Shape, ShapeTrait},
},
graph::GenericIndex,
layout::{
zone::{MakePolyShape, ZoneWeight},
Layout, NodeIndex,
},
layout::{zone::MakePolyShape, Layout, NodeIndex},
overlay::ratsnest::Ratsnest,
};
pub struct Overlay {
ratsnest: Ratsnest,
selection: HashSet<NodeIndex>,
active_layer: u64,
}
impl Overlay {
pub fn new() -> Self {
Self {
pub fn new(layout: &Layout<impl RulesTrait>) -> Result<Self, InsertionError> {
Ok(Self {
ratsnest: Ratsnest::new(layout)?,
selection: HashSet::new(),
active_layer: 0,
}
})
}
pub fn click(&mut self, layout: &Layout<impl RulesTrait>, at: Point) {
@ -88,6 +88,10 @@ impl Overlay {
}
}
pub fn ratsnest(&self) -> &Ratsnest {
&self.ratsnest
}
pub fn selection(&self) -> &HashSet<NodeIndex> {
&self.selection
}

76
src/overlay/ratsnest.rs Normal file
View File

@ -0,0 +1,76 @@
use geo::Point;
use petgraph::{
data::FromElements,
stable_graph::StableUnGraph,
visit::{self, EdgeRef, NodeIndexable},
};
use spade::{HasPosition, InsertionError, Point2};
use crate::{
drawing::{
dot::FixedDotIndex,
graph::{MakePrimitive, PrimitiveIndex},
primitive::MakePrimitiveShape,
rules::RulesTrait,
},
geometry::primitive::PrimitiveShapeTrait,
layout::Layout,
triangulation::{GetVertexIndex, Triangulation},
};
#[derive(Debug, Clone, Copy)]
pub struct TriangulationWeight {
vertex: FixedDotIndex,
pub pos: Point,
}
impl GetVertexIndex<FixedDotIndex> for TriangulationWeight {
fn vertex_index(&self) -> FixedDotIndex {
self.vertex
}
}
impl HasPosition for TriangulationWeight {
type Scalar = f64;
fn position(&self) -> Point2<Self::Scalar> {
Point2::new(self.pos.x(), self.pos.y())
}
}
pub struct Ratsnest {
graph: StableUnGraph<TriangulationWeight, (), usize>,
}
impl Ratsnest {
pub fn new(layout: &Layout<impl RulesTrait>) -> Result<Self, InsertionError> {
let mut this = Self {
graph: StableUnGraph::default(),
};
let mut triangulation =
Triangulation::new(layout.drawing().geometry().graph().node_bound());
for node in layout.drawing().primitive_nodes() {
let center = node.primitive(layout.drawing()).shape().center();
match node {
PrimitiveIndex::FixedDot(dot) => {
triangulation.add_vertex(TriangulationWeight {
vertex: dot,
pos: center,
})?;
}
_ => (),
}
}
this.graph =
StableUnGraph::from_elements(petgraph::algo::min_spanning_tree(&triangulation));
Ok(this)
}
pub fn graph(&self) -> &StableUnGraph<TriangulationWeight, (), usize> {
&self.graph
}
}

View File

@ -64,7 +64,7 @@ struct TriangulationWeight {
}
impl GetVertexIndex<TriangulationVertexIndex> for TriangulationWeight {
fn vertex(&self) -> TriangulationVertexIndex {
fn vertex_index(&self) -> TriangulationVertexIndex {
self.vertex
}
}
@ -153,12 +153,12 @@ impl visit::Data for Navmesh {
}
#[derive(Debug, Clone, Copy)]
pub struct MeshEdgeReference {
pub struct NavmeshEdgeReference {
from: VertexIndex,
to: VertexIndex,
}
impl visit::EdgeRef for MeshEdgeReference {
impl visit::EdgeRef for NavmeshEdgeReference {
type NodeId = VertexIndex;
type EdgeId = (VertexIndex, VertexIndex);
type Weight = ();
@ -203,7 +203,7 @@ impl<'a> visit::IntoNeighbors for &'a Navmesh {
fn edge_with_near_edges(
triangulation: &Triangulation<TriangulationVertexIndex, TriangulationWeight>,
edge: TriangulationEdgeReference<TriangulationVertexIndex>,
) -> impl Iterator<Item = MeshEdgeReference> {
) -> impl Iterator<Item = NavmeshEdgeReference> {
let mut from_vertices = vec![edge.source().into()];
// Append rails to the source.
@ -230,15 +230,15 @@ fn edge_with_near_edges(
from_vertices
.into_iter()
.cartesian_product(to_vertices.into_iter())
.map(|pair| MeshEdgeReference {
.map(|pair| NavmeshEdgeReference {
from: pair.0,
to: pair.1.into(),
})
}
impl<'a> visit::IntoEdgeReferences for &'a Navmesh {
type EdgeRef = MeshEdgeReference;
type EdgeReferences = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>;
type EdgeRef = NavmeshEdgeReference;
type EdgeReferences = Box<dyn Iterator<Item = NavmeshEdgeReference> + 'a>;
fn edge_references(self) -> Self::EdgeReferences {
Box::new(
@ -253,7 +253,7 @@ fn vertex_edges(
triangulation: &Triangulation<TriangulationVertexIndex, TriangulationWeight>,
from: VertexIndex,
to: TriangulationVertexIndex,
) -> impl Iterator<Item = MeshEdgeReference> {
) -> impl Iterator<Item = NavmeshEdgeReference> {
let from_vertices = vec![from];
let mut to_vertices = vec![to.into()];
@ -270,14 +270,14 @@ fn vertex_edges(
from_vertices
.into_iter()
.cartesian_product(to_vertices.into_iter())
.map(|pair| MeshEdgeReference {
.map(|pair| NavmeshEdgeReference {
from: pair.0,
to: pair.1,
})
}
impl<'a> visit::IntoEdges for &'a Navmesh {
type Edges = Box<dyn Iterator<Item = MeshEdgeReference> + 'a>;
type Edges = Box<dyn Iterator<Item = NavmeshEdgeReference> + 'a>;
fn edges(self, vertex: Self::NodeId) -> Self::Edges {
Box::new(

View File

@ -17,7 +17,7 @@ use crate::layout::Layout;
use crate::router::{
astar::{astar, AstarStrategy, PathTracker},
draw::DrawException,
navmesh::{MeshEdgeReference, Navmesh, VertexIndex},
navmesh::{Navmesh, NavmeshEdgeReference, VertexIndex},
tracer::{Trace, Tracer},
};
@ -41,12 +41,12 @@ pub enum RoutingErrorKind {
pub trait RouterObserverTrait<R: RulesTrait> {
fn on_rework(&mut self, tracer: &Tracer<R>, trace: &Trace);
fn before_probe(&mut self, tracer: &Tracer<R>, trace: &Trace, edge: MeshEdgeReference);
fn before_probe(&mut self, tracer: &Tracer<R>, trace: &Trace, edge: NavmeshEdgeReference);
fn on_probe(
&mut self,
tracer: &Tracer<R>,
trace: &Trace,
edge: MeshEdgeReference,
edge: NavmeshEdgeReference,
result: Result<(), DrawException>,
);
fn on_estimate(&mut self, tracer: &Tracer<R>, vertex: VertexIndex);
@ -94,7 +94,7 @@ impl<'a, RO: RouterObserverTrait<R>, R: RulesTrait> AstarStrategy<&Navmesh, f64>
self.tracer.finish(&mut self.trace, self.to, width).is_ok()
}
fn edge_cost(&mut self, edge: MeshEdgeReference) -> Option<f64> {
fn edge_cost(&mut self, edge: NavmeshEdgeReference) -> Option<f64> {
self.observer.before_probe(&self.tracer, &self.trace, edge);
if edge.target() == self.to.into() {
return None;

View File

@ -7,7 +7,7 @@ use spade::{handles::FixedVertexHandle, DelaunayTriangulation, HasPosition, Inse
use crate::graph::GetNodeIndex;
pub trait GetVertexIndex<I> {
fn vertex(&self) -> I;
fn vertex_index(&self) -> I;
}
#[derive(Debug, Clone)]
@ -31,7 +31,7 @@ impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scal
}
pub fn add_vertex(&mut self, weight: W) -> Result<(), InsertionError> {
let index = weight.vertex().node_index().index();
let index = weight.vertex_index().node_index().index();
self.vertex_to_handle[index] = Some(spade::Triangulation::insert(
&mut self.triangulation,
weight,
@ -60,7 +60,7 @@ impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scal
fn vertex(&self, handle: FixedVertexHandle) -> I {
spade::Triangulation::vertex(&self.triangulation, handle)
.as_ref()
.vertex()
.vertex_index()
}
fn handle(&self, vertex: I) -> FixedVertexHandle {
@ -78,7 +78,7 @@ impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scal
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
visit::Data for Triangulation<I, W>
{
type NodeWeight = ();
type NodeWeight = W;
type EdgeWeight = ();
}
@ -169,53 +169,62 @@ impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<
spade::Triangulation::fixed_vertices(&self.triangulation).map(|vertex| {
spade::Triangulation::s(&self.triangulation)
.vertex_data(vertex)
.vertex()
.vertex_index()
}),
)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TriangulationVertexReference<I> {
/*#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TriangulationVertexReference<I: Copy, W> {
index: I,
weight: &'a W,
}
impl<I: Copy> visit::NodeRef for TriangulationVertexReference<I> {
impl<I: Copy> visit::NodeRef for TriangulationVertexReference<I, W> {
type NodeId = I;
type Weight = ();
type Weight = W;
fn id(&self) -> Self::NodeId {
self.index
}
fn weight(&self) -> &Self::Weight {
&()
}
self.weight
}
}*/
impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
visit::IntoNodeReferences for &'a Triangulation<I, W>
{
type NodeRef = TriangulationVertexReference<I>;
type NodeReferences = Box<dyn Iterator<Item = TriangulationVertexReference<I>> + 'a>;
/*type NodeRef = TriangulationVertexReference<I, W>;
type NodeReferences = Box<dyn Iterator<Item = TriangulationVertexReference<I, W>> + 'a>;*/
type NodeRef = (I, &'a W);
type NodeReferences = Box<dyn Iterator<Item = (I, &'a W)> + 'a>;
fn node_references(self) -> Self::NodeReferences {
Box::new(
spade::Triangulation::fixed_vertices(&self.triangulation).map(|vertex| {
TriangulationVertexReference {
index: spade::Triangulation::s(&self.triangulation)
.vertex_data(vertex)
.vertex(),
}
let weight = spade::Triangulation::s(&self.triangulation).vertex_data(vertex);
/*TriangulationVertexReference {
index: weight.vertex_index(),
weight,
}*/
(weight.vertex_index(), weight)
}),
)
}
}
impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>>
visit::NodeIndexable for &'a Triangulation<I, W>
impl<
'a,
I: Copy + PartialEq + GetNodeIndex + std::fmt::Debug,
W: GetVertexIndex<I> + HasPosition<Scalar = f64>,
> visit::NodeIndexable for &'a Triangulation<I, W>
{
fn node_bound(&self) -> usize {
spade::Triangulation::num_vertices(&self.triangulation)
//spade::Triangulation::num_vertices(&self.triangulation)
self.vertex_to_handle.len()
}
fn to_index(&self, node: I) -> usize {
@ -225,6 +234,6 @@ impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<
fn from_index(&self, index: usize) -> I {
spade::Triangulation::s(&self.triangulation)
.vertex_data(self.vertex_to_handle[index].unwrap())
.vertex()
.vertex_index()
}
}