pybevy_math 0.2.1

Math types (Vec2, Vec3, Vec4, Quat, Mat3, Mat4) for PyBevy
Documentation
use bevy::math::{
    Vec3, Vec3A,
    bounding::{Aabb3d, BoundingVolume, IntersectsVolume},
};
use pybevy_core::{FromBorrowedStorage, ValueStorage};
use pyo3::prelude::*;

use super::bounding_sphere::PyBoundingSphere;
use crate::vec3::PyVec3;

#[pyclass(name = "Isometry3d", eq)]
#[derive(Debug, Clone, PartialEq)]
pub struct PyIsometry3d {
    rotation: bevy::math::Quat,
    translation: Vec3A,
}

impl From<PyIsometry3d> for bevy::math::Isometry3d {
    fn from(iso: PyIsometry3d) -> Self {
        bevy::math::Isometry3d::new(iso.translation, iso.rotation)
    }
}

impl From<bevy::math::Isometry3d> for PyIsometry3d {
    fn from(iso: bevy::math::Isometry3d) -> Self {
        PyIsometry3d {
            rotation: iso.rotation,
            translation: iso.translation,
        }
    }
}

#[pymethods]
impl PyIsometry3d {
    #[new]
    #[pyo3(signature = (translation = PyVec3::ZERO, rotation = crate::quat::PyQuat::IDENTITY))]
    pub fn new(translation: PyVec3, rotation: crate::quat::PyQuat) -> Self {
        let t: Vec3 = translation.into();
        PyIsometry3d {
            rotation: rotation.into(),
            translation: Vec3A::from(t),
        }
    }

    #[classattr]
    #[pyo3(name = "IDENTITY")]
    fn identity() -> Self {
        PyIsometry3d {
            rotation: bevy::math::Quat::IDENTITY,
            translation: Vec3A::ZERO,
        }
    }

    #[staticmethod]
    pub fn from_rotation(rotation: crate::quat::PyQuat) -> Self {
        PyIsometry3d {
            rotation: rotation.into(),
            translation: Vec3A::ZERO,
        }
    }

    #[staticmethod]
    pub fn from_translation(translation: PyVec3) -> Self {
        let t: Vec3 = translation.into();
        PyIsometry3d {
            rotation: bevy::math::Quat::IDENTITY,
            translation: Vec3A::from(t),
        }
    }

    #[staticmethod]
    pub fn from_xyz(x: f32, y: f32, z: f32) -> Self {
        PyIsometry3d {
            rotation: bevy::math::Quat::IDENTITY,
            translation: Vec3A::new(x, y, z),
        }
    }

    #[getter]
    pub fn translation(&self) -> PyVec3 {
        let v: Vec3 = self.translation.into();
        v.into()
    }

    #[getter]
    pub fn rotation(&self) -> crate::quat::PyQuat {
        self.rotation.into()
    }

    pub fn inverse(&self) -> Self {
        let inv_rot = self.rotation.inverse();
        PyIsometry3d {
            rotation: inv_rot,
            translation: inv_rot * -self.translation,
        }
    }

    pub fn inverse_mul(&self, rhs: &PyIsometry3d) -> Self {
        let inv_rot = self.rotation.inverse();
        let delta_translation = rhs.translation - self.translation;
        PyIsometry3d {
            rotation: inv_rot * rhs.rotation,
            translation: inv_rot * delta_translation,
        }
    }

    pub fn transform_point(&self, point: PyVec3) -> PyVec3 {
        let p: Vec3 = point.into();
        let result: Vec3 = (self.rotation * Vec3A::from(p) + self.translation).into();
        result.into()
    }

    pub fn inverse_transform_point(&self, point: PyVec3) -> PyVec3 {
        let p: Vec3 = point.into();
        let result: Vec3 = (self.rotation.inverse() * (Vec3A::from(p) - self.translation)).into();
        result.into()
    }

    fn __repr__(&self) -> String {
        let t: Vec3 = self.translation.into();
        format!(
            "Isometry3d(translation=Vec3({}, {}, {}), rotation=Quat({}, {}, {}, {}))",
            t.x, t.y, t.z, self.rotation.x, self.rotation.y, self.rotation.z, self.rotation.w
        )
    }
}

#[pyclass(name = "Aabb3d")]
#[derive(Debug, Clone)]
pub struct PyAabb3d {
    storage: ValueStorage<Aabb3d>,
}

impl From<PyAabb3d> for Aabb3d {
    #[inline(always)]
    fn from(py_aabb: PyAabb3d) -> Self {
        match py_aabb.storage.get() {
            Ok(val) => val,
            Err(_) => Aabb3d::new(Vec3A::ZERO, Vec3A::ZERO),
        }
    }
}

impl From<&PyAabb3d> for Aabb3d {
    #[inline(always)]
    fn from(py_aabb: &PyAabb3d) -> Self {
        match py_aabb.storage.get() {
            Ok(val) => val,
            Err(_) => Aabb3d::new(Vec3A::ZERO, Vec3A::ZERO),
        }
    }
}

impl From<Aabb3d> for PyAabb3d {
    #[inline(always)]
    fn from(aabb: Aabb3d) -> Self {
        PyAabb3d::from_aabb3d(aabb)
    }
}

impl FromBorrowedStorage<ValueStorage<Aabb3d>> for PyAabb3d {
    fn from_borrowed(storage: ValueStorage<Aabb3d>) -> Self {
        PyAabb3d { storage }
    }
}

