Skip to content

Commit a238171

Browse files
bretttullyclaude
andcommitted
gh-50 Add public geometry methods to PredicateOverlay
Add add_path_iter, add_contour, add_contours, add_shape, and add_shapes methods to match Overlay's public API. This enables external crates to use PredicateOverlay directly without accessing internal fields. Refactored FloatPredicateOverlay to use the new public methods. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6bdbdc8 commit a238171

2 files changed

Lines changed: 141 additions & 6 deletions

File tree

iOverlay/src/core/relate.rs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
use crate::build::sweep::{FillHandler, SweepRunner};
22
use crate::core::fill_rule::FillRule;
3+
use crate::core::overlay::ShapeType;
34
use crate::core::predicate::{InteriorsIntersectHandler, IntersectsHandler, TouchesHandler, WithinHandler};
45
use crate::core::solver::Solver;
56
use crate::segm::boolean::ShapeCountBoolean;
7+
use crate::segm::build::BuildSegments;
68
use crate::segm::segment::Segment;
79
use crate::split::solver::SplitSolver;
810
use alloc::vec::Vec;
11+
use i_float::int::point::IntPoint;
12+
use i_shape::int::shape::{IntContour, IntShape};
913

1014
/// Overlay structure optimized for spatial predicate evaluation.
1115
///
@@ -95,8 +99,143 @@ impl PredicateOverlay {
9599
self.evaluate(WithinHandler::new())
96100
}
97101

