Skip to main content

bevy_transform/components/
global_transform.rs

1use core::ops::Mul;
2
3use super::Transform;
4use bevy_math::{ops, Affine3A, Dir3, Isometry3d, Mat4, Quat, Vec3, Vec3A};
5use derive_more::derive::From;
6
7#[cfg(all(feature = "bevy_reflect", feature = "serialize"))]
8use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
9
10#[cfg(feature = "bevy-support")]
11use bevy_ecs::component::Component;
12
13#[cfg(feature = "bevy_reflect")]
14use {
15    bevy_ecs::reflect::ReflectComponent,
16    bevy_reflect::{std_traits::ReflectDefault, Reflect},
17};
18
19/// [`GlobalTransform`] is an affine transformation from entity-local coordinates to worldspace coordinates.
20///
21/// You cannot directly mutate [`GlobalTransform`]; instead, you change an entity's transform by manipulating
22/// its [`Transform`], which indirectly causes Bevy to update its [`GlobalTransform`].
23///
24/// * To get the global transform of an entity, you should get its [`GlobalTransform`].
25/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`].
26///   [`GlobalTransform`] is automatically inserted whenever [`Transform`] is inserted.
27///
28/// ## [`Transform`] and [`GlobalTransform`]
29///
30/// [`Transform`] transforms an entity relative to its parent's reference frame, or relative to world space coordinates,
31/// if it doesn't have a [`ChildOf`](bevy_ecs::hierarchy::ChildOf) component.
32///
33/// [`GlobalTransform`] is managed by Bevy; it is computed by successively applying the [`Transform`] of each ancestor
34/// entity which has a Transform. This is done automatically by Bevy-internal systems in the [`TransformSystems::Propagate`]
35/// system set.
36///
37/// This system runs during [`PostUpdate`](bevy_app::PostUpdate). If you
38/// update the [`Transform`] of an entity in this schedule or after, you will notice a 1 frame lag
39/// before the [`GlobalTransform`] is updated.
40///
41/// [`TransformSystems::Propagate`]: crate::TransformSystems::Propagate
42///
43/// # Examples
44///
45/// - [`transform`][transform_example]
46///
47/// [transform_example]: https://github.com/bevyengine/bevy/blob/latest/examples/transforms/transform.rs
48#[derive(#[automatically_derived]
impl ::core::fmt::Debug for GlobalTransform {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "GlobalTransform", &&self.0)
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for GlobalTransform {
    #[inline]
    fn eq(&self, other: &GlobalTransform) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::clone::Clone for GlobalTransform {
    #[inline]
    fn clone(&self) -> GlobalTransform {
        let _: ::core::clone::AssertParamIsClone<Affine3A>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for GlobalTransform { }Copy, #[allow(deprecated)]
#[allow(unreachable_code)]
#[automatically_derived]
impl derive_more::core::convert::From<(Affine3A)> for GlobalTransform {
    #[inline]
    fn from(value: (Affine3A)) -> Self { GlobalTransform(value) }
}From)]
49#[cfg_attr(feature = "serialize", derive(#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for GlobalTransform {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                _serde::Serializer::serialize_newtype_struct(__serializer,
                    "GlobalTransform", &self.0)
            }
        }
    };serde::Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for GlobalTransform {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<GlobalTransform>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = GlobalTransform;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "tuple struct GlobalTransform")
                    }
                    #[inline]
                    fn visit_newtype_struct<__E>(self, __e: __E)
                        -> _serde::__private228::Result<Self::Value, __E::Error>
                        where __E: _serde::Deserializer<'de> {
                        let __field0: Affine3A =
                            <Affine3A as _serde::Deserialize>::deserialize(__e)?;
                        _serde::__private228::Ok(GlobalTransform(__field0))
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<Affine3A>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"tuple struct GlobalTransform with 1 element")),
                            };
                        _serde::__private228::Ok(GlobalTransform(__field0))
                    }
                }
                _serde::Deserializer::deserialize_newtype_struct(__deserializer,
                    "GlobalTransform",
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<GlobalTransform>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };serde::Deserialize))]
50#[cfg_attr(feature = "bevy-support", derive(impl bevy_ecs::component::Component for GlobalTransform where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component))]
51#[cfg_attr(
52    feature = "bevy_reflect",
53    derive(const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for GlobalTransform where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectComponent, Self>();
                registration.register_type_data::<ReflectDefault, Self>();
                registration.register_type_data::<ReflectSerialize, Self>();
                registration.register_type_data::<ReflectDeserialize, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <Affine3A as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for GlobalTransform where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            bevy_reflect::TypeInfo::TupleStruct(bevy_reflect::tuple_struct::TupleStructInfo::new::<Self>(&[bevy_reflect::UnnamedField::new::<Affine3A>(0usize)]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for GlobalTransform where  {
            fn type_path() -> &'static str {
                "bevy_transform::components::global_transform::GlobalTransform"
            }
            fn short_type_path() -> &'static str { "GlobalTransform" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("GlobalTransform")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_transform::components::global_transform".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_transform::components::global_transform")
            }
        }
        impl bevy_reflect::Reflect for GlobalTransform where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        impl bevy_reflect::tuple_struct::TupleStruct for GlobalTransform where
             {
            fn field(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.0),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.0),
                    _ => ::core::option::Option::None,
                }
            }
            #[inline]
            fn field_len(&self) -> usize { 1usize }
            #[inline]
            fn iter_fields(&self)
                -> bevy_reflect::tuple_struct::TupleStructFieldIter {
                bevy_reflect::tuple_struct::TupleStructFieldIter::new(self)
            }
            fn to_dynamic_tuple_struct(&self)
                -> bevy_reflect::tuple_struct::DynamicTupleStruct {
                let mut dynamic:
                        bevy_reflect::tuple_struct::DynamicTupleStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed(bevy_reflect::PartialReflect::to_dynamic(&self.0));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for GlobalTransform where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::TupleStruct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (i, value) in
                        ::core::iter::Iterator::enumerate(bevy_reflect::tuple_struct::TupleStruct::iter_fields(struct_value))
                        {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::tuple_struct::TupleStruct::field_mut(self, i)
                            {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::TupleStruct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::TupleStruct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::TupleStruct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::TupleStruct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::TupleStruct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                let value =
                    <dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
                if let ::core::option::Option::Some(value) = value {
                    ::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
                            value))
                } else { ::core::option::Option::Some(false) }
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::tuple_struct::tuple_struct_partial_cmp)(self,
                    value)
            }
            fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
                -> ::core::fmt::Result {
                ::core::fmt::Debug::fmt(self, f)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for GlobalTransform where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::TupleStruct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let mut __this =
                        <Self as ::core::default::Default>::default();
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <Affine3A as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::tuple_struct::TupleStruct::field(__ref_struct,
                                                    0)?))() {
                        __this.0 = __field;
                    }
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect),
54    reflect(Component, Default, PartialEq, Debug, Clone)
55)]
56#[cfg_attr(
57    all(feature = "bevy_reflect", feature = "serialize"),
58    reflect(Serialize, Deserialize)
59)]
60pub struct GlobalTransform(Affine3A);
61
62macro_rules! impl_local_axis {
63    ($pos_name: ident, $neg_name: ident, $axis: ident) => {
64        #[doc=core::concat!("Return the local ", core::stringify!($pos_name), " vector (", core::stringify!($axis) ,").")]
65        #[inline]
66        pub fn $pos_name(&self) -> Dir3 {
67            Dir3::new_unchecked((self.0.matrix3 * Vec3::$axis).normalize())
68        }
69
70        #[doc=core::concat!("Return the local ", core::stringify!($neg_name), " vector (-", core::stringify!($axis) ,").")]
71        #[inline]
72        pub fn $neg_name(&self) -> Dir3 {
73            -self.$pos_name()
74        }
75    };
76}
77
78impl GlobalTransform {
79    /// An identity [`GlobalTransform`] that maps all points in space to themselves.
80    pub const IDENTITY: Self = Self(Affine3A::IDENTITY);
81
82    #[doc(hidden)]
83    #[inline]
84    pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
85        Self::from_translation(Vec3::new(x, y, z))
86    }
87
88    #[doc(hidden)]
89    #[inline]
90    pub fn from_translation(translation: Vec3) -> Self {
91        GlobalTransform(Affine3A::from_translation(translation))
92    }
93
94    #[doc(hidden)]
95    #[inline]
96    pub fn from_rotation(rotation: Quat) -> Self {
97        GlobalTransform(Affine3A::from_rotation_translation(rotation, Vec3::ZERO))
98    }
99
100    #[doc(hidden)]
101    #[inline]
102    pub fn from_scale(scale: Vec3) -> Self {
103        GlobalTransform(Affine3A::from_scale(scale))
104    }
105
106    #[doc(hidden)]
107    #[inline]
108    pub fn from_isometry(iso: Isometry3d) -> Self {
109        Self(iso.into())
110    }
111
112    /// Returns the 3d affine transformation matrix as a [`Mat4`].
113    #[inline]
114    pub fn to_matrix(&self) -> Mat4 {
115        Mat4::from(self.0)
116    }
117
118    /// Returns the 3d affine transformation matrix as an [`Affine3A`].
119    #[inline]
120    pub fn affine(&self) -> Affine3A {
121        self.0
122    }
123
124    /// Returns the transformation as a [`Transform`].
125    ///
126    /// The transform is expected to be non-degenerate and without shearing, or the output
127    /// will be invalid.
128    #[inline]
129    pub fn compute_transform(&self) -> Transform {
130        let (scale, rotation, translation) = self.0.to_scale_rotation_translation();
131        Transform {
132            translation,
133            rotation,
134            scale,
135        }
136    }
137
138    /// Computes a Scale-Rotation-Translation decomposition of the transformation and returns
139    /// the isometric part as an [isometry]. Any scaling done by the transformation will be ignored.
140    /// Note: this is a somewhat costly and lossy conversion.
141    ///
142    /// The transform is expected to be non-degenerate and without shearing, or the output
143    /// will be invalid.
144    ///
145    /// [isometry]: Isometry3d
146    #[inline]
147    pub fn to_isometry(&self) -> Isometry3d {
148        let (_, rotation, translation) = self.0.to_scale_rotation_translation();
149        Isometry3d::new(translation, rotation)
150    }
151
152    /// Returns the [`Transform`] `self` would have if it was a child of an entity
153    /// with the `parent` [`GlobalTransform`].
154    ///
155    /// This is useful if you want to "reparent" an [`Entity`](bevy_ecs::entity::Entity).
156    /// Say you have an entity `e1` that you want to turn into a child of `e2`,
157    /// but you want `e1` to keep the same global transform, even after re-parenting. You would use:
158    ///
159    /// ```
160    /// # use bevy_transform::prelude::{GlobalTransform, Transform};
161    /// # use bevy_ecs::prelude::{Entity, Query, Component, Commands, ChildOf};
162    /// #[derive(Component)]
163    /// struct ToReparent {
164    ///     new_parent: Entity,
165    /// }
166    /// fn reparent_system(
167    ///     mut commands: Commands,
168    ///     mut targets: Query<(&mut Transform, Entity, &GlobalTransform, &ToReparent)>,
169    ///     transforms: Query<&GlobalTransform>,
170    /// ) {
171    ///     for (mut transform, entity, initial, to_reparent) in targets.iter_mut() {
172    ///         if let Ok(parent_transform) = transforms.get(to_reparent.new_parent) {
173    ///             *transform = initial.reparented_to(parent_transform);
174    ///             commands.entity(entity)
175    ///                 .remove::<ToReparent>()
176    ///                 .insert(ChildOf(to_reparent.new_parent));
177    ///         }
178    ///     }
179    /// }
180    /// ```
181    ///
182    /// The transform is expected to be non-degenerate and without shearing, or the output
183    /// will be invalid.
184    #[inline]
185    pub fn reparented_to(&self, parent: &GlobalTransform) -> Transform {
186        let relative_affine = parent.affine().inverse() * self.affine();
187        let (scale, rotation, translation) = relative_affine.to_scale_rotation_translation();
188        Transform {
189            translation,
190            rotation,
191            scale,
192        }
193    }
194
195    /// Extracts `scale`, `rotation` and `translation` from `self`.
196    ///
197    /// The transform is expected to be non-degenerate and without shearing, or the output
198    /// will be invalid.
199    #[inline]
200    pub fn to_scale_rotation_translation(&self) -> (Vec3, Quat, Vec3) {
201        self.0.to_scale_rotation_translation()
202    }
203
204    #[doc = "Return the local right vector (X)."]
#[inline]
pub fn right(&self) -> Dir3 {
    Dir3::new_unchecked((self.0.matrix3 * Vec3::X).normalize())
}
#[doc = "Return the local left vector (-X)."]
#[inline]
pub fn left(&self) -> Dir3 { -self.right() }impl_local_axis!(right, left, X);
205    #[doc = "Return the local up vector (Y)."]
#[inline]
pub fn up(&self) -> Dir3 {
    Dir3::new_unchecked((self.0.matrix3 * Vec3::Y).normalize())
}
#[doc = "Return the local down vector (-Y)."]
#[inline]
pub fn down(&self) -> Dir3 { -self.up() }impl_local_axis!(up, down, Y);
206    #[doc = "Return the local back vector (Z)."]
#[inline]
pub fn back(&self) -> Dir3 {
    Dir3::new_unchecked((self.0.matrix3 * Vec3::Z).normalize())
}
#[doc = "Return the local forward vector (-Z)."]
#[inline]
pub fn forward(&self) -> Dir3 { -self.back() }impl_local_axis!(back, forward, Z);
207
208    /// Get the translation as a [`Vec3`].
209    #[inline]
210    pub fn translation(&self) -> Vec3 {
211        self.0.translation.into()
212    }
213
214    /// Get the translation as a [`Vec3A`].
215    #[inline]
216    pub fn translation_vec3a(&self) -> Vec3A {
217        self.0.translation
218    }
219
220    /// Get the rotation as a [`Quat`].
221    ///
222    /// The transform is expected to be non-degenerate and without shearing, or the output will be invalid.
223    ///
224    /// # Warning
225    ///
226    /// This is calculated using `to_scale_rotation_translation`, meaning that you
227    /// should probably use it directly if you also need translation or scale.
228    #[inline]
229    pub fn rotation(&self) -> Quat {
230        self.to_scale_rotation_translation().1
231    }
232
233    /// Get the scale as a [`Vec3`].
234    ///
235    /// The transform is expected to be non-degenerate and without shearing, or the output will be invalid.
236    ///
237    /// Some of the computations overlap with `to_scale_rotation_translation`, which means you should use
238    /// it instead if you also need rotation.
239    #[inline]
240    pub fn scale(&self) -> Vec3 {
241        //Formula based on glam's implementation https://github.com/bitshifter/glam-rs/blob/2e4443e70c709710dfb25958d866d29b11ed3e2b/src/f32/affine3a.rs#L290
242        let det = self.0.matrix3.determinant();
243        Vec3::new(
244            self.0.matrix3.x_axis.length() * ops::copysign(1., det),
245            self.0.matrix3.y_axis.length(),
246            self.0.matrix3.z_axis.length(),
247        )
248    }
249
250    /// Get an upper bound of the radius from the given `extents`.
251    #[inline]
252    pub fn radius_vec3a(&self, extents: Vec3A) -> f32 {
253        (self.0.matrix3 * extents).length()
254    }
255
256    /// Transforms the given point from local space to global space, applying shear, scale, rotation and translation.
257    ///
258    /// It can be used like this:
259    ///
260    /// ```
261    /// # use bevy_transform::prelude::{GlobalTransform};
262    /// # use bevy_math::prelude::Vec3;
263    /// let global_transform = GlobalTransform::from_xyz(1., 2., 3.);
264    /// let local_point = Vec3::new(1., 2., 3.);
265    /// let global_point = global_transform.transform_point(local_point);
266    /// assert_eq!(global_point, Vec3::new(2., 4., 6.));
267    /// ```
268    ///
269    /// ```
270    /// # use bevy_transform::prelude::{GlobalTransform};
271    /// # use bevy_math::Vec3;
272    /// let global_point = Vec3::new(2., 4., 6.);
273    /// let global_transform = GlobalTransform::from_xyz(1., 2., 3.);
274    /// let local_point = global_transform.affine().inverse().transform_point3(global_point);
275    /// assert_eq!(local_point, Vec3::new(1., 2., 3.))
276    /// ```
277    ///
278    /// To apply shear, scale, and rotation *without* applying translation, different functions are available:
279    /// ```
280    /// # use bevy_transform::prelude::{GlobalTransform};
281    /// # use bevy_math::prelude::Vec3;
282    /// let global_transform = GlobalTransform::from_xyz(1., 2., 3.);
283    /// let local_direction = Vec3::new(1., 2., 3.);
284    /// let global_direction = global_transform.affine().transform_vector3(local_direction);
285    /// assert_eq!(global_direction, Vec3::new(1., 2., 3.));
286    /// let roundtripped_local_direction = global_transform.affine().inverse().transform_vector3(global_direction);
287    /// assert_eq!(roundtripped_local_direction, local_direction);
288    /// ```
289    #[inline]
290    pub fn transform_point(&self, point: Vec3) -> Vec3 {
291        self.0.transform_point3(point)
292    }
293
294    /// Multiplies `self` with `transform` component by component, returning the
295    /// resulting [`GlobalTransform`]
296    #[inline]
297    pub fn mul_transform(&self, transform: Transform) -> Self {
298        Self(self.0 * transform.compute_affine())
299    }
300}
301
302impl Default for GlobalTransform {
303    fn default() -> Self {
304        Self::IDENTITY
305    }
306}
307
308impl From<Transform> for GlobalTransform {
309    fn from(transform: Transform) -> Self {
310        Self(transform.compute_affine())
311    }
312}
313
314impl From<Mat4> for GlobalTransform {
315    fn from(world_from_local: Mat4) -> Self {
316        Self(Affine3A::from_mat4(world_from_local))
317    }
318}
319
320impl Mul<GlobalTransform> for GlobalTransform {
321    type Output = GlobalTransform;
322
323    #[inline]
324    fn mul(self, global_transform: GlobalTransform) -> Self::Output {
325        GlobalTransform(self.0 * global_transform.0)
326    }
327}
328
329impl Mul<Transform> for GlobalTransform {
330    type Output = GlobalTransform;
331
332    #[inline]
333    fn mul(self, transform: Transform) -> Self::Output {
334        self.mul_transform(transform)
335    }
336}
337
338impl Mul<Vec3> for GlobalTransform {
339    type Output = Vec3;
340
341    #[inline]
342    fn mul(self, value: Vec3) -> Self::Output {
343        self.transform_point(value)
344    }
345}
346
347#[cfg(test)]
348mod test {
349    use super::*;
350
351    use bevy_math::EulerRot::XYZ;
352
353    fn transform_equal(left: GlobalTransform, right: Transform) -> bool {
354        left.0.abs_diff_eq(right.compute_affine(), 0.01)
355    }
356
357    #[test]
358    fn reparented_to_transform_identity() {
359        fn reparent_to_same(t1: GlobalTransform, t2: GlobalTransform) -> Transform {
360            t2.mul_transform(t1.into()).reparented_to(&t2)
361        }
362        let t1 = GlobalTransform::from(Transform {
363            translation: Vec3::new(1034.0, 34.0, -1324.34),
364            rotation: Quat::from_euler(XYZ, 1.0, 0.9, 2.1),
365            scale: Vec3::new(1.0, 1.0, 1.0),
366        });
367        let t2 = GlobalTransform::from(Transform {
368            translation: Vec3::new(0.0, -54.493, 324.34),
369            rotation: Quat::from_euler(XYZ, 1.9, 0.3, 3.0),
370            scale: Vec3::new(1.345, 1.345, 1.345),
371        });
372        let retransformed = reparent_to_same(t1, t2);
373        assert!(
374            transform_equal(t1, retransformed),
375            "t1:{:#?} retransformed:{:#?}",
376            t1.compute_transform(),
377            retransformed,
378        );
379    }
380    #[test]
381    fn reparented_usecase() {
382        let t1 = GlobalTransform::from(Transform {
383            translation: Vec3::new(1034.0, 34.0, -1324.34),
384            rotation: Quat::from_euler(XYZ, 0.8, 1.9, 2.1),
385            scale: Vec3::new(10.9, 10.9, 10.9),
386        });
387        let t2 = GlobalTransform::from(Transform {
388            translation: Vec3::new(28.0, -54.493, 324.34),
389            rotation: Quat::from_euler(XYZ, 0.0, 3.1, 0.1),
390            scale: Vec3::new(0.9, 0.9, 0.9),
391        });
392        // goal: find `X` such as `t2 * X = t1`
393        let reparented = t1.reparented_to(&t2);
394        let t1_prime = t2 * reparented;
395        assert!(
396            transform_equal(t1, t1_prime.into()),
397            "t1:{:#?} t1_prime:{:#?}",
398            t1.compute_transform(),
399            t1_prime.compute_transform(),
400        );
401    }
402
403    #[test]
404    fn scale() {
405        let test_values = [-42.42, 0., 42.42];
406        for x in test_values {
407            for y in test_values {
408                for z in test_values {
409                    let scale = Vec3::new(x, y, z);
410                    let gt = GlobalTransform::from_scale(scale);
411                    assert_eq!(gt.scale(), gt.to_scale_rotation_translation().0);
412                }
413            }
414        }
415    }
416}