diff --git a/iOverlay/src/bind/mod.rs b/iOverlay/src/bind/mod.rs index b66bfd3..8622f97 100644 --- a/iOverlay/src/bind/mod.rs +++ b/iOverlay/src/bind/mod.rs @@ -1,2 +1,2 @@ +pub(crate) mod segment; pub(crate) mod solver; -pub(crate) mod segment; \ No newline at end of file diff --git a/iOverlay/src/bind/segment.rs b/iOverlay/src/bind/segment.rs index 36ae8cb..b1a95de 100644 --- a/iOverlay/src/bind/segment.rs +++ b/iOverlay/src/bind/segment.rs @@ -1,6 +1,6 @@ -use alloc::vec::Vec; use crate::geom::v_segment::VSegment; use crate::vector::edge::{VectorEdge, VectorPath}; +use alloc::vec::Vec; use i_float::int::point::IntPoint; use i_shape::int::path::IntPath; @@ -139,4 +139,4 @@ impl IdSegments for VectorPath { inner(self.iter().rev().copied(), buffer, id_data, x_min, x_max); } } -} \ No newline at end of file +} diff --git a/iOverlay/src/build/boolean.rs b/iOverlay/src/build/boolean.rs index 934b7d6..f0c9c88 100644 --- a/iOverlay/src/build/boolean.rs +++ b/iOverlay/src/build/boolean.rs @@ -1,26 +1,30 @@ -use alloc::vec::Vec; -use i_shape::util::reserve::Reserve; -use crate::segm::boolean::ShapeCountBoolean; -use crate::core::link::OverlayLinkFilter; -use crate::core::graph::OverlayNode; -use crate::core::fill_rule::FillRule; -use crate::core::solver::Solver; use crate::build::builder::{FillStrategy, GraphBuilder, InclusionFilterStrategy}; use crate::core::extract::VisitState; +use crate::core::fill_rule::FillRule; use crate::core::graph::OverlayGraph; +use crate::core::graph::OverlayNode; use crate::core::link::OverlayLink; +use crate::core::link::OverlayLinkFilter; use crate::core::overlay::IntOverlayOptions; use crate::core::overlay_rule::OverlayRule; -use crate::segm::segment::{Segment, SegmentFill, ALL, BOTH_BOTTOM, BOTH_TOP, CLIP_BOTH, CLIP_BOTTOM, CLIP_TOP, SUBJ_BOTH, SUBJ_BOTTOM, SUBJ_TOP}; +use crate::core::solver::Solver; +use crate::segm::boolean::ShapeCountBoolean; +use crate::segm::segment::{ + ALL, BOTH_BOTTOM, BOTH_TOP, CLIP_BOTH, CLIP_BOTTOM, CLIP_TOP, SUBJ_BOTH, SUBJ_BOTTOM, SUBJ_TOP, + Segment, SegmentFill, +}; use crate::segm::winding::WindingCount; +use alloc::vec::Vec; +use i_shape::util::reserve::Reserve; impl GraphBuilder { #[inline] - pub(crate) fn build_boolean_all(&mut self, - fill_rule: FillRule, - options: IntOverlayOptions, - solver: &Solver, - segments: &[Segment], + pub(crate) fn build_boolean_all( + &mut self, + fill_rule: FillRule, + options: IntOverlayOptions, + solver: &Solver, + segments: &[Segment], ) -> OverlayGraph<'_> { self.build_boolean_fills(fill_rule, solver, segments); self.build_links_all(segments); @@ -28,14 +32,17 @@ impl GraphBuilder { } #[inline] - pub(crate) fn build_boolean_overlay(&mut self, - fill_rule: FillRule, - overlay_rule: OverlayRule, - options: IntOverlayOptions, - solver: &Solver, - segments: &[Segment], + #[rustfmt::skip] + pub(crate) fn build_boolean_overlay( + &mut self, + fill_rule: FillRule, + overlay_rule: OverlayRule, + options: IntOverlayOptions, + solver: &Solver, + segments: &[Segment], ) -> OverlayGraph<'_> { self.build_boolean_fills(fill_rule, solver, segments); + match overlay_rule { OverlayRule::Subject => self.build_links_by_filter::(segments), OverlayRule::Clip => self.build_links_by_filter::(segments), @@ -49,7 +56,13 @@ impl GraphBuilder { } #[inline] - fn build_boolean_fills(&mut self, fill_rule: FillRule, solver: &Solver, segments: &[Segment]) { + #[rustfmt::skip] + fn build_boolean_fills( + &mut self, + fill_rule: FillRule, + solver: &Solver, + segments: &[Segment], + ) { match fill_rule { FillRule::EvenOdd => self.build_fills_with_strategy::(solver, segments), FillRule::NonZero => self.build_fills_with_strategy::(solver, segments), @@ -64,7 +77,7 @@ impl GraphBuilder { OverlayGraph { nodes: &self.nodes, links: &self.links, - options + options, } } } @@ -307,37 +320,58 @@ impl OverlayLinkFilter for [OverlayLink] { #[inline] fn filter_subject(links: &[OverlayLink]) -> Vec { - links.iter().map(|link| VisitState::new(!link.fill.is_subject())).collect() + links + .iter() + .map(|link| VisitState::new(!link.fill.is_subject())) + .collect() } #[inline] fn filter_clip(links: &[OverlayLink]) -> Vec { - links.iter().map(|link| VisitState::new(!link.fill.is_clip())).collect() + links + .iter() + .map(|link| VisitState::new(!link.fill.is_clip())) + .collect() } #[inline] fn filter_intersect(links: &[OverlayLink]) -> Vec { - links.iter().map(|link| VisitState::new(!link.fill.is_intersect())).collect() + links + .iter() + .map(|link| VisitState::new(!link.fill.is_intersect())) + .collect() } #[inline] fn filter_union(links: &[OverlayLink]) -> Vec { - links.iter().map(|link| VisitState::new(!link.fill.is_union())).collect() + links + .iter() + .map(|link| VisitState::new(!link.fill.is_union())) + .collect() } #[inline] fn filter_difference(links: &[OverlayLink]) -> Vec { - links.iter().map(|link| VisitState::new(!link.fill.is_difference())).collect() + links + .iter() + .map(|link| VisitState::new(!link.fill.is_difference())) + .collect() } #[inline] fn filter_inverse_difference(links: &[OverlayLink]) -> Vec { - links.iter().map(|link| VisitState::new(!link.fill.is_inverse_difference())).collect() + links + .iter() + .map(|link| VisitState::new(!link.fill.is_inverse_difference())) + .collect() } #[inline] fn filter_xor(links: &[OverlayLink]) -> Vec { - links.iter().map(|link| VisitState::new(!link.fill.is_xor())).collect() + links + .iter() + .map(|link| VisitState::new(!link.fill.is_xor())) + .collect() } #[inline] @@ -401,4 +435,4 @@ fn filter_xor_into(links: &[OverlayLink], buffer: &mut Vec) { for link in links.iter() { buffer.push(VisitState::new(!link.fill.is_xor())); } -} \ No newline at end of file +} diff --git a/iOverlay/src/build/builder.rs b/iOverlay/src/build/builder.rs index b28e2a4..ef35d12 100644 --- a/iOverlay/src/build/builder.rs +++ b/iOverlay/src/build/builder.rs @@ -1,17 +1,17 @@ -use alloc::vec::Vec; +use crate::core::link::OverlayLink; use crate::core::solver::Solver; use crate::geom::end::End; +use crate::geom::id_point::IdPoint; use crate::geom::v_segment::VSegment; use crate::segm::segment::{NONE, Segment, SegmentFill}; use crate::segm::winding::WindingCount; use crate::util::log::Int; +use alloc::vec::Vec; use i_float::triangle::Triangle; use i_shape::util::reserve::Reserve; use i_tree::key::exp::KeyExpCollection; use i_tree::key::list::KeyExpList; use i_tree::key::tree::KeyExpTree; -use crate::core::link::OverlayLink; -use crate::geom::id_point::IdPoint; pub(super) trait FillStrategy { fn add_and_fill(this: C, bot: C) -> (C, SegmentFill); @@ -35,7 +35,6 @@ pub(crate) struct GraphBuilder { } impl GraphBuilder { - #[inline] pub(crate) fn new() -> Self { Self { @@ -49,7 +48,11 @@ impl GraphBuilder { } #[inline] - pub(super) fn build_fills_with_strategy>(&mut self, solver: &Solver, segments: &[Segment]) { + pub(super) fn build_fills_with_strategy>( + &mut self, + solver: &Solver, + segments: &[Segment], + ) { let count = segments.len(); if solver.is_list_fill(segments) { let capacity = count.log2_sqrt().max(4) * 2; @@ -65,7 +68,11 @@ impl GraphBuilder { } #[inline] - fn build_fills, S: KeyExpCollection>(&mut self, scan_list: &mut S, segments: &[Segment]) { + fn build_fills, S: KeyExpCollection>( + &mut self, + scan_list: &mut S, + segments: &[Segment], + ) { let mut node = Vec::with_capacity(4); let n = segments.len(); @@ -119,7 +126,10 @@ impl GraphBuilder { } #[inline] - pub(super) fn build_links_by_filter(&mut self, segments: &[Segment]) { + pub(super) fn build_links_by_filter( + &mut self, + segments: &[Segment], + ) { self.links.clear(); self.links.reserve_capacity(segments.len()); diff --git a/iOverlay/src/build/graph.rs b/iOverlay/src/build/graph.rs index cb63d8c..1b76e79 100644 --- a/iOverlay/src/build/graph.rs +++ b/iOverlay/src/build/graph.rs @@ -1,12 +1,11 @@ -use i_key_sort::sort::two_keys::TwoKeysSort; use crate::build::builder::{GraphBuilder, GraphNode}; use crate::core::solver::Solver; use crate::geom::end::End; use crate::segm::winding::WindingCount; use alloc::vec::Vec; +use i_key_sort::sort::two_keys::TwoKeysSort; impl GraphBuilder { - pub(super) fn build_nodes_and_connect_links(&mut self, solver: &Solver) { let n = self.links.len(); if n == 0 { @@ -93,7 +92,10 @@ impl GraphBuilder { point: link.b.point, }); } - self.ends - .sort_by_two_keys(solver.is_parallel_sort_allowed(), |e| e.point.x, |e| e.point.y); + self.ends.sort_by_two_keys( + solver.is_parallel_sort_allowed(), + |e| e.point.x, + |e| e.point.y, + ); } -} \ No newline at end of file +} diff --git a/iOverlay/src/build/mod.rs b/iOverlay/src/build/mod.rs index e2c78ee..ade5934 100644 --- a/iOverlay/src/build/mod.rs +++ b/iOverlay/src/build/mod.rs @@ -1,6 +1,6 @@ -pub(crate) mod builder; pub(crate) mod boolean; -pub(crate) mod string; +pub(crate) mod builder; mod graph; mod offset; -mod util; \ No newline at end of file +pub(crate) mod string; +mod util; diff --git a/iOverlay/src/build/offset.rs b/iOverlay/src/build/offset.rs index b6039d6..18a4ecb 100644 --- a/iOverlay/src/build/offset.rs +++ b/iOverlay/src/build/offset.rs @@ -8,9 +8,10 @@ use crate::segm::segment::{Segment, SegmentFill}; impl GraphBuilder { #[inline] - pub(crate) fn build_offset(&mut self, - solver: &Solver, - segments: &[Segment], + pub(crate) fn build_offset( + &mut self, + solver: &Solver, + segments: &[Segment], ) -> OffsetGraph<'_> { self.build_fills_with_strategy::(solver, segments); self.build_links_all(segments); @@ -31,9 +32,11 @@ struct SubjectOffsetStrategy; const BOLD_BIT: usize = 2; impl FillStrategy for SubjectOffsetStrategy { - #[inline(always)] - fn add_and_fill(this: ShapeCountOffset, bot: ShapeCountOffset) -> (ShapeCountOffset, SegmentFill) { + fn add_and_fill( + this: ShapeCountOffset, + bot: ShapeCountOffset, + ) -> (ShapeCountOffset, SegmentFill) { let top_subj = bot.subj + this.subj; let bot_subj = bot.subj; @@ -43,16 +46,18 @@ impl FillStrategy for SubjectOffsetStrategy { let bold = this.bold as SegmentFill; let fill = subj_top | (subj_bot << 1) | (bold << BOLD_BIT); - let top = ShapeCountOffset { subj: top_subj, bold: false }; // bold not need + let top = ShapeCountOffset { + subj: top_subj, + bold: false, // bold not need + }; (top, fill) } } - impl OverlayLink { #[inline(always)] pub(crate) fn is_bold(&self) -> bool { self.fill & (1 << BOLD_BIT) != 0 } -} \ No newline at end of file +} diff --git a/iOverlay/src/build/string.rs b/iOverlay/src/build/string.rs index 57c2117..62ac40c 100644 --- a/iOverlay/src/build/string.rs +++ b/iOverlay/src/build/string.rs @@ -1,18 +1,19 @@ -use alloc::vec::Vec; -use crate::segm::string::ShapeCountString; use crate::build::builder::{FillStrategy, GraphBuilder, InclusionFilterStrategy}; use crate::core::fill_rule::FillRule; use crate::core::solver::Solver; -use crate::segm::segment::{Segment, SegmentFill, CLIP_BOTH, SUBJ_BOTH}; +use crate::segm::segment::{CLIP_BOTH, SUBJ_BOTH, Segment, SegmentFill}; +use crate::segm::string::ShapeCountString; use crate::string::clip::ClipRule; use crate::string::graph::StringGraph; +use alloc::vec::Vec; impl GraphBuilder> { #[inline] - pub(crate) fn build_string_all(&mut self, - fill_rule: FillRule, - solver: &Solver, - segments: &[Segment], + pub(crate) fn build_string_all( + &mut self, + fill_rule: FillRule, + solver: &Solver, + segments: &[Segment], ) -> StringGraph<'_> { self.build_string_fills(fill_rule, solver, segments); self.build_links_all(segments); @@ -20,11 +21,12 @@ impl GraphBuilder> { } #[inline] - pub(crate) fn build_string_clip(&mut self, - fill_rule: FillRule, - clip_rule: ClipRule, - solver: &Solver, - segments: &[Segment], + pub(crate) fn build_string_clip( + &mut self, + fill_rule: FillRule, + clip_rule: ClipRule, + solver: &Solver, + segments: &[Segment], ) -> StringGraph<'_> { self.build_string_fills(fill_rule, solver, segments); match clip_rule { @@ -49,7 +51,13 @@ impl GraphBuilder> { } #[inline] - fn build_string_fills(&mut self, fill_rule: FillRule, solver: &Solver, segments: &[Segment]) { + #[rustfmt::skip] + fn build_string_fills( + &mut self, + fill_rule: FillRule, + solver: &Solver, + segments: &[Segment], + ) { match fill_rule { FillRule::EvenOdd => self.build_fills_with_strategy::(solver, segments), FillRule::NonZero => self.build_fills_with_strategy::(solver, segments), @@ -225,4 +233,4 @@ impl StringFillFilter for SegmentFill { false } } -} \ No newline at end of file +} diff --git a/iOverlay/src/core/divide.rs b/iOverlay/src/core/divide.rs index b6fc70f..39bbec7 100644 --- a/iOverlay/src/core/divide.rs +++ b/iOverlay/src/core/divide.rs @@ -1,9 +1,9 @@ +use crate::geom::id_point::IdPoint; use alloc::vec; use alloc::vec::Vec; use i_float::int::point::IntPoint; use i_shape::int::path::IntPath; use i_shape::int::shape::IntContour; -use crate::geom::id_point::IdPoint; struct SubPath { last: usize, @@ -39,7 +39,8 @@ impl ContourDecomposition for IntContour { if self.len() < 3 { return None; } - let mut id_points: Vec<_> = self.iter() + let mut id_points: Vec<_> = self + .iter() .enumerate() .map(|(i, &p)| IdPoint::new(i, p)) .collect(); @@ -69,7 +70,6 @@ impl ContourDecomposition for IntContour { anchors.sort_by(|p0, p1| p0.id.cmp(&p1.id)); - let mut contours = Vec::with_capacity((anchors.len() >> 1) + 1); let mut queue = vec![]; @@ -118,13 +118,12 @@ impl ContourDecomposition for IntContour { } } - #[cfg(test)] mod tests { + use crate::core::divide::ContourDecomposition; use alloc::vec; use i_float::int::point::IntPoint; use i_shape::int::shape::IntContour; - use crate::core::divide::ContourDecomposition; #[test] fn test_0() { @@ -278,6 +277,12 @@ mod tests { } fn rotate(contour: &IntContour, s: usize) -> IntContour { - contour.iter().cycle().skip(s).take(contour.len()).cloned().collect() + contour + .iter() + .cycle() + .skip(s) + .take(contour.len()) + .cloned() + .collect() } -} \ No newline at end of file +} diff --git a/iOverlay/src/core/extract.rs b/iOverlay/src/core/extract.rs index d6bf618..8eef2b8 100644 --- a/iOverlay/src/core/extract.rs +++ b/iOverlay/src/core/extract.rs @@ -51,7 +51,8 @@ impl OverlayGraph<'_> { overlay_rule: OverlayRule, buffer: &mut BooleanExtractionBuffer, ) -> IntShapes { - self.links.filter_by_overlay_into(overlay_rule, &mut buffer.visited); + self.links + .filter_by_overlay_into(overlay_rule, &mut buffer.visited); if self.options.ogc { self.extract_ogc(overlay_rule, buffer) } else { @@ -548,8 +549,8 @@ impl GraphUtil { // SAFETY: first_index originates from indices, so it is within links. links.get_unchecked(first_index) } - .other(node_id) - .point; + .other(node_id) + .point; let mut vector_solver = NearestVector::new(c, a, b, first_index, clockwise); // add second vector @@ -558,8 +559,8 @@ impl GraphUtil { // SAFETY: second_index comes from indices just like first_index. links.get_unchecked(second_index) } - .other(node_id) - .point, + .other(node_id) + .point, second_index, ); @@ -570,8 +571,8 @@ impl GraphUtil { // SAFETY: every link_index here is sourced from indices, so it addresses links. links.get_unchecked(link_index) } - .other(node_id) - .point; + .other(node_id) + .point; vector_solver.add(p, link_index); } } @@ -613,4 +614,4 @@ mod tests { debug_assert!(shapes_1.len() == 1); } -} \ No newline at end of file +} diff --git a/iOverlay/src/core/fill_rule.rs b/iOverlay/src/core/fill_rule.rs index 8e7c167..235d47d 100644 --- a/iOverlay/src/core/fill_rule.rs +++ b/iOverlay/src/core/fill_rule.rs @@ -11,7 +11,7 @@ pub enum FillRule { #[default] NonZero, Positive, - Negative + Negative, } impl fmt::Display for FillRule { @@ -25,4 +25,4 @@ impl fmt::Display for FillRule { write!(f, "{}", text) } -} \ No newline at end of file +} diff --git a/iOverlay/src/core/link.rs b/iOverlay/src/core/link.rs index 0030567..ca11646 100644 --- a/iOverlay/src/core/link.rs +++ b/iOverlay/src/core/link.rs @@ -1,8 +1,8 @@ -use alloc::vec::Vec; use crate::core::extract::VisitState; use crate::core::overlay_rule::OverlayRule; use crate::geom::id_point::IdPoint; use crate::segm::segment::SegmentFill; +use alloc::vec::Vec; #[derive(Debug, Clone, Copy)] pub(crate) struct OverlayLink { @@ -31,4 +31,4 @@ impl OverlayLink { pub(crate) trait OverlayLinkFilter { fn filter_by_overlay(&self, fill_rule: OverlayRule) -> Vec; fn filter_by_overlay_into(&self, overlay_rule: OverlayRule, buffer: &mut Vec); -} \ No newline at end of file +} diff --git a/iOverlay/src/core/mod.rs b/iOverlay/src/core/mod.rs index 13e14bc..0877a7c 100644 --- a/iOverlay/src/core/mod.rs +++ b/iOverlay/src/core/mod.rs @@ -1,6 +1,6 @@ pub mod divide; -mod extract_ogc; pub mod extract; +mod extract_ogc; pub mod fill_rule; pub mod graph; pub(crate) mod link; diff --git a/iOverlay/src/core/nearest_vector.rs b/iOverlay/src/core/nearest_vector.rs index 32b7063..597bc2a 100644 --- a/iOverlay/src/core/nearest_vector.rs +++ b/iOverlay/src/core/nearest_vector.rs @@ -2,17 +2,23 @@ use i_float::fix_vec::FixVec; use i_float::int::point::IntPoint; pub(crate) struct NearestVector { - c: IntPoint, // center - va: FixVec, // our target vector - vb: FixVec, // nearest vector to Va by specified rotation - ab_more_180: bool, // is angle between Va and Vb more than 180 degrees + c: IntPoint, // center + va: FixVec, // our target vector + vb: FixVec, // nearest vector to Va by specified rotation + ab_more_180: bool, // is angle between Va and Vb more than 180 degrees pub(crate) best_id: usize, - rotation_factor: i64, // +1 for clockwise, -1 for counterclockwise + rotation_factor: i64, // +1 for clockwise, -1 for counterclockwise } impl NearestVector { #[inline] - pub(crate) fn new(c: IntPoint, a: IntPoint, b: IntPoint, best_id: usize, clockwise: bool) -> Self { + pub(crate) fn new( + c: IntPoint, + a: IntPoint, + b: IntPoint, + best_id: usize, + clockwise: bool, + ) -> Self { let va = a.subtract(c); let vb = b.subtract(c); let (ab_more_180, rotation_factor) = if clockwise { @@ -20,7 +26,14 @@ impl NearestVector { } else { (va.cross_product(vb) <= 0, -1) }; - Self { c, va, vb, ab_more_180, best_id, rotation_factor } + Self { + c, + va, + vb, + ab_more_180, + best_id, + rotation_factor, + } } #[inline] @@ -43,9 +56,9 @@ impl NearestVector { #[cfg(test)] mod tests { + use crate::core::nearest_vector::NearestVector; use i_float::fix_vec::FixVec; use i_float::int::point::IntPoint; - use crate::core::nearest_vector::NearestVector; #[test] fn test_nearest_ccw_vector_creation() { @@ -104,7 +117,7 @@ mod tests { #[test] fn test_ccw_0() { let c = IntPoint::new(-1, -1); - let a = IntPoint::new( 0, -1); + let a = IntPoint::new(0, -1); let b = IntPoint::new(-2, -1); let mut nearest_ccw = NearestVector::new(c, a, b, 1, false); diff --git a/iOverlay/src/core/overlay.rs b/iOverlay/src/core/overlay.rs index 4679140..867b3e3 100644 --- a/iOverlay/src/core/overlay.rs +++ b/iOverlay/src/core/overlay.rs @@ -267,7 +267,8 @@ impl Overlay { let mut buffer = self.boolean_buffer.take().unwrap_or_default(); - let shapes = self.graph_builder + let shapes = self + .graph_builder .build_boolean_overlay( fill_rule, overlay_rule, @@ -419,24 +420,22 @@ impl IntOverlayOptions { #[cfg(test)] mod tests { + use crate::core::fill_rule::FillRule; + use crate::core::overlay::Overlay; + use crate::core::overlay_rule::OverlayRule; use alloc::vec; use i_float::int::point::IntPoint; use i_shape::int::area::Area; use i_shape::int::shape::IntContour; - use crate::core::fill_rule::FillRule; - use crate::core::overlay::Overlay; - use crate::core::overlay_rule::OverlayRule; #[test] fn test_0() { - let subj = [ - vec![ - IntPoint::new(0, 0), - IntPoint::new(10, 0), - IntPoint::new(10, 10), - IntPoint::new(0, 10), - ], - ]; + let subj = [vec![ + IntPoint::new(0, 0), + IntPoint::new(10, 0), + IntPoint::new(10, 10), + IntPoint::new(0, 10), + ]]; let mut overlay = Overlay::with_contours(&subj, &[]); let result = overlay.overlay(OverlayRule::Subject, FillRule::EvenOdd); @@ -845,5 +844,5 @@ mod tests { let result = overlay.overlay(OverlayRule::Subject, FillRule::NonZero); assert_eq!(result.len(), 0); - } + } } diff --git a/iOverlay/src/core/overlay_rule.rs b/iOverlay/src/core/overlay_rule.rs index b9095aa..734addf 100644 --- a/iOverlay/src/core/overlay_rule.rs +++ b/iOverlay/src/core/overlay_rule.rs @@ -1,5 +1,5 @@ +use crate::segm::segment::{BOTH_BOTTOM, BOTH_TOP, CLIP_TOP, NONE, SUBJ_TOP, SegmentFill}; use core::fmt; -use crate::segm::segment::{SegmentFill, BOTH_BOTTOM, BOTH_TOP, CLIP_TOP, NONE, SUBJ_TOP}; /// Defines the types of overlay/boolean operations that can be applied to shapes. For a visual description, see [Overlay Rules](https://ishape-rust.github.io/iShape-js/overlay/overlay_rules/overlay_rules.html). /// - `Subject`: Processes the subject shape, useful for resolving self-intersections and degenerate cases within the subject itself. @@ -53,4 +53,4 @@ impl fmt::Display for OverlayRule { write!(f, "{}", text) } -} \ No newline at end of file +} diff --git a/iOverlay/src/core/simplify.rs b/iOverlay/src/core/simplify.rs index f0d4040..6211c03 100644 --- a/iOverlay/src/core/simplify.rs +++ b/iOverlay/src/core/simplify.rs @@ -1,18 +1,18 @@ //! This module provides methods to simplify paths and shapes by reducing complexity //! (e.g., removing small artifacts or shapes below a certain area threshold) based on a build rule. -use i_shape::flat::buffer::FlatContoursBuffer; -use crate::core::overlay::ContourDirection; -use alloc::vec; -use crate::i_float::int::point::IntPoint; use crate::core::fill_rule::FillRule; +use crate::core::overlay::ContourDirection; use crate::core::overlay::ContourDirection::Clockwise; use crate::core::overlay::{IntOverlayOptions, Overlay, ShapeType}; use crate::core::overlay_rule::OverlayRule; +use crate::i_float::int::point::IntPoint; +use alloc::vec; +use i_shape::flat::buffer::FlatContoursBuffer; use crate::segm::build::BuildSegments; -use i_shape::int::path::ContourExtension; use i_shape::int::count::PointsCount; +use i_shape::int::path::ContourExtension; use i_shape::int::shape::{IntContour, IntShape, IntShapes}; /// Trait `Simplify` provides a method to simplify geometric shapes by reducing the number of points in contours or shapes @@ -68,11 +68,10 @@ impl Simplify for [IntShape] { enum ContourFillDirection { Reverse, Correct, - Empty + Empty, } impl Overlay { - /// Fast-path simplification for a single contour. /// /// Skips full overlay if the contour is already simple (no splits, no loops, no collinear issues). @@ -92,9 +91,8 @@ impl Overlay { if is_perfect { // the path is already perfect // need to check fill rule direction - let fill_direction = Self::contour_direction( - self.options.output_direction, fill_rule, contour - ); + let fill_direction = + Self::contour_direction(self.options.output_direction, fill_rule, contour); return match fill_direction { ContourFillDirection::Reverse => { @@ -103,8 +101,8 @@ impl Overlay { Some(vec![vec![rev_contour]]) } ContourFillDirection::Correct => None, - ContourFillDirection::Empty => Some(vec![]) - } + ContourFillDirection::Empty => Some(vec![]), + }; } let mut boolean_buffer = self.boolean_buffer.take().unwrap_or_default(); @@ -160,7 +158,11 @@ impl Overlay { } #[inline] - pub fn simplify_shape(&mut self, shape: &[IntContour], fill_rule: FillRule) -> Option { + pub fn simplify_shape( + &mut self, + shape: &[IntContour], + fill_rule: FillRule, + ) -> Option { if shape.len() == 1 { return self.simplify_contour(&shape[0], fill_rule); } @@ -177,7 +179,11 @@ impl Overlay { } #[inline] - pub fn simplify_flat_buffer(&mut self, flat_buffer: &mut FlatContoursBuffer, fill_rule: FillRule) { + pub fn simplify_flat_buffer( + &mut self, + flat_buffer: &mut FlatContoursBuffer, + fill_rule: FillRule, + ) { self.clear(); if flat_buffer.is_single_contour() { @@ -188,22 +194,25 @@ impl Overlay { // the path is already perfect // need to check fill rule direction let fill_direction = Self::contour_direction( - self.options.output_direction, fill_rule, first_contour + self.options.output_direction, + fill_rule, + first_contour, ); match fill_direction { ContourFillDirection::Reverse => { flat_buffer.as_first_contour_mut().reverse(); } - ContourFillDirection::Correct => {}, - ContourFillDirection::Empty => flat_buffer.clear_and_reserve(0, 0) + ContourFillDirection::Correct => {} + ContourFillDirection::Empty => flat_buffer.clear_and_reserve(0, 0), } - return + return; } } else { self.add_flat_buffer(flat_buffer, ShapeType::Subject); - self.split_solver.split_segments(&mut self.segments, &self.solver); + self.split_solver + .split_segments(&mut self.segments, &self.solver); if self.segments.is_empty() { flat_buffer.clear_and_reserve(0, 0); return; @@ -212,8 +221,7 @@ impl Overlay { let mut boolean_buffer = self.boolean_buffer.take().unwrap_or_default(); - self - .graph_builder + self.graph_builder .build_boolean_overlay( fill_rule, OverlayRule::Subject, @@ -242,7 +250,9 @@ impl Overlay { } let mut buffer = self.boolean_buffer.take().unwrap_or_default(); - let has_loops = self.graph_builder.test_contour_for_loops(contour, &mut buffer.points); + let has_loops = self + .graph_builder + .test_contour_for_loops(contour, &mut buffer.points); self.boolean_buffer = Some(buffer); !has_loops @@ -409,7 +419,7 @@ mod tests { #[test] fn test_near_collinear_paths() { let contour = vec![ - IntPoint::new(-100, -100), + IntPoint::new(-100, -100), IntPoint::new(0, 0), IntPoint::new(101, 100), ]; diff --git a/iOverlay/src/core/solver.rs b/iOverlay/src/core/solver.rs index 09bd690..144011c 100644 --- a/iOverlay/src/core/solver.rs +++ b/iOverlay/src/core/solver.rs @@ -185,5 +185,4 @@ impl Solver { pub(crate) fn is_parallel_sort_allowed(&self) -> bool { self.multithreading.is_some() } - } diff --git a/iOverlay/src/float/graph.rs b/iOverlay/src/float/graph.rs index 88bed58..d8f25b8 100644 --- a/iOverlay/src/float/graph.rs +++ b/iOverlay/src/float/graph.rs @@ -2,6 +2,7 @@ //! subject and clip polygons after boolean operations. The graph helps in extracting final shapes //! based on the overlay rule applied. +use crate::core::extract::BooleanExtractionBuffer; use crate::core::graph::OverlayGraph; use crate::core::overlay_rule::OverlayRule; use i_float::adapter::FloatPointAdapter; @@ -11,7 +12,6 @@ use i_shape::base::data::Shapes; use i_shape::float::adapter::ShapesToFloat; use i_shape::float::despike::DeSpikeContour; use i_shape::float::simple::SimplifyContour; -use crate::core::extract::BooleanExtractionBuffer; /// The `FloatOverlayGraph` struct represents an overlay graph with floating point precision, /// providing methods to extract geometric shapes from the graph after applying boolean operations. @@ -19,13 +19,21 @@ use crate::core::extract::BooleanExtractionBuffer; pub struct FloatOverlayGraph<'a, P: FloatPointCompatible, T: FloatNumber> { pub graph: OverlayGraph<'a>, pub adapter: FloatPointAdapter, - clean_result: bool + clean_result: bool, } impl<'a, P: FloatPointCompatible, T: FloatNumber> FloatOverlayGraph<'a, P, T> { #[inline] - pub(crate) fn new(graph: OverlayGraph<'a>, adapter: FloatPointAdapter, clean_result: bool) -> Self { - Self { graph, adapter, clean_result } + pub(crate) fn new( + graph: OverlayGraph<'a>, + adapter: FloatPointAdapter, + clean_result: bool, + ) -> Self { + Self { + graph, + adapter, + clean_result, + } } /// Extracts shapes from the overlay graph based on the specified overlay rule. @@ -46,10 +54,12 @@ impl<'a, P: FloatPointCompatible, T: FloatNumber> FloatOverlayGraph<'a, P, T> /// /// Note: Outer boundary paths have a counterclockwise order, and holes have a clockwise order. #[inline] - pub fn extract_shapes(&self, overlay_rule: OverlayRule, buffer: &mut BooleanExtractionBuffer) -> Shapes

{ - let shapes = self - .graph - .extract_shapes(overlay_rule, buffer); + pub fn extract_shapes( + &self, + overlay_rule: OverlayRule, + buffer: &mut BooleanExtractionBuffer, + ) -> Shapes

{ + let shapes = self.graph.extract_shapes(overlay_rule, buffer); let mut float = shapes.to_float(&self.adapter); if self.clean_result { diff --git a/iOverlay/src/float/overlay.rs b/iOverlay/src/float/overlay.rs index 7b1b7eb..09f4252 100644 --- a/iOverlay/src/float/overlay.rs +++ b/iOverlay/src/float/overlay.rs @@ -2,6 +2,11 @@ //! boolean operations (union, intersection, etc.) on polygons. It provides structures and methods to //! manage subject and clip polygons and convert them into graphs for further operations. +use crate::core::fill_rule::FillRule; +use crate::core::overlay::{ContourDirection, IntOverlayOptions, Overlay, ShapeType}; +use crate::core::overlay_rule::OverlayRule; +use crate::core::solver::Solver; +use crate::float::graph::FloatOverlayGraph; use crate::i_shape::source::resource::ShapeResource; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; @@ -11,11 +16,6 @@ use i_shape::base::data::Shapes; use i_shape::float::adapter::ShapesToFloat; use i_shape::float::despike::DeSpikeContour; use i_shape::float::simple::SimplifyContour; -use crate::core::fill_rule::FillRule; -use crate::core::overlay::{ContourDirection, IntOverlayOptions, Overlay, ShapeType}; -use crate::core::overlay_rule::OverlayRule; -use crate::core::solver::Solver; -use crate::float::graph::FloatOverlayGraph; #[derive(Debug, Clone, Copy)] pub struct OverlayOptions { @@ -69,10 +69,19 @@ impl, T: FloatNumber> FloatOverlay { /// - `capacity`: Initial capacity for storing segments, ideally matching the total number of /// segments for efficient memory allocation. #[inline] - pub fn new_custom(adapter: FloatPointAdapter, options: OverlayOptions, solver: Solver, capacity: usize) -> Self { + pub fn new_custom( + adapter: FloatPointAdapter, + options: OverlayOptions, + solver: Solver, + capacity: usize, + ) -> Self { let clean_result = options.clean_result; let overlay = Overlay::new_custom(capacity, options.int_with_adapter(&adapter), solver); - Self { overlay, clean_result, adapter } + Self { + overlay, + clean_result, + adapter, + } } /// Constructs a new `FloatOverlay`, a builder for overlaying geometric shapes @@ -86,7 +95,11 @@ impl, T: FloatNumber> FloatOverlay { let clean_result = options.clean_result; let adapter = FloatPointAdapter::new(FloatRect::zero()); let overlay = Overlay::new_custom(capacity, options.int_default(), solver); - Self { overlay, clean_result, adapter } + Self { + overlay, + clean_result, + adapter, + } } /// Creates a new `FloatOverlay` instance and initializes it with subject and clip shapes. @@ -98,8 +111,8 @@ impl, T: FloatNumber> FloatOverlay { /// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours. pub fn with_subj_and_clip(subj: &R0, clip: &R1) -> Self where - R0: ShapeResource +?Sized, - R1: ShapeResource +?Sized, + R0: ShapeResource + ?Sized, + R1: ShapeResource + ?Sized, P: FloatPointCompatible, T: FloatNumber, { @@ -122,10 +135,15 @@ impl, T: FloatNumber> FloatOverlay { /// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours. /// - `options`: Adjust custom behavior. /// - `solver`: Type of solver to use. - pub fn with_subj_and_clip_custom(subj: &R0, clip: &R1, options: OverlayOptions, solver: Solver) -> Self + pub fn with_subj_and_clip_custom( + subj: &R0, + clip: &R1, + options: OverlayOptions, + solver: Solver, + ) -> Self where - R0: ShapeResource +?Sized, - R1: ShapeResource +?Sized, + R0: ShapeResource + ?Sized, + R1: ShapeResource + ?Sized, P: FloatPointCompatible, T: FloatNumber, { @@ -147,7 +165,7 @@ impl, T: FloatNumber> FloatOverlay { /// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours. pub fn with_subj(subj: &R) -> Self where - R: ShapeResource +?Sized, + R: ShapeResource + ?Sized, P: FloatPointCompatible, T: FloatNumber, { @@ -155,8 +173,7 @@ impl, T: FloatNumber> FloatOverlay { let adapter = FloatPointAdapter::with_iter(iter); let subj_capacity = subj.iter_paths().fold(0, |s, c| s + c.len()); - Self::with_adapter(adapter, subj_capacity) - .unsafe_add_source(subj, ShapeType::Subject) + Self::with_adapter(adapter, subj_capacity).unsafe_add_source(subj, ShapeType::Subject) } /// Creates a new `FloatOverlay` instance and initializes it with subject. @@ -169,7 +186,7 @@ impl, T: FloatNumber> FloatOverlay { /// - `solver`: Type of solver to use. pub fn with_subj_custom(subj: &R, options: OverlayOptions, solver: Solver) -> Self where - R: ShapeResource +?Sized, + R: ShapeResource + ?Sized, P: FloatPointCompatible, T: FloatNumber, { @@ -189,7 +206,11 @@ impl, T: FloatNumber> FloatOverlay { /// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours. /// - `shape_type`: Specifies the role of the added paths in the overlay operation, either as `Subject` or `Clip`. #[inline] - pub fn unsafe_add_source +?Sized>(mut self, resource: &R, shape_type: ShapeType) -> Self { + pub fn unsafe_add_source + ?Sized>( + mut self, + resource: &R, + shape_type: ShapeType, + ) -> Self { self.add_source(resource, shape_type); self } @@ -200,7 +221,10 @@ impl, T: FloatNumber> FloatOverlay { /// - **Safety**: Marked `unsafe` because it assumes the path is fully contained within the bounding box. #[inline] pub fn unsafe_add_contour(mut self, contour: &[P], shape_type: ShapeType) -> Self { - self.overlay.add_path_iter(contour.iter().map(|p| self.adapter.float_to_int(p)), shape_type); + self.overlay.add_path_iter( + contour.iter().map(|p| self.adapter.float_to_int(p)), + shape_type, + ); self } @@ -210,9 +234,12 @@ impl, T: FloatNumber> FloatOverlay { } #[inline] - fn add_source +?Sized>(&mut self, resource: &R, shape_type: ShapeType) { + fn add_source + ?Sized>(&mut self, resource: &R, shape_type: ShapeType) { for contour in resource.iter_paths() { - self.overlay.add_path_iter(contour.iter().map(|p| self.adapter.float_to_int(p)), shape_type); + self.overlay.add_path_iter( + contour.iter().map(|p| self.adapter.float_to_int(p)), + shape_type, + ); } } @@ -225,8 +252,8 @@ impl, T: FloatNumber> FloatOverlay { /// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours. pub fn reinit_with_subj_and_clip(&mut self, subj: &R0, clip: &R1) where - R0: ShapeResource +?Sized, - R1: ShapeResource +?Sized, + R0: ShapeResource + ?Sized, + R1: ShapeResource + ?Sized, P: FloatPointCompatible, T: FloatNumber, { @@ -246,7 +273,7 @@ impl, T: FloatNumber> FloatOverlay { /// - `Shapes`: A collection of shapes, where each shape may consist of multiple contours. pub fn reinit_with_subj(&mut self, subj: &R) where - R: ShapeResource +?Sized, + R: ShapeResource + ?Sized, P: FloatPointCompatible, T: FloatNumber, { @@ -262,7 +289,11 @@ impl, T: FloatNumber> FloatOverlay { #[inline] pub fn build_graph_view(&mut self, fill_rule: FillRule) -> Option> { let graph = self.overlay.build_graph_view(fill_rule)?; - Some(FloatOverlayGraph::new(graph, self.adapter.clone(), self.clean_result)) + Some(FloatOverlayGraph::new( + graph, + self.adapter.clone(), + self.clean_result, + )) } /// Executes a single Boolean operation on the current geometry using the specified overlay and build rules. @@ -336,7 +367,10 @@ impl Default for OverlayOptions { } impl OverlayOptions { - pub(crate) fn int_with_adapter>(&self, adapter: &FloatPointAdapter) -> IntOverlayOptions { + pub(crate) fn int_with_adapter>( + &self, + adapter: &FloatPointAdapter, + ) -> IntOverlayOptions { IntOverlayOptions { preserve_input_collinear: self.preserve_input_collinear, output_direction: self.output_direction, @@ -372,10 +406,10 @@ impl OverlayOptions { #[cfg(test)] mod tests { - use alloc::vec; -use crate::core::fill_rule::FillRule; + use crate::core::fill_rule::FillRule; use crate::core::overlay_rule::OverlayRule; use crate::float::overlay::FloatOverlay; + use alloc::vec; #[test] fn test_contour_fixed() { @@ -383,10 +417,7 @@ use crate::core::fill_rule::FillRule; let right_rect = [[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; let shapes = FloatOverlay::with_subj_and_clip(&left_rect, &right_rect) - .overlay( - OverlayRule::Union, - FillRule::EvenOdd, - ); + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -398,12 +429,8 @@ use crate::core::fill_rule::FillRule; let left_rect = vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]]; let right_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; - let shapes = FloatOverlay::with_subj_and_clip(&left_rect, &right_rect) - .overlay( - OverlayRule::Union, - FillRule::EvenOdd - ); + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -416,10 +443,7 @@ use crate::core::fill_rule::FillRule; let right_rect = [[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; let shapes = FloatOverlay::with_subj_and_clip(left_rect.as_slice(), right_rect.as_slice()) - .overlay( - OverlayRule::Union, - FillRule::EvenOdd - ); + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -429,23 +453,14 @@ use crate::core::fill_rule::FillRule; #[test] fn test_contours_vec() { let rects = vec![ - vec![ - [0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0] - ], - vec![ - [0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0] - ], - vec![ - [1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0] - ] + vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]], + vec![[0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0]], + vec![[1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0]], ]; let right_bottom_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; let shapes = FloatOverlay::with_subj_and_clip(&rects.as_slice(), &right_bottom_rect) - .overlay( - OverlayRule::Union, - FillRule::EvenOdd - ); + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -455,23 +470,15 @@ use crate::core::fill_rule::FillRule; #[test] fn test_contours_slice() { let rects = vec![ - vec![ - [0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0] - ], - vec![ - [0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0] - ], - vec![ - [1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0] - ] + vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]], + vec![[0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0]], + vec![[1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0]], ]; let right_bottom_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; - let shapes = FloatOverlay::with_subj_and_clip(rects.as_slice(), right_bottom_rect.as_slice()) - .overlay( - OverlayRule::Union, - FillRule::EvenOdd - ); + let shapes = + FloatOverlay::with_subj_and_clip(rects.as_slice(), right_bottom_rect.as_slice()) + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -480,27 +487,15 @@ use crate::core::fill_rule::FillRule; #[test] fn test_shapes() { - let shapes = vec![ - vec![ - vec![ - [0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0] - ], - vec![ - [0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0] - ], - vec![ - [1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0] - ] - ] - ]; + let shapes = vec![vec![ + vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]], + vec![[0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0]], + vec![[1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0]], + ]]; let right_bottom_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; - let shapes = FloatOverlay::with_subj_and_clip(&shapes, &right_bottom_rect) - .overlay( - OverlayRule::Union, - FillRule::EvenOdd - ); + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -509,28 +504,16 @@ use crate::core::fill_rule::FillRule; #[test] fn test_different_resource() { - let res_0 = vec![ - vec![ - vec![ - [0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0] - ], - vec![ - [0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0] - ], - vec![ - [1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0] - ] - ] - ]; + let res_0 = vec![vec![ + vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]], + vec![[0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0]], + vec![[1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0]], + ]]; let res_1 = [[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; - let shapes = FloatOverlay::with_subj_and_clip(&res_0, &res_1.as_slice()) - .overlay( - OverlayRule::Union, - FillRule::EvenOdd - ); + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -540,26 +523,92 @@ use crate::core::fill_rule::FillRule; #[test] fn test_grid() { let subj = vec![ - vec![vec![[175.0, 475.0], [175.0, 375.0], [275.0, 375.0], [275.0, 475.0]]], - vec![vec![[175.0, 325.0], [175.0, 225.0], [275.0, 225.0], [275.0, 325.0]]], - vec![vec![[175.0, 175.0], [175.0, 75.0], [275.0, 75.0], [275.0, 175.0]]], - vec![vec![[325.0, 475.0], [325.0, 375.0], [425.0, 375.0], [425.0, 475.0]]], - vec![vec![[325.0, 325.0], [325.0, 225.0], [425.0, 225.0], [425.0, 325.0]]], - vec![vec![[325.0, 175.0], [325.0, 75.0], [425.0, 75.0], [425.0, 175.0]]], - vec![vec![[475.0, 475.0], [475.0, 375.0], [575.0, 375.0], [575.0, 475.0]]], - vec![vec![[475.0, 325.0], [475.0, 225.0], [575.0, 225.0], [575.0, 325.0]]], - vec![vec![[475.0, 175.0], [475.0, 75.0], [575.0, 75.0], [575.0, 175.0]]]]; + vec![vec![ + [175.0, 475.0], + [175.0, 375.0], + [275.0, 375.0], + [275.0, 475.0], + ]], + vec![vec![ + [175.0, 325.0], + [175.0, 225.0], + [275.0, 225.0], + [275.0, 325.0], + ]], + vec![vec![ + [175.0, 175.0], + [175.0, 75.0], + [275.0, 75.0], + [275.0, 175.0], + ]], + vec![vec![ + [325.0, 475.0], + [325.0, 375.0], + [425.0, 375.0], + [425.0, 475.0], + ]], + vec![vec![ + [325.0, 325.0], + [325.0, 225.0], + [425.0, 225.0], + [425.0, 325.0], + ]], + vec![vec![ + [325.0, 175.0], + [325.0, 75.0], + [425.0, 75.0], + [425.0, 175.0], + ]], + vec![vec![ + [475.0, 475.0], + [475.0, 375.0], + [575.0, 375.0], + [575.0, 475.0], + ]], + vec![vec![ + [475.0, 325.0], + [475.0, 225.0], + [575.0, 225.0], + [575.0, 325.0], + ]], + vec![vec![ + [475.0, 175.0], + [475.0, 75.0], + [575.0, 75.0], + [575.0, 175.0], + ]], + ]; let clip = vec![ - vec![vec![[250.0, 400.0], [250.0, 300.0], [350.0, 300.0], [350.0, 400.0]]], - vec![vec![[250.0, 250.0], [250.0, 150.0], [350.0, 150.0], [350.0, 250.0]]], - vec![vec![[400.0, 400.0], [400.0, 300.0], [500.0, 300.0], [500.0, 400.0]]], - vec![vec![[400.0, 250.0], [400.0, 150.0], [500.0, 150.0], [500.0, 250.0]]] + vec![vec![ + [250.0, 400.0], + [250.0, 300.0], + [350.0, 300.0], + [350.0, 400.0], + ]], + vec![vec![ + [250.0, 250.0], + [250.0, 150.0], + [350.0, 150.0], + [350.0, 250.0], + ]], + vec![vec![ + [400.0, 400.0], + [400.0, 300.0], + [500.0, 300.0], + [500.0, 400.0], + ]], + vec![vec![ + [400.0, 250.0], + [400.0, 150.0], + [500.0, 150.0], + [500.0, 250.0], + ]], ]; let mut overlay = FloatOverlay::with_subj_and_clip(&subj, &clip); - let result = overlay.overlay(OverlayRule::Intersect, FillRule::EvenOdd ); + let result = overlay.overlay(OverlayRule::Intersect, FillRule::EvenOdd); assert_eq!(result.len(), 16); } diff --git a/iOverlay/src/float/scale.rs b/iOverlay/src/float/scale.rs index 98c8d5d..a5b1691 100644 --- a/iOverlay/src/float/scale.rs +++ b/iOverlay/src/float/scale.rs @@ -229,9 +229,10 @@ mod tests { ]]; let right_bottom_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; - let shapes = FloatOverlay::with_subj_and_clip_fixed_scale(&shapes, &right_bottom_rect, 10.0) - .unwrap() - .overlay(OverlayRule::Union, FillRule::EvenOdd); + let shapes = + FloatOverlay::with_subj_and_clip_fixed_scale(&shapes, &right_bottom_rect, 10.0) + .unwrap() + .overlay(OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -249,7 +250,8 @@ mod tests { let scale = (1u64 << 32) as f64; - let result = FloatOverlay::with_subj_and_clip_fixed_scale(&shapes, &right_bottom_rect, scale); + let result = + FloatOverlay::with_subj_and_clip_fixed_scale(&shapes, &right_bottom_rect, scale); assert!(!result.is_ok()); } @@ -259,9 +261,19 @@ mod tests { let left_rect = vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]]; let right_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; - assert!(FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, -1.0).is_err()); - assert!(FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, 0.0).is_err()); - assert!(FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, f64::NAN).is_err()); - assert!(FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, f64::INFINITY).is_err()); + assert!( + FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, -1.0).is_err() + ); + assert!( + FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, 0.0).is_err() + ); + assert!( + FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, f64::NAN) + .is_err() + ); + assert!( + FloatOverlay::with_subj_and_clip_fixed_scale(&left_rect, &right_rect, f64::INFINITY) + .is_err() + ); } } diff --git a/iOverlay/src/float/simplify.rs b/iOverlay/src/float/simplify.rs index b0efd16..753fca5 100644 --- a/iOverlay/src/float/simplify.rs +++ b/iOverlay/src/float/simplify.rs @@ -1,11 +1,11 @@ -use i_float::float::compatible::FloatPointCompatible; -use i_float::float::number::FloatNumber; -use i_shape::base::data::Shapes; -use i_shape::source::resource::ShapeResource; use crate::core::fill_rule::FillRule; use crate::core::overlay_rule::OverlayRule; use crate::core::solver::Solver; use crate::float::overlay::{FloatOverlay, OverlayOptions}; +use i_float::float::compatible::FloatPointCompatible; +use i_float::float::number::FloatNumber; +use i_shape::base::data::Shapes; +use i_shape::source::resource::ShapeResource; /// Trait `Simplify` provides a method to simplify geometric shapes by reducing the number of points in contours or shapes /// while preserving overall shape and topology. The method applies a minimum area threshold and a build rule to @@ -24,7 +24,12 @@ pub trait SimplifyShape { /// - Returns: A collection of Shapes

that represents the simplified geometry. /// /// Note: Outer boundary paths have a **main_direction** order, and holes have an opposite to **main_direction** order. - fn simplify_shape_custom(&self, fill_rule: FillRule, options: OverlayOptions, solver: Solver) -> Shapes

; + fn simplify_shape_custom( + &self, + fill_rule: FillRule, + options: OverlayOptions, + solver: Solver, + ) -> Shapes

; } impl SimplifyShape for S @@ -40,7 +45,12 @@ where } #[inline] - fn simplify_shape_custom(&self, fill_rule: FillRule, options: OverlayOptions, solver: Solver) -> Shapes

{ + fn simplify_shape_custom( + &self, + fill_rule: FillRule, + options: OverlayOptions, + solver: Solver, + ) -> Shapes

{ FloatOverlay::with_subj_custom(self, options, solver) .overlay(OverlayRule::Subject, fill_rule) } @@ -48,9 +58,9 @@ where #[cfg(test)] mod tests { - use alloc::vec; use crate::core::fill_rule::FillRule; use crate::float::simplify::SimplifyShape; + use alloc::vec; #[test] fn test_contour_slice() { @@ -73,4 +83,4 @@ mod tests { assert_eq!(shapes[0].len(), 1); assert_eq!(shapes[0][0].len(), 4); } -} \ No newline at end of file +} diff --git a/iOverlay/src/float/single.rs b/iOverlay/src/float/single.rs index 6283d50..984d7f0 100644 --- a/iOverlay/src/float/single.rs +++ b/iOverlay/src/float/single.rs @@ -1,10 +1,10 @@ +use crate::core::fill_rule::FillRule; +use crate::core::overlay_rule::OverlayRule; +use crate::float::overlay::FloatOverlay; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; use i_shape::base::data::Shapes; use i_shape::source::resource::ShapeResource; -use crate::core::fill_rule::FillRule; -use crate::core::overlay_rule::OverlayRule; -use crate::float::overlay::FloatOverlay; /// Trait `SingleFloatOverlay` provides methods for overlay operations between various geometric entities. /// This trait supports boolean operations on contours, shapes, and collections of shapes, using customizable overlay and build rules. @@ -43,19 +43,18 @@ where #[cfg(test)] mod tests { - use alloc::vec; use crate::core::fill_rule::FillRule; use crate::core::overlay_rule::OverlayRule; use crate::float::overlay::FloatOverlay; use crate::float::single::SingleFloatOverlay; + use alloc::vec; #[test] fn test_contour() { let left_rect = vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]]; let right_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; - let shapes = left_rect - .overlay(&right_rect, OverlayRule::Union, FillRule::EvenOdd); + let shapes = left_rect.overlay(&right_rect, OverlayRule::Union, FillRule::EvenOdd); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -65,15 +64,9 @@ mod tests { #[test] fn test_contours() { let r3 = vec![ - vec![ - [0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0] - ], - vec![ - [0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0] - ], - vec![ - [1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0] - ] + vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]], + vec![[0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0]], + vec![[1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0]], ]; let right_bottom_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; @@ -87,19 +80,11 @@ mod tests { #[test] fn test_shapes() { - let shapes = vec![ - vec![ - vec![ - [0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0] - ], - vec![ - [0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0] - ], - vec![ - [1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0] - ] - ] - ]; + let shapes = vec![vec![ + vec![[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]], + vec![[0.0, 1.0], [0.0, 2.0], [1.0, 2.0], [1.0, 1.0]], + vec![[1.0, 1.0], [1.0, 2.0], [2.0, 2.0], [2.0, 1.0]], + ]]; let right_bottom_rect = vec![[1.0, 0.0], [1.0, 1.0], [2.0, 1.0], [2.0, 0.0]]; let shapes = FloatOverlay::with_subj_and_clip(&shapes, &right_bottom_rect) @@ -109,4 +94,4 @@ mod tests { assert_eq!(shapes[0].len(), 1); assert_eq!(shapes[0][0].len(), 4); } -} \ No newline at end of file +} diff --git a/iOverlay/src/float/string_graph.rs b/iOverlay/src/float/string_graph.rs index 8df49ac..aece5ce 100644 --- a/iOverlay/src/float/string_graph.rs +++ b/iOverlay/src/float/string_graph.rs @@ -1,3 +1,6 @@ +use crate::float::overlay::OverlayOptions; +use crate::string::graph::StringGraph; +use crate::string::rule::StringRule; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; @@ -5,9 +8,6 @@ use i_shape::base::data::Shapes; use i_shape::float::adapter::ShapesToFloat; use i_shape::float::despike::DeSpikeContour; use i_shape::float::simple::SimplifyContour; -use crate::float::overlay::OverlayOptions; -use crate::string::graph::StringGraph; -use crate::string::rule::StringRule; /// The `FloatStringGraph` struct represents a graph structure with floating-point precision, /// providing methods to extract geometric shapes from the graph after applying string-based operations. @@ -57,18 +57,24 @@ impl, T: FloatNumber> FloatStringGraph<'_, P, T> { /// /// Note: Outer boundary paths have a **main_direction** order, and holes have an opposite to **main_direction** order. #[inline] - pub fn extract_shapes_custom(&self, string_rule: StringRule, options: OverlayOptions) -> Shapes

{ - let shapes = self.graph.extract_shapes_custom(string_rule, options.int_with_adapter(&self.adapter)); + pub fn extract_shapes_custom( + &self, + string_rule: StringRule, + options: OverlayOptions, + ) -> Shapes

{ + let shapes = self + .graph + .extract_shapes_custom(string_rule, options.int_with_adapter(&self.adapter)); let mut float = shapes.to_float(&self.adapter); if options.clean_result { if options.preserve_output_collinear { - float.despike_contour(&self.adapter); + float.despike_contour(&self.adapter); } else { - float.simplify_contour(&self.adapter); + float.simplify_contour(&self.adapter); } } float } -} \ No newline at end of file +} diff --git a/iOverlay/src/geom/id_point.rs b/iOverlay/src/geom/id_point.rs index 60f961f..d9a82f1 100644 --- a/iOverlay/src/geom/id_point.rs +++ b/iOverlay/src/geom/id_point.rs @@ -10,4 +10,4 @@ impl IdPoint { pub(crate) fn new(id: usize, point: IntPoint) -> Self { Self { id, point } } -} \ No newline at end of file +} diff --git a/iOverlay/src/geom/line_range.rs b/iOverlay/src/geom/line_range.rs index 96548ea..1a0bc40 100644 --- a/iOverlay/src/geom/line_range.rs +++ b/iOverlay/src/geom/line_range.rs @@ -2,4 +2,4 @@ pub(crate) struct LineRange { pub(crate) min: i32, pub(crate) max: i32, -} \ No newline at end of file +} diff --git a/iOverlay/src/geom/mod.rs b/iOverlay/src/geom/mod.rs index 9272657..1e03434 100644 --- a/iOverlay/src/geom/mod.rs +++ b/iOverlay/src/geom/mod.rs @@ -1,5 +1,5 @@ -pub(crate) mod x_segment; -pub(crate) mod v_segment; pub(crate) mod end; +pub(crate) mod id_point; pub(crate) mod line_range; -pub(crate) mod id_point; \ No newline at end of file +pub(crate) mod v_segment; +pub(crate) mod x_segment; diff --git a/iOverlay/src/geom/v_segment.rs b/iOverlay/src/geom/v_segment.rs index a9a2bd9..3ea0e6d 100644 --- a/iOverlay/src/geom/v_segment.rs +++ b/iOverlay/src/geom/v_segment.rs @@ -1,8 +1,8 @@ +use crate::geom::x_segment::XSegment; use core::cmp::Ordering; -use i_tree::ExpiredKey; use i_float::int::point::IntPoint; use i_float::triangle::Triangle; -use crate::geom::x_segment::XSegment; +use i_tree::ExpiredKey; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct VSegment { @@ -31,15 +31,9 @@ impl VSegment { #[inline(always)] pub(crate) fn is_under_segment(&self, other: &VSegment) -> bool { match self.a.cmp(&other.a) { - Ordering::Less => { - Triangle::is_clockwise_point(self.a, other.a, self.b) - } - Ordering::Equal => { - Triangle::is_clockwise_point(self.a, other.b, self.b) - } - Ordering::Greater => { - Triangle::is_clockwise_point(other.a, other.b, self.a) - } + Ordering::Less => Triangle::is_clockwise_point(self.a, other.a, self.b), + Ordering::Equal => Triangle::is_clockwise_point(self.a, other.b, self.b), + Ordering::Greater => Triangle::is_clockwise_point(other.a, other.b, self.a), } } @@ -84,15 +78,18 @@ impl ExpiredKey for VSegment { #[cfg(test)] mod tests { + use crate::geom::v_segment::VSegment; use core::cmp::Ordering; use i_float::int::point::IntPoint; - use crate::geom::v_segment::VSegment; #[test] fn test_00() { let p = IntPoint::new(-10, 10); - let s = VSegment { a: IntPoint::new(-10, -10), b: IntPoint::new(10, -10) }; + let s = VSegment { + a: IntPoint::new(-10, -10), + b: IntPoint::new(10, -10), + }; let order = s.is_under_point_order(p); assert_eq!(order, Ordering::Less); } -} \ No newline at end of file +} diff --git a/iOverlay/src/geom/x_segment.rs b/iOverlay/src/geom/x_segment.rs index 4b64e6b..cae600b 100644 --- a/iOverlay/src/geom/x_segment.rs +++ b/iOverlay/src/geom/x_segment.rs @@ -1,6 +1,6 @@ +use crate::geom::line_range::LineRange; use core::cmp::Ordering; use i_float::int::point::IntPoint; -use crate::geom::line_range::LineRange; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct XSegment { @@ -12,9 +12,15 @@ impl XSegment { #[inline(always)] pub(crate) fn y_range(&self) -> LineRange { if self.a.y < self.b.y { - LineRange { min: self.a.y, max: self.b.y } + LineRange { + min: self.a.y, + max: self.b.y, + } } else { - LineRange { min: self.b.y, max: self.a.y } + LineRange { + min: self.b.y, + max: self.a.y, + } } } @@ -23,7 +29,6 @@ impl XSegment { self.a.x != self.b.x } - #[inline(always)] pub(crate) fn is_not_intersect_y_range(&self, range: &LineRange) -> bool { range.min > self.a.y && range.min > self.b.y || range.max < self.a.y && range.max < self.b.y @@ -47,4 +52,4 @@ impl Ord for XSegment { a } } -} \ No newline at end of file +} diff --git a/iOverlay/src/lib.rs b/iOverlay/src/lib.rs index 27b3ac3..16db78a 100644 --- a/iOverlay/src/lib.rs +++ b/iOverlay/src/lib.rs @@ -190,18 +190,18 @@ #![no_std] extern crate alloc; -pub mod mesh; pub mod build; pub mod core; -pub mod vector; pub mod float; -pub mod string; +pub mod mesh; pub mod segm; +pub mod string; +pub mod vector; -pub(crate) mod split; pub(crate) mod bind; pub(crate) mod geom; +pub(crate) mod split; pub(crate) mod util; pub use i_float; -pub use i_shape; \ No newline at end of file +pub use i_shape; diff --git a/iOverlay/src/mesh/extract.rs b/iOverlay/src/mesh/extract.rs index e086b5e..e0b22d5 100644 --- a/iOverlay/src/mesh/extract.rs +++ b/iOverlay/src/mesh/extract.rs @@ -1,18 +1,22 @@ -use alloc::vec; -use alloc::vec::Vec; -use i_shape::int::shape::{IntContour, IntShapes}; use crate::bind::segment::{ContourIndex, IdSegment}; use crate::bind::solver::{JoinHoles, LeftBottomSegment}; -use crate::core::extract::{GraphUtil, StartPathData, GraphContour, Visit, VisitState}; +use crate::core::extract::{GraphContour, GraphUtil, StartPathData, Visit, VisitState}; use crate::core::link::OverlayLinkFilter; use crate::core::overlay::ContourDirection; use crate::core::overlay_rule::OverlayRule; use crate::geom::v_segment::VSegment; use crate::mesh::graph::OffsetGraph; use crate::segm::segment::SUBJ_TOP; +use alloc::vec; +use alloc::vec::Vec; +use i_shape::int::shape::{IntContour, IntShapes}; impl OffsetGraph<'_> { - pub(crate) fn extract_offset(&self, main_direction: ContourDirection, min_area: u64) -> IntShapes { + pub(crate) fn extract_offset( + &self, + main_direction: ContourDirection, + min_area: u64, + ) -> IntShapes { let visited = self.links.filter_by_overlay(OverlayRule::Subject); self.extract_offset_shapes(visited, main_direction, min_area) } @@ -54,8 +58,7 @@ impl OffsetGraph<'_> { let start_data = StartPathData::new(direction, link, left_top_link); - let mut contour = - self.get_fill_contour(&start_data, direction, &mut bold, visited); + let mut contour = self.get_fill_contour(&start_data, direction, &mut bold, visited); if !bold { link_index += 1; continue; @@ -124,14 +127,8 @@ impl OffsetGraph<'_> { // Find a closed tour while node_id != last_node_id { - link_id = GraphUtil::next_link( - self.links, - self.nodes, - link_id, - node_id, - clockwise, - visited, - ); + link_id = + GraphUtil::next_link(self.links, self.nodes, link_id, node_id, clockwise, visited); let link = unsafe { // SAFETY: `link_id` is always derived from a previous in-bounds index or diff --git a/iOverlay/src/mesh/graph.rs b/iOverlay/src/mesh/graph.rs index 67e4980..169ceda 100644 --- a/iOverlay/src/mesh/graph.rs +++ b/iOverlay/src/mesh/graph.rs @@ -4,4 +4,4 @@ use crate::core::link::OverlayLink; pub struct OffsetGraph<'a> { pub(crate) nodes: &'a [OverlayNode], pub(crate) links: &'a [OverlayLink], -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/math.rs b/iOverlay/src/mesh/math.rs index c12cf6d..b81f3a7 100644 --- a/iOverlay/src/mesh/math.rs +++ b/iOverlay/src/mesh/math.rs @@ -17,4 +17,4 @@ impl> Math { let t = P::from_xy(-p.y(), p.x()); FloatPointMath::scale(&t, s) } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/mod.rs b/iOverlay/src/mesh/mod.rs index df0fb80..d6f71b7 100644 --- a/iOverlay/src/mesh/mod.rs +++ b/iOverlay/src/mesh/mod.rs @@ -1,10 +1,10 @@ -pub mod stroke; -pub mod outline; -pub(crate) mod math; +mod extract; pub(crate) mod graph; -mod rotator; -mod subject; -pub mod style; +pub(crate) mod math; mod miter; +pub mod outline; mod overlay; -mod extract; \ No newline at end of file +mod rotator; +pub mod stroke; +pub mod style; +mod subject; diff --git a/iOverlay/src/mesh/outline/builder.rs b/iOverlay/src/mesh/outline/builder.rs index 6c157d8..202af53 100644 --- a/iOverlay/src/mesh/outline/builder.rs +++ b/iOverlay/src/mesh/outline/builder.rs @@ -1,14 +1,16 @@ +use crate::mesh::outline::builder_join::{ + BevelJoinBuilder, JoinBuilder, MiterJoinBuilder, RoundJoinBuilder, +}; +use crate::mesh::outline::section::{Section, SectionToSegment}; +use crate::mesh::style::LineJoin; +use crate::segm::offset::ShapeCountOffset; +use crate::segm::segment::Segment; use alloc::boxed::Box; use alloc::vec::Vec; use core::marker::PhantomData; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; -use crate::mesh::outline::builder_join::{JoinBuilder, BevelJoinBuilder, MiterJoinBuilder, RoundJoinBuilder}; -use crate::mesh::outline::section::{Section, SectionToSegment}; -use crate::mesh::style::LineJoin; -use crate::segm::offset::ShapeCountOffset; -use crate::segm::segment::Segment; trait OutlineBuild, T: FloatNumber> { fn build( @@ -23,7 +25,7 @@ trait OutlineBuild, T: FloatNumber> { } pub(super) struct OutlineBuilder, T: FloatNumber> { - builder: Box> + builder: Box>, } struct Builder, P: FloatPointCompatible, T: FloatNumber> { @@ -34,7 +36,6 @@ struct Builder, P: FloatPointCompatible, T: FloatNumber> impl + 'static, T: FloatNumber + 'static> OutlineBuilder { pub(super) fn new(radius: T, join: &LineJoin) -> OutlineBuilder { - let builder: Box> = match join { LineJoin::Miter(ratio) => Box::new(Builder { radius, @@ -67,10 +68,7 @@ impl + 'static, T: FloatNumber + 'static> OutlineBuil } #[inline] - pub(super) fn capacity( - &self, - points_count: usize, - ) -> usize { + pub(super) fn capacity(&self, points_count: usize) -> usize { self.builder.capacity(points_count) } @@ -80,7 +78,8 @@ impl + 'static, T: FloatNumber + 'static> OutlineBuil } } -impl, P: FloatPointCompatible, T: FloatNumber> OutlineBuild for Builder +impl, P: FloatPointCompatible, T: FloatNumber> OutlineBuild + for Builder { #[inline] fn build( @@ -89,12 +88,16 @@ impl, P: FloatPointCompatible, T: FloatNumber> OutlineBu adapter: &FloatPointAdapter, segments: &mut Vec>, ) { - if path.len() < 2 { return; } + if path.len() < 2 { + return; + } // build segments only from points which are not equal in int space let i0 = path.len() - 1; let i1 = Self::next_unique_point(i0, 0, path, adapter); - if i1 == usize::MAX { return } + if i1 == usize::MAX { + return; + } let start = Section::new(self.radius, &path[i0], &path[i1]); let mut s0 = start.clone(); @@ -127,7 +130,12 @@ impl, P: FloatPointCompatible, T: FloatNumber> OutlineBu impl, P: FloatPointCompatible, T: FloatNumber> Builder { #[inline] - fn next_unique_point(start: usize, index: usize, path: &[P], adapter: &FloatPointAdapter) -> usize { + fn next_unique_point( + start: usize, + index: usize, + path: &[P], + adapter: &FloatPointAdapter, + ) -> usize { let a = adapter.float_to_int(&path[start]); for (j, p) in path.iter().enumerate().skip(index) { let b = adapter.float_to_int(p); @@ -138,4 +146,4 @@ impl, P: FloatPointCompatible, T: FloatNumber> Builder, T: FloatNumber> { fn add_join( @@ -48,7 +48,6 @@ impl BevelJoinBuilder { segments.push(Segment::weak_subject_ab(ia, ib)); } } - } impl> JoinBuilder for BevelJoinBuilder { @@ -120,7 +119,7 @@ impl> JoinBuilder for MiterJoin let turn = cross_product >= T::from_float(0.0); if turn == self.expand { BevelJoinBuilder::join_weak(s0, s1, adapter, segments); - return + return; } let pa = s0.b_top; @@ -132,7 +131,7 @@ impl> JoinBuilder for MiterJoin let sq_len = ia.sqr_distance(ib); if sq_len < 4 { BevelJoinBuilder::join_weak(s0, s1, adapter, segments); - return + return; } let dot_product = FloatPointMath::dot_product(&s0.dir, &s1.dir); @@ -167,7 +166,7 @@ impl> JoinBuilder for MiterJoin SharpMiter::AcB(a, c, b) => { segments.push(Segment::bold_subject_ab(a, c)); segments.push(Segment::bold_subject_ab(c, b)); - }, + } SharpMiter::Degenerate => {} } } @@ -227,7 +226,7 @@ impl> JoinBuilder for RoundJoin let turn = cross_product >= T::from_float(0.0); if turn == self.expand { BevelJoinBuilder::join_weak(s0, s1, adapter, segments); - return + return; } let dot_product = FloatPointMath::dot_product(&s0.dir, &s1.dir); @@ -277,4 +276,4 @@ impl> JoinBuilder for RoundJoin // add extra 10% to avoid problems with floating point precision. T::from_float(1.1) * radius } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/outline/mod.rs b/iOverlay/src/mesh/outline/mod.rs index 5a72b90..adf7353 100644 --- a/iOverlay/src/mesh/outline/mod.rs +++ b/iOverlay/src/mesh/outline/mod.rs @@ -1,4 +1,4 @@ -pub mod offset; mod builder; mod builder_join; +pub mod offset; mod section; diff --git a/iOverlay/src/mesh/outline/offset.rs b/iOverlay/src/mesh/outline/offset.rs index 088bc06..98fc9c9 100644 --- a/iOverlay/src/mesh/outline/offset.rs +++ b/iOverlay/src/mesh/outline/offset.rs @@ -1,23 +1,23 @@ -use i_shape::source::resource::ShapeResource; -use alloc::vec; -use alloc::vec::Vec; use crate::core::fill_rule::FillRule; use crate::core::overlay::{ContourDirection, Overlay, ShapeType}; use crate::core::overlay_rule::OverlayRule; use crate::float::overlay::OverlayOptions; use crate::float::scale::FixedScaleOverlayError; use crate::mesh::outline::builder::OutlineBuilder; +use crate::mesh::overlay::OffsetOverlay; use crate::mesh::style::OutlineStyle; +use alloc::vec; +use alloc::vec::Vec; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; use i_float::float::rect::FloatRect; use i_shape::base::data::Shapes; use i_shape::float::adapter::ShapesToFloat; -use i_shape::float::int_area::IntArea; use i_shape::float::despike::DeSpikeContour; +use i_shape::float::int_area::IntArea; use i_shape::float::simple::SimplifyContour; -use crate::mesh::overlay::OffsetOverlay; +use i_shape::source::resource::ShapeResource; pub trait OutlineOffset, T: FloatNumber> { /// Generates an outline shapes for contours, or shapes. @@ -175,7 +175,10 @@ impl + 'static, T: FloatNumber + 'static> OutlineSolv } fn build>(self, source: &S, options: OverlayOptions) -> Shapes

{ - let int_min_area = self.adapter.sqr_float_to_int(options.min_output_area).max(1); + let int_min_area = self + .adapter + .sqr_float_to_int(options.min_output_area) + .max(1); let shapes = if self.paths_count <= 1 { // fast solution for a single path @@ -250,7 +253,8 @@ impl + 'static, T: FloatNumber + 'static> OutlineSolv } segments.clear(); - self.inner_builder.build(&inverted, &self.adapter, &mut segments); + self.inner_builder + .build(&inverted, &self.adapter, &mut segments); offset_overlay.clear(); offset_overlay.add_segments(&segments); @@ -289,9 +293,9 @@ impl + 'static, T: FloatNumber + 'static> OutlineSolv #[cfg(test)] mod tests { - use alloc::vec; use crate::mesh::outline::offset::OutlineOffset; use crate::mesh::style::{LineJoin, OutlineStyle}; + use alloc::vec; use core::f32::consts::PI; #[test] @@ -408,10 +412,15 @@ mod tests { #[test] fn test_float_square_0() { let shape = vec![vec![ - [300.0, 300.0], [500.0, 300.0], [500.0, 500.0], [300.0, 500.0] + [300.0, 300.0], + [500.0, 300.0], + [500.0, 500.0], + [300.0, 500.0], ]]; - let style = OutlineStyle::default().outer_offset(50.0).inner_offset(50.0); + let style = OutlineStyle::default() + .outer_offset(50.0) + .inner_offset(50.0); let shapes = shape.outline(&style); @@ -474,7 +483,7 @@ mod tests { [5400.0, 5891947.742386343], [5400.0, 5892817.151239874], [4804.8188261491, 5892876.799252035], - [4804.81882805645, 5892876.799253942] + [4804.81882805645, 5892876.799253942], ]; let angle = 10.0f64 / (core::f64::consts::PI / 2.0f64); diff --git a/iOverlay/src/mesh/outline/section.rs b/iOverlay/src/mesh/outline/section.rs index 7785dec..b2a93ef 100644 --- a/iOverlay/src/mesh/outline/section.rs +++ b/iOverlay/src/mesh/outline/section.rs @@ -1,12 +1,12 @@ +use crate::mesh::math::Math; +use crate::segm::offset::ShapeCountOffset; +use crate::segm::segment::Segment; use alloc::vec::Vec; use core::marker::PhantomData; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; use i_float::float::vector::FloatPointMath; -use crate::mesh::math::Math; -use crate::segm::offset::ShapeCountOffset; -use crate::segm::segment::Segment; #[derive(Debug, Clone)] pub(super) struct Section, T: FloatNumber> { @@ -39,7 +39,9 @@ pub(crate) trait SectionToSegment> { fn add_section(&mut self, section: &Section, adapter: &FloatPointAdapter); } -impl> SectionToSegment for Vec> { +impl> SectionToSegment + for Vec> +{ fn add_section(&mut self, section: &Section, adapter: &FloatPointAdapter) { let a_top = adapter.float_to_int(§ion.a_top); let b_top = adapter.float_to_int(§ion.b_top); @@ -47,4 +49,4 @@ impl> SectionToSegment for Vec< self.push(Segment::bold_subject_ab(a_top, b_top)); } } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/overlay.rs b/iOverlay/src/mesh/overlay.rs index a0a1c8d..26dbb90 100644 --- a/iOverlay/src/mesh/overlay.rs +++ b/iOverlay/src/mesh/overlay.rs @@ -1,4 +1,3 @@ -use alloc::vec::Vec; use crate::build::builder::GraphBuilder; use crate::core::graph::OverlayNode; use crate::core::solver::Solver; @@ -6,11 +5,12 @@ use crate::mesh::graph::OffsetGraph; use crate::segm::offset::ShapeCountOffset; use crate::segm::segment::Segment; use crate::split::solver::SplitSolver; +use alloc::vec::Vec; pub struct OffsetOverlay { pub(super) segments: Vec>, pub(crate) split_solver: SplitSolver, - pub(crate) graph_builder: GraphBuilder + pub(crate) graph_builder: GraphBuilder, } impl OffsetOverlay { @@ -19,7 +19,7 @@ impl OffsetOverlay { Self { segments: Vec::with_capacity(capacity), split_solver: SplitSolver::new(), - graph_builder: GraphBuilder::::new() + graph_builder: GraphBuilder::::new(), } } @@ -28,7 +28,6 @@ impl OffsetOverlay { self.segments.clear(); } - #[inline] pub fn add_segments(&mut self, segments: &[Segment]) { self.segments.extend_from_slice(segments); @@ -39,20 +38,19 @@ impl OffsetOverlay { Self { segments, split_solver: SplitSolver::new(), - graph_builder: GraphBuilder::::new() + graph_builder: GraphBuilder::::new(), } } #[inline] pub fn build_graph_view_with_solver(&mut self, solver: Solver) -> Option> { - self.split_solver.split_segments(&mut self.segments, &solver); + self.split_solver + .split_segments(&mut self.segments, &solver); if self.segments.is_empty() { return None; } - let graph = self - .graph_builder - .build_offset(&solver, &self.segments); + let graph = self.graph_builder.build_offset(&solver, &self.segments); Some(graph) } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/rotator.rs b/iOverlay/src/mesh/rotator.rs index 8e49967..5ab4e93 100644 --- a/iOverlay/src/mesh/rotator.rs +++ b/iOverlay/src/mesh/rotator.rs @@ -9,7 +9,6 @@ pub(crate) struct Rotator { } impl Rotator { - #[inline] pub(crate) fn new(cs: T, sn: T) -> Self { let a_x = cs; @@ -17,12 +16,7 @@ impl Rotator { let b_x = -a_y; let b_y = a_x; - Self { - a_x, - a_y, - b_x, - b_y, - } + Self { a_x, a_y, b_x, b_y } } #[inline] @@ -48,9 +42,8 @@ impl Rotator { #[cfg(test)] mod tests { - use core::f64::consts::PI; use crate::mesh::rotator::Rotator; - + use core::f64::consts::PI; #[test] fn test_ccw_rotate() { @@ -88,4 +81,4 @@ mod tests { assert!((v0[0] - v1[0]).abs() < 0.0001); assert!((v0[1] - v1[1]).abs() < 0.0001); } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/stroke/builder.rs b/iOverlay/src/mesh/stroke/builder.rs index 6c5784a..76c6222 100644 --- a/iOverlay/src/mesh/stroke/builder.rs +++ b/iOverlay/src/mesh/stroke/builder.rs @@ -1,16 +1,16 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; use crate::mesh::stroke::builder_cap::CapBuilder; use crate::mesh::stroke::builder_join::{ BevelJoinBuilder, JoinBuilder, MiterJoinBuilder, RoundJoinBuilder, }; use crate::mesh::stroke::section::{Section, SectionToSegment}; use crate::mesh::style::{LineJoin, StrokeStyle}; +use crate::segm::offset::ShapeCountOffset; use crate::segm::segment::Segment; +use alloc::boxed::Box; +use alloc::vec::Vec; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; -use crate::segm::offset::ShapeCountOffset; trait StrokeBuild, T: FloatNumber> { fn build( @@ -85,7 +85,8 @@ impl + 'static, T: FloatNumber + 'static> StrokeBuild points_count: usize, is_closed_path: bool, ) -> usize { - self.builder.capacity(paths_count, points_count, is_closed_path) + self.builder + .capacity(paths_count, points_count, is_closed_path) } #[inline] @@ -94,7 +95,8 @@ impl + 'static, T: FloatNumber + 'static> StrokeBuild } } -impl, P: FloatPointCompatible, T: FloatNumber> StrokeBuild for Builder +impl, P: FloatPointCompatible, T: FloatNumber> StrokeBuild + for Builder { #[inline] fn build( @@ -142,7 +144,7 @@ impl, P: FloatPointCompatible, T: FloatNumber> Builder, P: FloatPointCompatible, T: FloatNumber> Builder= n { return; } + if j >= n { + return; + } ip = adapter.float_to_int(&path[j]); } @@ -162,13 +166,14 @@ impl, P: FloatPointCompatible, T: FloatNumber> Builder= n { break 'main_loop; } + if j >= n { + break 'main_loop; + } p = &path[j]; ip = adapter.float_to_int(p); } @@ -188,12 +193,16 @@ impl, P: FloatPointCompatible, T: FloatNumber> Builder, segments: &mut Vec>, ) { - if path.len() < 2 { return; } + if path.len() < 2 { + return; + } // build segments only from points which are not equal in int space let i0 = path.len() - 1; let i1 = Self::next_unique_point(i0, 0, path, adapter); - if i1 == usize::MAX { return } + if i1 == usize::MAX { + return; + } let start = Section::new(self.radius, &path[i0], &path[i1]); let mut s0 = start.clone(); @@ -214,7 +223,12 @@ impl, P: FloatPointCompatible, T: FloatNumber> Builder) -> usize { + fn next_unique_point( + start: usize, + index: usize, + path: &[P], + adapter: &FloatPointAdapter, + ) -> usize { let a = adapter.float_to_int(&path[start]); for (j, p) in path.iter().enumerate().skip(index) { let b = adapter.float_to_int(p); @@ -225,5 +239,4 @@ impl, P: FloatPointCompatible, T: FloatNumber> Builder { @@ -20,16 +20,18 @@ pub(super) struct CapBuilder { } impl> CapBuilder { - pub(super) fn new(cap: LineCap, radius: T) -> Self { let points = match cap { LineCap::Butt => None, LineCap::Round(ratio) => Some(Self::round_points(ratio, radius)), LineCap::Square => Some(Self::square_points(radius)), - LineCap::Custom(points) => Some(Self::custom_points(points.to_vec(), radius)) + LineCap::Custom(points) => Some(Self::custom_points(points.to_vec(), radius)), }; - Self { points, _phantom: Default::default() } + Self { + points, + _phantom: Default::default(), + } } pub(super) fn round_points(angle: T, r: T) -> Vec

{ @@ -69,7 +71,12 @@ impl> CapBuilder { scaled } - pub(super) fn add_to_start(&self, section: &Section, adapter: &FloatPointAdapter, segments: &mut Vec>) { + pub(super) fn add_to_start( + &self, + section: &Section, + adapter: &FloatPointAdapter, + segments: &mut Vec>, + ) { let mut a = adapter.float_to_int(§ion.a_top); if let Some(points) = &self.points { let dir = P::from_xy(-section.dir.x(), -section.dir.y()); @@ -86,7 +93,12 @@ impl> CapBuilder { segments.push(Segment::bold_subject_ab(a, last)); } - pub(super) fn add_to_end(&self, section: &Section, adapter: &FloatPointAdapter, segments: &mut Vec>) { + pub(super) fn add_to_end( + &self, + section: &Section, + adapter: &FloatPointAdapter, + segments: &mut Vec>, + ) { let mut a = adapter.float_to_int(§ion.b_bot); if let Some(points) = &self.points { let rotator = Rotator::with_vector(§ion.dir); @@ -123,4 +135,4 @@ impl> CapBuilder { T::from_float(0.0) } } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/stroke/builder_join.rs b/iOverlay/src/mesh/stroke/builder_join.rs index 80e269c..33760d9 100644 --- a/iOverlay/src/mesh/stroke/builder_join.rs +++ b/iOverlay/src/mesh/stroke/builder_join.rs @@ -1,14 +1,14 @@ -use alloc::vec::Vec; +use crate::mesh::miter::{Miter, SharpMiter}; +use crate::mesh::rotator::Rotator; use crate::mesh::stroke::section::Section; +use crate::segm::offset::ShapeCountOffset; use crate::segm::segment::Segment; +use alloc::vec::Vec; +use core::f64::consts::PI; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; -use core::f64::consts::PI; use i_float::float::vector::FloatPointMath; -use crate::mesh::miter::{Miter, SharpMiter}; -use crate::mesh::rotator::Rotator; -use crate::segm::offset::ShapeCountOffset; pub(super) trait JoinBuilder, T: FloatNumber> { fn add_join( @@ -58,7 +58,6 @@ impl BevelJoinBuilder { segments.push(Segment::bold_subject_ab(ib, ia)); } } - } impl> JoinBuilder for BevelJoinBuilder { @@ -113,7 +112,7 @@ impl MiterJoinBuilder { Self { limit_dot_product, max_offset, - max_length + max_length, } } } @@ -200,7 +199,7 @@ impl> JoinBuilder for MiterJoin SharpMiter::AcB(a, c, b) => { segments.push(Segment::bold_subject_ab(c, a)); segments.push(Segment::bold_subject_ab(b, c)); - }, + } SharpMiter::Degenerate => {} } } @@ -299,4 +298,4 @@ impl> JoinBuilder for RoundJoin // add extra 10% to avoid problems with floating point precision. T::from_float(1.1) * radius } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/stroke/mod.rs b/iOverlay/src/mesh/stroke/mod.rs index 79abf62..4d1e138 100644 --- a/iOverlay/src/mesh/stroke/mod.rs +++ b/iOverlay/src/mesh/stroke/mod.rs @@ -1,5 +1,5 @@ -pub mod offset; +mod builder; +mod builder_cap; mod builder_join; +pub mod offset; mod section; -mod builder; -mod builder_cap; \ No newline at end of file diff --git a/iOverlay/src/mesh/stroke/section.rs b/iOverlay/src/mesh/stroke/section.rs index fb54f58..a62f0bb 100644 --- a/iOverlay/src/mesh/stroke/section.rs +++ b/iOverlay/src/mesh/stroke/section.rs @@ -1,12 +1,12 @@ +use crate::mesh::math::Math; +use crate::segm::offset::ShapeCountOffset; +use crate::segm::segment::Segment; use alloc::vec::Vec; use core::marker::PhantomData; use i_float::adapter::FloatPointAdapter; use i_float::float::compatible::FloatPointCompatible; use i_float::float::number::FloatNumber; use i_float::float::vector::FloatPointMath; -use crate::mesh::math::Math; -use crate::segm::offset::ShapeCountOffset; -use crate::segm::segment::Segment; #[derive(Debug, Clone)] pub(super) struct Section, T: FloatNumber> { @@ -48,7 +48,9 @@ pub(crate) trait SectionToSegment> { fn add_section(&mut self, section: &Section, adapter: &FloatPointAdapter); } -impl> SectionToSegment for Vec> { +impl> SectionToSegment + for Vec> +{ fn add_section(&mut self, section: &Section, adapter: &FloatPointAdapter) { let a_top = adapter.float_to_int(§ion.a_top); let b_top = adapter.float_to_int(§ion.b_top); @@ -62,4 +64,4 @@ impl> SectionToSegment for Vec< self.push(Segment::bold_subject_ab(a_bot, b_bot)); } } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/style.rs b/iOverlay/src/mesh/style.rs index 1d91944..5ddbf45 100644 --- a/iOverlay/src/mesh/style.rs +++ b/iOverlay/src/mesh/style.rs @@ -14,7 +14,7 @@ pub enum LineCap, T: FloatNumber> { /// A line with a squared-off end. An extended distance equal to half the line width. Square, /// Set a custom end with template points. - Custom(Rc<[P]>) + Custom(Rc<[P]>), } /// The join style of a line. @@ -75,7 +75,7 @@ impl LineJoin { let a = angle.to_f64().clamp(0.01 * PI, 0.25 * PI); LineJoin::Round(T::from_float(a)) } - _ => self + _ => self, } } } @@ -83,7 +83,10 @@ impl LineJoin { impl, T: FloatNumber> StrokeStyle { /// Creates a new `StrokeStyle` with the specified width. pub fn new(width: T) -> Self { - Self { width, ..Default::default() } + Self { + width, + ..Default::default() + } } /// Sets the stroke width. @@ -117,16 +120,19 @@ impl, T: FloatNumber> Default for StrokeStyle { width: T::from_float(1.0), start_cap: LineCap::Butt, end_cap: LineCap::Butt, - join: LineJoin::Bevel + join: LineJoin::Bevel, } } } impl OutlineStyle { - /// Creates a new `OutlineStyle` with the specified offset. pub fn new(offset: T) -> Self { - Self { outer_offset: offset, inner_offset: offset, ..Default::default() } + Self { + outer_offset: offset, + inner_offset: offset, + ..Default::default() + } } /// Sets the offset distance. @@ -160,7 +166,7 @@ impl Default for OutlineStyle { Self { outer_offset: T::from_float(1.0), inner_offset: T::from_float(1.0), - join: LineJoin::Bevel + join: LineJoin::Bevel, } } -} \ No newline at end of file +} diff --git a/iOverlay/src/mesh/subject.rs b/iOverlay/src/mesh/subject.rs index 11c9294..bfa2dc6 100644 --- a/iOverlay/src/mesh/subject.rs +++ b/iOverlay/src/mesh/subject.rs @@ -1,21 +1,26 @@ use crate::geom::x_segment::XSegment; +use crate::segm::offset::ShapeCountOffset; use crate::segm::segment::Segment; use i_float::int::point::IntPoint; -use crate::segm::offset::ShapeCountOffset; impl Segment { - #[inline] pub(crate) fn bold_subject_ab(p0: IntPoint, p1: IntPoint) -> Self { if p0 < p1 { Self { x_segment: XSegment { a: p0, b: p1 }, - count: ShapeCountOffset { subj: 1, bold: true }, + count: ShapeCountOffset { + subj: 1, + bold: true, + }, } } else { Self { x_segment: XSegment { a: p1, b: p0 }, - count: ShapeCountOffset { subj: -1, bold: true }, + count: ShapeCountOffset { + subj: -1, + bold: true, + }, } } } @@ -25,13 +30,19 @@ impl Segment { if p0 < p1 { Self { x_segment: XSegment { a: p0, b: p1 }, - count: ShapeCountOffset { subj: 1, bold: false }, + count: ShapeCountOffset { + subj: 1, + bold: false, + }, } } else { Self { x_segment: XSegment { a: p1, b: p0 }, - count: ShapeCountOffset { subj: -1, bold: false }, + count: ShapeCountOffset { + subj: -1, + bold: false, + }, } } } -} \ No newline at end of file +} diff --git a/iOverlay/src/segm/boolean.rs b/iOverlay/src/segm/boolean.rs index 10b5a15..13662d4 100644 --- a/iOverlay/src/segm/boolean.rs +++ b/iOverlay/src/segm/boolean.rs @@ -16,16 +16,26 @@ impl ShapeCountBoolean { impl WindingCount for ShapeCountBoolean { #[inline(always)] - fn is_not_empty(&self) -> bool { self.subj != 0 || self.clip != 0 } + fn is_not_empty(&self) -> bool { + self.subj != 0 || self.clip != 0 + } #[inline(always)] - fn new(subj: i32, clip: i32) -> Self { Self { subj, clip } } + fn new(subj: i32, clip: i32) -> Self { + Self { subj, clip } + } #[inline(always)] fn with_shape_type(shape_type: ShapeType) -> (Self, Self) { match shape_type { - ShapeType::Subject => (ShapeCountBoolean::SUBJ_DIRECT, ShapeCountBoolean::SUBJ_INVERT), - ShapeType::Clip => (ShapeCountBoolean::CLIP_DIRECT, ShapeCountBoolean::CLIP_INVERT) + ShapeType::Subject => ( + ShapeCountBoolean::SUBJ_DIRECT, + ShapeCountBoolean::SUBJ_INVERT, + ), + ShapeType::Clip => ( + ShapeCountBoolean::CLIP_DIRECT, + ShapeCountBoolean::CLIP_INVERT, + ), } } @@ -45,6 +55,9 @@ impl WindingCount for ShapeCountBoolean { #[inline(always)] fn invert(self) -> Self { - Self { subj: -self.subj, clip: -self.clip } + Self { + subj: -self.subj, + clip: -self.clip, + } } -} \ No newline at end of file +} diff --git a/iOverlay/src/segm/build.rs b/iOverlay/src/segm/build.rs index 21e26d7..083a73b 100644 --- a/iOverlay/src/segm/build.rs +++ b/iOverlay/src/segm/build.rs @@ -36,8 +36,16 @@ fn build_segments_with_filter, C: W shape_type: ShapeType, ) -> bool { // our goal add all not degenerate segments - let mut p0 = if let Some(p) = iter.next() { p } else { return false; }; - let mut p1 = if let Some(p) = iter.find(|p| p0.ne(p)) { p } else { return true; }; + let mut p0 = if let Some(p) = iter.next() { + p + } else { + return false; + }; + let mut p1 = if let Some(p) = iter.find(|p| p0.ne(p)) { + p + } else { + return true; + }; let mut filtered = false; diff --git a/iOverlay/src/segm/merge.rs b/iOverlay/src/segm/merge.rs index ffab199..d383858 100644 --- a/iOverlay/src/segm/merge.rs +++ b/iOverlay/src/segm/merge.rs @@ -1,6 +1,6 @@ -use alloc::vec::Vec; use crate::segm::segment::Segment; use crate::segm::winding::WindingCount; +use alloc::vec::Vec; pub(crate) trait ShapeSegmentsMerge { fn merge_if_needed(&mut self) -> bool; @@ -8,7 +8,9 @@ pub(crate) trait ShapeSegmentsMerge { impl ShapeSegmentsMerge for Vec> { fn merge_if_needed(&mut self) -> bool { - if self.len() < 2 { return false; } + if self.len() < 2 { + return false; + } let mut prev = &self[0].x_segment; for i in 1..self.len() { @@ -53,16 +55,19 @@ fn merge(segments: &mut [Segment], after: usize) -> usize { #[cfg(test)] mod tests { - use alloc::vec; -use crate::segm::boolean::ShapeCountBoolean; -use i_float::int::point::IntPoint; use super::*; + use crate::segm::boolean::ShapeCountBoolean; + use alloc::vec; + use i_float::int::point::IntPoint; #[test] fn test_merge_if_needed_empty() { let mut segments: Vec> = Vec::new(); segments.merge_if_needed(); - assert!(segments.is_empty(), "Empty vector should remain empty after merge"); + assert!( + segments.is_empty(), + "Empty vector should remain empty after merge" + ); } #[test] @@ -74,7 +79,10 @@ use i_float::int::point::IntPoint; let mut segments = vec![segment]; segments.merge_if_needed(); assert_eq!(segments.len(), 1, "Single segment should remain unchanged"); - assert_eq!(segments[0], segment, "Segment should be unchanged after merge"); + assert_eq!( + segments[0], segment, + "Segment should be unchanged after merge" + ); } #[test] @@ -92,9 +100,19 @@ use i_float::int::point::IntPoint; let mut segments = vec![segment1, segment2]; segments.merge_if_needed(); - assert_eq!(segments.len(), 2, "Segments with different x_segments should not be merged"); - assert_eq!(segments[0], segment1, "First segment should remain unchanged"); - assert_eq!(segments[1], segment2, "Second segment should remain unchanged"); + assert_eq!( + segments.len(), + 2, + "Segments with different x_segments should not be merged" + ); + assert_eq!( + segments[0], segment1, + "First segment should remain unchanged" + ); + assert_eq!( + segments[1], segment2, + "Second segment should remain unchanged" + ); } #[test] @@ -115,7 +133,10 @@ use i_float::int::point::IntPoint; assert_eq!(segments.len(), 1, "Segments should be merged into one"); let merged_count = ShapeCountBoolean::new(1, 1); let expected_segment = Segment::create_and_validate(a1, b1, merged_count); - assert_eq!(segments[0], expected_segment, "Merged segment should have combined counts"); + assert_eq!( + segments[0], expected_segment, + "Merged segment should have combined counts" + ); } #[test] @@ -137,7 +158,10 @@ use i_float::int::point::IntPoint; assert_eq!(segments.len(), 1, "All segments should be merged into one"); let merged_count = ShapeCountBoolean::new(3, 3); let expected_segment = Segment::create_and_validate(a, b, merged_count); - assert_eq!(segments[0], expected_segment, "Merged segment should have combined counts"); + assert_eq!( + segments[0], expected_segment, + "Merged segment should have combined counts" + ); } #[test] @@ -157,11 +181,19 @@ use i_float::int::point::IntPoint; segments.merge_if_needed(); // Both segments should have the same ordered x_segment - assert_eq!(segments.len(), 1, "Segments with inverted points should be merged"); + assert_eq!( + segments.len(), + 1, + "Segments with inverted points should be merged" + ); let merged_count = ShapeCountBoolean::new(1, 1); - let expected_segment = Segment::create_and_validate(IntPoint::new(1, 2), IntPoint::new(3, 4), merged_count); - assert_eq!(segments[0], expected_segment, "Merged segment should have combined counts and ordered points"); + let expected_segment = + Segment::create_and_validate(IntPoint::new(1, 2), IntPoint::new(3, 4), merged_count); + assert_eq!( + segments[0], expected_segment, + "Merged segment should have combined counts and ordered points" + ); } #[test] @@ -184,9 +216,22 @@ use i_float::int::point::IntPoint; let mut segments = vec![segment1, segment2, segment3]; segments.merge_if_needed(); - assert_eq!(segments.len(), 3, "Segments with different x_segments should not be merged"); - assert_eq!(segments[0], segment1, "First segment should remain unchanged"); - assert_eq!(segments[1], segment2, "Second segment should remain unchanged"); - assert_eq!(segments[2], segment3, "Third segment should remain unchanged"); + assert_eq!( + segments.len(), + 3, + "Segments with different x_segments should not be merged" + ); + assert_eq!( + segments[0], segment1, + "First segment should remain unchanged" + ); + assert_eq!( + segments[1], segment2, + "Second segment should remain unchanged" + ); + assert_eq!( + segments[2], segment3, + "Third segment should remain unchanged" + ); } } diff --git a/iOverlay/src/segm/mod.rs b/iOverlay/src/segm/mod.rs index 844acd6..857ffd7 100644 --- a/iOverlay/src/segm/mod.rs +++ b/iOverlay/src/segm/mod.rs @@ -1,8 +1,8 @@ -pub mod winding; pub mod boolean; -pub mod string; +pub(crate) mod build; +pub(crate) mod merge; pub mod offset; pub(crate) mod segment; -pub(crate) mod merge; -pub(crate) mod build; -pub(crate) mod sort; \ No newline at end of file +pub(crate) mod sort; +pub mod string; +pub mod winding; diff --git a/iOverlay/src/segm/offset.rs b/iOverlay/src/segm/offset.rs index 6a17033..341fb14 100644 --- a/iOverlay/src/segm/offset.rs +++ b/iOverlay/src/segm/offset.rs @@ -9,18 +9,21 @@ pub struct ShapeCountOffset { impl WindingCount for ShapeCountOffset { #[inline(always)] - fn is_not_empty(&self) -> bool { self.subj != 0 } + fn is_not_empty(&self) -> bool { + self.subj != 0 + } #[inline(always)] fn new(subj: i32, _: i32) -> Self { - Self {subj, bold: true} + Self { subj, bold: true } } #[inline(always)] + #[rustfmt::skip] fn with_shape_type(shape_type: ShapeType) -> (Self, Self) { match shape_type { - ShapeType::Subject => (Self {subj: 1, bold: true}, Self {subj: -1, bold: true}), - ShapeType::Clip => (Self {subj: 0, bold: true}, Self {subj: 0, bold: true}), + ShapeType::Subject => (Self { subj: 1, bold: true }, Self { subj: -1, bold: true }), + ShapeType::Clip => (Self { subj: 0, bold: true }, Self { subj: 0, bold: true }), } } @@ -28,7 +31,7 @@ impl WindingCount for ShapeCountOffset { fn add(self, count: Self) -> Self { let subj = self.subj + count.subj; let bold = self.bold || count.bold; - Self {subj, bold} + Self { subj, bold } } #[inline(always)] @@ -40,6 +43,9 @@ impl WindingCount for ShapeCountOffset { #[inline(always)] fn invert(self) -> Self { let subj = -self.subj; - Self {subj, bold: self.bold} + Self { + subj, + bold: self.bold, + } } -} \ No newline at end of file +} diff --git a/iOverlay/src/segm/sort.rs b/iOverlay/src/segm/sort.rs index 52e0f90..263265e 100644 --- a/iOverlay/src/segm/sort.rs +++ b/iOverlay/src/segm/sort.rs @@ -1,5 +1,5 @@ -use i_key_sort::sort::two_keys_cmp::TwoKeysAndCmpSort; use crate::segm::segment::Segment; +use i_key_sort::sort::two_keys_cmp::TwoKeysAndCmpSort; pub(crate) trait ShapeSegmentsSort { fn sort_by_ab(&mut self, parallel: bool); @@ -12,7 +12,7 @@ impl ShapeSegmentsSort for [Segment] { parallel, |s| s.x_segment.a.x, |s| s.x_segment.a.y, - |s0, s1| s0.x_segment.b.cmp(&s1.x_segment.b) + |s0, s1| s0.x_segment.b.cmp(&s1.x_segment.b), ) } -} \ No newline at end of file +} diff --git a/iOverlay/src/segm/string.rs b/iOverlay/src/segm/string.rs index d7abfc8..72c7be4 100644 --- a/iOverlay/src/segm/string.rs +++ b/iOverlay/src/segm/string.rs @@ -1,6 +1,6 @@ -use core::cmp::Ordering; use crate::core::overlay::ShapeType; use crate::segm::winding::WindingCount; +use core::cmp::Ordering; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ShapeCountString { @@ -13,7 +13,9 @@ pub(crate) const STRING_BACK_CLIP: u8 = 0b1; impl WindingCount for ShapeCountString { #[inline(always)] - fn is_not_empty(&self) -> bool { self.subj != 0 || self.clip != 0 } + fn is_not_empty(&self) -> bool { + self.subj != 0 || self.clip != 0 + } #[inline(always)] fn new(subj: i32, clip: i32) -> Self { @@ -28,10 +30,11 @@ impl WindingCount for ShapeCountString { } #[inline(always)] + #[rustfmt::skip] fn with_shape_type(shape_type: ShapeType) -> (Self, Self) { match shape_type { ShapeType::Subject => (Self { subj: 1, clip: 0 }, Self { subj: -1, clip: 0 }), - ShapeType::Clip => (Self { subj: 0, clip: STRING_FORWARD_CLIP }, Self { subj: 0, clip: STRING_BACK_CLIP }) + ShapeType::Clip => (Self { subj: 0, clip: STRING_FORWARD_CLIP }, Self {subj: 0, clip: STRING_BACK_CLIP }), } } @@ -55,6 +58,9 @@ impl WindingCount for ShapeCountString { let b1 = self.clip & 0b10; let clip = (b0 << 1) | (b1 >> 1); - Self { subj: -self.subj, clip } + Self { + subj: -self.subj, + clip, + } } -} \ No newline at end of file +} diff --git a/iOverlay/src/segm/winding.rs b/iOverlay/src/segm/winding.rs index 3b62900..81cc7b3 100644 --- a/iOverlay/src/segm/winding.rs +++ b/iOverlay/src/segm/winding.rs @@ -10,4 +10,4 @@ where fn add(self, count: Self) -> Self; fn apply(&mut self, count: Self); fn invert(self) -> Self; -} \ No newline at end of file +} diff --git a/iOverlay/src/split/cross_solver.rs b/iOverlay/src/split/cross_solver.rs index 7f23382..4528545 100644 --- a/iOverlay/src/split/cross_solver.rs +++ b/iOverlay/src/split/cross_solver.rs @@ -1,8 +1,8 @@ +use crate::geom::x_segment::XSegment; use i_float::fix_vec::FixVec; use i_float::int::point::IntPoint; use i_float::triangle::Triangle; use i_float::u128::UInt128; -use crate::geom::x_segment::XSegment; pub(super) type CollinearMask = u8; @@ -21,7 +21,6 @@ const OTHER_A: u8 = 0b0100; const OTHER_B: u8 = 0b1000; impl EndMask for CollinearMask { - #[inline(always)] fn is_target_a(&self) -> bool { self & TARGET_A == TARGET_A @@ -69,7 +68,6 @@ pub(super) enum CrossType { pub(super) struct CrossSolver {} impl CrossSolver { - pub(super) fn cross(target: &XSegment, other: &XSegment, radius: i64) -> Option { let a0b0a1 = Triangle::clock_direction_point(target.a, target.b, other.a); let a0b0b1 = Triangle::clock_direction_point(target.a, target.b, other.b); @@ -136,7 +134,7 @@ impl CrossSolver { let ab0 = (a0 - b1).dot_product(v1).signum(); let ba0 = (b0 - a1).dot_product(v1).signum(); let bb0 = (b0 - b1).dot_product(v1).signum(); - + let aa1 = -aa0; let ab1 = -ba0; let ba1 = -ab0; @@ -154,7 +152,9 @@ impl CrossSolver { fn middle_cross(target: &XSegment, other: &XSegment, radius: i64) -> Option { let p = CrossSolver::cross_point(target, other); - if Triangle::is_line_point(target.a, p, target.b) && Triangle::is_line_point(other.a, p, other.b) { + if Triangle::is_line_point(target.a, p, target.b) + && Triangle::is_line_point(other.a, p, other.b) + { return Some(CrossResult { point: p, cross_type: CrossType::Pure, @@ -309,8 +309,6 @@ trait RoundDivide { } impl RoundDivide for UInt128 { - - fn divide_with_rounding(&self, divisor: u64) -> u64 { if self.high == 0 { let result = self.low / divisor; @@ -353,9 +351,9 @@ impl RoundDivide for UInt128 { #[cfg(test)] mod tests { - use i_float::int::point::IntPoint; - use crate::split::cross_solver::{CrossSolver, CrossType}; use crate::geom::x_segment::XSegment; + use crate::split::cross_solver::{CrossSolver, CrossType}; + use i_float::int::point::IntPoint; impl XSegment { fn new(a: IntPoint, b: IntPoint) -> Self { @@ -506,8 +504,14 @@ mod tests { #[test] fn test_real_case_2() { - let ea = XSegment::new(IntPoint::new(-8555798, -1599355), IntPoint::new(-1024000, 0)); - let eb = XSegment::new(IntPoint::new(-8571363, 1513719), IntPoint::new(-1023948, -10239)); + let ea = XSegment::new( + IntPoint::new(-8555798, -1599355), + IntPoint::new(-1024000, 0), + ); + let eb = XSegment::new( + IntPoint::new(-8571363, 1513719), + IntPoint::new(-1023948, -10239), + ); let result = CrossSolver::cross(&ea, &eb, 2).unwrap(); @@ -523,8 +527,14 @@ mod tests { #[test] fn test_real_case_3() { - let ea = XSegment::new(IntPoint::new(-8555798, -1599355), IntPoint::new(513224, -5243)); - let eb = XSegment::new(IntPoint::new(-8555798, -1599355), IntPoint::new(513224, -5243)); + let ea = XSegment::new( + IntPoint::new(-8555798, -1599355), + IntPoint::new(513224, -5243), + ); + let eb = XSegment::new( + IntPoint::new(-8555798, -1599355), + IntPoint::new(513224, -5243), + ); let result = CrossSolver::cross(&ea, &eb, 2).unwrap(); @@ -579,4 +589,4 @@ mod tests { } } } -} \ No newline at end of file +} diff --git a/iOverlay/src/split/fragment.rs b/iOverlay/src/split/fragment.rs index 995a510..63e898d 100644 --- a/iOverlay/src/split/fragment.rs +++ b/iOverlay/src/split/fragment.rs @@ -1,5 +1,5 @@ -use i_float::int::rect::IntRect; use crate::geom::x_segment::XSegment; +use i_float::int::rect::IntRect; #[derive(Debug, Clone)] pub(super) struct Fragment { @@ -9,7 +9,6 @@ pub(super) struct Fragment { } impl Fragment { - #[inline] pub(super) fn with_index_and_segment(index: usize, x_segment: XSegment) -> Self { let (min_y, max_y) = if x_segment.a.y < x_segment.b.y { @@ -31,4 +30,4 @@ impl Fragment { x_segment, } } -} \ No newline at end of file +} diff --git a/iOverlay/src/split/grid_layout.rs b/iOverlay/src/split/grid_layout.rs index 9ae2ce1..091913c 100644 --- a/iOverlay/src/split/grid_layout.rs +++ b/iOverlay/src/split/grid_layout.rs @@ -242,7 +242,6 @@ impl FragmentBuffer { } true } - } pub(super) struct GridLayout { diff --git a/iOverlay/src/split/line_mark.rs b/iOverlay/src/split/line_mark.rs index 6f6c360..21e7931 100644 --- a/iOverlay/src/split/line_mark.rs +++ b/iOverlay/src/split/line_mark.rs @@ -9,20 +9,12 @@ pub(super) struct LineMark { } pub(super) trait SortMarkByIndexAndPoint { - fn sort_by_index_and_point( - &mut self, - parallel: bool, - reusable_buffer: &mut Vec, - ); + fn sort_by_index_and_point(&mut self, parallel: bool, reusable_buffer: &mut Vec); } impl SortMarkByIndexAndPoint for [LineMark] { #[inline] - fn sort_by_index_and_point( - &mut self, - parallel: bool, - reusable_buffer: &mut Vec, - ) { + fn sort_by_index_and_point(&mut self, parallel: bool, reusable_buffer: &mut Vec) { self.sort_by_one_key_then_by_and_buffer( parallel, reusable_buffer, diff --git a/iOverlay/src/split/mod.rs b/iOverlay/src/split/mod.rs index 394056c..7371a0c 100644 --- a/iOverlay/src/split/mod.rs +++ b/iOverlay/src/split/mod.rs @@ -2,9 +2,9 @@ pub(crate) mod solver; mod cross_solver; mod fragment; +mod grid_layout; +mod line_mark; +mod snap_radius; +mod solver_fragment; mod solver_list; mod solver_tree; -mod snap_radius; -mod line_mark; -mod grid_layout; -mod solver_fragment; \ No newline at end of file diff --git a/iOverlay/src/split/snap_radius.rs b/iOverlay/src/split/snap_radius.rs index d8a5222..2a13b7a 100644 --- a/iOverlay/src/split/snap_radius.rs +++ b/iOverlay/src/split/snap_radius.rs @@ -22,4 +22,4 @@ impl Solver { step: self.precision.progression, } } -} \ No newline at end of file +} diff --git a/iOverlay/src/split/solver_fragment.rs b/iOverlay/src/split/solver_fragment.rs index dfbbcde..cd653fb 100644 --- a/iOverlay/src/split/solver_fragment.rs +++ b/iOverlay/src/split/solver_fragment.rs @@ -1,4 +1,3 @@ -use alloc::vec::Vec; use crate::core::solver::Solver; use crate::segm::segment::Segment; use crate::segm::winding::WindingCount; @@ -8,13 +7,14 @@ use crate::split::grid_layout::{BorderVSegment, FragmentBuffer, GridLayout}; use crate::split::line_mark::LineMark; use crate::split::snap_radius::SnapRadius; use crate::split::solver::SplitSolver; +use alloc::vec::Vec; impl SplitSolver { pub(super) fn fragment_split( &mut self, snap_radius: SnapRadius, segments: &mut Vec>, - solver: &Solver + solver: &Solver, ) -> bool { let layout = if let Some(layout) = GridLayout::new(segments.iter().map(|it| it.x_segment), segments.len()) @@ -181,7 +181,7 @@ impl SplitSolver { &mut self, border_x: i32, fragments: &[Fragment], - vertical_segments: &mut [BorderVSegment] + vertical_segments: &mut [BorderVSegment], ) { let mut points = Vec::new(); for fragment in fragments.iter() { @@ -217,7 +217,7 @@ impl SplitSolver { fi: &Fragment, fj: &Fragment, radius: i64, - marks: &mut Vec + marks: &mut Vec, ) -> bool { let cross = if let Some(cross) = CrossSolver::cross(&fi.x_segment, &fj.x_segment, radius) { cross diff --git a/iOverlay/src/split/solver_list.rs b/iOverlay/src/split/solver_list.rs index c9b9cec..c048b17 100644 --- a/iOverlay/src/split/solver_list.rs +++ b/iOverlay/src/split/solver_list.rs @@ -1,16 +1,16 @@ -use alloc::vec::Vec; use crate::core::solver::Solver; use crate::segm::segment::Segment; use crate::segm::winding::WindingCount; use crate::split::snap_radius::SnapRadius; use crate::split::solver::SplitSolver; +use alloc::vec::Vec; impl SplitSolver { pub(super) fn list_split( &mut self, snap_radius: SnapRadius, segments: &mut Vec>, - solver: &Solver + solver: &Solver, ) -> bool { let mut need_to_fix = true; diff --git a/iOverlay/src/split/solver_tree.rs b/iOverlay/src/split/solver_tree.rs index 587f7f7..184877b 100644 --- a/iOverlay/src/split/solver_tree.rs +++ b/iOverlay/src/split/solver_tree.rs @@ -1,14 +1,14 @@ -use alloc::vec::Vec; -use i_tree::ExpiredVal; +use crate::core::solver::Solver; use crate::geom::line_range::LineRange; use crate::geom::x_segment::XSegment; use crate::segm::segment::Segment; use crate::segm::winding::WindingCount; use crate::split::snap_radius::SnapRadius; use crate::split::solver::SplitSolver; +use alloc::vec::Vec; +use i_tree::ExpiredVal; use i_tree::seg::exp::{SegExpCollection, SegRange}; use i_tree::seg::tree::SegExpTree; -use crate::core::solver::Solver; #[derive(Debug, Clone, Copy)] struct IdSegment { @@ -28,7 +28,7 @@ impl SplitSolver { &mut self, snap_radius: SnapRadius, segments: &mut Vec>, - solver: &Solver + solver: &Solver, ) -> bool { let range: SegRange = segments.ver_range().into(); let mut tree: SegExpTree = if let Some(tree) = SegExpTree::new(range) { diff --git a/iOverlay/src/string/clip.rs b/iOverlay/src/string/clip.rs index 3d9d935..cf9fd94 100644 --- a/iOverlay/src/string/clip.rs +++ b/iOverlay/src/string/clip.rs @@ -1,15 +1,15 @@ -use alloc::vec::Vec; -use crate::segm::string::{STRING_BACK_CLIP, STRING_FORWARD_CLIP}; -use i_float::int::point::IntPoint; -use i_shape::int::path::IntPath; -use i_shape::int::shape::{IntShape, IntShapes}; use crate::core::fill_rule::FillRule; use crate::core::link::OverlayLink; use crate::geom::id_point::IdPoint; use crate::segm::segment::SegmentFill; +use crate::segm::string::{STRING_BACK_CLIP, STRING_FORWARD_CLIP}; use crate::string::graph::StringGraph; use crate::string::line::IntLine; use crate::string::overlay::StringOverlay; +use alloc::vec::Vec; +use i_float::int::point::IntPoint; +use i_shape::int::path::IntPath; +use i_shape::int::shape::{IntShape, IntShapes}; #[derive(Debug, Clone, Copy)] pub struct ClipRule { @@ -20,7 +20,6 @@ pub struct ClipRule { pub boundary_included: bool, } - impl StringGraph<'_> { #[inline] pub(super) fn into_clip_string_lines(self) -> Vec { @@ -60,7 +59,12 @@ impl StringGraph<'_> { } #[inline] - fn find_next_point(nodes: &[Vec], links: &mut [OverlayLink], a: IdPoint, is_out_node: bool) -> Option { + fn find_next_point( + nodes: &[Vec], + links: &mut [OverlayLink], + a: IdPoint, + is_out_node: bool, + ) -> Option { let node = unsafe { // SAFETY: a.id comes from an existing link endpoint, so it indexes nodes. nodes.get_unchecked(a.id) @@ -132,7 +136,12 @@ pub trait IntClip { /// /// # Returns /// A vector of `IntPath` instances containing the clipped portions of the input lines. - fn clip_lines(&self, lines: &[IntLine], fill_rule: FillRule, clip_rule: ClipRule) -> Vec; + fn clip_lines( + &self, + lines: &[IntLine], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec; /// Clips a single path according to the specified build and clip rules. /// - `path`: A reference to an `IntPath`, which is a sequence of points representing the path to be clipped. @@ -150,7 +159,12 @@ pub trait IntClip { /// /// # Returns /// A vector of `IntPath` instances containing the clipped portions of the input paths. - fn clip_paths(&self, paths: &[IntPath], fill_rule: FillRule, clip_rule: ClipRule) -> Vec; + fn clip_paths( + &self, + paths: &[IntPath], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec; } impl IntClip for IntShapes { @@ -162,7 +176,12 @@ impl IntClip for IntShapes { } #[inline] - fn clip_lines(&self, lines: &[IntLine], fill_rule: FillRule, clip_rule: ClipRule) -> Vec { + fn clip_lines( + &self, + lines: &[IntLine], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec { let mut overlay = StringOverlay::with_shapes(self); overlay.add_string_lines(lines); overlay.clip_string_lines(fill_rule, clip_rule) @@ -176,7 +195,12 @@ impl IntClip for IntShapes { } #[inline] - fn clip_paths(&self, paths: &[IntPath], fill_rule: FillRule, clip_rule: ClipRule) -> Vec { + fn clip_paths( + &self, + paths: &[IntPath], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec { let mut overlay = StringOverlay::with_shapes(self); overlay.add_string_paths(paths); overlay.clip_string_lines(fill_rule, clip_rule) @@ -192,7 +216,12 @@ impl IntClip for IntShape { } #[inline] - fn clip_lines(&self, lines: &[IntLine], fill_rule: FillRule, clip_rule: ClipRule) -> Vec { + fn clip_lines( + &self, + lines: &[IntLine], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec { let mut overlay = StringOverlay::with_shape(self); overlay.add_string_lines(lines); overlay.clip_string_lines(fill_rule, clip_rule) @@ -206,7 +235,12 @@ impl IntClip for IntShape { } #[inline] - fn clip_paths(&self, paths: &[IntPath], fill_rule: FillRule, clip_rule: ClipRule) -> Vec { + fn clip_paths( + &self, + paths: &[IntPath], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec { let mut overlay = StringOverlay::with_shape(self); overlay.add_string_paths(paths); overlay.clip_string_lines(fill_rule, clip_rule) @@ -222,7 +256,12 @@ impl IntClip for [IntPoint] { } #[inline] - fn clip_lines(&self, lines: &[IntLine], fill_rule: FillRule, clip_rule: ClipRule) -> Vec { + fn clip_lines( + &self, + lines: &[IntLine], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec { let mut overlay = StringOverlay::with_shape_contour(self); overlay.add_string_lines(lines); overlay.clip_string_lines(fill_rule, clip_rule) @@ -236,7 +275,12 @@ impl IntClip for [IntPoint] { } #[inline] - fn clip_paths(&self, paths: &[IntPath], fill_rule: FillRule, clip_rule: ClipRule) -> Vec { + fn clip_paths( + &self, + paths: &[IntPath], + fill_rule: FillRule, + clip_rule: ClipRule, + ) -> Vec { let mut overlay = StringOverlay::with_shape_contour(self); overlay.add_string_paths(paths); overlay.clip_string_lines(fill_rule, clip_rule) @@ -245,11 +289,11 @@ impl IntClip for [IntPoint] { #[cfg(test)] mod tests { + use crate::core::fill_rule::FillRule; + use crate::string::clip::{ClipRule, IntClip}; use alloc::vec; use i_float::int::point::IntPoint; use i_shape::int::path::IntPath; - use crate::core::fill_rule::FillRule; - use crate::string::clip::{ClipRule, IntClip}; #[test] fn test_empty_path() { @@ -257,13 +301,19 @@ mod tests { let result_0 = path.clip_line( [IntPoint::new(0, 0), IntPoint::new(0, 0)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + ClipRule { + invert: false, + boundary_included: false, + }, ); let result_1 = path.clip_line( [IntPoint::new(0, 0), IntPoint::new(10, 0)], FillRule::NonZero, - ClipRule { invert: true, boundary_included: false }, + ClipRule { + invert: true, + boundary_included: false, + }, ); assert!(result_0.is_empty()); @@ -282,13 +332,19 @@ mod tests { let result_0 = path.clip_line( [IntPoint::new(0, -15), IntPoint::new(0, 15)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + ClipRule { + invert: false, + boundary_included: false, + }, ); let result_1 = path.clip_line( [IntPoint::new(0, -15), IntPoint::new(0, 15)], FillRule::NonZero, - ClipRule { invert: true, boundary_included: false }, + ClipRule { + invert: true, + boundary_included: false, + }, ); assert_eq!(result_0.len(), 1); @@ -307,13 +363,19 @@ mod tests { let result_0 = path.clip_line( [IntPoint::new(-10, -15), IntPoint::new(-10, 15)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + ClipRule { + invert: false, + boundary_included: false, + }, ); let result_1 = path.clip_line( [IntPoint::new(-10, -15), IntPoint::new(-10, 15)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: true }, + ClipRule { + invert: false, + boundary_included: true, + }, ); assert_eq!(result_0.len(), 0); @@ -339,15 +401,25 @@ mod tests { IntPoint::new(5, -5), IntPoint::new(0, -10), IntPoint::new(-5, -5), - IntPoint::new(-15, -15) + IntPoint::new(-15, -15), ]; - let result_0 = rect.clip_path(&path, FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + let result_0 = rect.clip_path( + &path, + FillRule::NonZero, + ClipRule { + invert: false, + boundary_included: false, + }, ); - let result_1 = rect.clip_path(&path, FillRule::NonZero, - ClipRule { invert: false, boundary_included: true }, + let result_1 = rect.clip_path( + &path, + FillRule::NonZero, + ClipRule { + invert: false, + boundary_included: true, + }, ); assert_eq!(result_0.len(), 3); @@ -365,13 +437,19 @@ mod tests { let result_0 = path.clip_line( [IntPoint::new(0, -1), IntPoint::new(0, 2)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + ClipRule { + invert: false, + boundary_included: false, + }, ); let result_1 = path.clip_line( [IntPoint::new(0, -1), IntPoint::new(0, 2)], FillRule::NonZero, - ClipRule { invert: true, boundary_included: false }, + ClipRule { + invert: true, + boundary_included: false, + }, ); assert_eq!(result_0.len(), 1); @@ -390,13 +468,19 @@ mod tests { let result_0 = path.clip_line( [IntPoint::new(-1, -1), IntPoint::new(1, -1)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + ClipRule { + invert: false, + boundary_included: false, + }, ); let result_1 = path.clip_line( [IntPoint::new(-1, -1), IntPoint::new(1, -1)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: true }, + ClipRule { + invert: false, + boundary_included: true, + }, ); assert_eq!(result_0.len(), 0); @@ -419,12 +503,22 @@ mod tests { IntPoint::new(4, 1), ]; - let result_0 = contour.clip_path(&path, FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + let result_0 = contour.clip_path( + &path, + FillRule::NonZero, + ClipRule { + invert: false, + boundary_included: false, + }, ); - let result_1 = contour.clip_path(&path, FillRule::NonZero, - ClipRule { invert: false, boundary_included: true }, + let result_1 = contour.clip_path( + &path, + FillRule::NonZero, + ClipRule { + invert: false, + boundary_included: true, + }, ); assert_eq!(result_0.len(), 0); @@ -444,13 +538,19 @@ mod tests { let result_0 = path.clip_line( [IntPoint::new(-3, 2), IntPoint::new(3, 2)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + ClipRule { + invert: false, + boundary_included: false, + }, ); let result_1 = path.clip_line( [IntPoint::new(-3, 2), IntPoint::new(3, 2)], FillRule::NonZero, - ClipRule { invert: false, boundary_included: false }, + ClipRule { + invert: false, + boundary_included: false, + }, ); assert_eq!(result_0.len(), 0); diff --git a/iOverlay/src/string/extract.rs b/iOverlay/src/string/extract.rs index 594a698..59c1c05 100644 --- a/iOverlay/src/string/extract.rs +++ b/iOverlay/src/string/extract.rs @@ -145,7 +145,10 @@ impl StringGraph<'_> { } let (link, fill) = unsafe { // SAFETY: link_index comes from the adjacency list; fills shares the same length as links. - (self.links.get_unchecked(link_index), *fills.get_unchecked(link_index)) + ( + self.links.get_unchecked(link_index), + *fills.get_unchecked(link_index), + ) }; if link.is_move_possible(fill, node_id, clockwise) { if is_first { @@ -162,7 +165,10 @@ impl StringGraph<'_> { if first_index == usize::MAX { let (link, fill) = unsafe { // SAFETY: target_index is the caller's current link id, so it is within bounds for both arrays. - (self.links.get_unchecked(target_index), *fills.get_unchecked(target_index)) + ( + self.links.get_unchecked(target_index), + *fills.get_unchecked(target_index), + ) }; if link.is_move_possible(fill, node_id, clockwise) { return target_index; @@ -175,7 +181,6 @@ impl StringGraph<'_> { return first_index; } - let target = unsafe { // SAFETY: target_index is either target_index or first_index; both were validated above. self.links.get_unchecked(target_index) @@ -208,7 +213,10 @@ impl StringGraph<'_> { for &link_index in indices.iter().skip(pos + 1) { let (link, fill) = unsafe { // SAFETY: link_index traverses the same adjacency slice; indices and arrays are aligned. - (self.links.get_unchecked(link_index), *fills.get_unchecked(link_index)) + ( + self.links.get_unchecked(link_index), + *fills.get_unchecked(link_index), + ) }; if link.is_move_possible(fill, node_id, clockwise) { let p = link.other(node_id).point; diff --git a/iOverlay/src/string/filter.rs b/iOverlay/src/string/filter.rs index 48db20f..c2b8298 100644 --- a/iOverlay/src/string/filter.rs +++ b/iOverlay/src/string/filter.rs @@ -1,8 +1,8 @@ -use alloc::vec::Vec; use crate::core::link::OverlayLink; use crate::segm::segment::{SUBJ_BOTH, SUBJ_BOTTOM, SUBJ_TOP}; use crate::string::graph::StringGraph; use crate::string::rule::StringRule; +use alloc::vec::Vec; impl OverlayLink { #[inline] diff --git a/iOverlay/src/string/graph.rs b/iOverlay/src/string/graph.rs index 307a43d..901c239 100644 --- a/iOverlay/src/string/graph.rs +++ b/iOverlay/src/string/graph.rs @@ -1,6 +1,6 @@ -use alloc::vec::Vec; use crate::build::builder::GraphNode; use crate::core::link::OverlayLink; +use alloc::vec::Vec; pub struct StringGraph<'a> { pub(crate) nodes: &'a [Vec], @@ -12,4 +12,4 @@ impl GraphNode for Vec { fn with_indices(indices: &[usize]) -> Self { indices.to_vec() } -} \ No newline at end of file +} diff --git a/iOverlay/src/string/mod.rs b/iOverlay/src/string/mod.rs index dcbc411..bf61810 100644 --- a/iOverlay/src/string/mod.rs +++ b/iOverlay/src/string/mod.rs @@ -1,9 +1,9 @@ -pub mod slice; +pub mod clip; +pub mod extract; +mod filter; +pub mod graph; pub mod line; -pub mod rule; pub mod overlay; -pub mod graph; +pub mod rule; +pub mod slice; pub mod split; -pub mod clip; -pub mod extract; -mod filter; \ No newline at end of file diff --git a/iOverlay/src/string/overlay.rs b/iOverlay/src/string/overlay.rs index b40f9d6..25247ec 100644 --- a/iOverlay/src/string/overlay.rs +++ b/iOverlay/src/string/overlay.rs @@ -1,11 +1,3 @@ -use alloc::vec::Vec; -use crate::segm::string::STRING_FORWARD_CLIP; -use crate::segm::string::STRING_BACK_CLIP; -use crate::segm::string::ShapeCountString; -use i_float::int::point::IntPoint; -use i_shape::int::count::PointsCount; -use i_shape::int::path::IntPath; -use i_shape::int::shape::{IntContour, IntShape}; use crate::build::builder::GraphBuilder; use crate::core::fill_rule::FillRule; use crate::core::overlay::{IntOverlayOptions, ShapeType}; @@ -13,16 +5,25 @@ use crate::core::solver::Solver; use crate::geom::x_segment::XSegment; use crate::segm::build::BuildSegments; use crate::segm::segment::Segment; +use crate::segm::string::STRING_BACK_CLIP; +use crate::segm::string::STRING_FORWARD_CLIP; +use crate::segm::string::ShapeCountString; use crate::split::solver::SplitSolver; use crate::string::clip::ClipRule; use crate::string::graph::StringGraph; use crate::string::line::IntLine; +use alloc::vec::Vec; +use core::cmp::Ordering; +use i_float::int::point::IntPoint; +use i_shape::int::count::PointsCount; +use i_shape::int::path::IntPath; +use i_shape::int::shape::{IntContour, IntShape}; pub struct StringOverlay { pub options: IntOverlayOptions, pub(super) segments: Vec>, pub(crate) split_solver: SplitSolver, - pub(crate) graph_builder: GraphBuilder> + pub(crate) graph_builder: GraphBuilder>, } impl StringOverlay { @@ -35,7 +36,7 @@ impl StringOverlay { options: Default::default(), segments: Vec::with_capacity(capacity), split_solver: SplitSolver::new(), - graph_builder: GraphBuilder::>::new() + graph_builder: GraphBuilder::>::new(), } } @@ -48,7 +49,7 @@ impl StringOverlay { options, segments: Vec::with_capacity(capacity), split_solver: SplitSolver::new(), - graph_builder: GraphBuilder::>::new() + graph_builder: GraphBuilder::>::new(), } } @@ -93,8 +94,9 @@ impl StringOverlay { /// when paths are not directly stored in a collection. /// - `iter`: An iterator over references to `IntPoint` that defines the path. #[inline] - pub fn add_shape_contour_iter>(&mut self, iter: I) { - self.segments.append_path_iter(iter, ShapeType::Subject, false); + pub fn add_shape_contour_iter>(&mut self, iter: I) { + self.segments + .append_path_iter(iter, ShapeType::Subject, false); } /// Adds a single path to the overlay as a shape paths. @@ -128,9 +130,21 @@ impl StringOverlay { let a = line[0]; let b = line[1]; let segment = match a.cmp(&b) { - core::cmp::Ordering::Less => Segment { x_segment: XSegment { a, b }, count: ShapeCountString { subj: 0, clip: STRING_BACK_CLIP } }, - core::cmp::Ordering::Greater => Segment { x_segment: XSegment { a: b, b: a }, count: ShapeCountString { subj: 0, clip: STRING_FORWARD_CLIP } }, - core::cmp::Ordering::Equal => return, + Ordering::Less => Segment { + x_segment: XSegment { a, b }, + count: ShapeCountString { + subj: 0, + clip: STRING_BACK_CLIP, + }, + }, + Ordering::Greater => Segment { + x_segment: XSegment { a: b, b: a }, + count: ShapeCountString { + subj: 0, + clip: STRING_FORWARD_CLIP, + }, + }, + Ordering::Equal => return, }; self.segments.push(segment); @@ -152,7 +166,11 @@ impl StringOverlay { if path.len() < 2 { return; } - let mut a = if let Some(&p) = path.first() { p } else { return; }; + let mut a = if let Some(&p) = path.first() { + p + } else { + return; + }; for &b in path.iter().skip(1) { self.add_string_line([a, b]); a = b; @@ -166,7 +184,11 @@ impl StringOverlay { if contour.len() < 2 { return; } - let mut a = if let Some(&p) = contour.last() { p } else { return; }; + let mut a = if let Some(&p) = contour.last() { + p + } else { + return; + }; for &b in contour.iter() { self.add_string_line([a, b]); a = b; @@ -209,8 +231,14 @@ impl StringOverlay { /// # Returns /// A vector of `IntPath` instances representing the clipped sections of the input lines. #[inline] - pub fn clip_string_lines_with_solver(mut self, fill_rule: FillRule, clip_rule: ClipRule, solver: Solver) -> Vec { - self.split_solver.split_segments(&mut self.segments, &solver); + pub fn clip_string_lines_with_solver( + mut self, + fill_rule: FillRule, + clip_rule: ClipRule, + solver: Solver, + ) -> Vec { + self.split_solver + .split_segments(&mut self.segments, &solver); if self.segments.is_empty() { return Vec::new(); } @@ -232,11 +260,19 @@ impl StringOverlay { /// - `fill_rule`: The rule that defines how to build shapes (e.g., non-zero, even-odd). /// - `solver`: A solver type to be used for advanced control over the graph building process. #[inline] - pub fn build_graph_view_with_solver(&mut self, fill_rule: FillRule, solver: Solver) -> Option> { - self.split_solver.split_segments(&mut self.segments, &solver); + pub fn build_graph_view_with_solver( + &mut self, + fill_rule: FillRule, + solver: Solver, + ) -> Option> { + self.split_solver + .split_segments(&mut self.segments, &solver); if self.segments.is_empty() { return None; } - Some(self.graph_builder.build_string_all(fill_rule, &solver, &self.segments)) + Some( + self.graph_builder + .build_string_all(fill_rule, &solver, &self.segments), + ) } -} \ No newline at end of file +} diff --git a/iOverlay/src/string/rule.rs b/iOverlay/src/string/rule.rs index 75eb3c5..7f1a255 100644 --- a/iOverlay/src/string/rule.rs +++ b/iOverlay/src/string/rule.rs @@ -1,4 +1,4 @@ #[derive(Debug, Clone, Copy, PartialEq)] pub enum StringRule { - Slice -} \ No newline at end of file + Slice, +} diff --git a/iOverlay/src/string/slice.rs b/iOverlay/src/string/slice.rs index 140660d..95af363 100644 --- a/iOverlay/src/string/slice.rs +++ b/iOverlay/src/string/slice.rs @@ -1,10 +1,10 @@ -use i_float::int::point::IntPoint; -use i_shape::int::path::IntPath; -use i_shape::int::shape::{IntShape, IntShapes}; use crate::core::fill_rule::FillRule; use crate::string::line::IntLine; use crate::string::overlay::StringOverlay; use crate::string::rule::StringRule; +use i_float::int::point::IntPoint; +use i_shape::int::path::IntPath; +use i_shape::int::shape::{IntShape, IntShapes}; pub trait IntSlice { fn slice_by_line(&self, line: IntLine, fill_rule: FillRule) -> IntShapes; @@ -141,10 +141,10 @@ impl IntSlice for [IntPoint] { #[cfg(test)] mod tests { - use alloc::vec; - use i_float::int::point::IntPoint; use crate::core::fill_rule::FillRule; use crate::string::slice::IntSlice; + use alloc::vec; + use i_float::int::point::IntPoint; #[test] fn test_empty_input() { @@ -341,7 +341,7 @@ mod tests { assert_eq!(shapes.len(), 2); assert_eq!(shapes[0][0].len(), 3); - assert_eq!(shapes[1][0].len(), 3); + assert_eq!(shapes[1][0].len(), 3); } #[test] @@ -414,4 +414,4 @@ mod tests { assert_eq!(shapes.len(), 1); } -} \ No newline at end of file +} diff --git a/iOverlay/src/util/log.rs b/iOverlay/src/util/log.rs index 37ba835..68bb8e8 100644 --- a/iOverlay/src/util/log.rs +++ b/iOverlay/src/util/log.rs @@ -1,10 +1,8 @@ - pub(crate) trait Int { fn log2_sqrt(&self) -> usize; } impl Int for usize { - #[inline] fn log2_sqrt(&self) -> usize { let z = self.leading_zeros(); @@ -16,9 +14,9 @@ impl Int for usize { #[cfg(test)] mod tests { + use crate::util::log::Int; use alloc::vec; use alloc::vec::Vec; - use crate::util::log::Int; #[test] fn test_0() { @@ -38,4 +36,4 @@ mod tests { assert_eq!(a, b); } } -} \ No newline at end of file +} diff --git a/iOverlay/src/util/mod.rs b/iOverlay/src/util/mod.rs index a7a35ee..2248444 100644 --- a/iOverlay/src/util/mod.rs +++ b/iOverlay/src/util/mod.rs @@ -1 +1 @@ -pub(crate) mod log; \ No newline at end of file +pub(crate) mod log; diff --git a/iOverlay/src/vector/edge.rs b/iOverlay/src/vector/edge.rs index 8206330..a4eae6a 100644 --- a/iOverlay/src/vector/edge.rs +++ b/iOverlay/src/vector/edge.rs @@ -35,11 +35,7 @@ pub struct VectorEdge { impl VectorEdge { pub(crate) fn new(fill: SideFill, a: IntPoint, b: IntPoint) -> Self { - let fill = if a < b { - fill - } else { - fill.reverse() - }; + let fill = if a < b { fill } else { fill.reverse() }; Self { a, b, fill } } @@ -53,4 +49,4 @@ impl ToPath for VectorPath { fn to_path(&self) -> IntPath { self.iter().map(|e| e.a).collect() } -} \ No newline at end of file +} diff --git a/iOverlay/src/vector/extract.rs b/iOverlay/src/vector/extract.rs index 170c116..e9fc762 100644 --- a/iOverlay/src/vector/extract.rs +++ b/iOverlay/src/vector/extract.rs @@ -31,7 +31,8 @@ impl OverlayGraph<'_> { buffer: &mut BooleanExtractionBuffer, ) -> Vec { let clockwise = self.options.output_direction == ContourDirection::Clockwise; - self.links.filter_by_overlay_into(overlay_rule, &mut buffer.visited); + self.links + .filter_by_overlay_into(overlay_rule, &mut buffer.visited); let mut holes = Vec::new(); let mut shapes = Vec::new(); @@ -63,7 +64,8 @@ impl OverlayGraph<'_> { let direction = is_hole == clockwise; let start_data = StartVectorPathData::new(direction, link, left_top_link); - let mut contour = self.find_vector_contour(start_data, direction, visited_state, &mut buffer.visited); + let mut contour = + self.find_vector_contour(start_data, direction, visited_state, &mut buffer.visited); let (is_valid, is_modified) = contour.validate( self.options.min_output_area, self.options.preserve_output_collinear, @@ -186,7 +188,8 @@ trait JoinHoles { &mut self, holes: Vec, anchors: Vec, - clockwise: bool); + clockwise: bool, + ); fn scan_join(&mut self, holes: Vec, hole_segments: Vec, clockwise: bool); } @@ -213,7 +216,12 @@ impl JoinHoles for Vec { self.scan_join(holes, anchors, clockwise); } - fn scan_join(&mut self, holes: Vec, hole_segments: Vec, clockwise: bool) { + fn scan_join( + &mut self, + holes: Vec, + hole_segments: Vec, + clockwise: bool, + ) { let x_min = hole_segments[0].v_segment.a.x; let x_max = hole_segments[hole_segments.len() - 1].v_segment.a.x; diff --git a/iOverlay/src/vector/simplify.rs b/iOverlay/src/vector/simplify.rs index 4576b14..387cdfe 100644 --- a/iOverlay/src/vector/simplify.rs +++ b/iOverlay/src/vector/simplify.rs @@ -1,5 +1,5 @@ -use alloc::vec; use crate::vector::edge::{VectorEdge, VectorPath, VectorShape}; +use alloc::vec; use alloc::vec::Vec; use i_float::int::point::IntPoint; @@ -21,7 +21,6 @@ pub(super) trait VectorSimpleShape { fn simplified(&self) -> Option; } - impl VectorSimplify for VectorPath { #[inline] fn simplify_contour(&mut self) -> bool { @@ -121,13 +120,24 @@ impl VectorSimpleContour for [VectorEdge] { } let mut n = self.len(); - let mut nodes: Vec = vec![Node { next: 0, index: 0, prev: 0 }; n]; + let mut nodes: Vec = vec![ + Node { + next: 0, + index: 0, + prev: 0 + }; + n + ]; let mut validated: Vec = vec![false; n]; let mut i0 = n - 2; let mut i1 = n - 1; for i2 in 0..n { - nodes[i1] = Node { next: i2, index: i1, prev: i0 }; + nodes[i1] = Node { + next: i2, + index: i1, + prev: i0, + }; i0 = i1; i1 = i2; } @@ -236,10 +246,10 @@ fn direction(edge: &VectorEdge) -> IntPoint { #[cfg(test)] mod tests { + use crate::vector::edge::VectorEdge; use crate::vector::simplify::{IntPoint, VectorSimplify}; use alloc::vec; use i_float::int_pnt; - use crate::vector::edge::VectorEdge; #[test] fn test_0() { diff --git a/iOverlay/tests/data.rs b/iOverlay/tests/data.rs index a760415..9c0e760 100644 --- a/iOverlay/tests/data.rs +++ b/iOverlay/tests/data.rs @@ -2,11 +2,11 @@ pub mod overlay { // extern crate std; - use std::path::PathBuf; + use i_overlay::core::fill_rule::FillRule; use i_shape::int::path::IntPaths; use i_shape::int::shape::{IntContour, IntShapes}; use serde::{Deserialize, Deserializer}; - use i_overlay::core::fill_rule::FillRule; + use std::path::PathBuf; fn deserialize_fill_rule<'de, D>(deserializer: D) -> Result, D::Error> where @@ -49,9 +49,7 @@ pub mod overlay { path_buf.push(file_name); let data = match std::fs::read_to_string(path_buf.as_path()) { - Ok(data) => { - data - } + Ok(data) => data, Err(e) => { panic!("{:?}", e); } @@ -89,9 +87,7 @@ pub mod overlay { path_buf.push(file_name); let data = match std::fs::read_to_string(path_buf.as_path()) { - Ok(data) => { - data - } + Ok(data) => data, Err(e) => { panic!("{:?}", e); } diff --git a/iOverlay/tests/direction_tests.rs b/iOverlay/tests/direction_tests.rs index 67fbd78..284a062 100644 --- a/iOverlay/tests/direction_tests.rs +++ b/iOverlay/tests/direction_tests.rs @@ -3,9 +3,9 @@ mod tests { use i_float::int::point::IntPoint; use i_overlay::core::fill_rule::FillRule; use i_overlay::core::overlay::{ContourDirection, IntOverlayOptions, Overlay}; + use i_overlay::core::overlay_rule::OverlayRule; use i_overlay::core::simplify::Simplify; use i_shape::int::area::Area; - use i_overlay::core::overlay_rule::OverlayRule; #[test] fn test_0() { @@ -71,7 +71,7 @@ mod tests { min_output_area: 0, ogc: false, }; - + let r0 = &path.simplify(FillRule::NonZero, op0)[0]; debug_assert!(r0[0].area_two() < 0); debug_assert!(r0[1].area_two() > 0); diff --git a/iOverlay/tests/doc_tests.rs b/iOverlay/tests/doc_tests.rs index 5243eb5..40e09da 100644 --- a/iOverlay/tests/doc_tests.rs +++ b/iOverlay/tests/doc_tests.rs @@ -85,19 +85,9 @@ mod tests { #[test] fn test_slice() { - let polygon = [ - [1.0, 1.0], - [1.0, 4.0], - [4.0, 4.0], - [4.0, 1.0], - ]; + let polygon = [[1.0, 1.0], [1.0, 4.0], [4.0, 4.0], [4.0, 1.0]]; - let slicing_line = [ - [3.0, 5.0], - [2.0, 2.0], - [3.0, 3.0], - [2.0, 0.0], - ]; + let slicing_line = [[3.0, 5.0], [2.0, 2.0], [3.0, 3.0], [2.0, 0.0]]; let result = polygon.slice_by(&slicing_line, FillRule::NonZero); @@ -106,23 +96,16 @@ mod tests { #[test] fn test_clip() { - let polygon = [ - [1.0, 1.0], - [1.0, 4.0], - [4.0, 4.0], - [4.0, 1.0], - ]; + let polygon = [[1.0, 1.0], [1.0, 4.0], [4.0, 4.0], [4.0, 1.0]]; - let string_line = [ - [3.0, 5.0], - [2.0, 2.0], - [3.0, 3.0], - [2.0, 0.0], - ]; + let string_line = [[3.0, 5.0], [2.0, 2.0], [3.0, 3.0], [2.0, 0.0]]; - let clip_rule = ClipRule { invert: false, boundary_included: false }; + let clip_rule = ClipRule { + invert: false, + boundary_included: false, + }; let result = string_line.clip_by(&polygon, FillRule::NonZero, clip_rule); println!("result: {:?}", result); } -} \ No newline at end of file +} diff --git a/iOverlay/tests/dynamic_tests.rs b/iOverlay/tests/dynamic_tests.rs index f4d988e..5a7daca 100644 --- a/iOverlay/tests/dynamic_tests.rs +++ b/iOverlay/tests/dynamic_tests.rs @@ -29,7 +29,8 @@ mod tests { .build_graph_view(FillRule::NonZero) { graph.validate(); - let result = graph.extract_shapes(OverlayRule::Union, &mut Default::default()); + let result = + graph.extract_shapes(OverlayRule::Union, &mut Default::default()); assert!(result.len() > 0); } a += 0.005 @@ -185,7 +186,8 @@ mod tests { if let Some(graph) = overlay.build_graph_view(FillRule::NonZero) { graph.validate(); - let result = graph.extract_shapes(OverlayRule::Subject, &mut Default::default()); + let result = + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()); assert!(result.len() > 0); } } @@ -205,11 +207,13 @@ mod tests { let mut a = 0.0; while a < 2.0 * PI { let subj = create_star(r0, r, 4, a); - if let Some(graph) = Overlay::with_contours_custom(&subj, &clip, Default::default(), solver) - .build_graph_view(FillRule::NonZero) + if let Some(graph) = + Overlay::with_contours_custom(&subj, &clip, Default::default(), solver) + .build_graph_view(FillRule::NonZero) { graph.validate(); - let result = graph.extract_shapes(OverlayRule::Union, &mut Default::default()); + let result = + graph.extract_shapes(OverlayRule::Union, &mut Default::default()); assert!(result.len() > 0); } a += 0.005 @@ -247,9 +251,7 @@ mod tests { overlay.add_contour(&subj_path, ShapeType::Subject); overlay.add_contour(&clip_path, ShapeType::Clip); - if let Some(graph) = - overlay.build_graph_view(FillRule::NonZero) - { + if let Some(graph) = overlay.build_graph_view(FillRule::NonZero) { graph.validate(); let result = graph.extract_shapes(OverlayRule::Union, &mut Default::default()); assert!(result.len() > 0); @@ -264,9 +266,7 @@ mod tests { let subj_path = random(10, n); let mut overlay = Overlay::new(2 * n); overlay.add_contour(&subj_path, ShapeType::Subject); - if let Some(graph) = - overlay.build_graph_view(FillRule::NonZero) - { + if let Some(graph) = overlay.build_graph_view(FillRule::NonZero) { graph.validate(); let result = graph.extract_shapes(OverlayRule::Subject, &mut Default::default()); assert!(result.len() > 0); @@ -281,9 +281,7 @@ mod tests { let r = i as f64; let subj_path = random_float(r, n); let mut overlay = FloatOverlay::with_subj(&subj_path); - if let Some(graph) = - overlay.build_graph_view(FillRule::NonZero) - { + if let Some(graph) = overlay.build_graph_view(FillRule::NonZero) { graph.graph.validate(); let result = graph.extract_shapes(OverlayRule::Subject, &mut Default::default()); assert!(result.len() > 0); diff --git a/iOverlay/tests/empty_tests.rs b/iOverlay/tests/empty_tests.rs index 0a05da0..4076d0a 100644 --- a/iOverlay/tests/empty_tests.rs +++ b/iOverlay/tests/empty_tests.rs @@ -16,9 +16,12 @@ mod tests { #[test] fn test_01() { let mut overlay = Overlay::new(1); - overlay.add_contour(&[IntPoint::new(0, 0), IntPoint::new(1, 0)], ShapeType::Subject); + overlay.add_contour( + &[IntPoint::new(0, 0), IntPoint::new(1, 0)], + ShapeType::Subject, + ); let graph = overlay.build_graph_view(FillRule::NonZero); assert!(graph.is_none()); } -} \ No newline at end of file +} diff --git a/iOverlay/tests/fill_rule_tests.rs b/iOverlay/tests/fill_rule_tests.rs index 293b1c0..605a40a 100644 --- a/iOverlay/tests/fill_rule_tests.rs +++ b/iOverlay/tests/fill_rule_tests.rs @@ -1,10 +1,10 @@ #[cfg(test)] mod tests { use i_float::int::point::IntPoint; - use i_shape::int::path::IntPath; use i_overlay::core::fill_rule::FillRule; use i_overlay::core::overlay::{Overlay, ShapeType}; use i_overlay::core::overlay_rule::OverlayRule; + use i_shape::int::path::IntPath; #[test] fn test_both_clock_wise() { @@ -19,10 +19,22 @@ mod tests { let mut buffer = Default::default(); - let even_odd = overlay().build_graph_view(FillRule::EvenOdd).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let non_zero = overlay().build_graph_view(FillRule::NonZero).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let positive = overlay().build_graph_view(FillRule::Positive).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let negative = overlay().build_graph_view(FillRule::Negative).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); + let even_odd = overlay() + .build_graph_view(FillRule::EvenOdd) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let non_zero = overlay() + .build_graph_view(FillRule::NonZero) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let positive = overlay() + .build_graph_view(FillRule::Positive) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let negative = overlay() + .build_graph_view(FillRule::Negative) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); assert_eq!(even_odd.len(), 1); assert_eq!(even_odd[0].len(), 2); @@ -49,10 +61,22 @@ mod tests { let mut buffer = Default::default(); - let even_odd = overlay().build_graph_view(FillRule::EvenOdd).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let non_zero = overlay().build_graph_view(FillRule::NonZero).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let positive = overlay().build_graph_view(FillRule::Positive).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let negative = overlay().build_graph_view(FillRule::Negative).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); + let even_odd = overlay() + .build_graph_view(FillRule::EvenOdd) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let non_zero = overlay() + .build_graph_view(FillRule::NonZero) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let positive = overlay() + .build_graph_view(FillRule::Positive) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let negative = overlay() + .build_graph_view(FillRule::Negative) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); assert_eq!(even_odd.len(), 1); assert_eq!(even_odd[0].len(), 2); @@ -79,10 +103,22 @@ mod tests { let mut buffer = Default::default(); - let even_odd = overlay().build_graph_view(FillRule::EvenOdd).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let non_zero = overlay().build_graph_view(FillRule::NonZero).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let positive = overlay().build_graph_view(FillRule::Positive).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let negative = overlay().build_graph_view(FillRule::Negative).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); + let even_odd = overlay() + .build_graph_view(FillRule::EvenOdd) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let non_zero = overlay() + .build_graph_view(FillRule::NonZero) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let positive = overlay() + .build_graph_view(FillRule::Positive) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let negative = overlay() + .build_graph_view(FillRule::Negative) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); assert_eq!(even_odd.len(), 1); assert_eq!(even_odd[0].len(), 2); @@ -96,8 +132,6 @@ mod tests { assert_eq!(positive.len(), 0); } - - #[test] fn test_ccw_and_cw() { fn overlay() -> Overlay { @@ -111,10 +145,22 @@ mod tests { let mut buffer = Default::default(); - let even_odd = overlay().build_graph_view(FillRule::EvenOdd).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let non_zero = overlay().build_graph_view(FillRule::NonZero).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let positive = overlay().build_graph_view(FillRule::Positive).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); - let negative = overlay().build_graph_view(FillRule::Negative).unwrap().extract_shapes(OverlayRule::Subject, &mut buffer); + let even_odd = overlay() + .build_graph_view(FillRule::EvenOdd) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let non_zero = overlay() + .build_graph_view(FillRule::NonZero) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let positive = overlay() + .build_graph_view(FillRule::Positive) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); + let negative = overlay() + .build_graph_view(FillRule::Negative) + .unwrap() + .extract_shapes(OverlayRule::Subject, &mut buffer); assert_eq!(even_odd.len(), 1); assert_eq!(even_odd[0].len(), 2); @@ -133,8 +179,9 @@ mod tests { IntPoint::new(-radius, -radius), IntPoint::new(-radius, radius), IntPoint::new(radius, radius), - IntPoint::new(radius, -radius) - ].to_vec(); + IntPoint::new(radius, -radius), + ] + .to_vec(); if !is_clockwise { square.reverse() @@ -142,5 +189,4 @@ mod tests { square } - -} \ No newline at end of file +} diff --git a/iOverlay/tests/float_overlay_tests.rs b/iOverlay/tests/float_overlay_tests.rs index 30ab193..e168d11 100644 --- a/iOverlay/tests/float_overlay_tests.rs +++ b/iOverlay/tests/float_overlay_tests.rs @@ -53,7 +53,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -79,7 +80,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -106,7 +108,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -133,7 +136,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -159,7 +163,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -185,7 +190,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -211,7 +217,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -235,7 +242,8 @@ mod tests { ]]; let union = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) - .build_graph_view(FillRule::NonZero).unwrap() + .build_graph_view(FillRule::NonZero) + .unwrap() .extract_shapes(OverlayRule::Union, &mut Default::default()); assert_eq!(union.len(), 1); @@ -265,7 +273,9 @@ mod tests { let shapes = FloatOverlay::with_adapter(FloatPointAdapter::with_iter(path.iter()), path.len()) .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut Default::default())); + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()) + }); assert_eq!(shapes.is_empty(), true); } @@ -284,9 +294,11 @@ mod tests { FloatPointAdapter::with_iter(shape.iter().flatten()), shape.len(), ) - .unsafe_add_source(&shape, ShapeType::Subject) - .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut Default::default())); + .unsafe_add_source(&shape, ShapeType::Subject) + .build_graph_view(FillRule::NonZero) + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()) + }); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -306,7 +318,9 @@ mod tests { let shapes = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut Default::default())); + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()) + }); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -329,7 +343,9 @@ mod tests { let shapes = FloatOverlay::with_subj_and_clip(&shape_0, &shape_1) .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut Default::default())); + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()) + }); assert_eq!(shapes.len(), 1); assert_eq!(shapes[0].len(), 1); @@ -343,7 +359,9 @@ mod tests { FloatOverlay::with_adapter(FloatPointAdapter::with_iter(path.iter()), path.len()) .unsafe_add_contour(&path, ShapeType::Subject) .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut Default::default())); + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()) + }); assert_eq!(shapes.len(), 0); } @@ -354,8 +372,10 @@ mod tests { &vec![FPoint::new(0.0, 0.0)], &vec![FPoint::new(1.0, 0.0)], ) - .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut Default::default())); + .build_graph_view(FillRule::NonZero) + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()) + }); assert_eq!(shapes.len(), 0); } @@ -367,7 +387,9 @@ mod tests { FloatOverlay::with_adapter(FloatPointAdapter::with_iter(path.iter()), path.len()) .unsafe_add_contour(&path, ShapeType::Subject) .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut Default::default())); + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut Default::default()) + }); assert_eq!(shapes.len(), 0); } @@ -685,12 +707,10 @@ mod tests { ogc: false, clean_result: false, }; - - let result_with_filter = FloatOverlay::with_subj_and_clip_custom(&shape_0, &shape_1, opt, Default::default()) - .overlay( - OverlayRule::Intersect, - FillRule::EvenOdd, - ); + + let result_with_filter = + FloatOverlay::with_subj_and_clip_custom(&shape_0, &shape_1, opt, Default::default()) + .overlay(OverlayRule::Intersect, FillRule::EvenOdd); assert_eq!(result_no_filter.len(), 1); assert_eq!(result_with_filter.len(), 2); diff --git a/iOverlay/tests/float_point_adapter.rs b/iOverlay/tests/float_point_adapter.rs index ae62796..22d469e 100644 --- a/iOverlay/tests/float_point_adapter.rs +++ b/iOverlay/tests/float_point_adapter.rs @@ -2,11 +2,11 @@ mod tests { use i_float::adapter::FloatPointAdapter; use i_float::float::rect::FloatRect; - use i_shape::source::resource::ShapeResource; use i_overlay::core::fill_rule::FillRule; use i_overlay::core::overlay::ShapeType; use i_overlay::core::overlay_rule::OverlayRule; use i_overlay::float::overlay::FloatOverlay; + use i_shape::source::resource::ShapeResource; #[test] fn test_adapter_with_rect() { @@ -79,4 +79,4 @@ mod tests { println!("100: {:?}", c100); println!("1000: {:?}", c1000); } -} \ No newline at end of file +} diff --git a/iOverlay/tests/fragment_tests.rs b/iOverlay/tests/fragment_tests.rs index 23db8cc..d23ef7c 100644 --- a/iOverlay/tests/fragment_tests.rs +++ b/iOverlay/tests/fragment_tests.rs @@ -2,14 +2,14 @@ mod util; #[cfg(test)] mod tests { + use crate::util::overlay::JsonPrint; use i_float::int::point::IntPoint; - use i_shape::int::path::IntPath; use i_overlay::core::fill_rule::FillRule; use i_overlay::core::overlay::{Overlay, ShapeType}; use i_overlay::core::overlay_rule::OverlayRule; use i_overlay::core::solver::Solver; + use i_shape::int::path::IntPath; use i_shape::int::shape::IntContour; - use crate::util::overlay::JsonPrint; #[test] fn test_many_squares() { @@ -20,14 +20,29 @@ mod tests { let subj_paths = many_squares(IntPoint::new(0, 0), 20, 30, n); let clip_paths = many_squares(IntPoint::new(15, 15), 20, 30, n - 1); - let list_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::LIST) - .overlay(rule, fill); - - let tree_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::TREE) - .overlay(rule, fill); - - let frag_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::FRAG) - .overlay(rule, fill); + let list_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::LIST, + ) + .overlay(rule, fill); + + let tree_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::TREE, + ) + .overlay(rule, fill); + + let frag_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::FRAG, + ) + .overlay(rule, fill); assert_eq!(list_result, tree_result); assert_eq!(list_result, frag_result); @@ -43,14 +58,29 @@ mod tests { let subj_paths = repeat_xy(square(0, 0, 2), 0, 0, 10, 10, n); let clip_paths = repeat_xy(romb(0, 0, 4), 5, 5, 10, 10, n - 1); - let list_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::LIST) - .overlay(rule, fill); - - let tree_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::TREE) - .overlay(rule, fill); - - let frag_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::FRAG) - .overlay(rule, fill); + let list_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::LIST, + ) + .overlay(rule, fill); + + let tree_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::TREE, + ) + .overlay(rule, fill); + + let frag_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::FRAG, + ) + .overlay(rule, fill); assert_eq!(list_result, tree_result); assert_eq!(list_result, frag_result); @@ -67,14 +97,29 @@ mod tests { let subj_paths = many_lines_x(20, n); let clip_paths = many_lines_y(20, n); - let list_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::LIST) - .overlay(rule, fill); - - let tree_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::TREE) - .overlay(rule, fill); - - let frag_result = Overlay::with_contours_custom(&subj_paths, &clip_paths, Default::default(), Solver::FRAG) - .overlay(rule, fill); + let list_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::LIST, + ) + .overlay(rule, fill); + + let tree_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::TREE, + ) + .overlay(rule, fill); + + let frag_result = Overlay::with_contours_custom( + &subj_paths, + &clip_paths, + Default::default(), + Solver::FRAG, + ) + .overlay(rule, fill); assert_eq!(list_result, tree_result); assert_eq!(list_result, frag_result); @@ -195,7 +240,6 @@ mod tests { println!("clip: {}", clip.json_print()); } - fn many_squares(start: IntPoint, size: i32, offset: i32, n: usize) -> Vec { let mut result = Vec::with_capacity(n * n); let mut y = start.y; @@ -265,7 +309,6 @@ mod tests { // horizontal rects let mut r = 0; for _ in 0..count { - // bottom let r0x0 = -r; let r0x1 = r0x0; @@ -312,10 +355,30 @@ mod tests { r += a4; - rects.push(vec![IntPoint::new(r0x0, r0y0), IntPoint::new(r0x1, r0y1), IntPoint::new(r0x2, r0y2), IntPoint::new(r0x3, r0y3)]); - rects.push(vec![IntPoint::new(r1x0, r1y0), IntPoint::new(r1x1, r1y1), IntPoint::new(r1x2, r1y2), IntPoint::new(r1x3, r1y3)]); - rects.push(vec![IntPoint::new(r2x0, r2y0), IntPoint::new(r2x1, r2y1), IntPoint::new(r2x2, r2y2), IntPoint::new(r2x3, r2y3)]); - rects.push(vec![IntPoint::new(r3x0, r3y0), IntPoint::new(r3x1, r3y1), IntPoint::new(r3x2, r3y2), IntPoint::new(r3x3, r3y3)]); + rects.push(vec![ + IntPoint::new(r0x0, r0y0), + IntPoint::new(r0x1, r0y1), + IntPoint::new(r0x2, r0y2), + IntPoint::new(r0x3, r0y3), + ]); + rects.push(vec![ + IntPoint::new(r1x0, r1y0), + IntPoint::new(r1x1, r1y1), + IntPoint::new(r1x2, r1y2), + IntPoint::new(r1x3, r1y3), + ]); + rects.push(vec![ + IntPoint::new(r2x0, r2y0), + IntPoint::new(r2x1, r2y1), + IntPoint::new(r2x2, r2y2), + IntPoint::new(r2x3, r2y3), + ]); + rects.push(vec![ + IntPoint::new(r3x0, r3y0), + IntPoint::new(r3x1, r3y1), + IntPoint::new(r3x2, r3y2), + IntPoint::new(r3x3, r3y3), + ]); rects.push(romb(-r, r, a2)); rects.push(romb(-r, -r, a2)); @@ -344,7 +407,14 @@ mod tests { ] } - fn repeat_xy(origin: IntContour, x0: i32, y0: i32, dx: i32, dy: i32, count: usize) -> Vec { + fn repeat_xy( + origin: IntContour, + x0: i32, + y0: i32, + dx: i32, + dy: i32, + count: usize, + ) -> Vec { let mut contours = Vec::with_capacity(8 * count); let mut x = x0; for _ in 0..count { @@ -395,4 +465,4 @@ mod tests { contours } -} \ No newline at end of file +} diff --git a/iOverlay/tests/overlay_tests.rs b/iOverlay/tests/overlay_tests.rs index 84872fa..d306e15 100644 --- a/iOverlay/tests/overlay_tests.rs +++ b/iOverlay/tests/overlay_tests.rs @@ -30,7 +30,7 @@ mod tests { } let mut buffer = Default::default(); - + for solver in SOLVERS { let mut ovr = overlay(&test, options, solver); let graph = if let Some(graph) = ovr.build_graph_view(fill_rule) { @@ -40,47 +40,30 @@ mod tests { }; let subject_0 = graph.extract_shapes(OverlayRule::Subject, &mut buffer); - let subject_1 = overlay(&test, options, solver).overlay( - OverlayRule::Subject, - fill_rule - ); + let subject_1 = + overlay(&test, options, solver).overlay(OverlayRule::Subject, fill_rule); let clip_0 = graph.extract_shapes(OverlayRule::Clip, &mut buffer); - let clip_1 = overlay(&test, options, solver).overlay( - OverlayRule::Clip, - fill_rule, - ); + let clip_1 = overlay(&test, options, solver).overlay(OverlayRule::Clip, fill_rule); let difference_0 = graph.extract_shapes(OverlayRule::Difference, &mut buffer); - let difference_1 = overlay(&test, options, solver).overlay( - OverlayRule::Difference, - fill_rule, - ); + let difference_1 = + overlay(&test, options, solver).overlay(OverlayRule::Difference, fill_rule); let inverse_difference_0 = graph.extract_shapes(OverlayRule::InverseDifference, &mut buffer); - let inverse_difference_1 = overlay(&test, options, solver).overlay( - OverlayRule::InverseDifference, - fill_rule, - ); + let inverse_difference_1 = + overlay(&test, options, solver).overlay(OverlayRule::InverseDifference, fill_rule); let intersect_0 = graph.extract_shapes(OverlayRule::Intersect, &mut buffer); - let intersect_1 = overlay(&test, options, solver).overlay( - OverlayRule::Intersect, - fill_rule, - ); + let intersect_1 = + overlay(&test, options, solver).overlay(OverlayRule::Intersect, fill_rule); let union_0 = graph.extract_shapes(OverlayRule::Union, &mut buffer); - let union_1 = overlay(&test, options, solver).overlay( - OverlayRule::Union, - fill_rule, - ); + let union_1 = overlay(&test, options, solver).overlay(OverlayRule::Union, fill_rule); let xor_0 = graph.extract_shapes(OverlayRule::Xor, &mut buffer); - let xor_1 = overlay(&test, options, solver).overlay( - OverlayRule::Xor, - fill_rule, - ); + let xor_1 = overlay(&test, options, solver).overlay(OverlayRule::Xor, fill_rule); assert_eq!(subject_0, subject_1); assert_eq!(clip_0, clip_1); @@ -121,7 +104,12 @@ mod tests { #[allow(dead_code)] fn debug_execute(index: usize, overlay_rule: OverlayRule, fill_rule: FillRule, solver: Solver) { let test = BooleanTest::load(index); - let mut overlay = Overlay::with_contours_custom(&test.subj_paths, &test.clip_paths, Default::default(), solver); + let mut overlay = Overlay::with_contours_custom( + &test.subj_paths, + &test.clip_paths, + Default::default(), + solver, + ); let graph = overlay.build_graph_view(fill_rule).unwrap(); let result = graph.extract_shapes(overlay_rule, &mut Default::default()); diff --git a/iOverlay/tests/simplify_tests.rs b/iOverlay/tests/simplify_tests.rs index 7a98a8f..5aa6ef1 100644 --- a/iOverlay/tests/simplify_tests.rs +++ b/iOverlay/tests/simplify_tests.rs @@ -1,24 +1,23 @@ #[cfg(test)] mod tests { use i_float::int::point::IntPoint; - use i_shape::int::shape::IntShape; use i_overlay::core::fill_rule::FillRule; use i_overlay::core::overlay::{ContourDirection, IntOverlayOptions, Overlay, ShapeType}; use i_overlay::core::overlay_rule::OverlayRule; use i_overlay::core::simplify::Simplify; use i_overlay::core::solver::{Precision, Solver}; + use i_shape::int::shape::IntShape; #[test] fn test_0() { - let paths = - [ - [ - IntPoint::new(10614, 4421), - IntPoint::new(10609, 4421), - IntPoint::new(10609, 4415), - IntPoint::new(10614, 4415) - ].to_vec() - ].to_vec(); + let paths = [[ + IntPoint::new(10614, 4421), + IntPoint::new(10609, 4421), + IntPoint::new(10609, 4415), + IntPoint::new(10614, 4415), + ] + .to_vec()] + .to_vec(); let op = IntOverlayOptions { preserve_input_collinear: true, @@ -36,17 +35,17 @@ mod tests { #[test] fn test_1() { - let paths = - [ - square(IntPoint::new(-10, -10)), - square(IntPoint::new(-10, 0)), - square(IntPoint::new(-10, 10)), - square(IntPoint::new(0, -10)), - square(IntPoint::new(0, 10)), - square(IntPoint::new(10, -10)), - square(IntPoint::new(10, 0)), - square(IntPoint::new(10, 10)) - ].to_vec(); + let paths = [ + square(IntPoint::new(-10, -10)), + square(IntPoint::new(-10, 0)), + square(IntPoint::new(-10, 10)), + square(IntPoint::new(0, -10)), + square(IntPoint::new(0, 10)), + square(IntPoint::new(10, -10)), + square(IntPoint::new(10, 0)), + square(IntPoint::new(10, 10)), + ] + .to_vec(); let op = IntOverlayOptions { preserve_input_collinear: true, @@ -64,17 +63,17 @@ mod tests { #[test] fn test_2() { - let shapes = - [ - square_shape(IntPoint::new(-10, -10)), - square_shape(IntPoint::new(-10, 0)), - square_shape(IntPoint::new(-10, 10)), - square_shape(IntPoint::new(0, -10)), - square_shape(IntPoint::new(0, 10)), - square_shape(IntPoint::new(10, -10)), - square_shape(IntPoint::new(10, 0)), - square_shape(IntPoint::new(10, 10)) - ].to_vec(); + let shapes = [ + square_shape(IntPoint::new(-10, -10)), + square_shape(IntPoint::new(-10, 0)), + square_shape(IntPoint::new(-10, 10)), + square_shape(IntPoint::new(0, -10)), + square_shape(IntPoint::new(0, 10)), + square_shape(IntPoint::new(10, -10)), + square_shape(IntPoint::new(10, 0)), + square_shape(IntPoint::new(10, 10)), + ] + .to_vec(); let op = IntOverlayOptions { preserve_input_collinear: true, @@ -92,13 +91,13 @@ mod tests { #[test] fn test_3() { - let path = - [ - IntPoint::new(0, 0), - IntPoint::new(3, 1), - IntPoint::new(0, 3), - IntPoint::new(3, 0) - ].to_vec(); + let path = [ + IntPoint::new(0, 0), + IntPoint::new(3, 1), + IntPoint::new(0, 3), + IntPoint::new(3, 0), + ] + .to_vec(); let mut buffer = Default::default(); @@ -116,11 +115,15 @@ mod tests { let simple_0 = overlay_0 .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut buffer)); + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut buffer) + }); let simple_1 = overlay_1 .build_graph_view(FillRule::NonZero) - .map_or(Default::default(), |graph|graph.extract_shapes(OverlayRule::Subject, &mut buffer)); + .map_or(Default::default(), |graph| { + graph.extract_shapes(OverlayRule::Subject, &mut buffer) + }); assert_eq!(simple_0.len(), 1); assert_eq!(simple_0[0].len(), 1); @@ -134,13 +137,13 @@ mod tests { vec![ IntPoint::new(-5, 0), IntPoint::new(0, 0), - IntPoint::new(0, 5) + IntPoint::new(0, 5), ], vec![ IntPoint::new(-3, 2), IntPoint::new(-1, 2), - IntPoint::new(-1, 1) - ] + IntPoint::new(-1, 1), + ], ]; let op = IntOverlayOptions { @@ -164,8 +167,9 @@ mod tests { IntPoint::new(-5 + pos.x, -5 + pos.y), IntPoint::new(-5 + pos.x, 5 + pos.y), IntPoint::new(5 + pos.x, 5 + pos.y), - IntPoint::new(5 + pos.x, -5 + pos.y) - ].to_vec() + IntPoint::new(5 + pos.x, -5 + pos.y), + ] + .to_vec() } fn square_shape(pos: IntPoint) -> IntShape { diff --git a/iOverlay/tests/string_tests.rs b/iOverlay/tests/string_tests.rs index eb7d10d..6c0f19e 100644 --- a/iOverlay/tests/string_tests.rs +++ b/iOverlay/tests/string_tests.rs @@ -3,25 +3,48 @@ mod util; #[cfg(test)] mod tests { - use i_overlay::core::fill_rule::FillRule; - use i_overlay::string::clip::{ClipRule, IntClip}; - use i_overlay::string::slice::IntSlice; use crate::data::overlay::StringTest; use crate::util::overlay; use crate::util::overlay::JsonPrint; + use i_overlay::core::fill_rule::FillRule; + use i_overlay::string::clip::{ClipRule, IntClip}; + use i_overlay::string::slice::IntSlice; fn execute(index: usize) { let test = StringTest::load(index); let fill_rule = test.fill_rule.unwrap_or(FillRule::EvenOdd); let slice = test.body.slice_by_paths(&test.string, fill_rule); - assert_eq!(true, overlay::is_group_of_shapes_one_of(&slice, &test.slice)); - - let clip_direct = test.body.clip_paths(&test.string, fill_rule, ClipRule { invert: false, boundary_included: false }); - assert_eq!(true, overlay::is_paths_one_of(&clip_direct, &test.clip_direct)); - - let clip_invert = test.body.clip_paths(&test.string, fill_rule, ClipRule { invert: true, boundary_included: false }); - assert_eq!(true, overlay::is_paths_one_of(&clip_invert, &test.clip_invert)); + assert_eq!( + true, + overlay::is_group_of_shapes_one_of(&slice, &test.slice) + ); + + let clip_direct = test.body.clip_paths( + &test.string, + fill_rule, + ClipRule { + invert: false, + boundary_included: false, + }, + ); + assert_eq!( + true, + overlay::is_paths_one_of(&clip_direct, &test.clip_direct) + ); + + let clip_invert = test.body.clip_paths( + &test.string, + fill_rule, + ClipRule { + invert: true, + boundary_included: false, + }, + ); + assert_eq!( + true, + overlay::is_paths_one_of(&clip_invert, &test.clip_invert) + ); } fn debug_execute_slice(index: usize) { @@ -36,7 +59,14 @@ mod tests { let test = StringTest::load(index); let fill_rule = test.fill_rule.unwrap_or(FillRule::EvenOdd); - let clip = test.body.clip_paths(&test.string, fill_rule, ClipRule { invert, boundary_included: false }); + let clip = test.body.clip_paths( + &test.string, + fill_rule, + ClipRule { + invert, + boundary_included: false, + }, + ); println!("clip {}: {}", invert, clip.json_print()); } @@ -108,4 +138,4 @@ mod tests { debug_execute_clip(index, false); debug_execute_clip(index, true); } -} \ No newline at end of file +} diff --git a/iOverlay/tests/util.rs b/iOverlay/tests/util.rs index 4727aa2..3a92e8c 100644 --- a/iOverlay/tests/util.rs +++ b/iOverlay/tests/util.rs @@ -137,4 +137,3 @@ pub mod overlay { } } } - diff --git a/iOverlay/tests/vector_tests.rs b/iOverlay/tests/vector_tests.rs index 8995ccd..9724cf5 100644 --- a/iOverlay/tests/vector_tests.rs +++ b/iOverlay/tests/vector_tests.rs @@ -12,14 +12,14 @@ mod tests { IntPoint::new(-10240, -10240), IntPoint::new(-10240, 10240), IntPoint::new(10240, 10240), - IntPoint::new(10240, -10240) + IntPoint::new(10240, -10240), ]; let clip = [ IntPoint::new(-5120, -5120), IntPoint::new(-5120, 5120), IntPoint::new(5120, 5120), - IntPoint::new(5120, -5120) + IntPoint::new(5120, -5120), ]; let mut overlay = Overlay::new(2); @@ -34,25 +34,25 @@ mod tests { let vectors = &shapes[0][0]; let template = [ VectorEdge { - a: IntPoint::new(-10240,10240), - b: IntPoint::new(-10240,-10240), - fill: 1 + a: IntPoint::new(-10240, 10240), + b: IntPoint::new(-10240, -10240), + fill: 1, }, VectorEdge { - a: IntPoint::new(-10240,-10240), - b: IntPoint::new(10240,-10240), - fill: 1 + a: IntPoint::new(-10240, -10240), + b: IntPoint::new(10240, -10240), + fill: 1, }, VectorEdge { - a: IntPoint::new(10240,-10240), - b: IntPoint::new(10240,10240), - fill: 1 + a: IntPoint::new(10240, -10240), + b: IntPoint::new(10240, 10240), + fill: 1, }, VectorEdge { - a: IntPoint::new(10240,10240), - b: IntPoint::new(-10240,10240), - fill: 1 - } + a: IntPoint::new(10240, 10240), + b: IntPoint::new(-10240, 10240), + fill: 1, + }, ]; assert_eq!(vectors.as_slice(), template.as_slice()); @@ -64,14 +64,14 @@ mod tests { IntPoint::new(-10240, -10240), IntPoint::new(-10240, 10240), IntPoint::new(10240, 10240), - IntPoint::new(10240, -10240) + IntPoint::new(10240, -10240), ]; let clip = [ - IntPoint::new(-5120,-5120), - IntPoint::new(-5120,15360), - IntPoint::new(15360,15360), - IntPoint::new(15360,-5120) + IntPoint::new(-5120, -5120), + IntPoint::new(-5120, 15360), + IntPoint::new(15360, 15360), + IntPoint::new(15360, -5120), ]; let mut overlay = Overlay::new(2); @@ -86,37 +86,37 @@ mod tests { let vectors = &shapes[0][0]; let template = [ VectorEdge { - a: IntPoint::new(-10240,10240), - b: IntPoint::new(-10240,-10240), - fill: 1 + a: IntPoint::new(-10240, 10240), + b: IntPoint::new(-10240, -10240), + fill: 1, }, VectorEdge { - a: IntPoint::new(-10240,-10240), - b: IntPoint::new(10240,-10240), - fill: 1 + a: IntPoint::new(-10240, -10240), + b: IntPoint::new(10240, -10240), + fill: 1, }, VectorEdge { - a: IntPoint::new(10240,-10240), - b: IntPoint::new(10240,-5120), - fill: 1 + a: IntPoint::new(10240, -10240), + b: IntPoint::new(10240, -5120), + fill: 1, }, VectorEdge { - a: IntPoint::new(10240,-5120), - b: IntPoint::new(-5120,-5120), - fill: 11 + a: IntPoint::new(10240, -5120), + b: IntPoint::new(-5120, -5120), + fill: 11, }, VectorEdge { - a: IntPoint::new(-5120,-5120), - b: IntPoint::new(-5120,10240), - fill: 11 + a: IntPoint::new(-5120, -5120), + b: IntPoint::new(-5120, 10240), + fill: 11, }, VectorEdge { - a: IntPoint::new(-5120,10240), - b: IntPoint::new(-10240,10240), - fill: 1 - } + a: IntPoint::new(-5120, 10240), + b: IntPoint::new(-10240, 10240), + fill: 1, + }, ]; assert_eq!(vectors.as_slice(), template.as_slice()); } -} \ No newline at end of file +}