mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-30 03:58:11 +08:00
Fix joining paths from different layers with Ctrl+J fails (#3534)
* 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 * fix: use position-based lookup when joining paths from different layers * fix cmd + g group case * fix check for grouped folder * add in the single layer inside a group case * use ApplyPointDelta instead of creating a dummy segment * Update editor/src/messages/tool/common_functionality/shape_editor.rs Co-authored-by: James Lindsay <78500760+0HyperCube@users.noreply.github.com> * Update editor/src/messages/tool/common_functionality/shape_editor.rs Co-authored-by: James Lindsay <78500760+0HyperCube@users.noreply.github.com> * encapsulate point connection logic in defer_connect_points_by_position * reduce tolerance to 1e-6 * remove wrong comments --------- Co-authored-by: James Lindsay <78500760+0HyperCube@users.noreply.github.com>
This commit is contained in:
co-authored by
James Lindsay
parent
d98f19bf4a
commit
33e3a88458
@@ -73,6 +73,11 @@ pub enum PathToolMessage {
|
||||
},
|
||||
Escape,
|
||||
ClosePath,
|
||||
ConnectPointsByPosition {
|
||||
layer: LayerNodeIdentifier,
|
||||
start_position: DVec2,
|
||||
end_position: DVec2,
|
||||
},
|
||||
DoubleClick {
|
||||
extend_selection: Key,
|
||||
shrink_selection: Key,
|
||||
@@ -2669,6 +2674,60 @@ impl Fsm for PathToolFsmState {
|
||||
|
||||
self
|
||||
}
|
||||
(_, PathToolMessage::ConnectPointsByPosition { layer, start_position, end_position }) => {
|
||||
// Get the merged vector
|
||||
let Some(vector) = document.network_interface.compute_modified_vector(layer) else {
|
||||
return self;
|
||||
};
|
||||
|
||||
// Find points by their positions (with small tolerance for floating point comparison)
|
||||
const POSITION_TOLERANCE: f64 = 1e-6;
|
||||
|
||||
let positions = vector.point_domain.positions();
|
||||
let point_ids = vector.point_domain.ids();
|
||||
|
||||
let mut start_point_id = None;
|
||||
let mut end_point_id = None;
|
||||
|
||||
// Get the merged layer's transform to convert local positions to document space
|
||||
let layer_transform = document.metadata().transform_to_document(layer);
|
||||
|
||||
for (i, &local_pos) in positions.iter().enumerate() {
|
||||
// Transform the local position to document space for comparison
|
||||
let doc_pos = layer_transform.transform_point2(local_pos);
|
||||
|
||||
let start_distance = (doc_pos - start_position).length();
|
||||
let end_distance = (doc_pos - end_position).length();
|
||||
|
||||
if start_point_id.is_none() && start_distance < POSITION_TOLERANCE {
|
||||
start_point_id = Some(point_ids[i]);
|
||||
}
|
||||
if end_point_id.is_none() && end_distance < POSITION_TOLERANCE {
|
||||
end_point_id = Some(point_ids[i]);
|
||||
}
|
||||
if start_point_id.is_some() && end_point_id.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(start_id), Some(end_id)) = (start_point_id, end_point_id) {
|
||||
// Create segment directly
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
let segment_id = SegmentId::generate();
|
||||
let modification_type = VectorModificationType::InsertSegment {
|
||||
id: segment_id,
|
||||
points: [end_id, start_id],
|
||||
handles: [None, None],
|
||||
};
|
||||
|
||||
responses.add(GraphOperationMessage::Vector { layer, modification_type });
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
(_, PathToolMessage::StartSlidingPoint) => {
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
if tool_data.start_sliding_point(shape_editor, document) {
|
||||
|
||||
Reference in New Issue
Block a user