Files
Graphite/libraries/path-bool/src/parsing/path_command.rs
Dennis Kobert 3eb98c6d6d Add path-bool library (#1952)
* Add path-bool library

* Cleanup code

* Cargo format

* Integrate boolean ops into graphite

* Add test for editor crash

* Fix edge sort floating point instability

* Add unit test for red-dress failure

* Backport tests and aux functions

* Use curvature based sorting

* Convert linear cubic splines to line segments

* Deduplicate reversed path segments

* Fix epsilon for empty segments

* Remove parameter based intersection pruning

* Add support for reversed paths

* Add benchmark infrastructure

* Add intersection benchmark

* Add recursion bound

* Implement support for overlapping path segments

* Remove rouge prinln

* Fix sorting for bezier segments with one control point at the start of the segment

* Cleanup log statements

* Directly translate graphite paths to Path segments

* Round data before passing it to path_bool

* Fix flag_faces traversal order

* Add test for white dots in bottom right of painted dreams

* Make rounding configurable

* Update demo artwork to remove manual path modifications

* Convert from path segments to manipulator groups directly

* Remove dead code

* Fix clippy lints

* Replace functions in path segment with methods and add documentation

* Add more documentation

* Close subpaths

* Reorganize files and add README.md

* Add license information

* Code review

* Fix license info

* Adopt new node macro and fix demo artwork

* Close subpaths with Z

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
2024-09-21 02:06:43 -07:00

125 lines
3.1 KiB
Rust

use glam::DVec2;
#[derive(Clone, Debug)]
pub enum AbsolutePathCommand {
H(f64),
V(f64),
M(DVec2),
L(DVec2),
C(DVec2, DVec2, DVec2),
S(DVec2, DVec2),
Q(DVec2, DVec2),
T(DVec2),
A(f64, f64, f64, bool, bool, DVec2),
Z,
}
#[derive(Clone, Debug)]
pub enum RelativePathCommand {
H(f64),
V(f64),
M(f64, f64),
L(f64, f64),
C(f64, f64, f64, f64, f64, f64),
S(f64, f64, f64, f64),
Q(f64, f64, f64, f64),
T(f64, f64),
A(f64, f64, f64, bool, bool, f64, f64),
}
#[derive(Clone, Debug)]
pub enum PathCommand {
Absolute(AbsolutePathCommand),
Relative(RelativePathCommand),
}
pub fn to_absolute_commands<I>(commands: I) -> impl Iterator<Item = AbsolutePathCommand>
where
I: IntoIterator<Item = PathCommand>,
{
let mut last_point = DVec2::ZERO;
let mut first_point = last_point;
commands.into_iter().flat_map(move |cmd| match cmd {
PathCommand::Absolute(abs_cmd) => {
match abs_cmd {
AbsolutePathCommand::H(x) => {
last_point.x = x;
}
AbsolutePathCommand::V(y) => {
last_point.y = y;
}
AbsolutePathCommand::M(point) => {
last_point = point;
first_point = point;
}
AbsolutePathCommand::L(point) => {
last_point = point;
}
AbsolutePathCommand::C(_, _, end) => {
last_point = end;
}
AbsolutePathCommand::S(_, end) => {
last_point = end;
}
AbsolutePathCommand::Q(_, end) => {
last_point = end;
}
AbsolutePathCommand::T(end) => {
last_point = end;
}
AbsolutePathCommand::A(_, _, _, _, _, end) => {
last_point = end;
}
AbsolutePathCommand::Z => {
last_point = first_point;
}
}
vec![abs_cmd]
}
PathCommand::Relative(rel_cmd) => match rel_cmd {
RelativePathCommand::H(dx) => {
last_point.x += dx;
vec![AbsolutePathCommand::L(last_point)]
}
RelativePathCommand::V(dy) => {
last_point.y += dy;
vec![AbsolutePathCommand::L(last_point)]
}
RelativePathCommand::M(dx, dy) => {
last_point += DVec2::new(dx, dy);
first_point = last_point;
vec![AbsolutePathCommand::M(last_point)]
}
RelativePathCommand::L(dx, dy) => {
last_point += DVec2::new(dx, dy);
vec![AbsolutePathCommand::L(last_point)]
}
RelativePathCommand::C(dx1, dy1, dx2, dy2, dx, dy) => {
let c1 = last_point + DVec2::new(dx1, dy1);
let c2 = last_point + DVec2::new(dx2, dy2);
last_point += DVec2::new(dx, dy);
vec![AbsolutePathCommand::C(c1, c2, last_point)]
}
RelativePathCommand::S(dx2, dy2, dx, dy) => {
let c2 = last_point + DVec2::new(dx2, dy2);
last_point += DVec2::new(dx, dy);
vec![AbsolutePathCommand::S(c2, last_point)]
}
RelativePathCommand::Q(dx1, dy1, dx, dy) => {
let control = last_point + DVec2::new(dx1, dy1);
last_point += DVec2::new(dx, dy);
vec![AbsolutePathCommand::Q(control, last_point)]
}
RelativePathCommand::T(dx, dy) => {
last_point += DVec2::new(dx, dy);
vec![AbsolutePathCommand::T(last_point)]
}
RelativePathCommand::A(rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, dx, dy) => {
last_point += DVec2::new(dx, dy);
vec![AbsolutePathCommand::A(rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, last_point)]
}
},
})
}