1use core::f32::consts::TAU;
2
3use glam::FloatExt;
4
5use crate::{
6 ops,
7 prelude::{Mat2, Vec2},
8};
9
10#[cfg(feature = "bevy_reflect")]
11use bevy_reflect::{std_traits::ReflectDefault, Reflect};
12#[cfg(all(feature = "serialize", feature = "bevy_reflect"))]
13use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
14
15#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for Rot2 {
}
#[automatically_derived]impl ::core::clone::Clone for Rot2 {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<f32>;
*self
}
}Clone, #[automatically_derived]impl ::core::marker::Copy for Rot2 { }Copy, #[automatically_derived]impl ::core::fmt::Debug for Rot2 {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Rot2", "cos",
&self.cos, "sin", &&self.sin)
}
}Debug, #[automatically_derived]impl ::core::marker::StructuralPartialEq for Rot2 { }
#[automatically_derived]impl ::core::cmp::PartialEq for Rot2 {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.cos == other.cos && self.sin == other.sin
}
}PartialEq)]
41#[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 Rot2 {
fn serialize<__S>(&self, __serializer: __S)
-> _serde::__private229::Result<__S::Ok, __S::Error> where
__S: _serde::Serializer {
let mut __serde_state =
_serde::Serializer::serialize_struct(__serializer, "Rot2",
false as usize + 1 + 1)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"cos", &self.cos)?;
_serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
"sin", &self.sin)?;
_serde::ser::SerializeStruct::end(__serde_state)
}
}
};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 Rot2 {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
#[allow(non_camel_case_types)]
#[doc(hidden)]
enum __Field { __field0, __field1, __ignore, }
#[doc(hidden)]
struct __FieldVisitor;
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"field identifier")
}
fn visit_u64<__E>(self, __value: u64)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
0u64 => _serde::__private229::Ok(__Field::__field0),
1u64 => _serde::__private229::Ok(__Field::__field1),
_ => _serde::__private229::Ok(__Field::__ignore),
}
}
fn visit_str<__E>(self, __value: &str)
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
"cos" => _serde::__private229::Ok(__Field::__field0),
"sin" => _serde::__private229::Ok(__Field::__field1),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
fn visit_bytes<__E>(self, __value: &[u8])
-> _serde::__private229::Result<Self::Value, __E> where
__E: _serde::de::Error {
match __value {
b"cos" => _serde::__private229::Ok(__Field::__field0),
b"sin" => _serde::__private229::Ok(__Field::__field1),
_ => { _serde::__private229::Ok(__Field::__ignore) }
}
}
}
#[automatically_derived]
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private229::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
_serde::Deserializer::deserialize_identifier(__deserializer,
__FieldVisitor)
}
}
#[doc(hidden)]
struct __Visitor<'de> {
marker: _serde::__private229::PhantomData<Rot2>,
lifetime: _serde::__private229::PhantomData<&'de ()>,
}
#[automatically_derived]
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = Rot2;
fn expecting(&self,
__formatter: &mut _serde::__private229::Formatter)
-> _serde::__private229::fmt::Result {
_serde::__private229::Formatter::write_str(__formatter,
"struct Rot2")
}
#[inline]
fn visit_seq<__A>(self, mut __seq: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::SeqAccess<'de> {
let __field0 =
match _serde::de::SeqAccess::next_element::<f32>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(0usize,
&"struct Rot2 with 2 elements")),
};
let __field1 =
match _serde::de::SeqAccess::next_element::<f32>(&mut __seq)?
{
_serde::__private229::Some(__value) => __value,
_serde::__private229::None =>
return _serde::__private229::Err(_serde::de::Error::invalid_length(1usize,
&"struct Rot2 with 2 elements")),
};
_serde::__private229::Ok(Rot2 {
cos: __field0,
sin: __field1,
})
}
#[inline]
fn visit_map<__A>(self, mut __map: __A)
-> _serde::__private229::Result<Self::Value, __A::Error>
where __A: _serde::de::MapAccess<'de> {
let mut __field0: _serde::__private229::Option<f32> =
_serde::__private229::None;
let mut __field1: _serde::__private229::Option<f32> =
_serde::__private229::None;
while let _serde::__private229::Some(__key) =
_serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
match __key {
__Field::__field0 => {
if _serde::__private229::Option::is_some(&__field0) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("cos"));
}
__field0 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<f32>(&mut __map)?);
}
__Field::__field1 => {
if _serde::__private229::Option::is_some(&__field1) {
return _serde::__private229::Err(<__A::Error as
_serde::de::Error>::duplicate_field("sin"));
}
__field1 =
_serde::__private229::Some(_serde::de::MapAccess::next_value::<f32>(&mut __map)?);
}
_ => {
let _ =
_serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
}
}
}
let __field0 =
match __field0 {
_serde::__private229::Some(__field0) => __field0,
_serde::__private229::None =>
_serde::__private229::de::missing_field("cos")?,
};
let __field1 =
match __field1 {
_serde::__private229::Some(__field1) => __field1,
_serde::__private229::None =>
_serde::__private229::de::missing_field("sin")?,
};
_serde::__private229::Ok(Rot2 {
cos: __field0,
sin: __field1,
})
}
}
#[doc(hidden)]
const FIELDS: &'static [&'static str] = &["cos", "sin"];
_serde::Deserializer::deserialize_struct(__deserializer,
"Rot2", FIELDS,
__Visitor {
marker: _serde::__private229::PhantomData::<Rot2>,
lifetime: _serde::__private229::PhantomData,
})
}
}
};serde::Deserialize))]
42#[cfg_attr(
43 feature = "bevy_reflect",
44 derive(const _: () =
{
impl bevy_reflect::GetTypeRegistration for Rot2 where {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.register_type_data_with::<ReflectDefault, Self,
_>(());
registration.register_type_data_with::<ReflectSerialize, Self,
_>(());
registration.register_type_data_with::<ReflectDeserialize,
Self, _>(());
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<f32 as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl bevy_reflect::Typed for Rot2 where {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
bevy_reflect::utility::NonGenericTypeInfoCell::new();
CELL.get_or_set(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<f32>("cos"),
bevy_reflect::NamedField::new::<f32>("sin")]))
})
}
}
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for Rot2 where {
fn type_path() -> &'static str { "bevy_math::rotation2d::Rot2" }
fn short_type_path() -> &'static str { "Rot2" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("Rot2")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_math::rotation2d".split(':').next().unwrap())
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_math::rotation2d")
}
}
impl bevy_reflect::Reflect for Rot2 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::structs::Struct for Rot2 where {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name {
"cos" => ::core::option::Option::Some(&self.cos),
"sin" => ::core::option::Option::Some(&self.sin),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name {
"cos" => ::core::option::Option::Some(&mut self.cos),
"sin" => ::core::option::Option::Some(&mut self.sin),
_ => ::core::option::Option::None,
}
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&self.cos),
1usize => ::core::option::Option::Some(&self.sin),
_ => ::core::option::Option::None,
}
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&mut self.cos),
1usize => ::core::option::Option::Some(&mut self.sin),
_ => ::core::option::Option::None,
}
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index {
0usize => ::core::option::Option::Some("cos"),
1usize => ::core::option::Option::Some("sin"),
_ => ::core::option::Option::None,
}
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name {
"cos" => ::core::option::Option::Some(0usize),
"sin" => ::core::option::Option::Some(1usize),
_ => ::core::option::Option::None,
}
}
fn field_len(&self) -> usize { 2usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
->
::core::result::Result<bevy_reflect::structs::DynamicStruct,
bevy_reflect::ReflectCloneError> {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
dynamic.insert_boxed("cos",
bevy_reflect::PartialReflect::to_dynamic(&self.cos)?);
dynamic.insert_boxed("sin",
bevy_reflect::PartialReflect::to_dynamic(&self.sin)?);
::core::result::Result::Ok(dynamic)
}
}
impl bevy_reflect::PartialReflect for Rot2 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::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
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::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(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::structs::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 Rot2 where {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let mut __this =
<Self as ::core::default::Default>::default();
if let ::core::option::Option::Some(__field) =
(||
<f32 as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"cos")?))() {
__this.cos = __field;
}
if let ::core::option::Option::Some(__field) =
(||
<f32 as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"sin")?))() {
__this.sin = __field;
}
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};Reflect),
45 reflect(Debug, PartialEq, Default, Clone)
46)]
47#[cfg_attr(
48 all(feature = "serialize", feature = "bevy_reflect"),
49 reflect(Serialize, Deserialize)
50)]
51#[doc(alias = "rotation", alias = "rotation2d", alias = "rotation_2d")]
52pub struct Rot2 {
53 pub cos: f32,
57 pub sin: f32,
61}
62
63impl Default for Rot2 {
64 fn default() -> Self {
65 Self::IDENTITY
66 }
67}
68
69impl Rot2 {
70 pub const IDENTITY: Self = Self { cos: 1.0, sin: 0.0 };
79
80 pub const PI: Self = Self {
83 cos: -1.0,
84 sin: 0.0,
85 };
86
87 pub const FRAC_PI_2: Self = Self { cos: 0.0, sin: 1.0 };
90
91 pub const FRAC_PI_3: Self = Self {
94 cos: 0.5,
95 sin: 0.866_025_4,
96 };
97
98 pub const FRAC_PI_4: Self = Self {
101 cos: core::f32::consts::FRAC_1_SQRT_2,
102 sin: core::f32::consts::FRAC_1_SQRT_2,
103 };
104
105 pub const FRAC_PI_6: Self = Self {
108 cos: 0.866_025_4,
109 sin: 0.5,
110 };
111
112 pub const FRAC_PI_8: Self = Self {
115 cos: 0.923_879_5,
116 sin: 0.382_683_43,
117 };
118
119 #[inline]
147 pub fn radians(radians: f32) -> Self {
148 let (sin, cos) = ops::sin_cos(radians);
149 Self::from_sin_cos(sin, cos)
150 }
151
152 #[inline]
179 pub fn degrees(degrees: f32) -> Self {
180 Self::radians(degrees.to_radians())
181 }
182
183 #[inline]
210 pub fn turn_fraction(fraction: f32) -> Self {
211 Self::radians(TAU * fraction)
212 }
213
214 #[inline]
222 pub fn from_sin_cos(sin: f32, cos: f32) -> Self {
223 let rotation = Self { sin, cos };
224 if true {
if !rotation.is_normalized() {
{
::core::panicking::panic_fmt(format_args!("the given sine and cosine produce an invalid rotation"));
}
};
};debug_assert!(
225 rotation.is_normalized(),
226 "the given sine and cosine produce an invalid rotation"
227 );
228 rotation
229 }
230
231 #[inline]
233 pub fn as_radians(self) -> f32 {
234 ops::atan2(self.sin, self.cos)
235 }
236
237 #[inline]
239 pub fn as_degrees(self) -> f32 {
240 self.as_radians().to_degrees()
241 }
242
243 #[inline]
245 pub fn as_turn_fraction(self) -> f32 {
246 self.as_radians() / TAU
247 }
248
249 #[inline]
251 pub const fn sin_cos(self) -> (f32, f32) {
252 (self.sin, self.cos)
253 }
254
255 #[inline]
261 #[doc(alias = "norm")]
262 pub fn length(self) -> f32 {
263 Vec2::new(self.sin, self.cos).length()
264 }
265
266 #[inline]
275 #[doc(alias = "norm2")]
276 pub fn length_squared(self) -> f32 {
277 Vec2::new(self.sin, self.cos).length_squared()
278 }
279
280 #[inline]
284 pub fn length_recip(self) -> f32 {
285 Vec2::new(self.sin, self.cos).length_recip()
286 }
287
288 #[inline]
298 pub fn try_normalize(self) -> Option<Self> {
299 let recip = self.length_recip();
300 if recip.is_finite() && recip > 0.0 {
301 Some(Self::from_sin_cos(self.sin * recip, self.cos * recip))
302 } else {
303 None
304 }
305 }
306
307 #[inline]
318 pub fn normalize(self) -> Self {
319 let length_recip = self.length_recip();
320 Self::from_sin_cos(self.sin * length_recip, self.cos * length_recip)
321 }
322
323 #[inline]
327 pub fn fast_renormalize(self) -> Self {
328 let length_squared = self.length_squared();
329 let length_recip_approx = 0.5 * (3.0 - length_squared);
331 Rot2 {
332 sin: self.sin * length_recip_approx,
333 cos: self.cos * length_recip_approx,
334 }
335 }
336
337 #[inline]
339 pub const fn is_finite(self) -> bool {
340 self.sin.is_finite() && self.cos.is_finite()
341 }
342
343 #[inline]
345 pub const fn is_nan(self) -> bool {
346 self.sin.is_nan() || self.cos.is_nan()
347 }
348
349 #[inline]
353 pub fn is_normalized(self) -> bool {
354 ops::abs(self.length_squared() - 1.0) <= 2e-4
358 }
359
360 #[inline]
362 pub fn is_near_identity(self) -> bool {
363 let threshold_angle_sin = 0.000_049_692_047; self.cos > 0.0 && ops::abs(self.sin) < threshold_angle_sin
366 }
367
368 #[inline]
370 pub fn angle_to(self, other: Self) -> f32 {
371 (other * self.inverse()).as_radians()
372 }
373
374 #[inline]
377 #[must_use]
378 #[doc(alias = "conjugate")]
379 pub const fn inverse(self) -> Self {
380 Self {
381 cos: self.cos,
382 sin: -self.sin,
383 }
384 }
385
386 #[inline]
424 pub fn nlerp(self, end: Self, s: f32) -> Self {
425 Self {
426 sin: self.sin.lerp(end.sin, s),
427 cos: self.cos.lerp(end.cos, s),
428 }
429 .try_normalize()
430 .unwrap_or(self)
434 }
435
436 #[inline]
462 pub fn slerp(self, end: Self, s: f32) -> Self {
463 self * Self::radians(self.angle_to(end) * s)
464 }
465}
466
467impl From<f32> for Rot2 {
468 fn from(rotation: f32) -> Self {
470 Self::radians(rotation)
471 }
472}
473
474impl From<Rot2> for Mat2 {
475 fn from(rot: Rot2) -> Self {
477 Mat2::from_cols_array(&[rot.cos, rot.sin, -rot.sin, rot.cos])
478 }
479}
480
481impl core::ops::Mul for Rot2 {
482 type Output = Self;
483
484 fn mul(self, rhs: Self) -> Self::Output {
485 Self {
486 cos: self.cos * rhs.cos - self.sin * rhs.sin,
487 sin: self.sin * rhs.cos + self.cos * rhs.sin,
488 }
489 }
490}
491
492impl core::ops::MulAssign for Rot2 {
493 fn mul_assign(&mut self, rhs: Self) {
494 *self = *self * rhs;
495 }
496}
497
498impl core::ops::Mul<Vec2> for Rot2 {
499 type Output = Vec2;
500
501 fn mul(self, rhs: Vec2) -> Self::Output {
503 Vec2::new(
504 rhs.x * self.cos - rhs.y * self.sin,
505 rhs.x * self.sin + rhs.y * self.cos,
506 )
507 }
508}
509
510#[cfg(any(feature = "approx", test))]
511impl approx::AbsDiffEq for Rot2 {
512 type Epsilon = f32;
513 fn default_epsilon() -> f32 {
514 f32::EPSILON
515 }
516 fn abs_diff_eq(&self, other: &Self, epsilon: f32) -> bool {
517 self.cos.abs_diff_eq(&other.cos, epsilon) && self.sin.abs_diff_eq(&other.sin, epsilon)
518 }
519}
520
521#[cfg(any(feature = "approx", test))]
522impl approx::RelativeEq for Rot2 {
523 fn default_max_relative() -> f32 {
524 f32::EPSILON
525 }
526 fn relative_eq(&self, other: &Self, epsilon: f32, max_relative: f32) -> bool {
527 self.cos.relative_eq(&other.cos, epsilon, max_relative)
528 && self.sin.relative_eq(&other.sin, epsilon, max_relative)
529 }
530}
531
532#[cfg(any(feature = "approx", test))]
533impl approx::UlpsEq for Rot2 {
534 fn default_max_ulps() -> u32 {
535 4
536 }
537 fn ulps_eq(&self, other: &Self, epsilon: f32, max_ulps: u32) -> bool {
538 self.cos.ulps_eq(&other.cos, epsilon, max_ulps)
539 && self.sin.ulps_eq(&other.sin, epsilon, max_ulps)
540 }
541}
542
543#[cfg(test)]
544mod tests {
545 use core::f32::consts::FRAC_PI_2;
546
547 use approx::assert_relative_eq;
548
549 use crate::{ops, Dir2, Mat2, Rot2, Vec2};
550
551 #[test]
552 fn creation() {
553 let rotation1 = Rot2::radians(FRAC_PI_2);
554 let rotation2 = Rot2::degrees(90.0);
555 let rotation3 = Rot2::from_sin_cos(1.0, 0.0);
556 let rotation4 = Rot2::turn_fraction(0.25);
557
558 assert_relative_eq!(rotation1.sin, rotation2.sin);
560 assert_relative_eq!(rotation1.cos, rotation2.cos);
561 assert_relative_eq!(rotation1.sin, rotation3.sin);
562 assert_relative_eq!(rotation1.cos, rotation3.cos);
563 assert_relative_eq!(rotation1.sin, rotation4.sin);
564 assert_relative_eq!(rotation1.cos, rotation4.cos);
565
566 assert_relative_eq!(rotation1.as_radians(), FRAC_PI_2);
568 assert_relative_eq!(rotation1.as_degrees(), 90.0);
569 assert_relative_eq!(rotation1.as_turn_fraction(), 0.25);
570 }
571
572 #[test]
573 fn rotate() {
574 let rotation = Rot2::degrees(90.0);
575
576 assert_relative_eq!(rotation * Vec2::X, Vec2::Y);
577 assert_relative_eq!(rotation * Dir2::Y, Dir2::NEG_X);
578 }
579
580 #[test]
581 fn rotation_range() {
582 assert_relative_eq!(Rot2::radians(3.0 * FRAC_PI_2), Rot2::radians(-FRAC_PI_2));
585 assert_relative_eq!(Rot2::degrees(270.0), Rot2::degrees(-90.0));
586 assert_relative_eq!(Rot2::turn_fraction(0.75), Rot2::turn_fraction(-0.25));
587 }
588
589 #[test]
590 fn add() {
591 let rotation1 = Rot2::degrees(90.0);
592 let rotation2 = Rot2::degrees(180.0);
593
594 assert_eq!((rotation1 * rotation2).as_degrees(), -90.0);
596 }
597
598 #[test]
599 fn subtract() {
600 let rotation1 = Rot2::degrees(90.0);
601 let rotation2 = Rot2::degrees(45.0);
602
603 assert_relative_eq!((rotation1 * rotation2.inverse()).as_degrees(), 45.0);
604
605 assert_relative_eq!(rotation2.angle_to(rotation1), core::f32::consts::FRAC_PI_4);
607 }
608
609 #[test]
610 fn length() {
611 let rotation = Rot2 {
612 sin: 10.0,
613 cos: 5.0,
614 };
615
616 assert_eq!(rotation.length_squared(), 125.0);
617 assert_eq!(rotation.length(), 11.18034);
618 assert!(ops::abs(rotation.normalize().length() - 1.0) < 10e-7);
619 }
620
621 #[test]
622 fn is_near_identity() {
623 assert!(!Rot2::radians(0.1).is_near_identity());
624 assert!(!Rot2::radians(-0.1).is_near_identity());
625 assert!(Rot2::radians(0.00001).is_near_identity());
626 assert!(Rot2::radians(-0.00001).is_near_identity());
627 assert!(Rot2::radians(0.0).is_near_identity());
628 }
629
630 #[test]
631 fn normalize() {
632 let rotation = Rot2 {
633 sin: 10.0,
634 cos: 5.0,
635 };
636 let normalized_rotation = rotation.normalize();
637
638 assert_eq!(normalized_rotation.sin, 0.89442724);
639 assert_eq!(normalized_rotation.cos, 0.44721362);
640
641 assert!(!rotation.is_normalized());
642 assert!(normalized_rotation.is_normalized());
643 }
644
645 #[test]
646 fn fast_renormalize() {
647 let rotation = Rot2 { sin: 1.0, cos: 0.5 };
648 let normalized_rotation = rotation.normalize();
649
650 let mut unnormalized_rot = rotation;
651 let mut renormalized_rot = rotation;
652 let mut initially_normalized_rot = normalized_rotation;
653 let mut fully_normalized_rot = normalized_rotation;
654
655 for _ in 0..6 {
657 unnormalized_rot = unnormalized_rot * unnormalized_rot;
658 renormalized_rot = renormalized_rot * renormalized_rot;
659 initially_normalized_rot = initially_normalized_rot * initially_normalized_rot;
660 fully_normalized_rot = fully_normalized_rot * fully_normalized_rot;
661
662 renormalized_rot = renormalized_rot.fast_renormalize();
663 fully_normalized_rot = fully_normalized_rot.normalize();
664 }
665
666 assert!(!unnormalized_rot.is_normalized());
667
668 assert!(renormalized_rot.is_normalized());
669 assert!(fully_normalized_rot.is_normalized());
670
671 assert_relative_eq!(fully_normalized_rot, renormalized_rot, epsilon = 0.000001);
672 assert_relative_eq!(
673 fully_normalized_rot,
674 unnormalized_rot.normalize(),
675 epsilon = 0.000001
676 );
677 assert_relative_eq!(
678 fully_normalized_rot,
679 initially_normalized_rot.normalize(),
680 epsilon = 0.000001
681 );
682 }
683
684 #[test]
685 fn try_normalize() {
686 assert!(Rot2 {
688 sin: 10.0,
689 cos: 5.0,
690 }
691 .try_normalize()
692 .is_some());
693
694 assert!(Rot2 {
696 sin: f32::NAN,
697 cos: 5.0,
698 }
699 .try_normalize()
700 .is_none());
701
702 assert!(Rot2 { sin: 0.0, cos: 0.0 }.try_normalize().is_none());
704
705 assert!(Rot2 {
707 sin: f32::INFINITY,
708 cos: 5.0,
709 }
710 .try_normalize()
711 .is_none());
712 }
713
714 #[test]
715 fn nlerp() {
716 let rot1 = Rot2::IDENTITY;
717 let rot2 = Rot2::degrees(135.0);
718
719 assert_eq!(rot1.nlerp(rot2, 1.0 / 3.0).as_degrees(), 28.675055);
720 assert!(rot1.nlerp(rot2, 0.0).is_near_identity());
721 assert_eq!(rot1.nlerp(rot2, 0.5).as_degrees(), 67.5);
722 assert_eq!(rot1.nlerp(rot2, 1.0).as_degrees(), 135.0);
723
724 let rot1 = Rot2::IDENTITY;
725 let rot2 = Rot2::from_sin_cos(0.0, -1.0);
726
727 assert!(rot1.nlerp(rot2, 1.0 / 3.0).is_near_identity());
728 assert!(rot1.nlerp(rot2, 0.0).is_near_identity());
729 assert_eq!(rot1.nlerp(rot2, 0.5).as_degrees(), 0.0);
731 assert_eq!(ops::abs(rot1.nlerp(rot2, 1.0).as_degrees()), 180.0);
732 }
733
734 #[test]
735 fn slerp() {
736 let rot1 = Rot2::IDENTITY;
737 let rot2 = Rot2::degrees(135.0);
738
739 assert_eq!(rot1.slerp(rot2, 1.0 / 3.0).as_degrees(), 45.0);
740 assert!(rot1.slerp(rot2, 0.0).is_near_identity());
741 assert_eq!(rot1.slerp(rot2, 0.5).as_degrees(), 67.5);
742 assert_eq!(rot1.slerp(rot2, 1.0).as_degrees(), 135.0);
743
744 let rot1 = Rot2::IDENTITY;
745 let rot2 = Rot2::from_sin_cos(0.0, -1.0);
746
747 assert!(ops::abs(rot1.slerp(rot2, 1.0 / 3.0).as_degrees() - 60.0) < 10e-6);
748 assert!(rot1.slerp(rot2, 0.0).is_near_identity());
749 assert_eq!(rot1.slerp(rot2, 0.5).as_degrees(), 90.0);
750 assert_eq!(ops::abs(rot1.slerp(rot2, 1.0).as_degrees()), 180.0);
751 }
752
753 #[test]
754 fn rotation_matrix() {
755 let rotation = Rot2::degrees(90.0);
756 let matrix: Mat2 = rotation.into();
757
758 assert_relative_eq!(matrix.x_axis, Vec2::Y);
760 assert_relative_eq!(matrix.y_axis, Vec2::NEG_X);
761
762 assert_relative_eq!(matrix * Vec2::X, Vec2::Y);
764 assert_relative_eq!(matrix * Vec2::Y, Vec2::NEG_X);
765 assert_relative_eq!(matrix * Vec2::NEG_X, Vec2::NEG_Y);
766 assert_relative_eq!(matrix * Vec2::NEG_Y, Vec2::X);
767 }
768}