topola/src/bin/topola-egui/overlay.rs

117 lines
3.4 KiB
Rust

use std::collections::HashSet;
use geo::Point;
use rstar::AABB;
use spade::InsertionError;
use topola::{
autorouter::{ratsnest::Ratsnest, selection::Selection},
board::{mesadata::MesadataTrait, Board},
drawing::{
graph::{GetLayer, MakePrimitive},
primitive::MakePrimitiveShape,
},
geometry::{
compound::CompoundManagerTrait,
shape::{Shape, ShapeTrait},
},
graph::{GenericIndex, GetNodeIndex},
layout::{
via::ViaWeight,
zone::{MakePolyShape, Zone, ZoneWeight},
CompoundWeight, Layout, NodeIndex,
},
};
pub struct Overlay {
ratsnest: Ratsnest,
selection: Selection,
active_layer: usize,
}
impl Overlay {
pub fn new(board: &Board<impl MesadataTrait>) -> Result<Self, InsertionError> {
Ok(Self {
ratsnest: Ratsnest::new(board.layout())?,
selection: Selection::new(),
active_layer: 0,
})
}
pub fn click(&mut self, board: &Board<impl MesadataTrait>, at: Point) {
let geoms: Vec<_> = board
.layout()
.drawing()
.rtree()
.locate_in_envelope_intersecting(&AABB::<[f64; 3]>::from_corners(
[at.x(), at.y(), -f64::INFINITY],
[at.x(), at.y(), f64::INFINITY],
))
.collect();
if let Some(geom) = geoms.iter().find(|&&geom| match geom.data {
NodeIndex::Primitive(primitive) => {
primitive.primitive(board.layout().drawing()).layer() == self.active_layer
}
NodeIndex::Compound(compound) => false,
}) {
if self.toggle_selection_if_contains_point(board, geom.data, at) {
return;
}
}
for geom in geoms {
if self.toggle_selection_if_contains_point(board, geom.data, at) {
return;
}
}
}
fn toggle_selection_if_contains_point(
&mut self,
board: &Board<impl MesadataTrait>,
node: NodeIndex,
p: Point,
) -> bool {
let shape: Shape = match node {
NodeIndex::Primitive(primitive) => {
primitive.primitive(board.layout().drawing()).shape().into()
}
NodeIndex::Compound(compound) => {
match board.layout().drawing().compound_weight(compound) {
/*CompoundWeight::Zone(zone) => Zone::new(
GenericIndex::<ZoneWeight>::new(compound.node_index()),
board.layout(),
)
.shape()
.into(),*/
CompoundWeight::Zone(weight) => board
.layout()
.zone(GenericIndex::<ZoneWeight>::new(compound.node_index()))
.shape()
.into(),
CompoundWeight::Via(weight) => board
.layout()
.via(GenericIndex::<ViaWeight>::new(compound.node_index()))
.shape()
.into(),
}
}
};
if shape.contains_point(p) {
self.selection.toggle_at_node(board, node);
return true;
}
false
}
pub fn ratsnest(&self) -> &Ratsnest {
&self.ratsnest
}
pub fn selection(&self) -> &Selection {
&self.selection
}
}