|
1 | 1 | use crate::build::sweep::{FillHandler, SweepRunner}; |
2 | 2 | use crate::core::fill_rule::FillRule; |
| 3 | +use crate::core::overlay::ShapeType; |
3 | 4 | use crate::core::predicate::{InteriorsIntersectHandler, IntersectsHandler, TouchesHandler, WithinHandler}; |
4 | 5 | use crate::core::solver::Solver; |
5 | 6 | use crate::segm::boolean::ShapeCountBoolean; |
| 7 | +use crate::segm::build::BuildSegments; |
6 | 8 | use crate::segm::segment::Segment; |
7 | 9 | use crate::split::solver::SplitSolver; |
8 | 10 | use alloc::vec::Vec; |
| 11 | +use i_float::int::point::IntPoint; |
| 12 | +use i_shape::int::shape::{IntContour, IntShape}; |
9 | 13 |
|
10 | 14 | /// Overlay structure optimized for spatial predicate evaluation. |
11 | 15 | /// |
@@ -95,8 +99,143 @@ impl PredicateOverlay { |
95 | 99 | self.evaluate(WithinHandler::new()) |
96 | 100 | } |
97 | 101 |
|
| 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 | + |
98 | 149 | #[inline] |
99 | 150 | pub fn clear(&mut self) { |
100 | 151 | self.segments.clear(); |
101 | 152 | } |
102 | 153 | } |
| 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 | +} |
0 commit comments