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::{
board::{mesadata::AccessMesadata, BandName, Board, ResolvedSelector},
drawing::graph::{GetLayer, MakePrimitive, PrimitiveIndex},
geometry::{shape::AccessShape, GenericNode},
geometry::{
shape::{AccessShape, Shape},
GenericNode,
},
graph::{GenericIndex, GetPetgraphIndex},
layout::{poly::PolyWeight, CompoundWeight, NodeIndex},
};
@ -161,11 +164,11 @@ pub enum 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;
match self {
Self::CompletelyInside => bigger.contains_envelope(&smaller),
Self::MerelyIntersects => bigger.intersection_area(&smaller) > 0.0,
Self::CompletelyInside => bigger.contains_envelope(&smaller.bbox_without_margin()),
Self::MerelyIntersects => smaller.intersects_with_bbox(bigger),
}
}
}
@ -209,7 +212,7 @@ impl Selection {
if let Some(rsel) = ResolvedSelector::try_from_node(board, node) {
let rseli = selectors.entry(rsel).or_default();
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);
}
}
@ -234,7 +237,7 @@ impl Selection {
) {
let node = geom.data;
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) {
selectors.insert(rsel);

View File

@ -2,7 +2,10 @@
//
// 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 rstar::AABB;
@ -39,4 +42,8 @@ impl AccessShape for Polygon {
.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
}
#[inline]
fn contains_point(&self, p: Point) -> bool {
self.polygon().contains(&p)
}
#[inline]
fn bbox_without_margin(&self) -> AABB<[f64; 2]> {
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 {

View File

@ -26,6 +26,11 @@ pub trait AccessShape: MeasureLength {
[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)]