vox_geometry_rust 0.1.2

Geometry Tools for Rust
Documentation
/*
 * // Copyright (c) 2021 Feng Yang
 * //
 * // I am making my contributions/submissions to this project solely in my
 * // personal capacity and am not conveying any rights to any intellectual
 * // property of any third parties.
 */

use crate::vector2::Vector2D;
use crate::ray2::Ray2D;
use crate::bounding_box2::BoundingBox2D;

///
/// # Represents 2-D rigid body transform.
///
pub struct Transform2 {
    _translation: Vector2D,
    _orientation: f64,
    _cos_angle: f64,
    _sin_angle: f64,
}

impl Transform2 {
    /// Constructs identity transform.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// let t1 = Transform2::new_default();
    ///
    /// assert_eq!(Vector2D::new_default(), t1.translation());
    /// assert_eq!(0.0, t1.orientation());
    /// ```
    pub fn new_default() -> Transform2 {
        return Transform2 {
            _translation: Vector2D::new_default(),
            _orientation: 0.0,
            _cos_angle: 1.0,
            _sin_angle: 0.0,
        };
    }

    /// Constructs a transform with translation and orientation.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// use vox_geometry_rust::constants::K_QUARTER_PI_D;
    /// let t2 = Transform2::new(Vector2D::new_lst([2.0, -5.0]), K_QUARTER_PI_D);
    ///
    /// assert_eq!(Vector2D::new(2.0, -5.0), t2.translation());
    /// assert_eq!(K_QUARTER_PI_D, t2.orientation());
    /// ```
    pub fn new(translation: Vector2D, orientation: f64) -> Transform2 {
        return Transform2 {
            _translation: translation,
            _orientation: orientation,
            _cos_angle: orientation.cos(),
            _sin_angle: orientation.sin(),
        };
    }
}

impl Transform2 {
    /// Returns the translation.
    pub fn translation(&self) -> Vector2D {
        return self._translation;
    }

    /// Sets the translation.
    pub fn set_translation(&mut self, translation: Vector2D) {
        self._translation = translation;
    }

    /// Returns the orientation in radians.
    pub fn orientation(&self) -> f64 {
        return self._orientation;
    }

    /// Sets the orientation in radians.
    pub fn set_orientation(&mut self, orientation: f64) {
        self._orientation = orientation;
        self._cos_angle = f64::cos(orientation);
        self._sin_angle = f64::sin(orientation);
    }

    /// Transforms a point in world coordinate to the local frame.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// use vox_geometry_rust::constants::K_HALF_PI_D;
    /// use vox_geometry_rust::assert_delta;
    /// let t = Transform2::new(Vector2D::new(2.0, -5.0), K_HALF_PI_D);
    ///
    /// let r1 = t.to_world_vec(&Vector2D::new(4.0, 1.0));
    /// let r2 = t.to_local_vec(&r1);
    /// assert_eq!(4.0, r2.x);
    /// assert_eq!(1.0, r2.y);
    /// ```
    pub fn to_local_vec(&self, point_in_world: &Vector2D) -> Vector2D {
        // Convert to the local frame
        let xmt = *point_in_world - self._translation;
        return Vector2D::new(
            self._cos_angle * xmt.x + self._sin_angle * xmt.y,
            -self._sin_angle * xmt.x + self._cos_angle * xmt.y);
    }

    /// Transforms a direction in world coordinate to the local frame.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// use vox_geometry_rust::constants::K_HALF_PI_D;
    /// use vox_geometry_rust::assert_delta;
    /// let t = Transform2::new(Vector2D::new(2.0, -5.0), K_HALF_PI_D);
    ///
    /// let r3 = t.to_world_direction(&Vector2D::new(4.0, 1.0));
    /// let r4 = t.to_local_direction(&r3);
    /// assert_eq!(4.0, r4.x);
    /// assert_eq!(1.0, r4.y);
    /// ```
    pub fn to_local_direction(&self, dir_in_world: &Vector2D) -> Vector2D {
        // Convert to the local frame
        return Vector2D::new(
            self._cos_angle * dir_in_world.x + self._sin_angle * dir_in_world.y,
            -self._sin_angle * dir_in_world.x + self._cos_angle * dir_in_world.y);
    }

    /// Transforms a ray in world coordinate to the local frame.
    pub fn to_local_ray(&self, ray_in_world: &Ray2D) -> Ray2D {
        return Ray2D::new(
            self.to_local_vec(&ray_in_world.origin),
            self.to_local_direction(&ray_in_world.direction));
    }

