Skip to content

Commit bedc1d4

Browse files
author
Filyus
committed
fix(core): skip non-hole remnants in OGC extraction
1 parent 5fc4de6 commit bedc1d4

2 files changed

Lines changed: 55 additions & 3 deletions

File tree

iOverlay/src/core/extract_ogc.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,22 @@ where
124124
self.links.get_unchecked(left_top_link)
125125
};
126126

127-
debug_assert!(overlay_rule.is_fill_top(link.fill));
128-
129127
let start_data = StartPathData::new(is_main_dir_cw, link, left_top_link);
128+
if !overlay_rule.is_fill_top(link.fill) {
129+
// The first pass skips hole contours in the opposite traversal direction.
130+
// A self-touching hole can therefore leave non-hole remnants marked for
131+
// the second pass after the actual hole contour is extracted.
132+
self.find_contour(
133+
&start_data,
134+
is_main_dir_cw,
135+
VisitState::HullVisited,
136+
&mut buffer.visited,
137+
&mut buffer.points,
138+
);
139+
link_index += 1;
140+
continue;
141+
}
142+
debug_assert!(overlay_rule.is_fill_top(link.fill));
130143

131144
self.find_contour(
132145
&start_data,

iOverlay/tests/crash_tests.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#[cfg(test)]
22
mod tests {
3+
use i_float::adapter::FloatPointAdapter;
34
use i_float::int::number::int::IntNumber;
45
use i_float::int::point::IntPoint;
56
use i_key_sort::sort::key::SortKey;
67
use i_overlay::core::fill_rule::FillRule;
78
use i_overlay::core::overlay::{Overlay, ShapeType};
89
use i_overlay::core::overlay_rule::OverlayRule;
910
use i_overlay::core::solver::{Precision, Solver, Strategy};
10-
use i_overlay::float::overlay::FloatOverlay;
11+
use i_overlay::float::overlay::{FloatOverlay, OverlayOptions};
1112
use i_shape::base::data::{Path, Shape};
1213
use i_shape::{int_path, int_shape};
1314
use i_tree::{Expiration, LayoutNumber};
@@ -140,4 +141,42 @@ mod tests {
140141
let _ = graph.extract_shapes(OverlayRule::Subject, &mut Default::default());
141142
}
142143
}
144+
145+
#[test]
146+
fn test_05() {
147+
let subj = vec![
148+
vec![
149+
[24902.9222201258, 11129.9683052215],
150+
[24821.9592401258, 11107.1269052215],
151+
[24902.9218201258, 11129.9681852215],
152+
[24898.9601001258, 11128.8505052215],
153+
],
154+
vec![
155+
[20094.9253001258, 12125.6660652215],
156+
[20094.9253001258, 12125.6647652215],
157+
[29795.5156201258, 10942.5275852215],
158+
],
159+
vec![
160+
[24902.2200401258, 11129.7702052215],
161+
[24902.3098801258, 11129.7955452215],
162+
[24902.4788601258, 11129.8432252215],
163+
],
164+
vec![
165+
[24902.4819801258, 11129.8441052215],
166+
[24902.4832001258, 11129.8444452215],
167+
[24902.4821401258, 11129.8441452215],
168+
],
169+
];
170+
let points = subj.iter().flatten().collect::<Vec<_>>();
171+
let adapter =
172+
FloatPointAdapter::<_, i64>::with_iter_and_scale_checked(points.into_iter(), 50_000.0).unwrap();
173+
let mut options = OverlayOptions::default();
174+
options.clean_result = true;
175+
options.ogc = true;
176+
options.preserve_output_collinear = true;
177+
let mut overlay = FloatOverlay::new_custom(adapter, options, Default::default(), 13)
178+
.unsafe_add_source(&subj, ShapeType::Subject);
179+
180+
let _ = overlay.overlay(OverlayRule::Subject, FillRule::NonZero);
181+
}
143182
}

0 commit comments

Comments
 (0)