imlet/types/geometry/
sphere.rs

1use std::fmt::Debug;
2
3use log::error;
4use num_traits::Float;
5use serde::{Deserialize, Serialize};
6
7use crate::types::{
8    computation::{
9        model::{Data, DataType, Parameter},
10        traits::{ImplicitComponent, ImplicitFunction},
11    },
12    geometry::Vec3,
13};
14
15use super::{traits::SignedDistance, BoundingBox};
16
17static SPHERE_PARAMS: &[Parameter; 2] = &[
18    Parameter {
19        name: "Centre",
20        data_type: DataType::Vec3,
21    },
22    Parameter {
23        name: "Radius",
24        data_type: DataType::Value,
25    },
26];
27
28/// A sphere object, defined by a centre point and a radius.
29#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
30pub struct Sphere<T> {
31    pub centre: Vec3<T>,
32    pub radius: T,
33}
34
35impl<T> Sphere<T> {
36    /// Create a new sphere.
37    /// # Arguments
38    ///
39    /// * `centre` -The centre point of the sphere.
40    /// * `radius` -The radius of the sphere
41    pub fn new(centre: Vec3<T>, radius: T) -> Self {
42        Self { centre, radius }
43    }
44
45    /// Create a new sphere at a point defined by x, y and z coordinates.
46    /// # Arguments
47    ///
48    /// * `x` -The x coord of the centre of the sphere.
49    /// * `y` -The y coord of the centre of the sphere.
50    /// * `z` -The z coord of the centre of the sphere.
51    /// * `radius` -The radius of the sphere
52    pub fn at_coord(x: T, y: T, z: T, radius: T) -> Self {
53        Self {
54            centre: Vec3::new(x, y, z),
55            radius,
56        }
57    }
58}
59
60impl<T: Float> Sphere<T> {
61    /// Compute the bounding box for the sphere
62    pub fn bounds(&self) -> BoundingBox<T> {
63        let min = self.centre - Vec3::new(self.radius, self.radius, self.radius);
64        let max = self.centre + Vec3::new(self.radius, self.radius, self.radius);
65        BoundingBox::new(min, max)
66    }
67}
68
69impl<T: Float + Send + Sync> SignedDistance<T> for Sphere<T> {
70    fn signed_distance(&self, x: T, y: T, z: T) -> T {
71        self.centre.distance_to_coord(x, y, z) - self.radius
72    }
73}
74
75impl<T: Float + Send + Sync + Serialize> ImplicitFunction<T> for Sphere<T> {
76    fn eval(&self, x: T, y: T, z: T) -> T {
77        self.centre.distance_to_coord(x, y, z) - self.radius
78    }
79}
80
81impl<T: Float + Send + Sync + Serialize> ImplicitComponent<T> for Sphere<T> {
82    fn parameters(&self) -> &[Parameter] {
83        SPHERE_PARAMS
84    }
85
86    fn set_parameter(&mut self, parameter_name: &str, data: Data<T>) {
87        if !(Parameter::set_vec3_from_param(parameter_name, &data, "Centre", &mut self.centre)
88            || Parameter::set_value_from_param(parameter_name, &data, "Radius", &mut self.radius))
89        {
90            error!("Unknown parameter name: {}", parameter_name);
91        }
92    }
93
94    fn read_parameter(&self, parameter_name: &str) -> Option<Data<T>> {
95        match parameter_name {
96            "Centre" => Some(Data::Vec3(self.centre)),
97            "Radius" => Some(Data::Value(self.radius)),
98            _ => None,
99        }
100    }
101
102    fn name(&self) -> &'static str {
103        "Sphere"
104    }
105}
106
107#[cfg(test)]
108mod tests {
109
110    use super::*;
111
112    #[test]
113    fn test_get_assigns_params() {
114        let mut sphere = Sphere::new(Vec3::new(1., 1., 1.), 10.);
115
116        let params = sphere.parameters().to_vec();
117
118        for param in params {
119            match param.data_type {
120                DataType::Value => sphere.set_parameter(param.name, Data::Value(1.)),
121                DataType::Vec3 => {
122                    sphere.set_parameter(param.name, Data::Vec3(Vec3::new(1., 1., 1.)))
123                }
124                _ => panic!("Error in the param"),
125            }
126        }
127
128        assert!((sphere.radius - 1.).abs() < f64::epsilon());
129        assert!(sphere.centre.distance_to_coord(1., 1., 1.).abs() < f64::epsilon());
130    }
131}