use std::ops::{Add, AddAssign, Sub, SubAssign};
use crate::prelude::*;
use bevy::{math::DQuat, prelude::*};
#[cfg(all(feature = "2d", feature = "default-collider"))]
pub(crate) type RotationValue = Scalar;
#[cfg(all(feature = "3d", feature = "default-collider"))]
pub(crate) type RotationValue = Quaternion;
#[cfg(feature = "2d")]
#[derive(Reflect, Clone, Copy, Component, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[reflect(Component)]
pub struct Rotation {
cos: Scalar,
sin: Scalar,
}
#[cfg(feature = "3d")]
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[reflect(Component)]
pub struct Rotation(pub Quaternion);
impl Rotation {
#[cfg(feature = "2d")]
pub fn rotate_vec3(&self, vec: Vector3) -> Vector3 {
Vector3::new(
vec.x * self.cos() - vec.y * self.sin(),
vec.x * self.sin() + vec.y * self.cos(),
vec.z,
)
}
#[cfg(feature = "3d")]
pub fn rotate_vec3(&self, vec: Vector) -> Vector {
self.0 * vec
}
}
#[cfg(feature = "2d")]
impl Rotation {
pub const ZERO: Self = Self { cos: 1.0, sin: 0.0 };
pub fn cos(&self) -> Scalar {
self.cos
}
pub fn sin(&self) -> Scalar {
self.sin
}
pub fn from_radians(radians: Scalar) -> Self {
Self {
cos: radians.cos(),
sin: radians.sin(),
}
}
pub fn from_sin_cos(sin: Scalar, cos: Scalar) -> Self {
Self { sin, cos }
}
pub fn from_degrees(degrees: Scalar) -> Self {
Self::from_radians(degrees.to_radians())
}
pub fn as_radians(&self) -> Scalar {
Scalar::atan2(self.sin(), self.cos())
}
pub fn as_degrees(&self) -> Scalar {
self.as_radians().to_degrees()
}
pub fn rotate(&self, vec: Vector) -> Vector {
Vector::new(
vec.x * self.cos() - vec.y * self.sin(),
vec.x * self.sin() + vec.y * self.cos(),
)
}
pub fn inverse(&self) -> Self {
Self {
cos: self.cos,
sin: -self.sin,
}
}
pub fn mul(&self, rhs: Self) -> Self {
Self {
cos: self.cos * rhs.cos() - self.sin * rhs.sin(),
sin: self.sin * rhs.cos() + self.cos * rhs.sin(),
}
}
}
#[cfg(feature = "3d")]
impl Rotation {
pub fn rotate(&self, vec: Vector) -> Vector {
self.0 * vec
}
pub fn inverse(&self) -> Self {
Self(self.0.inverse())
}
}
#[cfg(feature = "2d")]
impl Default for Rotation {
fn default() -> Self {
Self::ZERO
}
}
#[cfg(feature = "2d")]
impl Add<Self> for Rotation {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self.mul(rhs)
}
}
#[cfg(feature = "3d")]
impl Add<Self> for Rotation {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Rotation(self.0 + rhs.0)
}
}
impl AddAssign<Self> for Rotation {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
#[cfg(feature = "2d")]
impl Sub<Self> for Rotation {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self.mul(rhs.inverse())
}
}
#[cfg(feature = "3d")]
impl Sub<Self> for Rotation {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Rotation(self.0 - rhs.0)
}
}
impl SubAssign<Self> for Rotation {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl core::ops::Mul<Vector> for Rotation {
type Output = Vector;
fn mul(self, vector: Vector) -> Self::Output {
self.rotate(vector)
}
}
impl core::ops::Mul<Dir> for Rotation {
type Output = Dir;
fn mul(self, direction: Dir) -> Self::Output {
Dir::new_unchecked(self.rotate(direction.adjust_precision()).f32())
}
}
impl core::ops::Mul<Vector> for &Rotation {
type Output = Vector;
fn mul(self, vector: Vector) -> Self::Output {
self.rotate(vector)
}
}
impl core::ops::Mul<Dir> for &Rotation {
type Output = Dir;
fn mul(self, direction: Dir) -> Self::Output {
Dir::new_unchecked(self.rotate(direction.adjust_precision()).f32())
}
}
#[cfg(feature = "2d")]
impl From<Rotation> for Scalar {
fn from(rot: Rotation) -> Self {
rot.as_radians()
}
}
#[cfg(feature = "2d")]
impl From<Scalar> for Rotation {
fn from(radians: Scalar) -> Self {
Self::from_radians(radians)
}
}
#[cfg(feature = "2d")]
impl From<Rotation> for Quaternion {
fn from(rot: Rotation) -> Self {
let z = rot.sin().signum() * ((1.0 - rot.cos()) / 2.0).abs().sqrt();
let w = ((1.0 + rot.cos()) / 2.0).abs().sqrt();
Quaternion::from_xyzw(0.0, 0.0, z, w)
}
}
#[cfg(feature = "3d")]
impl From<Rotation> for Quaternion {
fn from(rot: Rotation) -> Self {
rot.0
}
}
impl From<Transform> for Rotation {
fn from(value: Transform) -> Self {
Self::from(value.rotation)
}
}
impl From<GlobalTransform> for Rotation {
fn from(value: GlobalTransform) -> Self {
Self::from(value.compute_transform().rotation)
}
}
impl From<&GlobalTransform> for Rotation {
fn from(value: &GlobalTransform) -> Self {
Self::from(value.compute_transform().rotation)
}
}
#[cfg(feature = "2d")]
impl From<Quat> for Rotation {
fn from(quat: Quat) -> Self {
let angle = quat.to_euler(EulerRot::XYZ).2;
Self::from_radians(angle as Scalar)
}
}
#[cfg(feature = "2d")]
impl From<DQuat> for Rotation {
fn from(quat: DQuat) -> Self {
let angle = quat.to_euler(EulerRot::XYZ).2;
Self::from_radians(angle as Scalar)
}
}
#[cfg(feature = "3d")]
impl From<Quat> for Rotation {
fn from(quat: Quat) -> Self {
Self(Quaternion::from_xyzw(
quat.x as Scalar,
quat.y as Scalar,
quat.z as Scalar,
quat.w as Scalar,
))
}
}
#[cfg(feature = "3d")]
impl From<DQuat> for Rotation {
fn from(quat: DQuat) -> Self {
Self(Quaternion::from_xyzw(
quat.x as Scalar,
quat.y as Scalar,
quat.z as Scalar,
quat.w as Scalar,
))
}
}
#[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[reflect(Component)]
pub struct PreviousRotation(pub Rotation);