diff --git a/iOverlay/src/core/extract_ogc.rs b/iOverlay/src/core/extract_ogc.rs index 8ff78248..a8803c78 100644 --- a/iOverlay/src/core/extract_ogc.rs +++ b/iOverlay/src/core/extract_ogc.rs @@ -124,9 +124,22 @@ where self.links.get_unchecked(left_top_link) }; - debug_assert!(overlay_rule.is_fill_top(link.fill)); - let start_data = StartPathData::new(is_main_dir_cw, link, left_top_link); + if !overlay_rule.is_fill_top(link.fill) { + // The first pass skips hole contours in the opposite traversal direction. + // A self-touching hole can therefore leave non-hole remnants marked for + // the second pass after the actual hole contour is extracted. + self.find_contour( + &start_data, + is_main_dir_cw, + VisitState::HullVisited, + &mut buffer.visited, + &mut buffer.points, + ); + link_index += 1; + continue; + } + debug_assert!(overlay_rule.is_fill_top(link.fill)); self.find_contour( &start_data, diff --git a/iOverlay/tests/crash_tests.rs b/iOverlay/tests/crash_tests.rs index ea1a39c7..b4b17202 100644 --- a/iOverlay/tests/crash_tests.rs +++ b/iOverlay/tests/crash_tests.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod tests { + use i_float::adapter::FloatPointAdapter; use i_float::int::number::int::IntNumber; use i_float::int::point::IntPoint; use i_key_sort::sort::key::SortKey; @@ -7,7 +8,7 @@ mod tests { use i_overlay::core::overlay::{Overlay, ShapeType}; use i_overlay::core::overlay_rule::OverlayRule; use i_overlay::core::solver::{Precision, Solver, Strategy}; - use i_overlay::float::overlay::FloatOverlay; + use i_overlay::float::overlay::{FloatOverlay, OverlayOptions}; use i_shape::base::data::{Path, Shape}; use i_shape::{int_path, int_shape}; use i_tree::{Expiration, LayoutNumber}; @@ -140,4 +141,42 @@ mod tests { let _ = graph.extract_shapes(OverlayRule::Subject, &mut Default::default()); } } + + #[test] + fn test_05() { + let subj = vec![ + vec![ + [24902.9222201258, 11129.9683052215], + [24821.9592401258, 11107.1269052215], + [24902.9218201258, 11129.9681852215], + [24898.9601001258, 11128.8505052215], + ], + vec![ + [20094.9253001258, 12125.6660652215], + [20094.9253001258, 12125.6647652215], + [29795.5156201258, 10942.5275852215], + ], + vec![ + [24902.2200401258, 11129.7702052215], + [24902.3098801258, 11129.7955452215], + [24902.4788601258, 11129.8432252215], + ], + vec![ + [24902.4819801258, 11129.8441052215], + [24902.4832001258, 11129.8444452215], + [24902.4821401258, 11129.8441452215], + ], + ]; + let points = subj.iter().flatten().collect::>(); + let adapter = + FloatPointAdapter::<_, i64>::with_iter_and_scale_checked(points.into_iter(), 50_000.0).unwrap(); + let mut options = OverlayOptions::default(); + options.clean_result = true; + options.ogc = true; + options.preserve_output_collinear = true; + let mut overlay = FloatOverlay::new_custom(adapter, options, Default::default(), 13) + .unsafe_add_source(&subj, ShapeType::Subject); + + let _ = overlay.overlay(OverlayRule::Subject, FillRule::NonZero); + } }