mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-25 02:48:13 +08:00
Refactor internal shape and reduce reliance on Kurbo (#617)
* Dissolve Points from path * Add handling for removing the first anchor * Add function to turn handles into bez_paths * Created overlay manager, wip * WIP Refactor of VectorShape / Overlays / ShapeEditor * WIP stripping vector shape, anchor, point. * WIP Removed kurbo deps from vector shape, anchor, point * WIP Further work to make vector shapes / anchors / points more standalone. * WIP more pruning * WIP Progress on overlay_renderer * WIP more overlay_renderer work * WIP more pruning, cleared warnings * WIP decided ShapeRenderer wasn't an accurate name, ShapeAdapter now. Error squashing continues. * WIP squashed more errors, now need to decide if anchors should have unique IDs * WIP Errors squashed, now to actually make it work. * WIP Moved vector structs to graphene, beginning to remove bezpath from shape_layer * Refactoring: disentangle kurbo from apply_affine * Refactor internal shape and remove reliance on Kurbo (PR #617) - Disentangle Kurbo (#619) * Refactoring: disentangle kurbo from apply_affine * Broke boolean operations, refactor in state which compiles * "fixed" boolean operation refactor related errors * fixed apply_affine, which would not have applied any type of affine * Small Cleanup, readability * Fix issue with overlay styles no longer showing selection state. * Resolved error with point option * WIP, figuring out how to have one source of truth for VectorShape. Trying to avoid cloning. * WIP work on single source of truth vectorshapes * More steps toward single source of truth VectorShape * Continued wip on making VectorShapes mutably accessible without cloning * Wip using paths to reference vectorshapes instead, need to restructure ShapeEditor * Decided to allow temporary copies of vectorshapes. * Removed HashSet for selected shape indices * Added @TrueDoctor's id_storage.rs with some heavy modification. Added it to VectorShape. Isn't yet used for folders. * Integrated UniqueElements<T> with VectorShape to store VectorAnchors * Improved storage_id.rs perf and cleaned up it's interface * Iterator Implementations and fixes (#637) * Refactoring: disentangle kurbo from apply_affine * Broke boolean operations, refactor in state which compiles * "fixed" boolean operation refactor related errors * fixed apply_affine, which would not have applied any type of affine * implemented transforms for VectorAnchors implemented Not for VectorControlPointType * started adding Vector Shape implementations of shape prototypes * added several useful implemtations to UniqueElements * added another implemnation for UniqueElements to make working with iterators easier, fixed vector-shape errors * package-lock.json * clean up rebase, added back Layer paths * added deref implementation for VectorShape * unnecesary variable * simplify code by removing levels of indirection * fixed errors * merge cleanup * removed package-lock.json * Removed .selected from VectorShape, it isn't needed as layers are selected not shapes specifically. * Removed transform and layer_path from VectorShape * Auto-saving tentitively working. Work toward Overlay transform issues. * Overlays properly hiding and caching. Not clearing cache yet and some tool switching issues remain, but progress. * Putting layers in folders changes their unique ID. This is problematic. Assumed this was not the case. * Removed need for closed bool, changed VectorShape to a tuple struct. * WIP Switched to layer paths as opposed to VectorShapes. Next up add messages for changing VectorShapes. * Added initial messages to edit VectorShape points. * DeleteSelectedPoints messages implemented, selection isn't working currently though. * Selection messages arriving in document, but transform is wrong. * Selection, Deselection working, delete working for first point. * Working towards moving points again * Removed extra vec from UniqueElements, attempting to squash ordering bug. Still appears to occur though. * Delete more stable, clean up, renamed to HandleIn, HandleOut * Further vec_unique cleanup * Further cleanup * Removed Deref / DerefMut from VectorShape * Document version++, will likely revert before merge into master * Seleting / deleting handles tentitively working again. * Version number bump, fixed tests. * Fixed comment in VecUnique * Improved VecUnique descriptor comment * Renamed VecUnique to IdBackedVec to further clarify usage. * Resolved formatting. * WIP Fixing dragging points * Fixed an instance where an OverlayMessage could be sent to the main document incorrectly. * Deleting all of a shapes points now gracefully deletes the layer instead of crashing. * Fixed handle configurations that would panic on deletion * Single anchor dragging restored with multi-dragging next plus handles * sides.into() * Handle and Multi-point dragging working * WIP Handle symmetry working again * Handle mirroring functional again. * Cleaned up warnings * Fixed overlay outline not matching shape * Git branch fix of compatibility with new master * Fixed closed shape bug, replaced kurbo ellipse * Removed unused func, updated comments * Deleting points can undo, multiple shape selection deletes now working * Removed AddOverlay* operations * Partial fix for select drift, added helpers * Don't snap against dragging points * Properly cleanup path outline with multiple shapes * Clear all points in other selected shapes * Actually don't snap against dragging points * Fix path tool & add snap angle and break handle * Fix handle being set to NaN causing render issues * Fix cached overlays not showing line -> curve * Add operations for modifying paths * Remove kurbo from pen tool * Do not snap against handles when anchor selected * Fix overlays not being cleaned up on path tool * Fix handle position after dragging * Use `Anchor` for text & no kurbo in operations * Replace kurbo to_svg function * Ngon no longer center scales by default, still some weird behaviour when holding alt * Cleanup overlays * Fix render and bounding box doctests * Fix fun to_svg error * Fix compile error * Some code review * Remove legacy `SelectPoint` on doubleclick * Remove font from test document * Fix the pen tool selection changed * Reorder imports Co-authored-by: Dennis <dennis@kobert.dev> Co-authored-by: Caleb Dennis <caleb.dennis429@gmail.com> Co-authored-by: caleb <56044292+caleb-ad@users.noreply.github.com> Co-authored-by: Keavon Chambers <keavon@keavon.com> Co-authored-by: 0hypercube <0hypercube@gmail.com> Co-authored-by: 0HyperCube <78500760+0HyperCube@users.noreply.github.com>
This commit is contained in:
committed by
Keavon Chambers
co-authored by
Dennis
Caleb Dennis
caleb
Keavon Chambers
0hypercube
0HyperCube
parent
6042b32a86
commit
20cfd5f600
+27
-23
@@ -404,7 +404,7 @@ impl PathGraph {
|
||||
concat_paths(&mut curve, &self.edge(vertices[index - 1].0, vertices[index].0, vertices[index].1).unwrap().curve);
|
||||
}
|
||||
curve.push(PathEl::ClosePath);
|
||||
ShapeLayer::from_bez_path(BezPath::from_vec(curve), style.clone(), false)
|
||||
ShapeLayer::new(BezPath::from_vec(curve).iter().into(), style.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,24 +535,24 @@ pub fn composite_boolean_operation(mut select: BooleanOperation, shapes: &mut Ve
|
||||
// TODO: check if shapes are filled
|
||||
// TODO: Bug: shape with at least two subpaths and comprised of many unions sometimes has erroneous movetos embedded in edges
|
||||
pub fn boolean_operation(mut select: BooleanOperation, alpha: &mut ShapeLayer, beta: &mut ShapeLayer) -> Result<Vec<ShapeLayer>, BooleanOperationError> {
|
||||
if alpha.path.is_empty() || beta.path.is_empty() {
|
||||
if alpha.shape.anchors().is_empty() || beta.shape.anchors().is_empty() {
|
||||
return Err(BooleanOperationError::InvalidSelection);
|
||||
}
|
||||
if select == BooleanOperation::SubtractBack {
|
||||
select = BooleanOperation::SubtractFront;
|
||||
swap(alpha, beta);
|
||||
}
|
||||
alpha.path = close_path(&alpha.path);
|
||||
beta.path = close_path(&beta.path);
|
||||
let beta_reverse = close_path(&reverse_path(&beta.path));
|
||||
let alpha_dir = Cycle::direction_for_path(&alpha.path)?;
|
||||
let beta_dir = Cycle::direction_for_path(&beta.path)?;
|
||||
let mut alpha_shape = close_path(&(&alpha.shape).into());
|
||||
let beta_shape = close_path(&(&beta.shape).into());
|
||||
let beta_reverse = close_path(&reverse_path(&beta_shape));
|
||||
let alpha_dir = Cycle::direction_for_path(&alpha_shape)?;
|
||||
let beta_dir = Cycle::direction_for_path(&beta_shape)?;
|
||||
match select {
|
||||
BooleanOperation::Union => {
|
||||
match if beta_dir == alpha_dir {
|
||||
PathGraph::from_paths(&alpha.path, &beta.path)
|
||||
PathGraph::from_paths(&alpha_shape, &beta_shape)
|
||||
} else {
|
||||
PathGraph::from_paths(&alpha.path, &beta_reverse)
|
||||
PathGraph::from_paths(&alpha_shape, &beta_reverse)
|
||||
} {
|
||||
Ok(graph) => {
|
||||
let mut cycles = graph.get_cycles();
|
||||
@@ -562,16 +562,20 @@ pub fn boolean_operation(mut select: BooleanOperation, alpha: &mut ShapeLayer, b
|
||||
&alpha.style,
|
||||
);
|
||||
for interior in collect_shapes(&graph, &mut cycles, |dir| dir != alpha_dir, |_| &alpha.style)? {
|
||||
add_subpath(&mut boolean_union.path, interior.path);
|
||||
//TODO: this is not very efficient or nice to read
|
||||
let mut a_path: BezPath = (&boolean_union.shape).into();
|
||||
let b_path: BezPath = (&interior.shape).into();
|
||||
add_subpath(&mut a_path, b_path);
|
||||
boolean_union.shape = a_path.iter().into();
|
||||
}
|
||||
Ok(vec![boolean_union])
|
||||
}
|
||||
Err(BooleanOperationError::NoIntersections) => {
|
||||
// If shape is inside the other the Union is just the larger
|
||||
// Check could also be done with area and single ray cast
|
||||
if cast_horizontal_ray(point_on_curve(&beta.path), &alpha.path) % 2 != 0 {
|
||||
if cast_horizontal_ray(point_on_curve(&beta_shape), &alpha_shape) % 2 != 0 {
|
||||
Ok(vec![alpha.clone()])
|
||||
} else if cast_horizontal_ray(point_on_curve(&alpha.path), &beta.path) % 2 != 0 {
|
||||
} else if cast_horizontal_ray(point_on_curve(&alpha_shape), &beta_shape) % 2 != 0 {
|
||||
beta.style = alpha.style.clone();
|
||||
Ok(vec![beta.clone()])
|
||||
} else {
|
||||
@@ -583,17 +587,17 @@ pub fn boolean_operation(mut select: BooleanOperation, alpha: &mut ShapeLayer, b
|
||||
}
|
||||
BooleanOperation::Difference => {
|
||||
let graph = if beta_dir != alpha_dir {
|
||||
PathGraph::from_paths(&alpha.path, &beta.path)?
|
||||
PathGraph::from_paths(&alpha_shape, &beta_shape)?
|
||||
} else {
|
||||
PathGraph::from_paths(&alpha.path, &beta_reverse)?
|
||||
PathGraph::from_paths(&alpha_shape, &beta_reverse)?
|
||||
};
|
||||
collect_shapes(&graph, &mut graph.get_cycles(), |_| true, |dir| if dir == alpha_dir { &alpha.style } else { &beta.style })
|
||||
}
|
||||
BooleanOperation::Intersection => {
|
||||
match if beta_dir == alpha_dir {
|
||||
PathGraph::from_paths(&alpha.path, &beta.path)
|
||||
PathGraph::from_paths(&alpha_shape, &beta_shape)
|
||||
} else {
|
||||
PathGraph::from_paths(&alpha.path, &beta_reverse)
|
||||
PathGraph::from_paths(&alpha_shape, &beta_reverse)
|
||||
} {
|
||||
Ok(graph) => {
|
||||
let mut cycles = graph.get_cycles();
|
||||
@@ -610,10 +614,10 @@ pub fn boolean_operation(mut select: BooleanOperation, alpha: &mut ShapeLayer, b
|
||||
}
|
||||
Err(BooleanOperationError::NoIntersections) => {
|
||||
// Check could also be done with area and single ray cast
|
||||
if cast_horizontal_ray(point_on_curve(&beta.path), &alpha.path) % 2 != 0 {
|
||||
if cast_horizontal_ray(point_on_curve(&beta_shape), &alpha_shape) % 2 != 0 {
|
||||
beta.style = alpha.style.clone();
|
||||
Ok(vec![beta.clone()])
|
||||
} else if cast_horizontal_ray(point_on_curve(&alpha.path), &beta.path) % 2 != 0 {
|
||||
} else if cast_horizontal_ray(point_on_curve(&alpha_shape), &beta_shape) % 2 != 0 {
|
||||
Ok(vec![alpha.clone()])
|
||||
} else {
|
||||
Err(BooleanOperationError::NothingDone)
|
||||
@@ -627,14 +631,14 @@ pub fn boolean_operation(mut select: BooleanOperation, alpha: &mut ShapeLayer, b
|
||||
}
|
||||
BooleanOperation::SubtractFront => {
|
||||
match if beta_dir != alpha_dir {
|
||||
PathGraph::from_paths(&alpha.path, &beta.path)
|
||||
PathGraph::from_paths(&alpha_shape, &beta_shape)
|
||||
} else {
|
||||
PathGraph::from_paths(&alpha.path, &beta_reverse)
|
||||
PathGraph::from_paths(&alpha_shape, &beta_reverse)
|
||||
} {
|
||||
Ok(graph) => collect_shapes(&graph, &mut graph.get_cycles(), |dir| dir == alpha_dir, |_| &alpha.style),
|
||||
Err(BooleanOperationError::NoIntersections) => {
|
||||
if cast_horizontal_ray(point_on_curve(&beta.path), &alpha.path) % 2 != 0 {
|
||||
add_subpath(&mut alpha.path, if beta_dir == alpha_dir { reverse_path(&beta.path) } else { beta.path.clone() });
|
||||
if cast_horizontal_ray(point_on_curve(&beta_shape), &alpha_shape) % 2 != 0 {
|
||||
add_subpath(&mut alpha_shape, if beta_dir == alpha_dir { reverse_path(&beta_shape) } else { beta_shape });
|
||||
Ok(vec![alpha.clone()])
|
||||
} else {
|
||||
Err(BooleanOperationError::NothingDone)
|
||||
@@ -654,7 +658,7 @@ pub fn cast_horizontal_ray(from: Point, into: &BezPath) -> usize {
|
||||
});
|
||||
let mut intersects = Vec::new();
|
||||
for ref mut seg in into.segments() {
|
||||
if seg.bounding_box().x1 > from.x {
|
||||
if kurbo::ParamCurveExtrema::bounding_box(seg).x1 > from.x {
|
||||
line_curve_intersections((&mut ray, seg), |_, b| valid_t(b), &mut intersects);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user