Skip to content

Commit d604ef6

Browse files
committed
fix: handle PointId remapping when joining paths from different layers
When using Ctrl+J to join two points from different layers, the operation failed because PointIds change during merge due to collision resolution. The fix uses index-based point tracking instead of PointIds: 1. Before merge: Record the index of each selected point in its layer 2. Calculate post-merge indices using the point offset from layer1 3. After merge: Retrieve the actual PointIds at those indices 4. Create the connecting segment using the resolved PointIds This works because Vector::concat() preserves point ordering during merge, so we can use exact index arithmetic to find points after remapping. Fixes #3519
1 parent 4ab75c9 commit d604ef6

File tree

2 files changed

+60
-10
lines changed

2 files changed

+60
-10
lines changed

editor/src/messages/tool/common_functionality/shape_editor.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ impl ShapeState {
447447
let (layer2, end_point) = all_selected_points[1];
448448

449449
if layer1 == layer2 {
450+
// Same layer: create segment directly
450451
if start_point == end_point {
451452
return;
452453
}
@@ -459,16 +460,31 @@ impl ShapeState {
459460
};
460461
responses.add(GraphOperationMessage::Vector { layer: layer1, modification_type });
461462
} else {
462-
// Merge the layers
463-
merge_layers(document, layer1, layer2, responses);
464-
// Create segment between the two points
465-
let segment_id = SegmentId::generate();
466-
let modification_type = VectorModificationType::InsertSegment {
467-
id: segment_id,
468-
points: [end_point, start_point],
469-
handles: [None, None],
470-
};
471-
responses.add(GraphOperationMessage::Vector { layer: layer1, modification_type });
463+
// Different layers: merge first, then create segment
464+
465+
// Get the indices of the selected points in their respective vectors
466+
let start_index = document.network_interface.compute_modified_vector(layer1)
467+
.and_then(|v| v.point_domain.resolve_id(start_point));
468+
let end_index = document.network_interface.compute_modified_vector(layer2)
469+
.and_then(|v| v.point_domain.resolve_id(end_point));
470+
471+
// Get the number of points in layer1 (this will be the offset for layer2 points after merge)
472+
let layer1_point_count = document.network_interface.compute_modified_vector(layer1)
473+
.map(|v| v.point_domain.ids().len());
474+
475+
if let (Some(start_idx), Some(end_idx), Some(point_offset)) = (start_index, end_index, layer1_point_count) {
476+
// Merge the layers
477+
merge_layers(document, layer1, layer2, responses);
478+
479+
// After the graph runs and the merge is complete, restore selection and close path
480+
responses.add(DeferMessage::AfterGraphRun {
481+
messages: vec![ToolMessage::Path(PathToolMessage::RestoreSelectionAndClosePath {
482+
layer: layer1,
483+
start_index: start_idx,
484+
end_index: end_idx + point_offset,
485+
}).into()],
486+
});
487+
}
472488
}
473489
return;
474490
}

editor/src/messages/tool/tool_messages/path_tool.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ pub enum PathToolMessage {
7373
},
7474
Escape,
7575
ClosePath,
76+
RestoreSelectionAndClosePath {
77+
layer: LayerNodeIdentifier,
78+
start_index: usize,
79+
end_index: usize,
80+
},
7681
DoubleClick {
7782
extend_selection: Key,
7883
shrink_selection: Key,
@@ -2669,6 +2674,35 @@ impl Fsm for PathToolFsmState {
26692674

26702675
self
26712676
}
2677+
(_, PathToolMessage::RestoreSelectionAndClosePath { layer, start_index, end_index }) => {
2678+
// Get the merged vector
2679+
let Some(vector) = document.network_interface.compute_modified_vector(layer) else {
2680+
return self;
2681+
};
2682+
2683+
// Get the point IDs at the calculated indices
2684+
let point_ids = vector.point_domain.ids();
2685+
2686+
if start_index >= point_ids.len() || end_index >= point_ids.len() {
2687+
return self;
2688+
}
2689+
2690+
let start_point_id = point_ids[start_index];
2691+
let end_point_id = point_ids[end_index];
2692+
2693+
// Clear existing selection and select the merged layer
2694+
shape_editor.deselect_all_points();
2695+
shape_editor.set_selected_layers(vec![layer]);
2696+
2697+
// Select the two points
2698+
shape_editor.select_point_by_layer_and_id(ManipulatorPointId::Anchor(start_point_id), layer);
2699+
shape_editor.select_point_by_layer_and_id(ManipulatorPointId::Anchor(end_point_id), layer);
2700+
2701+
// Now call ClosePath which will see the selection and create the segment
2702+
responses.add(PathToolMessage::ClosePath);
2703+
2704+
self
2705+
}
26722706
(_, PathToolMessage::StartSlidingPoint) => {
26732707
responses.add(DocumentMessage::StartTransaction);
26742708
if tool_data.start_sliding_point(shape_editor, document) {

0 commit comments

Comments
 (0)