fix(topola-egui): Fix click-based selection of pins

- Do intersection calculation between DotShape and Rect=AABB properly
This commit is contained in:
Ellen Emilia Anna Zscheile 2025-05-15 19:42:23 +02:00 committed by mikolaj
parent 464e8abb89
commit 8d0681c07d
3 changed files with 34 additions and 33 deletions

View File

@ -12,7 +12,6 @@ use topola::{
selection::{BboxSelectionKind, Selection},
},
board::{AccessMesadata, Board},
geometry::shape::AccessShape,
layout::NodeIndex,
router::planar_incr_embed,
};
@ -191,29 +190,14 @@ impl Overlay {
return;
}
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| {
board.layout().node_shape(geom.data).contains_point(at)
// TODO: fix which layers to query
&& board
.layout()
.drawing()
// This should use:
// `.is_node_in_any_layer_of(geom.data, &appearance_panel.visible[..])`
// instead, but that doesn't work reliably
.is_node_in_layer(geom.data, 0)
}) {
self.selection.toggle_at_node(board, geom.data);
}
let old_selection = self.take_selection();
self.select_all_in_bbox(
board,
appearance_panel,
&AABB::from_point([at.x(), at.y()]),
BboxSelectionKind::MerelyIntersects,
);
self.selection ^= &old_selection;
}
pub fn select_all_in_bbox(

View File

@ -5,10 +5,7 @@
use geo::Line;
use crate::{
geometry::{
primitive::{AccessPrimitiveShape, PrimitiveShape},
shape::AccessShape,
},
geometry::{primitive::PrimitiveShape, shape::AccessShape, GetWidth},
math::{self, Circle, NoTangents, RotationSense},
};

View File

@ -6,20 +6,22 @@ use std::f64::consts::TAU;
use enum_dispatch::enum_dispatch;
use geo::algorithm::line_measures::{Distance, Euclidean};
use geo::{point, polygon, Contains, Intersects, Line, Point, Polygon, Rotate};
use geo::{point, polygon, Contains, Intersects, Line, Point, Polygon, Rect, Rotate};
use rstar::{RTreeObject, AABB};
use crate::{
geometry::shape::{AccessShape, MeasureLength},
geometry::{
shape::{AccessShape, MeasureLength},
GetWidth,
},
math::{self, Circle},
};
#[enum_dispatch]
pub trait AccessPrimitiveShape: AccessShape {
pub trait AccessPrimitiveShape: AccessShape + GetWidth {
fn priority(&self) -> usize;
fn inflate(&self, margin: f64) -> PrimitiveShape;
fn intersects(&self, other: &PrimitiveShape) -> bool;
fn width(&self) -> f64;
fn envelope_3d(&self, margin: f64, layer: usize) -> AABB<[f64; 3]> {
let envelope = self.bbox(margin);
@ -42,7 +44,7 @@ pub trait AccessPrimitiveShape: AccessShape {
}
}
#[enum_dispatch(MeasureLength, AccessShape, AccessPrimitiveShape)]
#[enum_dispatch(AccessShape, AccessPrimitiveShape, GetWidth, MeasureLength)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PrimitiveShape {
// Intentionally in different order to reorder `self.intersects(...)` properly.
@ -74,6 +76,11 @@ impl AccessShape for DotShape {
fn bbox_without_margin(&self) -> AABB<[f64; 2]> {
self.circle.bbox(0.0)
}
fn intersects_with_bbox(&self, bbox: &AABB<[f64; 2]>) -> bool {
let bbox = Rect::new(bbox.lower(), bbox.upper());
Euclidean::distance(&self.circle.pos, &bbox.to_polygon()) < self.circle.r
}
}
impl AccessPrimitiveShape for DotShape {
@ -120,7 +127,9 @@ impl AccessPrimitiveShape for DotShape {
}
}
}
}
impl GetWidth for DotShape {
fn width(&self) -> f64 {
self.circle.r * 2.0
}
@ -157,6 +166,13 @@ impl SegShape {
}
}
impl From<SegShape> for Polygon {
#[inline(always)]
fn from(x: SegShape) -> Polygon {
x.polygon()
}
}
impl MeasureLength for SegShape {
fn length(&self) -> f64 {
Euclidean::distance(&self.to, &self.from)
@ -227,7 +243,9 @@ impl AccessPrimitiveShape for SegShape {
}
}
}
}
impl GetWidth for SegShape {
fn width(&self) -> f64 {
self.width
}
@ -382,7 +400,9 @@ impl AccessPrimitiveShape for BendShape {
}
}
}
}
impl GetWidth for BendShape {
fn width(&self) -> f64 {
self.width
}