@@ -436,38 +436,54 @@ impl ShapeState {
436436 }
437437
438438 /// a two-step process: trigger reorganization, then use position-based lookup.
439- fn handle_grouped_transform_close_path ( document : & DocumentMessageHandler , layer : LayerNodeIdentifier , start_point : PointId , end_point : PointId , responses : & mut VecDeque < Message > ) {
440- // Get the layer's transform (handles rotation, scaling, translation)
441- let layer_transform = document. metadata ( ) . transform_to_document ( layer) ;
439+ /// Helper function to connect two points by their positions after graph reorganization.
440+ /// This transforms local point positions to document space and defers the connection until after the graph runs.
441+ fn defer_connect_points_by_position (
442+ document : & DocumentMessageHandler ,
443+ layer1 : LayerNodeIdentifier ,
444+ start_point : PointId ,
445+ layer2 : LayerNodeIdentifier ,
446+ end_point : PointId ,
447+ target_layer : LayerNodeIdentifier ,
448+ responses : & mut VecDeque < Message > ,
449+ ) {
450+ // Get the local positions of the selected points
451+ let start_local_pos = document. network_interface . compute_modified_vector ( layer1) . and_then ( |v| v. point_domain . position_from_id ( start_point) ) ;
452+ let end_local_pos = document. network_interface . compute_modified_vector ( layer2) . and_then ( |v| v. point_domain . position_from_id ( end_point) ) ;
442453
443- let start_local_pos = document. network_interface . compute_modified_vector ( layer) . and_then ( |v| v. point_domain . position_from_id ( start_point) ) ;
444- let end_local_pos = document. network_interface . compute_modified_vector ( layer) . and_then ( |v| v. point_domain . position_from_id ( end_point) ) ;
454+ // Transform to document/world space
455+ let start_transform = document. metadata ( ) . transform_to_document ( layer1) ;
456+ let end_transform = document. metadata ( ) . transform_to_document ( layer2) ;
445457
446458 let ( Some ( start_local) , Some ( end_local) ) = ( start_local_pos, end_local_pos) else {
447459 warn ! ( "Unable to resolve point ids for joining" ) ;
448460 return ;
449461 } ;
450- // Transform positions to document/world space
451- // These positions are stable (won't change during reorganization)
452- let start_pos = layer_transform. transform_point2 ( start_local) ;
453- let end_pos = layer_transform. transform_point2 ( end_local) ;
454-
455- // This zero-delta modification triggers point domain reorganization
456- Self :: add_dummy_modification_to_trigger_graph_reorganization ( layer, start_point, end_point, responses) ;
457-
458- // Defer position-based connection to run after reorganization completes
459- // By then, PointIds will be stable with their new remapped values
460- responses. add ( DeferMessage :: AfterGraphRun {
461- messages : vec ! [
462- ToolMessage :: Path ( PathToolMessage :: ConnectPointsByPosition {
463- layer,
464- start_position: start_pos,
465- end_position: end_pos,
466- } )
467- . into( ) ,
468- ] ,
462+ // Transform positions to document/world space
463+ // These positions are stable (won't change during reorganization)
464+ let start_pos = start_transform. transform_point2 ( start_local) ;
465+ let end_pos = end_transform. transform_point2 ( end_local) ;
466+
467+ // Defer position-based connection to run after reorganization completes
468+ // By then, PointIds will be stable with their new remapped values
469+ responses. add ( DeferMessage :: AfterGraphRun {
470+ messages : vec ! [
471+ ToolMessage :: Path ( PathToolMessage :: ConnectPointsByPosition {
472+ layer: target_layer,
473+ start_position: start_pos,
474+ end_position: end_pos,
475+ } )
476+ . into( ) ,
477+ ] ,
469478 } ) ;
470- }
479+ }
480+
481+ fn handle_grouped_transform_close_path ( document : & DocumentMessageHandler , layer : LayerNodeIdentifier , start_point : PointId , end_point : PointId , responses : & mut VecDeque < Message > ) {
482+ // This zero-delta modification triggers point domain reorganization
483+ Self :: add_dummy_modification_to_trigger_graph_reorganization ( layer, start_point, end_point, responses) ;
484+
485+ // Use the helper to defer the connection until after reorganization
486+ Self :: defer_connect_points_by_position ( document, layer, start_point, layer, end_point, layer, responses) ;
471487 }
472488
473489 pub fn close_selected_path ( & self , document : & DocumentMessageHandler , responses : & mut VecDeque < Message > ) {
@@ -520,32 +536,10 @@ impl ShapeState {
520536 }
521537 } else {
522538 // Different layers: merge first, then create segment
539+ merge_layers ( document, layer1, layer2, responses) ;
523540
524- // Get the local positions of the selected points
525- let start_local_pos = document. network_interface . compute_modified_vector ( layer1) . and_then ( |v| v. point_domain . position_from_id ( start_point) ) ;
526- let end_local_pos = document. network_interface . compute_modified_vector ( layer2) . and_then ( |v| v. point_domain . position_from_id ( end_point) ) ;
527-
528- // Transform to document/world space
529- let start_transform = document. metadata ( ) . transform_to_document ( layer1) ;
530- let end_transform = document. metadata ( ) . transform_to_document ( layer2) ;
531-
532- if let ( Some ( start_local) , Some ( end_local) ) = ( start_local_pos, end_local_pos) {
533- let start_pos = start_transform. transform_point2 ( start_local) ;
534- let end_pos = end_transform. transform_point2 ( end_local) ;
535-
536- merge_layers ( document, layer1, layer2, responses) ;
537-
538- responses. add ( DeferMessage :: AfterGraphRun {
539- messages : vec ! [
540- ToolMessage :: Path ( PathToolMessage :: ConnectPointsByPosition {
541- layer: layer1,
542- start_position: start_pos,
543- end_position: end_pos,
544- } )
545- . into( ) ,
546- ] ,
547- } ) ;
548- }
541+ // Use the helper to defer the connection until after reorganization
542+ Self :: defer_connect_points_by_position ( document, layer1, start_point, layer2, end_point, layer1, responses) ;
549543 }
550544 return ;
551545 }
0 commit comments