Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 20, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 61 additions & 19 deletions editor/src/messages/tool/tool_messages/pen_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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));
Expand Down
Loading