    /// Transforms a bounding box in world coordinate to the local frame.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// use vox_geometry_rust::bounding_box2::BoundingBox2D;
    /// use vox_geometry_rust::constants::K_HALF_PI_D;
    /// use vox_geometry_rust::assert_delta;
    /// let t = Transform2::new(Vector2D::new(2.0, -5.0), K_HALF_PI_D);
    ///
    /// let bbox = BoundingBox2D::new(Vector2D::new(-2.0, -1.0), Vector2D::new(2.0, 1.0));
    /// let r5 = t.to_world_aabb(&bbox);
    /// let r6 = t.to_local_aabb(&r5);
    /// assert_eq!(bbox.lower_corner.is_similar(&r6.lower_corner, Some(10.0*f64::EPSILON)), true);
    /// assert_eq!(bbox.upper_corner.is_similar(&r6.upper_corner, Some(10.0*f64::EPSILON)), true);
    /// ```
    pub fn to_local_aabb(&self, bbox_in_world: &BoundingBox2D) -> BoundingBox2D {
        let mut bbox_in_local = BoundingBox2D::new_default();
        for i in 0..4 {
            let corner_in_local = self.to_local_vec(&bbox_in_world.corner(i));
            bbox_in_local.lower_corner
                = crate::vector2::min(&bbox_in_local.lower_corner, &corner_in_local);
            bbox_in_local.upper_corner
                = crate::vector2::max(&bbox_in_local.upper_corner, &corner_in_local);
        }
        return bbox_in_local;
    }

    /// Transforms a point in local space to the world coordinate.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// use vox_geometry_rust::constants::K_HALF_PI_D;
    /// use vox_geometry_rust::assert_delta;
    /// let t = Transform2::new(Vector2D::new(2.0, -5.0), K_HALF_PI_D);
    ///
    /// let r1 = t.to_world_vec(&Vector2D::new(4.0, 1.0));
    /// assert_delta!(1.0, r1.x, f64::EPSILON);
    /// assert_eq!(-1.0, r1.y);
    /// ```
    pub fn to_world_vec(&self, point_in_local: &Vector2D) -> Vector2D {
        // Convert to the world frame
        return Vector2D::new(
            self._cos_angle * point_in_local.x - self._sin_angle * point_in_local.y
                + self._translation.x,
            self._sin_angle * point_in_local.x + self._cos_angle * point_in_local.y
                + self._translation.y);
    }

    /// Transforms a direction in local space to the world coordinate.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// use vox_geometry_rust::constants::K_HALF_PI_D;
    /// use vox_geometry_rust::assert_delta;
    /// let t = Transform2::new(Vector2D::new(2.0, -5.0), K_HALF_PI_D);
    ///
    /// let r3 = t.to_world_direction(&Vector2D::new(4.0, 1.0));
    /// assert_delta!(-1.0, r3.x, f64::EPSILON);
    /// assert_eq!(4.0, r3.y);
    /// ```
    pub fn to_world_direction(&self, dir_in_local: &Vector2D) -> Vector2D {
        // Convert to the world frame
        return Vector2D::new(
            self._cos_angle * dir_in_local.x - self._sin_angle * dir_in_local.y,
            self._sin_angle * dir_in_local.x + self._cos_angle * dir_in_local.y);
    }

    /// Transforms a ray in local space to the world coordinate.
    pub fn to_world_ray(&self, ray_in_local: Ray2D) -> Ray2D {
        return Ray2D::new(
            self.to_world_vec(&ray_in_local.origin),
            self.to_world_direction(&ray_in_local.direction));
    }

    /// Transforms a bounding box in local space to the world coordinate.
    /// ```
    /// use vox_geometry_rust::transform2::Transform2;
    /// use vox_geometry_rust::vector2::Vector2D;
    /// use vox_geometry_rust::bounding_box2::BoundingBox2D;
    /// use vox_geometry_rust::constants::K_HALF_PI_D;
    /// use vox_geometry_rust::assert_delta;
    /// let t = Transform2::new(Vector2D::new(2.0, -5.0), K_HALF_PI_D);
    ///
    /// let bbox = BoundingBox2D::new(Vector2D::new(-2.0, -1.0), Vector2D::new(2.0, 1.0));
    /// let r5 = t.to_world_aabb(&bbox);
    /// let result = BoundingBox2D::new(Vector2D::new(1.0, -7.0), Vector2D::new(3.0, -3.0));
    /// assert_eq!(result.lower_corner.is_similar(&r5.lower_corner, Some(10.0*f64::EPSILON)), true);
    /// assert_eq!(result.upper_corner, r5.upper_corner);
    /// ```
    pub fn to_world_aabb(&self, bbox_in_local: &BoundingBox2D) -> BoundingBox2D {
        let mut bbox_in_world = BoundingBox2D::new_default();
        for i in 0..4 {
            let corner_in_world = self.to_world_vec(&bbox_in_local.corner(i));
            bbox_in_world.lower_corner
                = crate::vector2::min(&bbox_in_world.lower_corner, &corner_in_world);
            bbox_in_world.upper_corner
                = crate::vector2::max(&bbox_in_world.upper_corner, &corner_in_world);
        }
        return bbox_in_world;
    }
}

impl Clone for Transform2 {
    fn clone(&self) -> Self {
        return Transform2 {
            _translation: self._translation,
            _orientation: self._orientation,
            _cos_angle: self._cos_angle,
            _sin_angle: self._sin_angle,
        };
    }
}