fix(BboxSelection): make intersection calculations against Polygons more accurate

This commit is contained in:
Alain Emilia Anna Zscheile 2025-01-05 13:12:24 +01:00 committed by mikolaj
parent c7d50fd79f
commit 59154c380f
4 changed files with 29 additions and 7 deletions

View File

@ -10,7 +10,10 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
board::{mesadata::AccessMesadata, BandName, Board, ResolvedSelector}, board::{mesadata::AccessMesadata, BandName, Board, ResolvedSelector},
drawing::graph::{GetLayer, MakePrimitive, PrimitiveIndex}, drawing::graph::{GetLayer, MakePrimitive, PrimitiveIndex},
geometry::{shape::AccessShape, GenericNode}, geometry::{
shape::{AccessShape, Shape},
GenericNode,
},
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
layout::{poly::PolyWeight, CompoundWeight, NodeIndex}, layout::{poly::PolyWeight, CompoundWeight, NodeIndex},
}; };
@ -161,11 +164,11 @@ pub enum BboxSelectionKind {
} }
impl BboxSelectionKind { impl BboxSelectionKind {
pub fn matches(&self, bigger: &AABB<[f64; 2]>, smaller: &AABB<[f64; 2]>) -> bool { pub fn matches(&self, bigger: &AABB<[f64; 2]>, smaller: &Shape) -> bool {
use rstar::Envelope; use rstar::Envelope;
match self { match self {
Self::CompletelyInside => bigger.contains_envelope(&smaller), Self::CompletelyInside => bigger.contains_envelope(&smaller.bbox_without_margin()),
Self::MerelyIntersects => bigger.intersection_area(&smaller) > 0.0, Self::MerelyIntersects => smaller.intersects_with_bbox(bigger),
} }
} }
} }
@ -209,7 +212,7 @@ impl Selection {
if let Some(rsel) = ResolvedSelector::try_from_node(board, node) { if let Some(rsel) = ResolvedSelector::try_from_node(board, node) {
let rseli = selectors.entry(rsel).or_default(); let rseli = selectors.entry(rsel).or_default();
rseli.0.insert(node); rseli.0.insert(node);
if kind.matches(aabb, &layout.node_shape(node).bbox(0.0)) { if kind.matches(aabb, &layout.node_shape(node)) {
rseli.1.insert(node); rseli.1.insert(node);
} }
} }
@ -234,7 +237,7 @@ impl Selection {
) { ) {
let node = geom.data; let node = geom.data;
if layout.is_node_in_layer(node, active_layer) if layout.is_node_in_layer(node, active_layer)
&& kind.matches(aabb, &layout.node_shape(node).bbox(0.0)) && kind.matches(aabb, &layout.node_shape(node))
{ {
if let Some(rsel) = ResolvedSelector::try_from_node(board, node) { if let Some(rsel) = ResolvedSelector::try_from_node(board, node) {
selectors.insert(rsel); selectors.insert(rsel);

View File

@ -2,7 +2,10 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use geo::algorithm::line_measures::{Euclidean, Length}; use geo::algorithm::{
line_measures::{Euclidean, Length},
Intersects,
};
use geo::{Centroid, Contains, Point, Polygon}; use geo::{Centroid, Contains, Point, Polygon};
use rstar::AABB; use rstar::AABB;
@ -39,4 +42,8 @@ impl AccessShape for Polygon {
.iter(), .iter(),
) )
} }
fn intersects_with_bbox(&self, bbox: &AABB<[f64; 2]>) -> bool {
geo::Rect::new(bbox.lower(), bbox.upper()).intersects(self)
}
} }

View File

@ -161,13 +161,20 @@ impl AccessShape for SegShape {
(self.from + self.to) / 2.0 (self.from + self.to) / 2.0
} }
#[inline]
fn contains_point(&self, p: Point) -> bool { fn contains_point(&self, p: Point) -> bool {
self.polygon().contains(&p) self.polygon().contains(&p)
} }
#[inline]
fn bbox_without_margin(&self) -> AABB<[f64; 2]> { fn bbox_without_margin(&self) -> AABB<[f64; 2]> {
self.polygon().bbox_without_margin() self.polygon().bbox_without_margin()
} }
#[inline]
fn intersects_with_bbox(&self, bbox: &AABB<[f64; 2]>) -> bool {
self.polygon().intersects_with_bbox(bbox)
}
} }
impl AccessPrimitiveShape for SegShape { impl AccessPrimitiveShape for SegShape {

View File

@ -26,6 +26,11 @@ pub trait AccessShape: MeasureLength {
[aabb.upper()[0] + margin, aabb.upper()[1] + margin], [aabb.upper()[0] + margin, aabb.upper()[1] + margin],
) )
} }
fn intersects_with_bbox(&self, bbox: &AABB<[f64; 2]>) -> bool {
use rstar::Envelope;
bbox.intersection_area(&self.bbox_without_margin()) > 0.0
}
} }
#[enum_dispatch(MeasureLength, AccessShape)] #[enum_dispatch(MeasureLength, AccessShape)]