pybevy_math 0.2.1

Math types (Vec2, Vec3, Vec4, Quat, Mat3, Mat4) for PyBevy
Documentation
use bevy::math::{
    Ray3d, Vec2, Vec3,
    bounding::{IntersectsVolume, RayCast2d, RayCast3d},
};
use pyo3::prelude::*;

use super::{
    aabb2d::PyAabb2d, aabb3d::PyAabb3d, bounding_circle::PyBoundingCircle,
    bounding_sphere::PyBoundingSphere,
};
use crate::{
    dir2::PyDir2,
    dir3::PyDir3,
    ray::{PyRay2d, PyRay3d},
    vec2::PyVec2,
    vec3::PyVec3,
};

#[pyclass(name = "RayCast2d")]
#[derive(Debug, Clone)]
pub struct PyRayCast2d {
    ray_cast: RayCast2d,
}

impl From<PyRayCast2d> for RayCast2d {
    fn from(py_raycast: PyRayCast2d) -> Self {
        py_raycast.ray_cast
    }
}

impl From<&PyRayCast2d> for RayCast2d {
    fn from(py_raycast: &PyRayCast2d) -> Self {
        py_raycast.ray_cast.clone()
    }
}

impl From<RayCast2d> for PyRayCast2d {
    fn from(ray_cast: RayCast2d) -> Self {
        PyRayCast2d { ray_cast }
    }
}

#[pymethods]
impl PyRayCast2d {
    #[new]
    pub fn new(origin: PyVec2, direction: PyDir2, max: f32) -> Self {
        let origin_vec: Vec2 = origin.into();
        let dir = direction.get();
        PyRayCast2d {
            ray_cast: RayCast2d::new(origin_vec, dir, max),
        }
    }

    #[staticmethod]
    pub fn from_ray(ray: &PyRay2d, max: f32) -> Self {
        PyRayCast2d {
            ray_cast: RayCast2d::from_ray(ray.to_ray2d(), max),
        }
    }

    #[getter]
    pub fn ray(&self) -> PyRay2d {
        PyRay2d::from_ray2d(self.ray_cast.ray)
    }

    #[getter]
    pub fn max(&self) -> f32 {
        self.ray_cast.max
    }

    pub fn intersects_aabb(&self, aabb: &PyAabb2d) -> bool {
        let aabb_2d: bevy::math::bounding::Aabb2d = aabb.into();
        self.ray_cast.intersects(&aabb_2d)
    }

    pub fn intersects_circle(&self, circle: &PyBoundingCircle) -> bool {
        let bounding_circle: bevy::math::bounding::BoundingCircle = circle.into();
        self.ray_cast.intersects(&bounding_circle)
    }

    pub fn aabb_intersection_at(&self, aabb: &PyAabb2d) -> Option<f32> {
        let aabb_2d: bevy::math::bounding::Aabb2d = aabb.into();
        self.ray_cast.aabb_intersection_at(&aabb_2d)
    }

    pub fn circle_intersection_at(&self, circle: &PyBoundingCircle) -> Option<f32> {
        let bounding_circle: bevy::math::bounding::BoundingCircle = circle.into();
        self.ray_cast.circle_intersection_at(&bounding_circle)
    }

    pub fn direction_recip(&self) -> PyVec2 {
        PyVec2::from_vec2(self.ray_cast.direction_recip())
    }

    fn __repr__(&self) -> String {
        format!(
            "RayCast2d(ray={:?}, max={})",
            self.ray_cast.ray, self.ray_cast.max
        )
    }
}

#[pyclass(name = "RayCast3d")]
#[derive(Debug, Clone)]
pub struct PyRayCast3d {
    ray_cast: RayCast3d,
}

impl From<PyRayCast3d> for RayCast3d {
    fn from(py_raycast: PyRayCast3d) -> Self {
        py_raycast.ray_cast
    }
}

impl From<&PyRayCast3d> for RayCast3d {
    fn from(py_raycast: &PyRayCast3d) -> Self {
        py_raycast.ray_cast.clone()
    }
}

impl From<RayCast3d> for PyRayCast3d {
    fn from(ray_cast: RayCast3d) -> Self {
        PyRayCast3d { ray_cast }
    }
}

#[pymethods]
impl PyRayCast3d {
    #[new]
    pub fn new(origin: PyVec3, direction: PyDir3, max: f32) -> Self {
        let origin_vec: Vec3 = origin.into();
        let dir = direction.get();
        PyRayCast3d {
            ray_cast: RayCast3d::new(origin_vec, dir, max),
        }
    }

    #[staticmethod]
    pub fn from_ray(ray: &PyRay3d, max: f32) -> Self {
        PyRayCast3d {
            ray_cast: RayCast3d::from_ray(ray.to_ray3d(), max),
        }
    }

    #[getter]
    pub fn ray(&self) -> PyRay3d {
        let dir3: bevy::math::Dir3 = self.ray_cast.direction.into();
        let ray = Ray3d::new(self.ray_cast.origin.into(), dir3);
        PyRay3d::from_ray3d(ray)
    }

    #[getter]
    pub fn max(&self) -> f32 {
        self.ray_cast.max
    }

    pub fn intersects_aabb(&self, aabb: &PyAabb3d) -> bool {
        let aabb_3d: bevy::math::bounding::Aabb3d = aabb.into();
        self.ray_cast.intersects(&aabb_3d)
    }

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

    pub fn aabb_intersection_at(&self, aabb: &PyAabb3d) -> Option<f32> {
        let aabb_3d: bevy::math::bounding::Aabb3d = aabb.into();
        self.ray_cast.aabb_intersection_at(&aabb_3d)
    }

    pub fn sphere_intersection_at(&self, sphere: &PyBoundingSphere) -> Option<f32> {
        let bounding_sphere: bevy::math::bounding::BoundingSphere = sphere.into();
        self.ray_cast.sphere_intersection_at(&bounding_sphere)
    }

    pub fn direction_recip(&self) -> PyVec3 {
        PyVec3::from_vec3(self.ray_cast.direction_recip().into())
    }

    fn __repr__(&self) -> String {
        format!(
            "RayCast3d(origin={:?}, direction={:?}, max={})",
            self.ray_cast.origin, self.ray_cast.direction, self.ray_cast.max
        )
    }
}