Files
vectorcraft/crates/geom/src/snap.rs
T
Brandon ThomasandClaude Opus 5.5 bfee80a22c M0: workspace skeleton — geom, color, doc, render, text, pathops, svg, tools, engine
Engine-first Cargo workspace for DrawCraft (clean-room Illustrator):
- geom: anchor-based path model, shapes, hit testing, snapping
- color: colours, paints, gradients, swatches, blend modes, harmonies
- doc: persistent Arc document tree, appearance stacks, text model, selection
- render: vello_cpu renderer (appearance, gradients, clip groups, blend modes)
- text: font DB, harfrust shaping, point/area/path layout
- pathops: curve booleans (linesweeper), Pathfinder, offset, simplify
- svg: import (usvg) and export
- tools: selection/direct/pen/shape tools emitting commands
- engine: Session, history with interactions, ~110 commands

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 05:53:29 -04:00

47 lines
1.3 KiB
Rust

//! Snapping math shared by tools and smart guides.
use kurbo::Point;
/// Snap a value to a grid with the given spacing and origin.
pub fn snap_to_grid(v: f64, spacing: f64, origin: f64) -> f64 {
if spacing <= 0.0 {
return v;
}
((v - origin) / spacing).round() * spacing + origin
}
pub fn snap_point_to_grid(p: Point, spacing: f64) -> Point {
Point::new(snap_to_grid(p.x, spacing, 0.0), snap_to_grid(p.y, spacing, 0.0))
}
/// A candidate alignment line for smart guides.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Axis {
X,
Y,
}
/// Find the closest target within `tol` to `v`. Returns (target, delta).
pub fn closest(v: f64, targets: impl IntoIterator<Item = f64>, tol: f64) -> Option<(f64, f64)> {
targets.into_iter().map(|t| (t, t - v)).filter(|(_, d)| d.abs() <= tol).min_by(|a, b| a.1.abs().total_cmp(&b.1.abs()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn grid() {
assert_eq!(snap_to_grid(13.0, 10.0, 0.0), 10.0);
assert_eq!(snap_to_grid(16.0, 10.0, 0.0), 20.0);
assert_eq!(snap_to_grid(16.0, 10.0, 3.0), 13.0);
assert_eq!(snap_to_grid(16.0, 0.0, 0.0), 16.0);
}
#[test]
fn closest_target() {
assert_eq!(closest(10.0, [0.0, 11.0, 9.5], 2.0), Some((9.5, -0.5)));
assert_eq!(closest(10.0, [0.0, 20.0], 2.0), None);
}
}