impl PyAabb3d {
    #[inline(always)]
    pub fn from_aabb3d(aabb: Aabb3d) -> Self {
        PyAabb3d {
            storage: ValueStorage::owned(aabb),
        }
    }

    #[inline(always)]
    fn as_ref(&self) -> PyResult<&Aabb3d> {
        Ok(self.storage.as_ref()?)
    }
}

#[pymethods]
impl PyAabb3d {
    #[new]
    #[pyo3(signature = (center, half_size))]
    pub fn new(center: PyVec3, half_size: PyVec3) -> Self {
        let center_vec: Vec3 = center.into();
        let half_size_vec: Vec3 = half_size.into();
        PyAabb3d::from_aabb3d(Aabb3d::new(
            Vec3A::from(center_vec),
            Vec3A::from(half_size_vec),
        ))
    }

    #[staticmethod]
    pub fn from_min_max(min: PyVec3, max: PyVec3) -> Self {
        let min_vec: Vec3 = min.into();
        let max_vec: Vec3 = max.into();
        PyAabb3d::from_aabb3d(Aabb3d::from_min_max(
            Vec3A::from(min_vec),
            Vec3A::from(max_vec),
        ))
    }

    #[getter]
    pub fn min(&self) -> PyResult<PyVec3> {
        Ok(PyVec3::from_vec3(self.as_ref()?.min.into()))
    }

    #[getter]
    pub fn max(&self) -> PyResult<PyVec3> {
        Ok(PyVec3::from_vec3(self.as_ref()?.max.into()))
    }

    pub fn center(&self) -> PyResult<PyVec3> {
        Ok(PyVec3::from_vec3(self.as_ref()?.center().into()))
    }

    pub fn half_size(&self) -> PyResult<PyVec3> {
        Ok(PyVec3::from_vec3(self.as_ref()?.half_size().into()))
    }

    pub fn closest_point(&self, point: PyVec3) -> PyResult<PyVec3> {
        let point_vec: Vec3 = point.into();
        Ok(PyVec3::from_vec3(
            self.as_ref()?.closest_point(Vec3A::from(point_vec)).into(),
        ))
    }

    pub fn contains(&self, other: &PyAabb3d) -> PyResult<bool> {
        let other_aabb: Aabb3d = other.into();
        Ok(self.as_ref()?.contains(&other_aabb))
    }

    pub fn merge(&self, other: &PyAabb3d) -> PyResult<PyAabb3d> {
        let other_aabb: Aabb3d = other.into();
        Ok(PyAabb3d::from_aabb3d(self.as_ref()?.merge(&other_aabb)))
    }

    pub fn grow(&self, amount: PyVec3) -> PyResult<PyAabb3d> {
        let amount_vec: Vec3 = amount.into();
        Ok(PyAabb3d::from_aabb3d(
            self.as_ref()?.grow(Vec3A::from(amount_vec)),
        ))
    }

    pub fn shrink(&self, amount: PyVec3) -> PyResult<PyAabb3d> {
        let amount_vec: Vec3 = amount.into();
        Ok(PyAabb3d::from_aabb3d(
            self.as_ref()?.shrink(Vec3A::from(amount_vec)),
        ))
    }

    pub fn scale_around_center(&self, scale: PyVec3) -> PyResult<PyAabb3d> {
        let scale_vec: Vec3 = scale.into();
        Ok(PyAabb3d::from_aabb3d(
            self.as_ref()?.scale_around_center(Vec3A::from(scale_vec)),
        ))
    }

    pub fn visible_area(&self) -> PyResult<f32> {
        Ok(self.as_ref()?.visible_area())
    }

    pub fn bounding_sphere(&self) -> PyResult<PyBoundingSphere> {
        Ok(PyBoundingSphere::from_bounding_sphere(
            self.as_ref()?.bounding_sphere(),
        ))
    }

    pub fn intersects_aabb(&self, other: &PyAabb3d) -> PyResult<bool> {
        let other_aabb: Aabb3d = other.into();
        Ok(self.as_ref()?.intersects(&other_aabb))
    }

    pub fn intersects_sphere(&self, sphere: &PyBoundingSphere) -> PyResult<bool> {
        let bounding_sphere: bevy::math::bounding::BoundingSphere = sphere.into();
        Ok(self.as_ref()?.intersects(&bounding_sphere))
    }

    #[staticmethod]
    pub fn from_point_cloud(isometry: PyIsometry3d, points: Vec<PyVec3>) -> PyResult<PyAabb3d> {
        use bevy::math::Isometry3d;

        let iso: Isometry3d = isometry.into();
        let point_refs: Vec<Vec3A> = points
            .into_iter()
            .map(|p| {
                let v: Vec3 = p.into();
                v.into()
            })
            .collect();

        Ok(PyAabb3d::from_aabb3d(Aabb3d::from_point_cloud(
            iso,
            point_refs.into_iter(),
        )))
    }

    pub fn __eq__(&self, other: &PyAabb3d) -> PyResult<bool> {
        Ok(self.as_ref()? == other.as_ref()?)
    }

    fn __repr__(&self) -> PyResult<String> {
        let aabb = self.as_ref()?;
        Ok(format!("Aabb3d(min={:?}, max={:?})", aabb.min, aabb.max))
    }
}