Make the Pen tool extend an endpoint by starting with a colinear, equidistant handle (#2295)

* Fixed Pen extension having collienar handles

* Reformat a little

* handles being colinear for GRS

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Adesh Gupta 2025-02-20 19:12:10 +05:30 committed by GitHub
parent 38e542e6c0
commit cf2a071fb9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 61 additions and 19 deletions

View File

@ -690,25 +690,9 @@ impl PenToolData {
self.handle_end = None;
let tolerance = crate::consts::SNAP_POINT_TOLERANCE;
if let Some((layer, point, position)) = should_extend(document, viewport, tolerance, selected_nodes.selected_layers(document.metadata()), preferences) {
// Perform extension of an existing path
let in_segment = if self.modifiers.lock_angle { self.end_point_segment } else { None };
self.add_point(LastPoint {
id: point,
pos: position,
in_segment,
handle_start: position,
});
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
self.next_point = position;
self.next_handle_start = position;
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
if self.modifiers.lock_angle {
self.set_lock_angle(&vector_data, point, segment);
}
let extension_choice = should_extend(document, viewport, tolerance, selected_nodes.selected_layers(document.metadata()), preferences);
if let Some((layer, point, position)) = extension_choice {
self.extend_existing_path(document, layer, point, position, responses);
return;
}
@ -759,6 +743,64 @@ impl PenToolData {
responses.add(PenToolMessage::AddPointLayerPosition { layer, viewport });
}
/// Perform extension of an existing path
fn extend_existing_path(&mut self, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, point: PointId, position: DVec2, responses: &mut VecDeque<Message>) {
let vector_data = document.network_interface.compute_modified_vector(layer);
let (handle_start, in_segment) = if let Some(vector_data) = &vector_data {
vector_data
.segment_bezier_iter()
.find_map(|(segment_id, bezier, start, end)| {
let is_end = point == end;
let is_start = point == start;
if !is_end && !is_start {
return None;
}
let handle = match bezier.handles {
BezierHandles::Cubic { handle_start, handle_end, .. } => {
if is_start {
handle_start
} else {
handle_end
}
}
BezierHandles::Quadratic { handle } => handle,
_ => return None,
};
Some((segment_id, is_end, handle))
})
.map(|(segment_id, is_end, handle)| {
let mirrored_handle = position * 2. - handle;
let in_segment = if is_end { Some(segment_id) } else { None };
(mirrored_handle, in_segment)
})
.unwrap_or_else(|| (position, None))
} else {
(position, None)
};
let in_segment = if self.modifiers.lock_angle { self.end_point_segment } else { in_segment };
self.add_point(LastPoint {
id: point,
pos: position,
in_segment,
handle_start,
});
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![layer.to_node()] });
self.next_point = position;
self.next_handle_start = handle_start;
let vector_data = document.network_interface.compute_modified_vector(layer).unwrap();
let segment = vector_data.all_connected(point).collect::<Vec<_>>().first().map(|s| s.segment);
if self.modifiers.lock_angle {
self.set_lock_angle(&vector_data, point, segment);
}
self.handle_mode = HandleMode::ColinearEquidistant;
}
// Stores the segment and point ID of the clicked endpoint
fn store_clicked_endpoint(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, preferences: &PreferencesMessageHandler) {
let point = SnapCandidatePoint::handle(document.metadata().document_to_viewport.inverse().transform_point2(input.mouse.position));