From 59154c380f45e863361caa2e857c9e2749e1cf45 Mon Sep 17 00:00:00 2001 From: Alain Emilia Anna Zscheile Date: Sun, 5 Jan 2025 13:12:24 +0100 Subject: [PATCH] fix(BboxSelection): make intersection calculations against Polygons more accurate --- src/autorouter/selection.rs | 15 +++++++++------ src/geometry/poly.rs | 9 ++++++++- src/geometry/primitive.rs | 7 +++++++ src/geometry/shape.rs | 5 +++++ 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/autorouter/selection.rs b/src/autorouter/selection.rs index 2397fc4..f8a9acf 100644 --- a/src/autorouter/selection.rs +++ b/src/autorouter/selection.rs @@ -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); diff --git a/src/geometry/poly.rs b/src/geometry/poly.rs index 85833b7..bfe157b 100644 --- a/src/geometry/poly.rs +++ b/src/geometry/poly.rs @@ -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) + } } diff --git a/src/geometry/primitive.rs b/src/geometry/primitive.rs index f7ec432..59082bb 100644 --- a/src/geometry/primitive.rs +++ b/src/geometry/primitive.rs @@ -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 { diff --git a/src/geometry/shape.rs b/src/geometry/shape.rs index 7979d55..4f4a28f 100644 --- a/src/geometry/shape.rs +++ b/src/geometry/shape.rs @@ -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)]