102+
/// Adds a path to the overlay using an iterator, allowing for more flexible path input.
103+
/// This function is particularly useful when working with dynamically generated paths or
104+
/// when paths are not directly stored in a collection.
105+
/// - `iter`: An iterator over references to `IntPoint` that defines the path.
106+
/// - `shape_type`: Specifies the role of the added path in the overlay operation, either as `Subject` or `Clip`.
107+
#[inline]
108+
pub fn add_path_iter<I: Iterator<Item = IntPoint>>(&mut self, iter: I, shape_type: ShapeType) {
109+
self.segments.append_path_iter(iter, shape_type, false);
110+
}
111+
112+
/// Adds a single path to the overlay as either subject or clip paths.
113+
/// - `contour`: An array of points that form a closed path.
114+
/// - `shape_type`: Specifies the role of the added path in the overlay operation, either as `Subject` or `Clip`.
115+
#[inline]
116+
pub fn add_contour(&mut self, contour: &[IntPoint], shape_type: ShapeType) {
117+
self.segments
118+
.append_path_iter(contour.iter().copied(), shape_type, false);
119+
}
120+
121+
/// Adds multiple paths to the overlay as either subject or clip paths.
122+
/// - `contours`: An array of `IntContour` instances to be added to the overlay.
123+
/// - `shape_type`: Specifies the role of the added paths in the overlay operation, either as `Subject` or `Clip`.
124+
#[inline]
125+
pub fn add_contours(&mut self, contours: &[IntContour], shape_type: ShapeType) {
126+
for contour in contours.iter() {
127+
self.add_contour(contour, shape_type);
128+
}
129+
}
130+
131+
/// Adds a single shape to the overlay as either a subject or clip shape.
132+
/// - `shape`: A reference to a `IntShape` instance to be added.
133+
/// - `shape_type`: Specifies the role of the added shape in the overlay operation, either as `Subject` or `Clip`.
134+
#[inline]
135+
pub fn add_shape(&mut self, shape: &IntShape, shape_type: ShapeType) {
136+
self.add_contours(shape, shape_type);
137+
}
138+
139+
/// Adds multiple shapes to the overlay as either subject or clip shapes.
140+
/// - `shapes`: An array of `IntShape` instances to be added to the overlay.
141+
/// - `shape_type`: Specifies the role of the added shapes in the overlay operation, either as `Subject` or `Clip`.
142+
#[inline]
143+
pub fn add_shapes(&mut self, shapes: &[IntShape], shape_type: ShapeType) {
144+
for shape in shapes.iter() {
145+
self.add_contours(shape, shape_type);
146+
}
147+
}
148+
98149
#[inline]
99150
pub fn clear(&mut self) {
100151
self.segments.clear();
101152
}
102153
}
154+
155+
#[cfg(test)]
156+
mod tests {
157+
use super::*;
158+
use alloc::vec;
159+
160+
fn square(x: i32, y: i32, size: i32) -> Vec<IntPoint> {
161+
vec![
162+
IntPoint::new(x, y),
163+
IntPoint::new(x, y + size),
164+
IntPoint::new(x + size, y + size),
165+
IntPoint::new(x + size, y),
166+
]
167+
}
168+
169+
#[test]
170+
fn test_add_contour_intersects() {
171+
let mut overlay = PredicateOverlay::new(16);
172+
overlay.add_contour(&square(0, 0, 10), ShapeType::Subject);
173+
overlay.add_contour(&square(5, 5, 10), ShapeType::Clip);
174+
assert!(overlay.intersects());
175+
}
176+
177+
#[test]
178+
fn test_add_contour_disjoint() {
179+
let mut overlay = PredicateOverlay::new(16);
180+
overlay.add_contour(&square(0, 0, 10), ShapeType::Subject);
181+
overlay.add_contour(&square(20, 20, 10), ShapeType::Clip);
182+
assert!(!overlay.intersects());
183+
}
184+
185+
#[test]
186+
fn test_add_contour_touches() {
187+
let mut overlay = PredicateOverlay::new(16);
188+
overlay.add_contour(&square(0, 0, 10), ShapeType::Subject);
189+
overlay.add_contour(&square(10, 0, 10), ShapeType::Clip);
190+
assert!(overlay.touches());
191+
192+
overlay.clear();
193+
overlay.add_contour(&square(0, 0, 10), ShapeType::Subject);
194+
overlay.add_contour(&square(10, 0, 10), ShapeType::Clip);
195+
assert!(!overlay.interiors_intersect());
196+
}
197+
198+
#[test]
199+
fn test_add_contour_within() {
200+
let mut overlay = PredicateOverlay::new(16);
201+
overlay.add_contour(&square(5, 5, 10), ShapeType::Subject);
202+
overlay.add_contour(&square(0, 0, 20), ShapeType::Clip);
203+
assert!(overlay.within());
204+
}
205+
206+
#[test]
207+
fn test_add_contours() {
208+
let mut overlay = PredicateOverlay::new(16);
209+
let contours = vec![square(0, 0, 5), square(10, 10, 5)];
210+
overlay.add_contours(&contours, ShapeType::Subject);
211+
overlay.add_contour(&square(2, 2, 3), ShapeType::Clip);
212+
assert!(overlay.intersects());
213+
}
214+
215+
#[test]
216+
fn test_add_shape() {
217+
let mut overlay = PredicateOverlay::new(16);
218+
let shape = vec![square(0, 0, 10)];
219+
overlay.add_shape(&shape, ShapeType::Subject);
220+
overlay.add_contour(&square(5, 5, 10), ShapeType::Clip);
221+
assert!(overlay.intersects());
222+
}
223+
224+
#[test]
225+
fn test_add_shapes() {
226+
let mut overlay = PredicateOverlay::new(16);
227+
let shapes = vec![vec![square(0, 0, 5)], vec![square(20, 20, 5)]];
228+
overlay.add_shapes(&shapes, ShapeType::Subject);
229+
overlay.add_contour(&square(2, 2, 3), ShapeType::Clip);
230+
assert!(overlay.intersects());
231+
}
232+
233+
#[test]
234+
fn test_add_path_iter() {
235+
let mut overlay = PredicateOverlay::new(16);
236+
let points = square(0, 0, 10);
237+
overlay.add_path_iter(points.into_iter(), ShapeType::Subject);
238+
overlay.add_contour(&square(5, 5, 10), ShapeType::Clip);
239+
assert!(overlay.intersects());
240+
}
241+
}

iOverlay/src/float/relate.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::core::fill_rule::FillRule;
22
use crate::core::overlay::ShapeType;
33
use crate::core::relate::PredicateOverlay;
44
use crate::core::solver::Solver;
5-
use crate::segm::build::BuildSegments;
65
use i_float::adapter::FloatPointAdapter;
76
use i_float::float::compatible::FloatPointCompatible;
87
use i_float::float::number::FloatNumber;
@@ -124,11 +123,8 @@ impl<P: FloatPointCompatible<T>, T: FloatNumber> FloatPredicateOverlay<P, T> {
124123
/// * `shape_type` - Whether to add as `Subject` or `Clip`.
125124
pub fn add_source<R: ShapeResource<P, T> + ?Sized>(&mut self, resource: &R, shape_type: ShapeType) {
126125
for contour in resource.iter_paths() {
127-
self.overlay.segments.append_path_iter(
128-
contour.iter().map(|p| self.adapter.float_to_int(p)),
129-
shape_type,
130-
false,
131-
);
126+
self.overlay
127+
.add_path_iter(contour.iter().map(|p| self.adapter.float_to_int(p)), shape_type);
132128
}
133129
}
134130

0 commit comments

Comments
 (0)