mirror of https://codeberg.org/topola/topola.git
overlay: new module, impl. basic mouse selection of primitives
Only check for intersection of the AABB as a starter.
This commit is contained in:
parent
df23ea8398
commit
4a9322d694
|
|
@ -1,4 +1,5 @@
|
||||||
use futures::executor;
|
use futures::executor;
|
||||||
|
use geo::point;
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
sync::mpsc::{channel, Receiver, Sender},
|
sync::mpsc::{channel, Receiver, Sender},
|
||||||
|
|
@ -7,9 +8,13 @@ use std::{
|
||||||
use topola::{
|
use topola::{
|
||||||
drawing::{graph::MakePrimitive, primitive::MakeShape, Drawing},
|
drawing::{graph::MakePrimitive, primitive::MakeShape, Drawing},
|
||||||
dsn::{design::DsnDesign, rules::DsnRules},
|
dsn::{design::DsnDesign, rules::DsnRules},
|
||||||
geometry::primitive::{BendShape, DotShape, PrimitiveShape, SegShape},
|
geometry::{
|
||||||
|
primitive::{BendShape, DotShape, PrimitiveShape, SegShape},
|
||||||
|
Node,
|
||||||
|
},
|
||||||
layout::{zone::MakePolygon, Layout},
|
layout::{zone::MakePolygon, Layout},
|
||||||
math::Circle,
|
math::Circle,
|
||||||
|
overlay::Overlay,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::painter::Painter;
|
use crate::painter::Painter;
|
||||||
|
|
@ -18,10 +23,10 @@ use crate::painter::Painter;
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
// Example stuff:
|
#[serde(skip)]
|
||||||
label: String,
|
overlay: Overlay,
|
||||||
|
|
||||||
#[serde(skip)] // Don't serialize this field.
|
#[serde(skip)]
|
||||||
text_channel: (Sender<String>, Receiver<String>),
|
text_channel: (Sender<String>, Receiver<String>),
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
|
@ -34,8 +39,7 @@ pub struct App {
|
||||||
impl Default for App {
|
impl Default for App {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
// Example stuff:
|
overlay: Overlay::new(),
|
||||||
label: "Hello World!".to_owned(),
|
|
||||||
text_channel: channel(),
|
text_channel: channel(),
|
||||||
layout: None,
|
layout: None,
|
||||||
from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0),
|
from_rect: egui::Rect::from_x_y_ranges(0.0..=1000000.0, 0.0..=500000.0),
|
||||||
|
|
@ -140,9 +144,22 @@ impl eframe::App for App {
|
||||||
let mut painter = Painter::new(ui, transform);
|
let mut painter = Painter::new(ui, transform);
|
||||||
|
|
||||||
if let Some(layout) = &self.layout {
|
if let Some(layout) = &self.layout {
|
||||||
|
if ctx.input(|i| i.pointer.any_click()) {
|
||||||
|
self.overlay.click(
|
||||||
|
layout,
|
||||||
|
point! {x: latest_pos.x as f64, y: -latest_pos.y as f64},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for node in layout.drawing().layer_primitive_nodes(1) {
|
for node in layout.drawing().layer_primitive_nodes(1) {
|
||||||
let shape = node.primitive(layout.drawing()).shape();
|
let shape = node.primitive(layout.drawing()).shape();
|
||||||
painter.paint_shape(&shape, egui::Color32::from_rgb(52, 52, 200));
|
|
||||||
|
let color = if self.overlay.selection().contains(&Node::Primitive(node)) {
|
||||||
|
egui::Color32::from_rgb(100, 100, 255)
|
||||||
|
} else {
|
||||||
|
egui::Color32::from_rgb(52, 52, 200)
|
||||||
|
};
|
||||||
|
painter.paint_shape(&shape, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
for zone in layout.layer_zones(1) {
|
for zone in layout.layer_zones(1) {
|
||||||
|
|
@ -154,7 +171,13 @@ impl eframe::App for App {
|
||||||
|
|
||||||
for node in layout.drawing().layer_primitive_nodes(0) {
|
for node in layout.drawing().layer_primitive_nodes(0) {
|
||||||
let shape = node.primitive(layout.drawing()).shape();
|
let shape = node.primitive(layout.drawing()).shape();
|
||||||
painter.paint_shape(&shape, egui::Color32::from_rgb(200, 52, 52));
|
|
||||||
|
let color = if self.overlay.selection().contains(&Node::Primitive(node)) {
|
||||||
|
egui::Color32::from_rgb(255, 100, 100)
|
||||||
|
} else {
|
||||||
|
egui::Color32::from_rgb(200, 52, 52)
|
||||||
|
};
|
||||||
|
painter.paint_shape(&shape, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
for zone in layout.layer_zones(0) {
|
for zone in layout.layer_zones(0) {
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ impl RulesTrait for SimpleRules {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clunky enum to work around borrow checker.
|
// Clunky enum to work around borrow checker.
|
||||||
enum RouterOrDrawing<'a, R: RulesTrait> {
|
enum RouterOrLayout<'a, R: RulesTrait> {
|
||||||
Router(&'a mut Router<R>),
|
Router(&'a mut Router<R>),
|
||||||
Layout(&'a Layout<R>),
|
Layout(&'a Layout<R>),
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +133,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
|
||||||
self.renderer,
|
self.renderer,
|
||||||
self.font_context,
|
self.font_context,
|
||||||
self.view,
|
self.view,
|
||||||
RouterOrDrawing::Layout(tracer.layout.drawing()),
|
RouterOrLayout::Layout(tracer.layout.drawing()),
|
||||||
None,
|
None,
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&trace.path,
|
&trace.path,
|
||||||
|
|
@ -152,7 +152,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
|
||||||
self.renderer,
|
self.renderer,
|
||||||
self.font_context,
|
self.font_context,
|
||||||
self.view,
|
self.view,
|
||||||
RouterOrDrawing::Layout(tracer.layout.drawing()),
|
RouterOrLayout::Layout(tracer.layout.drawing()),
|
||||||
None,
|
None,
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&path,
|
&path,
|
||||||
|
|
@ -184,7 +184,7 @@ impl<'a, R: RulesTrait> RouterObserverTrait<R> for DebugRouterObserver<'a> {
|
||||||
self.renderer,
|
self.renderer,
|
||||||
self.font_context,
|
self.font_context,
|
||||||
self.view,
|
self.view,
|
||||||
RouterOrDrawing::Layout(tracer.layout.drawing()),
|
RouterOrLayout::Layout(tracer.layout.drawing()),
|
||||||
None,
|
None,
|
||||||
Some(tracer.mesh.clone()),
|
Some(tracer.mesh.clone()),
|
||||||
&trace.path,
|
&trace.path,
|
||||||
|
|
@ -275,7 +275,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&font_context,
|
&font_context,
|
||||||
&mut view,
|
&mut view,
|
||||||
RouterOrDrawing::Layout(router.layout.drawing()),
|
RouterOrLayout::Layout(router.layout.drawing()),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
|
|
@ -299,7 +299,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&font_context,
|
&font_context,
|
||||||
&mut view,
|
&mut view,
|
||||||
RouterOrDrawing::Layout(router.layout.drawing()),
|
RouterOrLayout::Layout(router.layout.drawing()),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
|
|
@ -322,7 +322,7 @@ fn render_times(
|
||||||
renderer: &mut Renderer<GLDevice>,
|
renderer: &mut Renderer<GLDevice>,
|
||||||
font_context: &CanvasFontContext,
|
font_context: &CanvasFontContext,
|
||||||
view: &mut View,
|
view: &mut View,
|
||||||
mut router_or_layout: RouterOrDrawing<impl RulesTrait>,
|
mut router_or_layout: RouterOrLayout<impl RulesTrait>,
|
||||||
maybe_band: Option<BandIndex>,
|
maybe_band: Option<BandIndex>,
|
||||||
mut maybe_mesh: Option<Mesh>,
|
mut maybe_mesh: Option<Mesh>,
|
||||||
path: &[VertexIndex],
|
path: &[VertexIndex],
|
||||||
|
|
@ -371,7 +371,7 @@ fn render_times(
|
||||||
let mut painter = Painter::new(&mut canvas);
|
let mut painter = Painter::new(&mut canvas);
|
||||||
|
|
||||||
let drawing = match router_or_layout {
|
let drawing = match router_or_layout {
|
||||||
RouterOrDrawing::Router(ref mut router) => {
|
RouterOrLayout::Router(ref mut router) => {
|
||||||
let state = event_pump.mouse_state();
|
let state = event_pump.mouse_state();
|
||||||
|
|
||||||
if let Some(band) = maybe_band {
|
if let Some(band) = maybe_band {
|
||||||
|
|
@ -394,7 +394,7 @@ fn render_times(
|
||||||
|
|
||||||
router.layout.drawing()
|
router.layout.drawing()
|
||||||
}
|
}
|
||||||
RouterOrDrawing::Layout(layout) => layout,
|
RouterOrLayout::Layout(layout) => layout,
|
||||||
};
|
};
|
||||||
|
|
||||||
//let result = panic::catch_unwind(|| {
|
//let result = panic::catch_unwind(|| {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ use crate::drawing::{
|
||||||
};
|
};
|
||||||
use crate::geometry::compound::CompoundManagerTrait;
|
use crate::geometry::compound::CompoundManagerTrait;
|
||||||
use crate::geometry::with_rtree::BboxedIndex;
|
use crate::geometry::with_rtree::BboxedIndex;
|
||||||
use crate::geometry::NodeWeight;
|
use crate::geometry::Node;
|
||||||
use crate::geometry::{
|
use crate::geometry::{
|
||||||
primitive::{PrimitiveShape, PrimitiveShapeTrait},
|
primitive::{PrimitiveShape, PrimitiveShapeTrait},
|
||||||
with_rtree::GeometryWithRtree,
|
with_rtree::GeometryWithRtree,
|
||||||
|
|
@ -639,7 +639,7 @@ impl<CW: Copy, R: RulesTrait> Drawing<CW, R> {
|
||||||
.rtree()
|
.rtree()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|wrapper| {
|
.filter_map(|wrapper| {
|
||||||
if let NodeWeight::Primitive(primitive_node) = wrapper.data {
|
if let Node::Primitive(primitive_node) = wrapper.data {
|
||||||
Some(primitive_node)
|
Some(primitive_node)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -655,7 +655,7 @@ impl<CW: Copy, R: RulesTrait> Drawing<CW, R> {
|
||||||
[f64::INFINITY, f64::INFINITY, layer as f64],
|
[f64::INFINITY, f64::INFINITY, layer as f64],
|
||||||
))
|
))
|
||||||
.filter_map(|wrapper| {
|
.filter_map(|wrapper| {
|
||||||
if let NodeWeight::Primitive(primitive_node) = wrapper.data {
|
if let Node::Primitive(primitive_node) = wrapper.data {
|
||||||
Some(primitive_node)
|
Some(primitive_node)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -750,7 +750,7 @@ impl<CW: Copy, R: RulesTrait> Drawing<CW, R> {
|
||||||
.rtree()
|
.rtree()
|
||||||
.locate_in_envelope_intersecting(&limiting_shape.full_height_envelope_3d(0.0, 2))
|
.locate_in_envelope_intersecting(&limiting_shape.full_height_envelope_3d(0.0, 2))
|
||||||
.filter_map(|wrapper| {
|
.filter_map(|wrapper| {
|
||||||
if let NodeWeight::Primitive(primitive_node) = wrapper.data {
|
if let Node::Primitive(primitive_node) = wrapper.data {
|
||||||
Some(primitive_node)
|
Some(primitive_node)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -785,7 +785,7 @@ impl<CW: Copy, R: RulesTrait> Drawing<CW, R> {
|
||||||
.rtree()
|
.rtree()
|
||||||
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
|
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
|
||||||
.filter_map(|wrapper| {
|
.filter_map(|wrapper| {
|
||||||
if let NodeWeight::Primitive(primitive_node) = wrapper.data {
|
if let Node::Primitive(primitive_node) = wrapper.data {
|
||||||
Some(primitive_node)
|
Some(primitive_node)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -833,7 +833,7 @@ impl<CW: Copy, R: RulesTrait> Drawing<CW, R> {
|
||||||
|
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))]
|
||||||
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
#[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
|
||||||
pub fn rtree(&self) -> &RTree<BboxedIndex<NodeWeight<PrimitiveIndex, GenericIndex<CW>>>> {
|
pub fn rtree(&self) -> &RTree<BboxedIndex<Node<PrimitiveIndex, GenericIndex<CW>>>> {
|
||||||
self.geometry_with_rtree.rtree()
|
self.geometry_with_rtree.rtree()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ macro_rules! impl_loose_weight {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch(GetNodeIndex, MakePrimitive)]
|
#[enum_dispatch(GetNodeIndex, MakePrimitive)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum PrimitiveIndex {
|
pub enum PrimitiveIndex {
|
||||||
FixedDot(FixedDotIndex),
|
FixedDot(FixedDotIndex),
|
||||||
LooseDot(LooseDotIndex),
|
LooseDot(LooseDotIndex),
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
Drawing,
|
Drawing,
|
||||||
},
|
},
|
||||||
geometry::NodeWeight,
|
geometry::Node,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
|
|
@ -186,7 +186,7 @@ impl<'a, W, CW: Copy, R: RulesTrait> GenericPrimitive<'a, W, CW, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tagged_weight(&self) -> PrimitiveWeight {
|
fn tagged_weight(&self) -> PrimitiveWeight {
|
||||||
if let NodeWeight::Primitive(weight) = *self
|
if let Node::Primitive(weight) = *self
|
||||||
.drawing
|
.drawing
|
||||||
.geometry()
|
.geometry()
|
||||||
.graph()
|
.graph()
|
||||||
|
|
@ -262,15 +262,9 @@ impl<'a, CW: Copy, R: RulesTrait> FixedDot<'a, CW, R> {
|
||||||
.graph()
|
.graph()
|
||||||
.node_weight(ni.node_index())
|
.node_weight(ni.node_index())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if matches!(
|
if matches!(weight, Node::Primitive(PrimitiveWeight::LoneLooseSeg(..))) {
|
||||||
weight,
|
|
||||||
NodeWeight::Primitive(PrimitiveWeight::LoneLooseSeg(..))
|
|
||||||
) {
|
|
||||||
Some(LoneLooseSegIndex::new(ni.node_index()).into())
|
Some(LoneLooseSegIndex::new(ni.node_index()).into())
|
||||||
} else if matches!(
|
} else if matches!(weight, Node::Primitive(PrimitiveWeight::SeqLooseSeg(..))) {
|
||||||
weight,
|
|
||||||
NodeWeight::Primitive(PrimitiveWeight::SeqLooseSeg(..))
|
|
||||||
) {
|
|
||||||
Some(SeqLooseSegIndex::new(ni.node_index()).into())
|
Some(SeqLooseSegIndex::new(ni.node_index()).into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,10 @@ pub enum GeometryLabel {
|
||||||
Compound,
|
Compound,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum NodeWeight<PW, CW> {
|
pub enum Node<P, C> {
|
||||||
Primitive(PW),
|
Primitive(P),
|
||||||
Compound(CW),
|
Compound(C),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DotWeightTrait<CW>: GetPos + SetPos + GetWidth + Into<CW> + Copy {}
|
pub trait DotWeightTrait<CW>: GetPos + SetPos + GetWidth + Into<CW> + Copy {}
|
||||||
|
|
@ -80,7 +80,7 @@ pub struct Geometry<
|
||||||
SI: GetNodeIndex + Into<PI> + Copy,
|
SI: GetNodeIndex + Into<PI> + Copy,
|
||||||
BI: GetNodeIndex + Into<PI> + Copy,
|
BI: GetNodeIndex + Into<PI> + Copy,
|
||||||
> {
|
> {
|
||||||
graph: StableDiGraph<NodeWeight<PW, CW>, GeometryLabel, usize>,
|
graph: StableDiGraph<Node<PW, CW>, GeometryLabel, usize>,
|
||||||
weight_marker: PhantomData<PW>,
|
weight_marker: PhantomData<PW>,
|
||||||
dot_weight_marker: PhantomData<DW>,
|
dot_weight_marker: PhantomData<DW>,
|
||||||
seg_weight_marker: PhantomData<SW>,
|
seg_weight_marker: PhantomData<SW>,
|
||||||
|
|
@ -120,7 +120,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_dot<W: DotWeightTrait<PW>>(&mut self, weight: W) -> GenericIndex<W> {
|
pub fn add_dot<W: DotWeightTrait<PW>>(&mut self, weight: W) -> GenericIndex<W> {
|
||||||
GenericIndex::<W>::new(self.graph.add_node(NodeWeight::Primitive(weight.into())))
|
GenericIndex::<W>::new(self.graph.add_node(Node::Primitive(weight.into())))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_seg<W: SegWeightTrait<PW>>(
|
pub fn add_seg<W: SegWeightTrait<PW>>(
|
||||||
|
|
@ -129,7 +129,7 @@ impl<
|
||||||
to: DI,
|
to: DI,
|
||||||
weight: W,
|
weight: W,
|
||||||
) -> GenericIndex<W> {
|
) -> GenericIndex<W> {
|
||||||
let seg = GenericIndex::<W>::new(self.graph.add_node(NodeWeight::Primitive(weight.into())));
|
let seg = GenericIndex::<W>::new(self.graph.add_node(Node::Primitive(weight.into())));
|
||||||
|
|
||||||
self.graph
|
self.graph
|
||||||
.update_edge(from.node_index(), seg.node_index(), GeometryLabel::Joined);
|
.update_edge(from.node_index(), seg.node_index(), GeometryLabel::Joined);
|
||||||
|
|
@ -146,8 +146,7 @@ impl<
|
||||||
core: DI,
|
core: DI,
|
||||||
weight: W,
|
weight: W,
|
||||||
) -> GenericIndex<W> {
|
) -> GenericIndex<W> {
|
||||||
let bend =
|
let bend = GenericIndex::<W>::new(self.graph.add_node(Node::Primitive(weight.into())));
|
||||||
GenericIndex::<W>::new(self.graph.add_node(NodeWeight::Primitive(weight.into())));
|
|
||||||
|
|
||||||
self.graph
|
self.graph
|
||||||
.update_edge(from.node_index(), bend.node_index(), GeometryLabel::Joined);
|
.update_edge(from.node_index(), bend.node_index(), GeometryLabel::Joined);
|
||||||
|
|
@ -166,15 +165,13 @@ impl<
|
||||||
pub fn move_dot(&mut self, dot: DI, to: Point) {
|
pub fn move_dot(&mut self, dot: DI, to: Point) {
|
||||||
let mut weight = self.dot_weight(dot);
|
let mut weight = self.dot_weight(dot);
|
||||||
weight.set_pos(to);
|
weight.set_pos(to);
|
||||||
*self.graph.node_weight_mut(dot.node_index()).unwrap() =
|
*self.graph.node_weight_mut(dot.node_index()).unwrap() = Node::Primitive(weight.into());
|
||||||
NodeWeight::Primitive(weight.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shift_bend(&mut self, bend: BI, offset: f64) {
|
pub fn shift_bend(&mut self, bend: BI, offset: f64) {
|
||||||
let mut weight = self.bend_weight(bend);
|
let mut weight = self.bend_weight(bend);
|
||||||
weight.set_offset(offset);
|
weight.set_offset(offset);
|
||||||
*self.graph.node_weight_mut(bend.node_index()).unwrap() =
|
*self.graph.node_weight_mut(bend.node_index()).unwrap() = Node::Primitive(weight.into());
|
||||||
NodeWeight::Primitive(weight.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flip_bend(&mut self, bend: BI) {
|
pub fn flip_bend(&mut self, bend: BI) {
|
||||||
|
|
@ -270,7 +267,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primitive_weight(&self, index: NodeIndex<usize>) -> PW {
|
fn primitive_weight(&self, index: NodeIndex<usize>) -> PW {
|
||||||
if let NodeWeight::Primitive(weight) = *self.graph.node_weight(index).unwrap() {
|
if let Node::Primitive(weight) = *self.graph.node_weight(index).unwrap() {
|
||||||
weight
|
weight
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
@ -296,9 +293,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
|
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
|
||||||
if let NodeWeight::Compound(weight) =
|
if let Node::Compound(weight) = *self.graph.node_weight(compound.node_index()).unwrap() {
|
||||||
*self.graph.node_weight(compound.node_index()).unwrap()
|
|
||||||
{
|
|
||||||
weight
|
weight
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
@ -473,7 +468,7 @@ impl<
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn graph(&self) -> &StableDiGraph<NodeWeight<PW, CW>, GeometryLabel, usize> {
|
pub fn graph(&self) -> &StableDiGraph<Node<PW, CW>, GeometryLabel, usize> {
|
||||||
&self.graph
|
&self.graph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -491,7 +486,7 @@ impl<
|
||||||
> CompoundManagerTrait<CW, GenericIndex<CW>> for Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
> CompoundManagerTrait<CW, GenericIndex<CW>> for Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
||||||
{
|
{
|
||||||
fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> {
|
fn add_compound(&mut self, weight: CW) -> GenericIndex<CW> {
|
||||||
GenericIndex::<CW>::new(self.graph.add_node(NodeWeight::Compound(weight)))
|
GenericIndex::<CW>::new(self.graph.add_node(Node::Compound(weight)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_compound(&mut self, compound: GenericIndex<CW>) {
|
fn remove_compound(&mut self, compound: GenericIndex<CW>) {
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ use crate::{
|
||||||
geometry::{
|
geometry::{
|
||||||
compound::CompoundManagerTrait,
|
compound::CompoundManagerTrait,
|
||||||
primitive::{PrimitiveShape, PrimitiveShapeTrait},
|
primitive::{PrimitiveShape, PrimitiveShapeTrait},
|
||||||
BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel, GetWidth, NodeWeight,
|
BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel, GetWidth, Node, SegWeightTrait,
|
||||||
SegWeightTrait,
|
|
||||||
},
|
},
|
||||||
graph::{GenericIndex, GetNodeIndex},
|
graph::{GenericIndex, GetNodeIndex},
|
||||||
};
|
};
|
||||||
|
|
@ -49,7 +48,7 @@ pub struct GeometryWithRtree<
|
||||||
BI: GetNodeIndex + Into<PI> + Copy,
|
BI: GetNodeIndex + Into<PI> + Copy,
|
||||||
> {
|
> {
|
||||||
geometry: Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
geometry: Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||||
rtree: RTree<BboxedIndex<NodeWeight<PI, GenericIndex<CW>>>>,
|
rtree: RTree<BboxedIndex<Node<PI, GenericIndex<CW>>>>,
|
||||||
layer_count: u64,
|
layer_count: u64,
|
||||||
weight_marker: PhantomData<PW>,
|
weight_marker: PhantomData<PW>,
|
||||||
dot_weight_marker: PhantomData<DW>,
|
dot_weight_marker: PhantomData<DW>,
|
||||||
|
|
@ -102,7 +101,7 @@ impl<
|
||||||
.dot_shape(dot.into().try_into().unwrap_or_else(|_| unreachable!()))
|
.dot_shape(dot.into().try_into().unwrap_or_else(|_| unreachable!()))
|
||||||
.envelope_3d(0.0, weight.layer()),
|
.envelope_3d(0.0, weight.layer()),
|
||||||
),
|
),
|
||||||
NodeWeight::Primitive(dot.into()),
|
Node::Primitive(dot.into()),
|
||||||
));
|
));
|
||||||
dot
|
dot
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +122,7 @@ impl<
|
||||||
.seg_shape(seg.into().try_into().unwrap_or_else(|_| unreachable!()))
|
.seg_shape(seg.into().try_into().unwrap_or_else(|_| unreachable!()))
|
||||||
.envelope_3d(0.0, weight.layer()),
|
.envelope_3d(0.0, weight.layer()),
|
||||||
),
|
),
|
||||||
NodeWeight::Primitive(seg.into()),
|
Node::Primitive(seg.into()),
|
||||||
));
|
));
|
||||||
seg
|
seg
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +144,7 @@ impl<
|
||||||
.bend_shape(bend.into().try_into().unwrap_or_else(|_| unreachable!()))
|
.bend_shape(bend.into().try_into().unwrap_or_else(|_| unreachable!()))
|
||||||
.envelope_3d(0.0, weight.layer()),
|
.envelope_3d(0.0, weight.layer()),
|
||||||
),
|
),
|
||||||
NodeWeight::Primitive(bend.into()),
|
Node::Primitive(bend.into()),
|
||||||
));
|
));
|
||||||
bend
|
bend
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +264,7 @@ impl<
|
||||||
BI: GetNodeIndex + Into<PI> + Copy,
|
BI: GetNodeIndex + Into<PI> + Copy,
|
||||||
> GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
> GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
||||||
{
|
{
|
||||||
fn make_bbox(&self, primitive: PI) -> BboxedIndex<NodeWeight<PI, GenericIndex<CW>>> {
|
fn make_bbox(&self, primitive: PI) -> BboxedIndex<Node<PI, GenericIndex<CW>>> {
|
||||||
if let Ok(dot) = <PI as TryInto<DI>>::try_into(primitive) {
|
if let Ok(dot) = <PI as TryInto<DI>>::try_into(primitive) {
|
||||||
self.make_dot_bbox(dot)
|
self.make_dot_bbox(dot)
|
||||||
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(primitive) {
|
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(primitive) {
|
||||||
|
|
@ -277,50 +276,50 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dot_bbox(&self, dot: DI) -> BboxedIndex<NodeWeight<PI, GenericIndex<CW>>> {
|
fn make_dot_bbox(&self, dot: DI) -> BboxedIndex<Node<PI, GenericIndex<CW>>> {
|
||||||
BboxedIndex::new(
|
BboxedIndex::new(
|
||||||
Bbox::new(
|
Bbox::new(
|
||||||
self.geometry
|
self.geometry
|
||||||
.dot_shape(dot)
|
.dot_shape(dot)
|
||||||
.envelope_3d(0.0, self.layer(dot.into())),
|
.envelope_3d(0.0, self.layer(dot.into())),
|
||||||
),
|
),
|
||||||
NodeWeight::Primitive(dot.into()),
|
Node::Primitive(dot.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_seg_bbox(&self, seg: SI) -> BboxedIndex<NodeWeight<PI, GenericIndex<CW>>> {
|
fn make_seg_bbox(&self, seg: SI) -> BboxedIndex<Node<PI, GenericIndex<CW>>> {
|
||||||
BboxedIndex::new(
|
BboxedIndex::new(
|
||||||
Bbox::new(
|
Bbox::new(
|
||||||
self.geometry
|
self.geometry
|
||||||
.seg_shape(seg)
|
.seg_shape(seg)
|
||||||
.envelope_3d(0.0, self.layer(seg.into())),
|
.envelope_3d(0.0, self.layer(seg.into())),
|
||||||
),
|
),
|
||||||
NodeWeight::Primitive(seg.into()),
|
Node::Primitive(seg.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_bend_bbox(&self, bend: BI) -> BboxedIndex<NodeWeight<PI, GenericIndex<CW>>> {
|
fn make_bend_bbox(&self, bend: BI) -> BboxedIndex<Node<PI, GenericIndex<CW>>> {
|
||||||
BboxedIndex::new(
|
BboxedIndex::new(
|
||||||
Bbox::new(
|
Bbox::new(
|
||||||
self.geometry
|
self.geometry
|
||||||
.bend_shape(bend)
|
.bend_shape(bend)
|
||||||
.envelope_3d(0.0, self.layer(bend.into())),
|
.envelope_3d(0.0, self.layer(bend.into())),
|
||||||
),
|
),
|
||||||
NodeWeight::Primitive(bend.into()),
|
Node::Primitive(bend.into()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_compound_bbox(
|
fn make_compound_bbox(
|
||||||
&self,
|
&self,
|
||||||
compound: GenericIndex<CW>,
|
compound: GenericIndex<CW>,
|
||||||
) -> BboxedIndex<NodeWeight<PI, GenericIndex<CW>>> {
|
) -> BboxedIndex<Node<PI, GenericIndex<CW>>> {
|
||||||
let mut aabb = AABB::<[f64; 3]>::new_empty();
|
let mut aabb = AABB::<[f64; 3]>::new_empty();
|
||||||
|
|
||||||
for member in self.geometry.compound_members(compound) {
|
for member in self.geometry.compound_members(compound) {
|
||||||
aabb.merge(&self.make_bbox(member).geom().aabb);
|
aabb.merge(&self.make_bbox(member).geom().aabb);
|
||||||
}
|
}
|
||||||
|
|
||||||
BboxedIndex::new(Bbox::new(aabb), NodeWeight::Compound(compound))
|
BboxedIndex::new(Bbox::new(aabb), Node::Compound(compound))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shape(&self, primitive: PI) -> PrimitiveShape {
|
fn shape(&self, primitive: PI) -> PrimitiveShape {
|
||||||
|
|
@ -352,25 +351,25 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: The type appears wrong? I don't think it should contain CW?
|
// XXX: The type appears wrong? I don't think it should contain CW?
|
||||||
pub fn rtree(&self) -> &RTree<BboxedIndex<NodeWeight<PI, GenericIndex<CW>>>> {
|
pub fn rtree(&self) -> &RTree<BboxedIndex<Node<PI, GenericIndex<CW>>>> {
|
||||||
&self.rtree
|
&self.rtree
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn graph(&self) -> &StableDiGraph<NodeWeight<PW, CW>, GeometryLabel, usize> {
|
pub fn graph(&self) -> &StableDiGraph<Node<PW, CW>, GeometryLabel, usize> {
|
||||||
self.geometry.graph()
|
self.geometry.graph()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_envelopes(&self) -> bool {
|
fn test_envelopes(&self) -> bool {
|
||||||
!self.rtree.iter().any(|wrapper| {
|
!self.rtree.iter().any(|wrapper| {
|
||||||
// TODO: Test envelopes of compounds too.
|
// TODO: Test envelopes of compounds too.
|
||||||
let NodeWeight::Primitive(primitive_node) = wrapper.data else {
|
let Node::Primitive(primitive_node) = wrapper.data else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let shape = self.shape(primitive_node);
|
let shape = self.shape(primitive_node);
|
||||||
let layer = self.layer(primitive_node);
|
let layer = self.layer(primitive_node);
|
||||||
let wrapper = BboxedIndex::new(
|
let wrapper = BboxedIndex::new(
|
||||||
Bbox::new(shape.envelope_3d(0.0, layer)),
|
Bbox::new(shape.envelope_3d(0.0, layer)),
|
||||||
NodeWeight::Primitive(primitive_node),
|
Node::Primitive(primitive_node),
|
||||||
);
|
);
|
||||||
!self
|
!self
|
||||||
.rtree
|
.rtree
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
geometry::{
|
geometry::{
|
||||||
compound::CompoundManagerTrait, BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel,
|
compound::CompoundManagerTrait, BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel,
|
||||||
GetWidth, NodeWeight, SegWeightTrait,
|
GetWidth, Node, SegWeightTrait,
|
||||||
},
|
},
|
||||||
graph::{GenericIndex, GetNodeIndex},
|
graph::{GenericIndex, GetNodeIndex},
|
||||||
layout::{
|
layout::{
|
||||||
|
|
@ -170,7 +170,7 @@ impl<R: RulesTrait> Layout<R> {
|
||||||
|
|
||||||
pub fn zones(&self) -> impl Iterator<Item = ZoneIndex> + '_ {
|
pub fn zones(&self) -> impl Iterator<Item = ZoneIndex> + '_ {
|
||||||
self.drawing.rtree().iter().filter_map(|wrapper| {
|
self.drawing.rtree().iter().filter_map(|wrapper| {
|
||||||
if let NodeWeight::Compound(zone) = wrapper.data {
|
if let Node::Compound(zone) = wrapper.data {
|
||||||
Some(match self.drawing.geometry().compound_weight(zone) {
|
Some(match self.drawing.geometry().compound_weight(zone) {
|
||||||
ZoneWeight::Solid(..) => {
|
ZoneWeight::Solid(..) => {
|
||||||
ZoneIndex::Solid(SolidZoneIndex::new(zone.node_index()))
|
ZoneIndex::Solid(SolidZoneIndex::new(zone.node_index()))
|
||||||
|
|
@ -191,7 +191,7 @@ impl<R: RulesTrait> Layout<R> {
|
||||||
[f64::INFINITY, f64::INFINITY, layer as f64],
|
[f64::INFINITY, f64::INFINITY, layer as f64],
|
||||||
))
|
))
|
||||||
.filter_map(|wrapper| {
|
.filter_map(|wrapper| {
|
||||||
if let NodeWeight::Compound(zone) = wrapper.data {
|
if let Node::Compound(zone) = wrapper.data {
|
||||||
Some(match self.drawing.geometry().compound_weight(zone) {
|
Some(match self.drawing.geometry().compound_weight(zone) {
|
||||||
ZoneWeight::Solid(..) => {
|
ZoneWeight::Solid(..) => {
|
||||||
ZoneIndex::Solid(SolidZoneIndex::new(zone.node_index()))
|
ZoneIndex::Solid(SolidZoneIndex::new(zone.node_index()))
|
||||||
|
|
@ -212,7 +212,7 @@ impl<R: RulesTrait> Layout<R> {
|
||||||
.compound_members(GenericIndex::new(zone.node_index()))
|
.compound_members(GenericIndex::new(zone.node_index()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawing(&self) -> &Drawing<impl Copy, R> {
|
pub fn drawing(&self) -> &Drawing<ZoneWeight, R> {
|
||||||
&self.drawing
|
&self.drawing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,5 @@ pub mod dsn;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
|
pub mod overlay;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
mod overlay;
|
||||||
|
|
||||||
|
pub use overlay::*;
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use geo::Point;
|
||||||
|
use rstar::AABB;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
drawing::{graph::PrimitiveIndex, rules::RulesTrait},
|
||||||
|
geometry::Node,
|
||||||
|
graph::GenericIndex,
|
||||||
|
layout::{zone::ZoneWeight, Layout},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Overlay {
|
||||||
|
selection: HashSet<Node<PrimitiveIndex, GenericIndex<ZoneWeight>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Overlay {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
selection: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn click<R: RulesTrait>(&mut self, layout: &Layout<R>, at: Point) {
|
||||||
|
for geom in layout.drawing().rtree().locate_in_envelope_intersecting(
|
||||||
|
&AABB::<[f64; 3]>::from_corners(
|
||||||
|
[at.x(), at.y(), -f64::INFINITY],
|
||||||
|
[at.x(), at.y(), f64::INFINITY],
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
self.toggle_selection(geom.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_selection(&mut self, node: Node<PrimitiveIndex, GenericIndex<ZoneWeight>>) {
|
||||||
|
if !self.selection.insert(node) {
|
||||||
|
self.selection.remove(&node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn selection(&self) -> &HashSet<Node<PrimitiveIndex, GenericIndex<ZoneWeight>>> {
|
||||||
|
&self.selection
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue