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::surface2::*;
use crate::vector2::Vector2D;
use crate::transform2::Transform2;
use crate::bounding_box2::BoundingBox2D;
use crate::ray2::Ray2D;
use std::sync::{RwLock, Arc};

///
/// # 2-D sphere geometry.
///
/// This class represents 2-D sphere geometry which extends Surface2 by
/// overriding surface-related queries.
///
pub struct Sphere2 {
    /// Center of the sphere.
    pub center: Vector2D,

    /// Radius of the sphere.
    pub radius: f64,

    /// data from surface2
    pub surface_data: Surface2Data,
}

impl Sphere2 {
    /// Constructs a sphere with center at (0, 0) and radius of 1.
    pub fn new_default(transform: Option<Transform2>,
                       is_normal_flipped: Option<bool>) -> Sphere2 {
        return Sphere2 {
            center: Vector2D::new_default(),
            radius: 0.0,
            surface_data: Surface2Data::new(transform, is_normal_flipped),
        };
    }

    /// Constructs a sphere with \p center and \p radius.
    pub fn new(center: Vector2D,
               radius: f64,
               transform: Option<Transform2>,
               is_normal_flipped: Option<bool>) -> Sphere2 {
        return Sphere2 {
            center,
            radius,
            surface_data: Surface2Data::new(transform, is_normal_flipped),
        };
    }

    /// Returns builder fox Sphere2.
    pub fn builder() -> Builder {
        return Builder::new();
    }
}

impl Surface2 for Sphere2 {
    fn closest_point_local(&self, other_point: &Vector2D) -> Vector2D {
        return self.closest_normal_local(other_point) * self.radius + self.center;
    }

    fn bounding_box_local(&self) -> BoundingBox2D {
        let r = Vector2D::new(self.radius, self.radius);
        return BoundingBox2D::new(self.center - r, self.center + r);
    }

    fn closest_intersection_local(&self, ray: &Ray2D) -> SurfaceRayIntersection2 {
        let mut intersection = SurfaceRayIntersection2::new();
        let r = ray.origin - self.center;
        let b = ray.direction.dot(&r);
        let c = r.length_squared() - crate::math_utils::square(self.radius);
        let mut d = b * b - c;

        if d > 0.0 {
            d = f64::sqrt(d);
            let mut t_min = -b - d;
            let t_max = -b + d;

            if t_min < 0.0 {
                t_min = t_max;
            }

            if t_min < 0.0 {
                intersection.is_intersecting = false;
            } else {
                intersection.is_intersecting = true;
                intersection.distance = t_min;
                intersection.point = ray.origin + ray.direction * t_min;
                intersection.normal = (intersection.point - self.center).normalized();
            }
        } else {
            intersection.is_intersecting = false;
        }

        return intersection;
    }

    fn closest_normal_local(&self, other_point: &Vector2D) -> Vector2D {
        return if self.center.is_similar(&other_point, None) {
            Vector2D::new(1.0, 0.0)
        } else {
            (*other_point - self.center).normalized()
        };
    }

    fn intersects_local(&self, ray_local: &Ray2D) -> bool {
        let r = ray_local.origin - self.center;
        let b = ray_local.direction.dot(&r);
        let c = r.length_squared() - crate::math_utils::square(self.radius);
        let mut d = b * b - c;

        if d > 0.0 {
            d = f64::sqrt(d);
            let mut t_min = -b - d;
            let t_max = -b + d;

            if t_min < 0.0 {
                t_min = t_max;
            }

            if t_min >= 0.0 {
                return true;
            }
        }

        return false;
    }

    fn closest_distance_local(&self, other_point_local: &Vector2D) -> f64 {
        return f64::abs(self.center.distance_to(*other_point_local) - self.radius);
    }

    fn view(&self) -> &Surface2Data {
        return &self.surface_data;
    }
}

/// Shared pointer for the Sphere2 type.
pub type Sphere2Ptr = Arc<RwLock<Sphere2>>;

//--------------------------------------------------------------------------------------------------
///
/// # Front-end to create Sphere2 objects step by step.
///
pub struct Builder {
    _center: Vector2D,
    _radius: f64,

    _surface_data: Surface2Data,
}

impl Builder {
    /// Returns builder with sphere center.
    pub fn with_center(&mut self, center: Vector2D) -> &mut Self {
        self._center = center;
        return self;
    }

    /// Returns builder with sphere radius.
    pub fn with_radius(&mut self, radius: f64) -> &mut Self {
        self._radius = radius;
        return self;
    }

    /// Builds Sphere2.
    pub fn build(&mut self) -> Sphere2 {
        return Sphere2::new(self._center,
                            self._radius,
                            Some(self._surface_data.transform.clone()),
                            Some(self._surface_data.is_normal_flipped),
        );
    }

    /// Builds shared pointer of Sphere2 instance.
    pub fn make_shared(&mut self) -> Sphere2Ptr {
        return Sphere2Ptr::new(RwLock::new(self.build()));
    }

    /// constructor
    pub fn new() -> Builder {
        return Builder {
            _center: Vector2D::new_default(),
            _radius: 0.0,
            _surface_data: Surface2Data::new(None, None),
        };
    }
}

impl SurfaceBuilderBase2 for Builder {
    fn view(&mut self) -> &mut Surface2Data {
        return &mut self._surface_data;
    }
}