@@ -254,40 +254,36 @@ impl SelectedEdges {
254254 ( DAffine2 :: from_scale ( enlargement_factor) , pivot)
255255 }
256256
257- // TODO: Add free movement when Ctrl is pressed to allow dragging the whole edge, not just sliding it
258- pub fn skew_transform ( & self , mouse : DVec2 , to_viewport_transform : DAffine2 , _free_movement : bool ) -> DAffine2 {
259- // Skip if the matrix is singular (as it isn't really possible to skew).
257+ pub fn skew_transform ( & self , mouse : DVec2 , to_viewport_transform : DAffine2 , free_movement : bool ) -> DAffine2 {
258+ // Skip if the matrix is singular
260259 if !to_viewport_transform. matrix2 . determinant ( ) . recip ( ) . is_finite ( ) {
261260 return DAffine2 :: IDENTITY ;
262261 }
263262
264263 let opposite = self . pivot_from_bounds ( self . bounds [ 0 ] , self . bounds [ 1 ] ) ;
265- // This is the current handle that goes under the mouse.
266264 let dragging_point = self . pivot_from_bounds ( self . bounds [ 1 ] , self . bounds [ 0 ] ) ;
267265
268- let mut new_dragging_point = to_viewport_transform. transform_point2 ( dragging_point) ;
266+ let viewport_dragging_point = to_viewport_transform. transform_point2 ( dragging_point) ;
269267 let parallel_to_x = self . top || self . bottom ;
270268 let parallel_to_y = !parallel_to_x && ( self . left || self . right ) ;
271269
272- // The target point is the projection in viewport space onto the line that the skew is parallel to.
273- if parallel_to_x {
274- new_dragging_point += ( mouse - new_dragging_point) . project_onto ( to_viewport_transform. transform_vector2 ( DVec2 :: X ) ) ;
275- } else if parallel_to_y {
276- new_dragging_point += ( mouse - new_dragging_point) . project_onto ( to_viewport_transform. transform_vector2 ( DVec2 :: Y ) ) ;
277- }
278- new_dragging_point = to_viewport_transform. inverse ( ) . transform_point2 ( new_dragging_point) ;
270+ let drag_vector = mouse - viewport_dragging_point;
271+ let document_drag_vector = to_viewport_transform. inverse ( ) . transform_vector2 ( drag_vector) ;
279272
280- let movement = new_dragging_point - dragging_point;
273+ let bounds = ( self . bounds [ 1 ] - self . bounds [ 0 ] ) . abs ( ) ;
274+ let sign = if self . top || self . left { -1. } else { 1. } ;
275+ let signed_bounds = sign * bounds;
276+
277+ let scale_factor = if parallel_to_x { signed_bounds. y . recip ( ) } else { signed_bounds. x . recip ( ) } ;
278+ let scaled_document_drag = document_drag_vector * scale_factor;
281279
282- // Produce a skew that moves the dragging point to the new dragging point (assuming the opposite is origin).
283280 let skew = DAffine2 :: from_mat2 ( DMat2 :: from_cols_array ( & [
284- 1. ,
285- if parallel_to_y { movement . y / ( dragging_point - opposite ) . x } else { 0. } ,
286- if parallel_to_x { movement . x / ( dragging_point - opposite ) . y } else { 0. } ,
287- 1. ,
281+ 1. + if parallel_to_y && free_movement { scaled_document_drag . x } else { 0. } ,
282+ if parallel_to_y { scaled_document_drag . y } else { 0. } ,
283+ if parallel_to_x { scaled_document_drag . x } else { 0. } ,
284+ 1. + if parallel_to_x && free_movement { scaled_document_drag . y } else { 0. } ,
288285 ] ) ) ;
289286
290- // Combine that with a transform that makes opposite the origin.
291287 DAffine2 :: from_translation ( opposite) * skew * DAffine2 :: from_translation ( -opposite)
292288 }
293289}
@@ -810,21 +806,29 @@ fn skew_transform_correct() {
810806 let final_transform = edge. skew_transform ( mouse, to_viewport_transform, false ) ;
811807
812808 // This is the current handle that goes under the mouse.
809+ let opposite = edge. pivot_from_bounds ( edge. bounds [ 0 ] , edge. bounds [ 1 ] ) ;
813810 let dragging_point = edge. pivot_from_bounds ( edge. bounds [ 1 ] , edge. bounds [ 0 ] ) ;
814811
812+ let viewport_dragging_point = to_viewport_transform. transform_point2 ( dragging_point) ;
815813 let parallel_to_x = edge. top || edge. bottom ;
816814 let parallel_to_y = !parallel_to_x && ( edge. left || edge. right ) ;
817815
818- // The target point is the projection in viewport space onto the line that the skew is parallel to.
819- let mut target_dragging_point = to_viewport_transform. transform_point2 ( dragging_point) ;
820- if parallel_to_x {
821- target_dragging_point += ( mouse - target_dragging_point) . project_onto ( to_viewport_transform. transform_vector2 ( DVec2 :: X ) ) ;
822- } else if parallel_to_y {
823- target_dragging_point += ( mouse - target_dragging_point) . project_onto ( to_viewport_transform. transform_vector2 ( DVec2 :: Y ) ) ;
824- }
816+ let drag_vector = mouse - viewport_dragging_point;
817+ let document_drag_vector = to_viewport_transform. inverse ( ) . transform_vector2 ( drag_vector) ;
818+
819+ let sign = if edge. top || edge. left { -1. } else { 1. } ;
820+ let scale_factor = ( edge. bounds [ 1 ] - edge. bounds [ 0 ] ) [ parallel_to_x as usize ] . abs ( ) . recip ( ) * sign;
821+ let scaled_document_drag = document_drag_vector * scale_factor;
822+
823+ let skew = DAffine2 :: from_mat2 ( DMat2 :: from_cols_array ( & [
824+ 1. ,
825+ if parallel_to_y { scaled_document_drag. y } else { 0. } ,
826+ if parallel_to_x { scaled_document_drag. x } else { 0. } ,
827+ 1. ,
828+ ] ) ) ;
829+
830+ let constructed_transform = DAffine2 :: from_translation ( opposite) * skew * DAffine2 :: from_translation ( -opposite) ;
825831
826- // Compute the final point in viewport space.
827- let final_dragging_point = to_viewport_transform. transform_point2 ( final_transform. transform_point2 ( dragging_point) ) ;
828- assert_eq ! ( final_dragging_point, target_dragging_point) ;
832+ assert_eq ! ( constructed_transform, final_transform) ;
829833 }
830834}
0 commit comments