mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 07:18:04 +08:00
* 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>
125 lines
3.1 KiB
Rust
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)]
|
|
}
|
|
},
|
|
})
|
|
}
|