Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions iOverlay/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "i_overlay"
version = "7.0.1"
version = "7.0.2"
authors = ["Nail Sharipov <nailxsharipov@gmail.com>"]
edition = "2024"
rust-version = "1.88"
Expand All @@ -15,7 +15,7 @@ categories = ["algorithms", "graphics", "science::geo", "mathematics", "no-std"]
i_float = { version = "^3.0.0" }
i_shape = { version = "^3.0.0" }
i_tree = { version = "^0.19.0" }
i_key_sort = { version = "^0.10.1" }
i_key_sort = { version = "^0.10.3" }

#i_float = { path = "../../iFloat"}
#i_shape = { path = "../../iShape"}
Expand Down
32 changes: 23 additions & 9 deletions iOverlay/src/bind/solver.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::bind::segment::{ContourIndex, IdSegment, IdSegments};
use crate::geom::v_segment::VSegment;
use crate::geom::v_segment::{BottomSegment, VSegment};
use crate::util::log::Int;
use alloc::vec;
use alloc::vec::Vec;
use core::cmp::Ordering;
use i_float::int::number::int::IntNumber;
use i_float::int::point::IntPoint;
use i_key_sort::sort::key::SortKey;
use i_key_sort::sort::two_keys_cmp::TwoKeysAndCmpSort;
use i_shape::int::path::IntPath;
Expand Down Expand Up @@ -198,26 +199,39 @@ impl<I: IntNumber + Expiration + SortKey> JoinHoles<I> for Vec<IntShape<I>> {

pub(crate) trait LeftBottomSegment<I: IntNumber> {
fn left_bottom_segment(&self) -> VSegment<I>;
fn left_bottom_segment_from(&self, a: IntPoint<I>) -> VSegment<I>;
}

impl<I: IntNumber> LeftBottomSegment<I> for IntContour<I> {
fn left_bottom_segment(&self) -> VSegment<I> {
let mut index = 0;
let mut a = *self.first().unwrap();
for (i, &p) in self.iter().enumerate().skip(1) {
for &p in self.iter().skip(1) {
if p < a {
a = p;
index = i;
}
}

self.left_bottom_segment_from(a)
}

fn left_bottom_segment_from(&self, a: IntPoint<I>) -> VSegment<I> {
let n = self.len();
let b0 = self[(index + 1) % n];
let b1 = self[(index + n - 1) % n];
let mut result: Option<VSegment<I>> = None;

let s0 = VSegment { a, b: b0 };
let s1 = VSegment { a, b: b1 };
for (i, &p) in self.iter().enumerate() {
if p != a {
continue;
}

// Self-touching contours can visit the left-bottom point several times.
// Check every incident edge at that point and keep the lowest anchor edge.
let b0 = self[(i + 1) % n];
let b1 = self[(i + n - 1) % n];
result.update_if_under(VSegment { a, b: b0 });
result.update_if_under(VSegment { a, b: b1 });
}

if s0.is_under_segment(&s1) { s0 } else { s1 }
result.unwrap_or(VSegment { a, b: a })
}
}

Expand Down
15 changes: 3 additions & 12 deletions iOverlay/src/core/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::core::link::OverlayLink;
use crate::core::link::OverlayLinkFilter;
use crate::core::nearest_vector::NearestVector;
use crate::core::overlay::ContourDirection;
use crate::geom::v_segment::VSegment;
use crate::i_shape::flat::buffer::FlatContoursBuffer;
use alloc::vec;
use alloc::vec::Vec;
Expand Down Expand Up @@ -158,17 +157,9 @@ where
let contour = buffer.points.as_slice().to_vec();

if is_hole {
let mut v_segment = if clockwise {
VSegment {
a: contour[1],
b: contour[2],
}
} else {
VSegment {
a: contour[0],
b: contour[contour.len() - 1],
}
};
let left_bottom = if clockwise { contour[1] } else { contour[0] };
let mut v_segment = contour.left_bottom_segment_from(left_bottom);

if is_modified {
let most_left = contour.left_bottom_segment();
if most_left != v_segment {
Expand Down
14 changes: 2 additions & 12 deletions iOverlay/src/core/extract_ogc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::core::extract::{
use crate::core::graph::OverlayGraph;
use crate::core::overlay::ContourDirection;
use crate::core::overlay_rule::OverlayRule;
use crate::geom::v_segment::VSegment;
use alloc::vec;
use alloc::vec::Vec;
use i_float::int::number::int::IntNumber;
Expand Down Expand Up @@ -147,17 +146,8 @@ where
}
let contour = buffer.points.as_slice().to_vec();

let mut v_segment = if is_main_dir_cw {
VSegment {
a: contour[1],
b: contour[2],
}
} else {
VSegment {
a: contour[0],
b: contour[contour.len() - 1],
}
};
let left_bottom = if is_main_dir_cw { contour[1] } else { contour[0] };
let mut v_segment = contour.left_bottom_segment_from(left_bottom);

if is_modified {
let most_left = contour.left_bottom_segment();
Expand Down
17 changes: 17 additions & 0 deletions iOverlay/src/geom/v_segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,23 @@ impl<I: IntNumber> VSegment<I> {
}
}

pub(crate) trait BottomSegment<I: IntNumber> {
fn update_if_under(&mut self, segment: VSegment<I>);
}

impl<I: IntNumber> BottomSegment<I> for Option<VSegment<I>> {
#[inline(always)]
fn update_if_under(&mut self, segment: VSegment<I>) {
if let Some(best) = self {
if segment.is_under_segment(&best) {
*best = segment
}
} else {
*self = Some(segment);
}
}
}

impl<I: IntNumber> From<XSegment<I>> for VSegment<I> {
#[inline(always)]
fn from(seg: XSegment<I>) -> Self {
Expand Down
45 changes: 25 additions & 20 deletions iOverlay/src/vector/extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::core::graph::OverlayGraph;
use crate::core::link::{OverlayLink, OverlayLinkFilter};
use crate::core::overlay::ContourDirection;
use crate::core::overlay_rule::OverlayRule;
use crate::geom::v_segment::VSegment;
use crate::geom::v_segment::{BottomSegment, VSegment};
use crate::segm::segment::SegmentFill;
use crate::vector::edge::{DataVectorEdge, DataVectorPath, DataVectorShape};
use crate::vector::simplify::VectorSimplify;
Expand Down Expand Up @@ -92,17 +92,9 @@ where
}

if is_hole {
let mut v_segment = if clockwise {
VSegment {
a: contour[1].a,
b: contour[2].a,
}
} else {
VSegment {
a: contour[0].a,
b: contour[contour.len() - 1].a,
}
};
let left_bottom = if clockwise { contour[1].a } else { contour[0].a };
let mut v_segment = most_left_bottom_from(&contour, left_bottom);

if is_modified {
let most_left = most_left_bottom(&contour);
if most_left != v_segment {
Expand Down Expand Up @@ -308,22 +300,35 @@ where

#[inline]
fn most_left_bottom<I: IntNumber, D>(path: &DataVectorPath<I, D>) -> VSegment<I> {
let mut index = 0;
let mut a = path[0].a;
for (i, e) in path.iter().enumerate().skip(1) {
for e in path.iter().skip(1) {
if e.a < a {
a = e.a;
index = i;
}
}

most_left_bottom_from(path, a)
}

#[inline]
fn most_left_bottom_from<I: IntNumber, D>(path: &DataVectorPath<I, D>, a: IntPoint<I>) -> VSegment<I> {
let n = path.len();
let b0 = path[index].b;
let b1 = path[(index + n - 1) % n].a;
let mut result: Option<VSegment<I>> = None;

let s0 = VSegment { a, b: b0 };
let s1 = VSegment { a, b: b1 };
for (i, edge) in path.iter().enumerate() {
if edge.a != a {
continue;
}

// Self-touching contours can visit the left-bottom point several times.
// Check every incident edge at that point and keep the lowest anchor edge.
let b0 = edge.b;
let b1 = path[(i + n - 1) % n].a;
result.update_if_under(VSegment { a, b: b0 });
result.update_if_under(VSegment { a, b: b1 });
}

if s0.is_under_segment(&s1) { s0 } else { s1 }
result.unwrap_or(VSegment { a, b: a })
}

#[inline]
Expand Down
16 changes: 15 additions & 1 deletion iOverlay/tests/crash_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ mod tests {
use i_float::int::point::IntPoint;
use i_key_sort::sort::key::SortKey;
use i_overlay::core::fill_rule::FillRule;
use i_overlay::core::overlay::{Overlay, ShapeType};
use i_overlay::core::overlay::{IntOverlayOptions, Overlay, ShapeType};
use i_overlay::core::overlay_rule::OverlayRule;
use i_overlay::core::simplify::Simplify;
use i_overlay::core::solver::{Precision, Solver, Strategy};
use i_overlay::float::overlay::{FloatOverlay, OverlayOptions};
use i_shape::base::data::{Path, Shape};
Expand Down Expand Up @@ -179,4 +180,17 @@ mod tests {

let _ = overlay.overlay(OverlayRule::Subject, FillRule::NonZero);
}

#[test]
fn test_06() {
let shape = int_shape![
[[0, 0], [8, 0], [8, 8], [0, 8]],
[[2, 2], [2, 6], [6, 6], [6, 2], [2, 2], [5, 3], [3, 5]],
[[10, 0], [12, 0], [12, 2], [10, 2]],
];

let result = shape.simplify(FillRule::NonZero, IntOverlayOptions::default());

assert_eq!(result.len(), 2);
}
}
Loading