@@ -90,11 +90,32 @@ impl Isometry2d {
90
90
}
91
91
}
92
92
93
+ /// Compute `iso1.inverse() * iso2` in a more efficient way for one-shot cases.
94
+ ///
95
+ /// If the same isometry is used multiple times, it is more efficient to instead compute
96
+ /// the inverse once and use that for each transformation.
97
+ #[ inline]
98
+ pub fn inverse_mul ( & self , rhs : Self ) -> Self {
99
+ let inv_rot = self . rotation . inverse ( ) ;
100
+ let delta_translation = rhs. translation - self . translation ;
101
+ Self :: new ( inv_rot * delta_translation, inv_rot * rhs. rotation )
102
+ }
103
+
93
104
/// Transform a point by rotating and translating it using this isometry.
94
105
#[ inline]
95
106
pub fn transform_point ( & self , point : Vec2 ) -> Vec2 {
96
107
self . rotation * point + self . translation
97
108
}
109
+
110
+ /// Transform a point by rotating and translating it using the inverse of this isometry.
111
+ ///
112
+ /// This is more efficient than `iso.inverse().transform_point(point)` for one-shot cases.
113
+ /// If the same isometry is used multiple times, it is more efficient to instead compute
114
+ /// the inverse once and use that for each transformation.
115
+ #[ inline]
116
+ pub fn inverse_transform_point ( & self , point : Vec2 ) -> Vec2 {
117
+ self . rotation . inverse ( ) * ( point - self . translation )
118
+ }
98
119
}
99
120
100
121
impl From < Isometry2d > for Affine2 {
@@ -257,11 +278,32 @@ impl Isometry3d {
257
278
}
258
279
}
259
280
281
+ /// Compute `iso1.inverse() * iso2` in a more efficient way for one-shot cases.
282
+ ///
283
+ /// If the same isometry is used multiple times, it is more efficient to instead compute
284
+ /// the inverse once and use that for each transformation.
285
+ #[ inline]
286
+ pub fn inverse_mul ( & self , rhs : Self ) -> Self {
287
+ let inv_rot = self . rotation . inverse ( ) ;
288
+ let delta_translation = rhs. translation - self . translation ;
289
+ Self :: new ( inv_rot * delta_translation, inv_rot * rhs. rotation )
290
+ }
291
+
260
292
/// Transform a point by rotating and translating it using this isometry.
261
293
#[ inline]
262
294
pub fn transform_point ( & self , point : impl Into < Vec3A > ) -> Vec3A {
263
295
self . rotation * point. into ( ) + self . translation
264
296
}
297
+
298
+ /// Transform a point by rotating and translating it using the inverse of this isometry.
299
+ ///
300
+ /// This is more efficient than `iso.inverse().transform_point(point)` for one-shot cases.
301
+ /// If the same isometry is used multiple times, it is more efficient to instead compute
302
+ /// the inverse once and use that for each transformation.
303
+ #[ inline]
304
+ pub fn inverse_transform_point ( & self , point : impl Into < Vec3A > ) -> Vec3A {
305
+ self . rotation . inverse ( ) * ( point. into ( ) - self . translation )
306
+ }
265
307
}
266
308
267
309
impl From < Isometry3d > for Affine3 {
@@ -374,7 +416,7 @@ impl UlpsEq for Isometry3d {
374
416
#[ cfg( test) ]
375
417
mod tests {
376
418
use super :: * ;
377
- use crate :: { vec2, vec3} ;
419
+ use crate :: { vec2, vec3, vec3a } ;
378
420
use approx:: assert_abs_diff_eq;
379
421
use std:: f32:: consts:: { FRAC_PI_2 , FRAC_PI_3 } ;
380
422
@@ -386,6 +428,14 @@ mod tests {
386
428
assert_abs_diff_eq ! ( iso1 * iso2, expected) ;
387
429
}
388
430
431
+ #[ test]
432
+ fn inverse_mul_2d ( ) {
433
+ let iso1 = Isometry2d :: new ( vec2 ( 1.0 , 0.0 ) , Rot2 :: FRAC_PI_2 ) ;
434
+ let iso2 = Isometry2d :: new ( vec2 ( 0.0 , 0.0 ) , Rot2 :: PI ) ;
435
+ let expected = Isometry2d :: new ( vec2 ( 0.0 , 1.0 ) , Rot2 :: FRAC_PI_2 ) ;
436
+ assert_abs_diff_eq ! ( iso1. inverse_mul( iso2) , expected) ;
437
+ }
438
+
389
439
#[ test]
390
440
fn mul_3d ( ) {
391
441
let iso1 = Isometry3d :: new ( vec3 ( 1.0 , 0.0 , 0.0 ) , Quat :: from_rotation_x ( FRAC_PI_2 ) ) ;
@@ -394,6 +444,14 @@ mod tests {
394
444
assert_abs_diff_eq ! ( iso1 * iso2, expected) ;
395
445
}
396
446
447
+ #[ test]
448
+ fn inverse_mul_3d ( ) {
449
+ let iso1 = Isometry3d :: new ( vec3 ( 1.0 , 0.0 , 0.0 ) , Quat :: from_rotation_x ( FRAC_PI_2 ) ) ;
450
+ let iso2 = Isometry3d :: new ( vec3 ( 1.0 , 0.0 , 1.0 ) , Quat :: from_rotation_x ( FRAC_PI_2 ) ) ;
451
+ let expected = Isometry3d :: new ( vec3 ( 0.0 , 1.0 , 0.0 ) , Quat :: IDENTITY ) ;
452
+ assert_abs_diff_eq ! ( iso1. inverse_mul( iso2) , expected) ;
453
+ }
454
+
397
455
#[ test]
398
456
fn identity_2d ( ) {
399
457
let iso = Isometry2d :: new ( vec2 ( -1.0 , -0.5 ) , Rot2 :: degrees ( 75.0 ) ) ;
@@ -431,10 +489,24 @@ mod tests {
431
489
assert_abs_diff_eq ! ( vec2( -0.5 , 0.5 ) , iso * point) ;
432
490
}
433
491
492
+ #[ test]
493
+ fn inverse_transform_2d ( ) {
494
+ let iso = Isometry2d :: new ( vec2 ( 0.5 , -0.5 ) , Rot2 :: FRAC_PI_2 ) ;
495
+ let point = vec2 ( -0.5 , 0.5 ) ;
496
+ assert_abs_diff_eq ! ( vec2( 1.0 , 1.0 ) , iso. inverse_transform_point( point) ) ;
497
+ }
498
+
434
499
#[ test]
435
500
fn transform_3d ( ) {
436
501
let iso = Isometry3d :: new ( vec3 ( 1.0 , 0.0 , 0.0 ) , Quat :: from_rotation_y ( FRAC_PI_2 ) ) ;
437
502
let point = vec3 ( 1.0 , 1.0 , 1.0 ) ;
438
503
assert_abs_diff_eq ! ( vec3( 2.0 , 1.0 , -1.0 ) , iso * point) ;
439
504
}
505
+
506
+ #[ test]
507
+ fn inverse_transform_3d ( ) {
508
+ let iso = Isometry3d :: new ( vec3 ( 1.0 , 0.0 , 0.0 ) , Quat :: from_rotation_y ( FRAC_PI_2 ) ) ;
509
+ let point = vec3 ( 2.0 , 1.0 , -1.0 ) ;
510
+ assert_abs_diff_eq ! ( vec3a( 1.0 , 1.0 , 1.0 ) , iso. inverse_transform_point( point) ) ;
511
+ }
440
512
}
0 commit comments