@@ -76,6 +76,13 @@ impl Transform2D {
76
76
}
77
77
78
78
/// Constructs the transform from a given angle (in radians), translation, and scale.
79
+ ///
80
+ /// # Deprecation
81
+ /// This constructor has been deprecated due to the order of transformations applied deviate from one's expectations.
82
+ /// Using a non-zero rotation will affect the resulting transform's origin.
83
+ ///
84
+ /// Consider using [`Transform2D::from_scale_rotation_origin`] or applying transformations manually.
85
+ #[ deprecated = "Misleading behavior (see description); consider `from_scale_rotation_origin` or manual transformations." ]
79
86
#[ inline]
80
87
pub fn from_rotation_translation_scale (
81
88
translation : Vector2 ,
@@ -88,6 +95,29 @@ impl Transform2D {
88
95
. scaled ( scale)
89
96
}
90
97
98
+ /// Constructs the transform from a given scale, angle (in radians), and origin.
99
+ ///
100
+ /// This is **NOT** equivalent to either of these two lines:
101
+ /// ```ignore
102
+ /// Transform2D::IDENTITY.scaled(scale).rotated(rotation).translated(origin)
103
+ /// Transform2D::IDENTITY.translated(origin).rotated(rotation).scaled(scale)
104
+ /// ```
105
+ ///
106
+ /// Those transformations do not preserve the given origin; see documentation for [`rotated`], [`scaled`], and [`translated`].
107
+ ///
108
+ /// [`rotated`]: Self::rotated
109
+ /// [`scaled`]: Self::scaled
110
+ /// [`translated`]: Self::translated
111
+ #[ inline]
112
+ pub fn from_scale_rotation_origin ( scale : Vector2 , rotation : f32 , origin : Vector2 ) -> Self {
113
+ let mut tr = Self :: IDENTITY ;
114
+ tr. set_scale ( scale) ;
115
+ tr. set_rotation ( rotation) ;
116
+ tr. origin = origin;
117
+
118
+ tr
119
+ }
120
+
91
121
/// Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.
92
122
#[ inline]
93
123
pub fn affine_inverse ( & self ) -> Self {
@@ -164,7 +194,7 @@ impl Transform2D {
164
194
self . set_scale ( scale) ;
165
195
}
166
196
167
- /// Rotates the transform by the given angle (in radians), using matrix multiplication.
197
+ /// Rotates the transform by the given angle (in radians), using matrix multiplication. This will modify the transform's origin.
168
198
#[ inline]
169
199
pub fn rotated ( & self , rotation : f32 ) -> Self {
170
200
let mut tr = Self :: IDENTITY ;
@@ -186,7 +216,7 @@ impl Transform2D {
186
216
self . b = self . b . normalized ( ) * scale. y ;
187
217
}
188
218
189
- /// Scales the transform by the given scale factor, using matrix multiplication.
219
+ /// Scales the transform by the given scale factor, using matrix multiplication. This will modify the transform's origin.
190
220
#[ inline]
191
221
pub fn scaled ( & self , scale : Vector2 ) -> Self {
192
222
let mut new = * self ;
@@ -445,3 +475,25 @@ godot_test!(
445
475
test_transform2d_behavior_impl( )
446
476
}
447
477
) ;
478
+
479
+ #[ test]
480
+ fn test_transform2d_constructor ( ) {
481
+ use std:: f32:: consts:: PI ;
482
+
483
+ let scale = Vector2 :: new ( 2.0 , 0.5 ) ;
484
+ let rotation = PI / 4.0 ;
485
+ let origin = Vector2 :: new ( 250.0 , 150.0 ) ;
486
+
487
+ let tr = Transform2D :: from_scale_rotation_origin ( scale, rotation, origin) ;
488
+
489
+ assert_eq ! ( tr. origin, origin) ;
490
+
491
+ let actual_local_right = tr. basis_xform ( Vector2 :: RIGHT ) ;
492
+ let expected_local_right = Vector2 :: RIGHT . rotated ( -rotation) * scale;
493
+ assert ! (
494
+ actual_local_right. is_equal_approx( expected_local_right) ,
495
+ "{:?} != {:?}" ,
496
+ actual_local_right,
497
+ expected_local_right
498
+ ) ;
499
+ }
0 commit comments