Files
vectorcraft/crates/pathops/src/lib.rs
T
dotCooCoo 4fae51023e Paths: Remove Anchor Points removes many anchors of a subpath in one pass
Object > Path > Remove Anchor Points removed each selected anchor with
its own Vec::remove, shifting the rest of the subpath every time, so
removing k anchors from an n-anchor subpath took O(k*n) moves.

- pathops: remove_anchors removes a subpath's anchors the last first,
  reading each anchor's current neighbors, handles, length and closed
  state as removing them one at a time does, and compacts the anchor
  list once. remove_anchor and remove_anchors share one refit, so the
  result is bit for bit the same.
- engine: the command groups the selected anchors by subpath, works out
  the next selected anchor with each subpath reading only its own
  selected anchors, and takes emptied paths out of the selection
  together (Selection::remove_all).
- Tests compare remove_anchors bit for bit with remove_anchor over 600
  generated subpaths and focused cases, count the anchors moved (2001
  anchors, every other one removed: at most one move per anchor left,
  500,500 one at a time), and compare the next-anchor selection and
  the command on many paths and subpaths with removing one at a time.
2026-11-13 06:54:55 -08:00

50 lines
2.1 KiB
Rust

//! VectorCraft path operations: booleans (Pathfinder), shape builder regions, offset, outline stroke,
//! simplify and the other Object → Path commands.
//!
//! Booleans are curve-preserving: `linesweeper`'s robust sweep-line works directly on cubic
//! Béziers, and the pieces it splits curves into are refitted afterwards so results carry few
//! anchors. See the crate README for the API overview.
#![forbid(unsafe_code)]
pub mod addons;
mod boolean;
mod budget;
mod edit;
mod fit;
mod offset;
mod pathfinder;
mod planar;
mod sweep_axis;
mod trap;
pub use boolean::{
BoolOp, DEFAULT_PRECISION, area, boolean, boolean_n, normalize, try_area, try_boolean, try_boolean_n, try_normalize, try_unite_all,
try_unite_all_with, unite_all, unite_all_with,
};
pub use edit::{
AverageAxis, SIMPLIFY_LEVEL, SMOOTH_AUTO_LEVEL, SimplifiedPart, SimplifyOptions, add_anchor_points, auto_simplify_level, average, join,
remove_anchor, remove_anchors, remove_redundant_points, simplify, simplify_level_tolerance, simplify_part, simplify_with, smooth, smooth_level,
smooth_options, split_into_grid,
};
pub use fit::{fit_cubics, fit_cubics_through};
pub use offset::{Cap, Join, MAX_OFFSET_SEGMENT_PAIRS, offset_path, outline_stroke, stroke_region, try_offset_path};
pub use pathfinder::{FaceMerger, PathfinderOp, Region, Shape, merge_regions, pathfinder, pathfinder_with, region_at, regions, regions_within};
pub use planar::{
BuilderArrangement, SHAPE_BUILDER_MAX_GAP, SHAPE_BUILDER_MAX_SEGMENTS, cut_out, encloses_area, find_gaps, has_open_path, interior_point,
live_paint, live_paint_with_gaps, run_around, shape_builder, shape_builder_with_gap,
};
pub use trap::{TRAP_HEIGHT_WIDTH_RANGE, TRAP_MAX_WIDTH, TRAP_MIN_WIDTH, trap_band};
/// Errors from fallible operations.
#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
pub enum PathOpsError {
#[error("input contains NaN or infinite coordinates")]
NonFinite,
#[error("input path could not be closed")]
OpenPath,
#[error("the shapes are too degenerate to combine")]
Degenerate,
#[error("the shapes cross themselves and each other too often to combine")]
TooComplex,
}