use std::fmt::Debug;
use log::error;
use num_traits::Float;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::types::computation::{
model::{Data, DataType, Parameter},
traits::{ImplicitComponent, ImplicitFunction, ModelFloat},
};
use super::{traits::SignedDistance, Vec3};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy)]
pub struct Plane<T> {
origin: Vec3<T>,
normal: Vec3<T>,
}
static PLANE_PARAMS: &[Parameter; 2] = &[
Parameter {
name: "Origin",
data_type: DataType::Vec3,
},
Parameter {
name: "Normal",
data_type: DataType::Vec3,
},
];
impl<T: Float> Plane<T> {
pub fn new(origin: Vec3<T>, normal: Vec3<T>) -> Self {
Plane {
origin,
normal: normal.normalize(),
}
}
pub fn xy() -> Self {
Plane {
origin: Vec3::origin(),
normal: Vec3::z_axis().normalize(),
}
}
pub fn yz() -> Self {
Plane {
origin: Vec3::origin(),
normal: Vec3::x_axis().normalize(),
}
}
pub fn xz() -> Self {
Plane {
origin: Vec3::origin(),
normal: Vec3::y_axis().normalize(),
}
}
pub fn origin(&self) -> Vec3<T> {
self.origin
}
pub fn normal(&self) -> Vec3<T> {
self.normal
}
pub fn signed_distance_coord(&self, x: T, y: T, z: T) -> T {
self.normal
.dot_coord(x - self.origin.x, y - self.origin.y, z - self.origin.z)
}
}
impl<T: ModelFloat> SignedDistance<T> for Plane<T> {
fn signed_distance(&self, x: T, y: T, z: T) -> T {
self.signed_distance_coord(x, y, z)
}
}
impl<T: ModelFloat> ImplicitFunction<T> for Plane<T> {
fn eval(&self, x: T, y: T, z: T) -> T {
self.signed_distance_coord(x, y, z)
}
}
impl<T: ModelFloat> ImplicitComponent<T> for Plane<T> {
fn parameters(&self) -> &[Parameter] {
PLANE_PARAMS
}
fn set_parameter(&mut self, parameter_name: &str, data: Data<T>) {
if !(Parameter::set_vec3_from_param(parameter_name, &data, "Origin", &mut self.origin)
|| Parameter::set_vec3_from_param(parameter_name, &data, "Normal", &mut self.normal))
{
error!("Unknown parameter name: {}", parameter_name);
}
}
fn read_parameter(&self, parameter_name: &str) -> Option<Data<T>> {
match parameter_name {
"Origin" => Some(Data::Vec3(self.origin)),
"Normal" => Some(Data::Vec3(self.normal)),
_ => None,
}
}
fn name(&self) -> &'static str {
"Plane"
}
}