diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 570ac5219f..47cfb6761e 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -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::>().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) { + 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::>().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));