1+ use std:: f64:: consts:: PI ;
2+
13use super :: graph_modification_utils:: merge_layers;
24use super :: snapping:: { SnapCache , SnapCandidatePoint , SnapData , SnapManager , SnappedPoint } ;
35use super :: utility_functions:: { adjust_handle_colinearity, calculate_bezier_bbox, calculate_segment_angle, restore_g1_continuity, restore_previous_handle_position} ;
@@ -892,16 +894,20 @@ impl ShapeState {
892894 ManipulatorPointId :: Anchor ( point) => self . move_anchor ( point, & vector_data, delta, layer, None , responses) ,
893895 ManipulatorPointId :: PrimaryHandle ( segment) => {
894896 self . move_primary ( segment, delta, layer, responses) ;
895- if let Some ( handles) = point. get_handle_pair ( & vector_data) {
896- let modification_type = VectorModificationType :: SetG1Continuous { handles, enabled : false } ;
897- responses. add ( GraphOperationMessage :: Vector { layer, modification_type } ) ;
897+ if let Some ( handle) = point. as_handle ( ) {
898+ if let Some ( handles) = vector_data. colinear_manipulators . iter ( ) . find ( |handles| handles[ 0 ] == handle || handles[ 1 ] == handle) {
899+ let modification_type = VectorModificationType :: SetG1Continuous { handles : * handles, enabled : false } ;
900+ responses. add ( GraphOperationMessage :: Vector { layer, modification_type } ) ;
901+ }
898902 }
899903 }
900904 ManipulatorPointId :: EndHandle ( segment) => {
901905 self . move_end ( segment, delta, layer, responses) ;
902- if let Some ( handles) = point. get_handle_pair ( & vector_data) {
903- let modification_type = VectorModificationType :: SetG1Continuous { handles, enabled : false } ;
904- responses. add ( GraphOperationMessage :: Vector { layer, modification_type } ) ;
906+ if let Some ( handle) = point. as_handle ( ) {
907+ if let Some ( handles) = vector_data. colinear_manipulators . iter ( ) . find ( |handles| handles[ 0 ] == handle || handles[ 1 ] == handle) {
908+ let modification_type = VectorModificationType :: SetG1Continuous { handles : * handles, enabled : false } ;
909+ responses. add ( GraphOperationMessage :: Vector { layer, modification_type } ) ;
910+ }
905911 }
906912 }
907913 }
@@ -1028,8 +1034,8 @@ impl ShapeState {
10281034 /// If both or neither handles are selected, the angle of both handles will be averaged from their current angles, weighted by their lengths.
10291035 /// Assumes all selected manipulators have handles that are already not colinear.
10301036 ///
1031- /// For vector meshes, the handle which is nearest in the direction of 180° angle separation, becomes colinear with current handle,
1032- /// and if that handle was colinear with some other handle that constraint is removed from the vector data
1037+ /// For vector meshes, non colinear handle which is nearest in the direction of 180° angle separation, becomes colinear with current handle,
1038+ /// if there is no such handle, nothing happens
10331039 pub fn convert_selected_manipulators_to_colinear_handles ( & self , responses : & mut VecDeque < Message > , document : & DocumentMessageHandler ) {
10341040 let mut skip_set = HashSet :: new ( ) ;
10351041
@@ -1039,9 +1045,6 @@ impl ShapeState {
10391045 } ;
10401046 let transform = document. metadata ( ) . transform_to_document_if_feeds ( layer, & document. network_interface ) ;
10411047
1042- log:: info!( "reaching hereeeeee" ) ;
1043-
1044- // TODO: A point which has
10451048 for & point in layer_state. selected_points . iter ( ) {
10461049 // Skip a point which has more than 2 segments connected (vector meshes)
10471050 if let ManipulatorPointId :: Anchor ( anchor) = point {
@@ -1050,21 +1053,17 @@ impl ShapeState {
10501053 }
10511054 }
10521055
1053- // let Some(handles) = point.get_handle_pair(&vector_data) else { continue };
1054-
10551056 // Here we take handles as the current handle and the most opposite non-colinear-handle
10561057
10571058 let is_handle_non_colinear = |handle : HandleId | -> bool { !( vector_data. colinear_manipulators . iter ( ) . any ( |& handles| handles[ 0 ] == handle || handles[ 1 ] == handle) ) } ;
10581059
1059- log:: info!( "reaching here" ) ;
10601060 let other_handles = match point {
10611061 ManipulatorPointId :: Anchor ( _) => point. get_handle_pair ( & vector_data) ,
10621062 _ => {
1063- // something
10641063 point. get_all_connected_handles ( & vector_data) . and_then ( |handles| {
10651064 let mut non_colinear_handles = handles. iter ( ) . filter ( |& handle| is_handle_non_colinear ( * handle) ) . clone ( ) . collect :: < Vec < _ > > ( ) ;
10661065
1067- // Now sort these by angle from the current handle
1066+ // Sort these by angle from the current handle
10681067 non_colinear_handles. sort_by ( |& handle_a, & handle_b| {
10691068 let anchor = point. get_anchor_position ( & vector_data) . expect ( "No anchor position for handle" ) ;
10701069 let orig_handle_pos = point. get_position ( & vector_data) . expect ( "No handle position" ) ;
@@ -1567,9 +1566,11 @@ impl ShapeState {
15671566 responses. add ( GraphOperationMessage :: Vector { layer, modification_type } ) ;
15681567 }
15691568 }
1570- } else if let Some ( handles) = point. get_handle_pair ( & vector_data) {
1571- let modification_type = VectorModificationType :: SetG1Continuous { handles, enabled : false } ;
1572- responses. add ( GraphOperationMessage :: Vector { layer, modification_type } ) ;
1569+ } else if let Some ( handle) = point. as_handle ( ) {
1570+ if let Some ( handles) = vector_data. colinear_manipulators . iter ( ) . find ( |handles| handles[ 0 ] == handle || handles[ 1 ] == handle) {
1571+ let modification_type = VectorModificationType :: SetG1Continuous { handles : * handles, enabled : false } ;
1572+ responses. add ( GraphOperationMessage :: Vector { layer, modification_type } ) ;
1573+ }
15731574 }
15741575 }
15751576 }
@@ -1779,9 +1780,40 @@ impl ShapeState {
17791780 if point. as_anchor ( ) . is_some ( ) {
17801781 continue ;
17811782 }
1782- if let Some ( handles) = point. get_handle_pair ( & vector_data) {
1783- // handle[0] is selected, handle[1] is opposite / mirror handle
1784- handles_to_update. push ( ( layer, handles[ 0 ] . to_manipulator_point ( ) , handles[ 1 ] . to_manipulator_point ( ) ) ) ;
1783+
1784+ if let Some ( other_handles) = point. get_all_connected_handles ( & vector_data) {
1785+ // Find the next closest handle in the clockwise sense
1786+ let mut candidates = other_handles. clone ( ) ;
1787+ candidates. sort_by ( |& handle_a, & handle_b| {
1788+ let anchor = point. get_anchor_position ( & vector_data) . expect ( "No anchor position for handle" ) ;
1789+ let orig_handle_pos = point. get_position ( & vector_data) . expect ( "No handle position" ) ;
1790+
1791+ let a_pos = handle_a. to_manipulator_point ( ) . get_position ( & vector_data) . expect ( "No handle position" ) ;
1792+ let b_pos = handle_b. to_manipulator_point ( ) . get_position ( & vector_data) . expect ( "No handle position" ) ;
1793+
1794+ let v_orig = ( orig_handle_pos - anchor) . normalize_or_zero ( ) ;
1795+
1796+ let v_a = ( a_pos - anchor) . normalize_or_zero ( ) ;
1797+ let v_b = ( b_pos - anchor) . normalize_or_zero ( ) ;
1798+
1799+ let signed_angle = |base : DVec2 , to : DVec2 | -> f64 {
1800+ let angle = base. angle_to ( to) ;
1801+ let cross = base. perp_dot ( to) ;
1802+
1803+ if cross < 0.0 { 2.0 * PI - angle } else { angle }
1804+ } ;
1805+
1806+ let angle_a = signed_angle ( v_orig, v_a) ;
1807+ let angle_b = signed_angle ( v_orig, v_b) ;
1808+
1809+ angle_a. partial_cmp ( & angle_b) . unwrap_or ( std:: cmp:: Ordering :: Equal )
1810+ } ) ;
1811+
1812+ if candidates. is_empty ( ) {
1813+ continue ;
1814+ }
1815+
1816+ handles_to_update. push ( ( layer, * point, candidates[ 0 ] . to_manipulator_point ( ) ) ) ;
17851817 }
17861818 }
17871819 }
0 commit comments