Implement extending, joining, and creating new subpaths with the Spline tool (#2203)

* visualize spline end points using overlays

* implement for spline tool to extend path by draging end points

* allow holding Shift to begin drawing a new spline subpath in the same layer

* implement spline tool to join two endpoints

* fix naming

* refactor spline tool

* impl spline tool snapping and overlays

* fix joining path and refactor

* improve join_path comment

* fix snapping overlays flickering by ignoring snapping in current layer

* fix inserting single point on aborting spline tool

* add snapping for endpoint even when regular snapping is disabled

* fix extending

* fix inserting new point instead of extending and Add hint for Shift to append

* fix grammatical errors and code style

* Code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Priyanshu
2025-01-25 11:24:08 +00:00
committed by GitHub
co-authored by Keavon Chambers
parent 33ac141fb8
commit f7b7f6b9f4
5 changed files with 163 additions and 36 deletions
@@ -7,14 +7,32 @@ use glam::DVec2;
/// Determines if a path should be extended. Goal in viewport space. Returns the path and if it is extending from the start, if applicable.
pub fn should_extend(document: &DocumentMessageHandler, goal: DVec2, tolerance: f64, layers: impl Iterator<Item = LayerNodeIdentifier>) -> Option<(LayerNodeIdentifier, PointId, DVec2)> {
closest_point(document, goal, tolerance, layers, |_| false)
}
/// Determine the closest point to the goal point under max_distance.
/// Additionally exclude checking closeness to the point which given to exclude() returns true.
pub fn closest_point<T>(
document: &DocumentMessageHandler,
goal: DVec2,
max_distance: f64,
layers: impl Iterator<Item = LayerNodeIdentifier>,
exclude: T,
) -> Option<(LayerNodeIdentifier, PointId, DVec2)>
where
T: Fn(PointId) -> bool,
{
let mut best = None;
let mut best_distance_squared = tolerance * tolerance;
let mut best_distance_squared = max_distance * max_distance;
for layer in layers {
let viewspace = document.metadata().transform_to_viewport(layer);
let Some(vector_data) = document.network_interface.compute_modified_vector(layer) else {
continue;
};
for id in vector_data.single_connected_points() {
if exclude(id) {
continue;
}
let Some(point) = vector_data.point_domain.position_from_id(id) else { continue };
let distance_squared = viewspace.transform_point2(point).distance_squared(goal);