mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-12-23 10:11:54 +00:00
* Update to rust 2024 edition * Fixes * Clean up imports * Cargo fmt again --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
140 lines
4.3 KiB
Rust
140 lines
4.3 KiB
Rust
pub(crate) mod intersection_path_segment;
|
|
pub(crate) mod line_segment;
|
|
pub(crate) mod line_segment_aabb;
|
|
pub(crate) mod path_cubic_segment_self_intersection;
|
|
pub(crate) mod path_segment;
|
|
|
|
use glam::DVec2;
|
|
|
|
#[cfg(feature = "parsing")]
|
|
use crate::path_command::{AbsolutePathCommand, PathCommand, to_absolute_commands};
|
|
use crate::path_segment::PathSegment;
|
|
|
|
pub type Path = Vec<PathSegment>;
|
|
|
|
fn reflect_control_point(point: DVec2, control_point: DVec2) -> DVec2 {
|
|
point * 2. - control_point
|
|
}
|
|
|
|
#[cfg(feature = "parsing")]
|
|
pub fn path_from_commands<I>(commands: I) -> impl Iterator<Item = PathSegment>
|
|
where
|
|
I: IntoIterator<Item = PathCommand>,
|
|
{
|
|
let mut first_point: Option<DVec2> = None;
|
|
let mut last_point: Option<DVec2> = None;
|
|
let mut last_control_point: Option<DVec2> = None;
|
|
|
|
to_absolute_commands(commands).filter_map(move |cmd| match cmd {
|
|
AbsolutePathCommand::M(point) => {
|
|
last_point = Some(point);
|
|
first_point = Some(point);
|
|
last_control_point = None;
|
|
None
|
|
}
|
|
AbsolutePathCommand::L(point) => {
|
|
let start = last_point.unwrap();
|
|
last_point = Some(point);
|
|
last_control_point = None;
|
|
Some(PathSegment::Line(start, point))
|
|
}
|
|
AbsolutePathCommand::H(x) => {
|
|
let start = last_point.unwrap();
|
|
let point = DVec2::new(x, start.y);
|
|
last_point = Some(point);
|
|
last_control_point = None;
|
|
Some(PathSegment::Line(start, point))
|
|
}
|
|
AbsolutePathCommand::V(y) => {
|
|
let start = last_point.unwrap();
|
|
let point = DVec2::new(start.x, y);
|
|
last_point = Some(point);
|
|
last_control_point = None;
|
|
Some(PathSegment::Line(start, point))
|
|
}
|
|
AbsolutePathCommand::C(c1, c2, end) => {
|
|
let start = last_point.unwrap();
|
|
last_point = Some(end);
|
|
last_control_point = Some(c2);
|
|
Some(PathSegment::Cubic(start, c1, c2, end))
|
|
}
|
|
AbsolutePathCommand::S(c2, end) => {
|
|
let start = last_point.unwrap();
|
|
let c1 = reflect_control_point(start, last_control_point.unwrap_or(start));
|
|
last_point = Some(end);
|
|
last_control_point = Some(c2);
|
|
Some(PathSegment::Cubic(start, c1, c2, end))
|
|
}
|
|
AbsolutePathCommand::Q(c, end) => {
|
|
let start = last_point.unwrap();
|
|
last_point = Some(end);
|
|
last_control_point = Some(c);
|
|
Some(PathSegment::Quadratic(start, c, end))
|
|
}
|
|
AbsolutePathCommand::T(end) => {
|
|
let start = last_point.unwrap();
|
|
let c = reflect_control_point(start, last_control_point.unwrap_or(start));
|
|
last_point = Some(end);
|
|
last_control_point = Some(c);
|
|
Some(PathSegment::Quadratic(start, c, end))
|
|
}
|
|
AbsolutePathCommand::A(rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, end) => {
|
|
let start = last_point.unwrap();
|
|
last_point = Some(end);
|
|
last_control_point = None;
|
|
Some(PathSegment::Arc(start, rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, end))
|
|
}
|
|
AbsolutePathCommand::Z => {
|
|
let start = last_point.unwrap();
|
|
let end = first_point.unwrap();
|
|
last_point = Some(end);
|
|
last_control_point = None;
|
|
Some(PathSegment::Line(start, end))
|
|
}
|
|
})
|
|
}
|
|
|
|
#[cfg(feature = "parsing")]
|
|
pub fn path_to_commands<'a, I>(segments: I, eps: f64) -> impl Iterator<Item = PathCommand> + 'a
|
|
where
|
|
I: IntoIterator<Item = &'a PathSegment> + 'a,
|
|
{
|
|
let mut last_point: Option<DVec2> = None;
|
|
|
|
segments
|
|
.into_iter()
|
|
.flat_map(move |seg| {
|
|
let start = seg.start();
|
|
let mut commands = Vec::new();
|
|
|
|
if last_point.is_none_or(|lp| !start.abs_diff_eq(lp, eps)) {
|
|
if last_point.is_some() {
|
|
commands.push(PathCommand::Absolute(AbsolutePathCommand::Z));
|
|
}
|
|
|
|
commands.push(PathCommand::Absolute(AbsolutePathCommand::M(start)));
|
|
}
|
|
|
|
match seg {
|
|
PathSegment::Line(_, end) => {
|
|
commands.push(PathCommand::Absolute(AbsolutePathCommand::L(*end)));
|
|
last_point = Some(*end);
|
|
}
|
|
PathSegment::Cubic(_, c1, c2, end) => {
|
|
commands.push(PathCommand::Absolute(AbsolutePathCommand::C(*c1, *c2, *end)));
|
|
last_point = Some(*end);
|
|
}
|
|
PathSegment::Quadratic(_, c, end) => {
|
|
commands.push(PathCommand::Absolute(AbsolutePathCommand::Q(*c, *end)));
|
|
last_point = Some(*end);
|
|
}
|
|
PathSegment::Arc(_, rx, ry, x_axis_rotation, large_arc_flag, sweep_flag, end) => {
|
|
commands.push(PathCommand::Absolute(AbsolutePathCommand::A(*rx, *ry, *x_axis_rotation, *large_arc_flag, *sweep_flag, *end)));
|
|
last_point = Some(*end);
|
|
}
|
|
}
|
|
|
|
commands
|
|
})
|
|
.chain(std::iter::once(PathCommand::Absolute(AbsolutePathCommand::Z)))
|
|
}
|