mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-04 12:38:12 +08:00
Add nondestructive vector editing (#1676)
* Initial vector modify node * Initial extraction of data from monitor nodes * Migrate to point id * Start converting to modify node * Non destructive spline tool (tout le reste est cassé) * Fix unconnected modify node * Fix freehand tool * Pen tool * Migrate demo art * Select points * Fix the demo artwork * Fix the X and Y inputs for path tool * G1 continous toggle * Delete points * Fix test * Insert point * Improve robustness of handles * Fix GRS shortcuts on path * Dragging points * Fix build * Preserve opposing handle lengths * Update demo art and snapping * Fix polygon tool * Double click end anchor * Improve dragging * Fix text shifting * Select only connected verts * Colinear alt * Cleanup * Fix imports * Improve pen tool avoiding handle placement * Improve disolve * Remove pivot widget from Transform node properties * Fix demo art * Fix bugs * Re-save demo artwork * Code review * Serialize hashmap as tuple vec to enable deserialize_inputs * Fix migrate * Add document upgrade function to editor_api.rs * Finalize document upgrading * Rename to the Path node * Remove smoothing from Freehand tool * Upgrade demo artwork * Propertly disable raw-rs tests --------- Co-authored-by: Keavon Chambers <keavon@keavon.com> Co-authored-by: Adam <adamgerhant@gmail.com> Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
co-authored by
Keavon Chambers
Adam
Dennis Kobert
parent
fd3613018a
commit
1652c713a6
@@ -6,7 +6,7 @@ use crate::TValue;
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
use std::f64::consts::PI;
|
||||
|
||||
impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
impl<PointId: crate::Identifier> Subpath<PointId> {
|
||||
/// Calculate the point on the subpath based on the parametric `t`-value provided.
|
||||
/// Expects `t` to be within the inclusive range `[0, 1]`.
|
||||
/// <iframe frameBorder="0" width="100%" height="350px" src="https://graphite.rs/libraries/bezier-rs#subpath/evaluate/solo" title="Evaluate Demo"></iframe>
|
||||
@@ -39,7 +39,7 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
/// This function expects the following:
|
||||
/// - other: a [Bezier] curve to check intersections against
|
||||
/// - error: an optional f64 value to provide an error bound
|
||||
pub fn subpath_intersections(&self, other: &Subpath<ManipulatorGroupId>, error: Option<f64>, minimum_separation: Option<f64>) -> Vec<(usize, f64)> {
|
||||
pub fn subpath_intersections(&self, other: &Subpath<PointId>, error: Option<f64>, minimum_separation: Option<f64>) -> Vec<(usize, f64)> {
|
||||
let mut intersection_t_values: Vec<(usize, f64)> = other.iter().flat_map(|bezier| self.intersections(&bezier, error, minimum_separation)).collect();
|
||||
intersection_t_values.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
intersection_t_values
|
||||
@@ -302,6 +302,18 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
self.iter().map(|bezier| bezier.winding(target_point)).sum::<i32>() != 0
|
||||
}
|
||||
|
||||
/// Does a path contain a point? Based on the non zero winding. Automatically adds a linear segment if the subpath is not closed.
|
||||
pub fn contains_point_autoclose(&self, target_point: DVec2) -> bool {
|
||||
let mut winding = self.iter().map(|bezier| bezier.winding(target_point)).sum::<i32>();
|
||||
if !self.closed {
|
||||
if let [Some(first), Some(last)] = [self.manipulator_groups.first(), self.manipulator_groups.last()] {
|
||||
winding += Bezier::from_linear_dvec2(first.anchor, last.anchor).winding(target_point);
|
||||
}
|
||||
}
|
||||
|
||||
winding != 0
|
||||
}
|
||||
|
||||
/// Randomly places points across the filled surface of this subpath (which is assumed to be closed).
|
||||
/// The `separation_disk_diameter` determines the minimum distance between all points from one another.
|
||||
/// Conceptually, this works by "throwing a dart" at the subpath's bounding box and keeping the dart only if:
|
||||
@@ -342,7 +354,7 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
/// Alternatively, this can be interpreted as limiting the angle that the miter can form.
|
||||
/// When the limit is exceeded, no manipulator group will be returned.
|
||||
/// This value should be at least 1. If not, the default of 4 will be used.
|
||||
pub(crate) fn miter_line_join(&self, other: &Subpath<ManipulatorGroupId>, miter_limit: Option<f64>) -> Option<ManipulatorGroup<ManipulatorGroupId>> {
|
||||
pub(crate) fn miter_line_join(&self, other: &Subpath<PointId>, miter_limit: Option<f64>) -> Option<ManipulatorGroup<PointId>> {
|
||||
let miter_limit = match miter_limit {
|
||||
Some(miter_limit) if miter_limit >= 1. => miter_limit,
|
||||
_ => 4.,
|
||||
@@ -371,7 +383,7 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
anchor: intersection,
|
||||
in_handle: None,
|
||||
out_handle: None,
|
||||
id: ManipulatorGroupId::new(),
|
||||
id: PointId::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -384,7 +396,7 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
/// - The `out_handle` for the last manipulator group of `self`
|
||||
/// - The new manipulator group to be added
|
||||
/// - The `in_handle` for the first manipulator group of `other`
|
||||
pub(crate) fn round_line_join(&self, other: &Subpath<ManipulatorGroupId>, center: DVec2) -> (DVec2, ManipulatorGroup<ManipulatorGroupId>, DVec2) {
|
||||
pub(crate) fn round_line_join(&self, other: &Subpath<PointId>, center: DVec2) -> (DVec2, ManipulatorGroup<PointId>, DVec2) {
|
||||
let left = self.manipulator_groups[self.len() - 1].anchor;
|
||||
let right = other.manipulator_groups[0].anchor;
|
||||
|
||||
@@ -410,7 +422,7 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
/// - The `out_handle` for the last manipulator group of `self`
|
||||
/// - The new manipulator group to be added
|
||||
/// - The `in_handle` for the first manipulator group of `other`
|
||||
pub(crate) fn round_cap(&self, other: &Subpath<ManipulatorGroupId>) -> (DVec2, ManipulatorGroup<ManipulatorGroupId>, DVec2) {
|
||||
pub(crate) fn round_cap(&self, other: &Subpath<PointId>) -> (DVec2, ManipulatorGroup<PointId>, DVec2) {
|
||||
let left = self.manipulator_groups[self.len() - 1].anchor;
|
||||
let right = other.manipulator_groups[0].anchor;
|
||||
|
||||
@@ -423,7 +435,7 @@ impl<ManipulatorGroupId: crate::Identifier> Subpath<ManipulatorGroupId> {
|
||||
}
|
||||
|
||||
/// Returns the two manipulator groups that create a square cap between the end of `self` and the beginning of `other`.
|
||||
pub(crate) fn square_cap(&self, other: &Subpath<ManipulatorGroupId>) -> [ManipulatorGroup<ManipulatorGroupId>; 2] {
|
||||
pub(crate) fn square_cap(&self, other: &Subpath<PointId>) -> [ManipulatorGroup<PointId>; 2] {
|
||||
let left = self.manipulator_groups[self.len() - 1].anchor;
|
||||
let right = other.manipulator_groups[0].anchor;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user