imlet/types/geometry/
sphere.rs1use 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#[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 pub fn new(centre: Vec3<T>, radius: T) -> Self {
42 Self { centre, radius }
43 }
44
45 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 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}