use dyn_clone::DynClone;
use crate::structures::{dimension::Dimension, simbox::SimBox, vector3d::Vector3D};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct Sphere {
position: Vector3D,
radius: f32,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct Rectangular {
position: Vector3D,
x: f32,
y: f32,
z: f32,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct Cylinder {
position: Vector3D,
radius: f32,
height: f32,
orientation: Dimension,
plane: Dimension,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
pub struct TriangularPrism {
base1: Vector3D,
base2: Vector3D,
base3: Vector3D,
height: f32,
orientation: Dimension,
plane: Dimension,
}
pub trait Shape: DynClone {
fn inside(&self, point: &Vector3D, simbox: &SimBox) -> bool;
}
dyn_clone::clone_trait_object!(Shape);
impl Sphere {
pub fn new(position: Vector3D, radius: f32) -> Self {
Sphere { position, radius }
}
pub fn get_position(&self) -> &Vector3D {
&self.position
}
pub fn get_radius(&self) -> f32 {
self.radius
}
}
impl Shape for Sphere {
fn inside(&self, point: &Vector3D, simbox: &SimBox) -> bool {
point.distance(&self.position, Dimension::XYZ, simbox) < self.radius
}
}
impl Rectangular {
pub fn new(position: Vector3D, x: f32, y: f32, z: f32) -> Self {
Rectangular { position, x, y, z }
}
pub fn get_position(&self) -> &Vector3D {
&self.position
}
pub fn get_x(&self) -> f32 {
self.x
}
pub fn get_y(&self) -> f32 {
self.y
}
pub fn get_z(&self) -> f32 {
self.z
}
}
impl Shape for Rectangular {
fn inside(&self, point: &Vector3D, simbox: &SimBox) -> bool {
let mut dx = point.distance(&self.position, Dimension::X, simbox);
if dx < 0.0 {
dx += simbox.x;
}
let mut dy = point.distance(&self.position, Dimension::Y, simbox);
if dy < 0.0 {
dy += simbox.y;
}
let mut dz = point.distance(&self.position, Dimension::Z, simbox);
if dz < 0.0 {
dz += simbox.z;
}
dx <= self.x && dy <= self.y && dz <= self.z
}
}
impl Cylinder {
pub fn new(position: Vector3D, radius: f32, height: f32, orientation: Dimension) -> Self {
let plane = match orientation {
Dimension::X => Dimension::YZ,
Dimension::Y => Dimension::XZ,
Dimension::Z => Dimension::XY,
d => panic!(
"FATAL GROAN ERROR | Cylinder::new | Unsupported orientation dimension '{}'.",
d
),
};
Cylinder {
position,
radius,
height,
orientation,
plane,
}
}
pub fn get_position(&self) -> &Vector3D {
&self.position
}
pub fn get_radius(&self) -> f32 {
self.radius
}
pub fn get_height(&self) -> f32 {
self.height
}
pub fn get_orientation(&self) -> Dimension {
self.orientation
}
}
impl Shape for Cylinder {
fn inside(&self, point: &Vector3D, simbox: &SimBox) -> bool {
let mut distance_axis = point.distance(&self.position, self.orientation, simbox);
if distance_axis < 0.0 {
match self.orientation {
Dimension::X => distance_axis += simbox.x,
Dimension::Y => distance_axis += simbox.y,
Dimension::Z => distance_axis += simbox.z,
d => panic!("FATAL GROAN ERROR | Cylinder::inside | Orientation dimension '{}' should never occur in a cylinder shape.", d),
}
}
if distance_axis > self.height
|| point.distance(&self.position, self.plane, simbox) > self.radius
{
return false;
}
true
}
}
impl TriangularPrism {
pub fn new(base1: Vector3D, base2: Vector3D, base3: Vector3D, height: f32) -> Self {
let bases = [
(base1.x, base2.x, base3.x, Dimension::X, Dimension::YZ),
(base1.y, base2.y, base3.y, Dimension::Y, Dimension::XZ),
(base1.z, base2.z, base3.z, Dimension::Z, Dimension::XY),
];
let mut orientation = None;
let mut plane = Dimension::None;
for (val1, val2, val3, current_orientation, current_plane) in bases.iter() {
if val1 == val2 && val2 == val3 {
if orientation.is_some() {
panic!("FATAL GROAN ERROR | TriangularPrism::new | Base of the requested TriangularPrism can not be constructed.");
}
orientation = Some(*current_orientation);
plane = *current_plane;
}
}
if orientation.is_none() {
panic!("FATAL GROAN ERROR | TriangularPrism::new | Base of the requested TriangularPrism does not lie in xy, xz, nor yz plane.");
}
TriangularPrism {
base1,
base2,
base3,
height,
orientation: orientation.unwrap(),
plane,
}
}
pub fn get_base1(&self) -> &Vector3D {
&self.base1
}
pub fn get_base2(&self) -> &Vector3D {
&self.base2
}
pub fn get_base3(&self) -> &Vector3D {
&self.base3
}
pub fn get_height(&self) -> f32 {
self.height
}
pub fn get_orientation(&self) -> Dimension {
self.orientation
}
pub fn get_plane(&self) -> Dimension {
self.plane
}
fn sign(point1: &Vector3D, point2: &Vector3D, point3: &Vector3D, plane: Dimension) -> f32 {
match plane {
Dimension::XY => {
(point1.x - point3.x) * (point2.y - point3.y)
- (point2.x - point3.x) * (point1.y - point3.y)
}
Dimension::XZ => {
(point1.x - point3.x) * (point2.z - point3.z)
- (point2.x - point3.x) * (point1.z - point3.z)
}
Dimension::YZ => {
(point1.y - point3.y) * (point2.z - point3.z)
- (point2.y - point3.y) * (point1.z - point3.z)
}
_ => panic!(
"FATAL GROAN ERROR | TriangularPrism::sign | This dimension should never occur."
),
}
}
}
impl Shape for TriangularPrism {
fn inside(&self, point: &Vector3D, simbox: &SimBox) -> bool {
let mut distance_from_base =
point.distance(self.get_base1(), self.get_orientation(), simbox);
if distance_from_base < 0.0 {
match self.get_orientation() {
Dimension::X => distance_from_base += simbox.x,
Dimension::Y => distance_from_base += simbox.y,
Dimension::Z => distance_from_base += simbox.z,
d => panic!("FATAL GROAN ERROR | TriangularPrism::inside | Orientation dimension '{}' should never occur in a triangular prism.", d),
}
}
if distance_from_base >= self.get_height() {
return false;
}
let d1 = TriangularPrism::sign(point, self.get_base1(), self.get_base2(), self.get_plane());
let d2 = TriangularPrism::sign(point, self.get_base2(), self.get_base3(), self.get_plane());
let d3 = TriangularPrism::sign(point, self.get_base3(), self.get_base1(), self.get_plane());
let has_neg = (d1 < 0.0) || (d2 < 0.0) || (d3 < 0.0);
let has_pos = (d1 > 0.0) || (d2 > 0.0) || (d3 > 0.0);
!(has_neg && has_pos)
}
}
pub trait NaiveShape: DynClone {
fn inside_naive(&self, point: &Vector3D) -> bool;
}
impl NaiveShape for Sphere {
fn inside_naive(&self, point: &Vector3D) -> bool {
point.distance_naive(&self.position, Dimension::XYZ) < self.radius
}
}
impl NaiveShape for Cylinder {
fn inside_naive(&self, point: &Vector3D) -> bool {
let dist = point.distance_naive(&self.position, self.orientation);
dist >= 0.0
&& dist < self.height
&& point.distance_naive(&self.position, self.plane) < self.radius
}
}
impl NaiveShape for Rectangular {
fn inside_naive(&self, point: &Vector3D) -> bool {
let dx = point.distance_naive(&self.position, Dimension::X);
let dy = point.distance_naive(&self.position, Dimension::Y);
let dz = point.distance_naive(&self.position, Dimension::Z);
dx >= 0.0 && dx <= self.x && dy >= 0.0 && dy <= self.y && dz >= 0.0 && dz <= self.z
}
}
dyn_clone::clone_trait_object!(NaiveShape);
#[cfg(test)]
mod tests_sphere {
use super::*;
use float_cmp::assert_approx_eq;
use rand::RngExt;
#[test]
fn new() {
let sphere = Sphere::new([1.0, 2.0, 3.0].into(), 1.5);
assert_approx_eq!(f32, sphere.get_position().x, 1.0);
assert_approx_eq!(f32, sphere.get_position().y, 2.0);
assert_approx_eq!(f32, sphere.get_position().z, 3.0);
assert_approx_eq!(f32, sphere.get_radius(), 1.5);
}
#[test]
fn inside_nopbc() {
let sphere = Sphere::new([1.0, 2.0, 3.0].into(), 1.5);
let point = Vector3D::new(2.0, 2.5, 2.4);
let simbox = SimBox::from([5.0, 5.0, 5.0]);
assert!(sphere.inside(&point, &simbox));
}
#[test]
fn inside_pbc() {
let sphere = Sphere::new([1.0, 2.0, 4.5].into(), 1.5);
let point = Vector3D::new(4.8, 2.1, 0.3);
let simbox = SimBox::from([5.0, 5.0, 5.0]);
assert!(sphere.inside(&point, &simbox));
}
#[test]
fn not_inside() {
let sphere = Sphere::new([1.0, 2.0, 4.5].into(), 1.5);
let point = Vector3D::new(4.0, 2.1, 0.3);
let simbox = SimBox::from([5.0, 5.0, 5.0]);
assert!(!sphere.inside(&point, &simbox));
}
#[test]
fn inside_random() {
let sphere_center = Vector3D::new(1.0, 2.0, 3.0);
let sphere_radius = 2.5;
let sphere = Sphere::new(sphere_center.clone(), sphere_radius);
let simbox = SimBox::from([5.0, 5.0, 5.0]);
let mut rng = rand::rng();
for _ in 0..100 {
let x = rng.random_range(0.0..5.0);
let y = rng.random_range(0.0..5.0);
let z = rng.random_range(0.0..5.0);
let point = Vector3D::new(x, y, z);
assert_eq!(
sphere.inside(&point, &simbox),
point.distance(&sphere_center, Dimension::XYZ, &simbox) < sphere_radius
);
}
}
#[test]
fn inside_naive() {
let sphere = Sphere::new([1.0, 2.0, 3.0].into(), 1.5);
let point = Vector3D::new(2.0, 2.5, 2.4);
assert!(sphere.inside_naive(&point));
}
#[test]
fn not_inside_naive() {
let sphere = Sphere::new([1.0, 2.0, 4.5].into(), 1.5);
let point = Vector3D::new(4.8, 2.1, 0.3);
assert!(!sphere.inside_naive(&point));
let sphere = Sphere::new([1.0, 2.0, 4.5].into(), 1.5);
let point = Vector3D::new(4.0, 2.1, 0.3);
assert!(!sphere.inside_naive(&point));
}
#[test]
fn inside_random_naive() {
let sphere_center = Vector3D::new(1.0, 2.0, 3.0);
let sphere_radius = 2.5;
let sphere = Sphere::new(sphere_center.clone(), sphere_radius);
let mut rng = rand::rng();
for _ in 0..100 {
let x = rng.random_range(0.0..5.0);
let y = rng.random_range(0.0..5.0);
let z = rng.random_range(0.0..5.0);
let point = Vector3D::new(x, y, z);
assert_eq!(
sphere.inside_naive(&point),
point.distance_naive(&sphere_center, Dimension::XYZ) < sphere_radius
);
}
}
}
#[cfg(test)]
mod tests_rectangular {
use super::*;
use float_cmp::assert_approx_eq;
#[test]
fn new() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 2.0, 1.8, 0.7);
assert_approx_eq!(f32, rect.get_position().x, 1.0);
assert_approx_eq!(f32, rect.get_position().y, 2.0);
assert_approx_eq!(f32, rect.get_position().z, 3.0);
assert_approx_eq!(f32, rect.get_x(), 2.0);
assert_approx_eq!(f32, rect.get_y(), 1.8);
assert_approx_eq!(f32, rect.get_z(), 0.7);
}
#[test]
fn inside_nopbc_1() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 3.0, 2.0, 1.0);
let point = Vector3D::new(3.1, 3.8, 3.9);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(rect.inside(&point, &simbox));
assert!(rect.inside_naive(&point));
}
#[test]
fn inside_nopbc_2() {
let rect = Rectangular::new([2.5, 3.1, 0.3].into(), 1.2, 1.3, 5.0);
let point = Vector3D::new(2.6, 4.3, 4.9);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(rect.inside(&point, &simbox));
assert!(rect.inside_naive(&point));
}
#[test]
fn not_inside_nopbc_1() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 3.0, 2.0, 1.0);
let point = Vector3D::new(4.1, 3.8, 3.9);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!rect.inside(&point, &simbox));
assert!(!rect.inside_naive(&point));
}
#[test]
fn not_inside_nopbc_2() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 3.0, 2.0, 1.0);
let point = Vector3D::new(2.1, 1.9, 3.9);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!rect.inside(&point, &simbox));
assert!(!rect.inside_naive(&point));
}
#[test]
fn not_inside_nopbc_3() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 3.0, 2.0, 1.0);
let point = Vector3D::new(2.1, 2.5, 4.1);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!rect.inside(&point, &simbox));
assert!(!rect.inside_naive(&point));
}
#[test]
fn inside_pbc_1() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 4.0, 2.0, 1.5);
let point = Vector3D::new(0.5, 3.8, 3.3);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(rect.inside(&point, &simbox));
assert!(!rect.inside_naive(&point));
}
#[test]
fn inside_pbc_2() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 1.0, 4.0, 1.5);
let point = Vector3D::new(1.3, 1.2, 3.5);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(rect.inside(&point, &simbox));
assert!(!rect.inside_naive(&point));
}
#[test]
fn inside_pbc_3() {
let rect = Rectangular::new([1.0, 2.0, 3.0].into(), 1.0, 2.0, 1.5);
let point = Vector3D::new(1.9, 2.2, 0.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(rect.inside(&point, &simbox));
assert!(!rect.inside_naive(&point));
}
}
#[cfg(test)]
mod tests_cylinder {
use super::*;
use float_cmp::assert_approx_eq;
#[test]
fn new() {
let cyl = Cylinder::new([1.0, 2.0, 3.0].into(), 0.8, 4.3, Dimension::Y);
assert_approx_eq!(f32, cyl.get_position().x, 1.0);
assert_approx_eq!(f32, cyl.get_position().y, 2.0);
assert_approx_eq!(f32, cyl.get_position().z, 3.0);
assert_eq!(cyl.get_orientation(), Dimension::Y);
assert_approx_eq!(f32, cyl.get_radius(), 0.8);
assert_approx_eq!(f32, cyl.get_height(), 4.3);
}
#[test]
fn inside_x_nopbc() {
let cylinder = Cylinder::new([2.0, 1.0, 3.0].into(), 2.0, 4.0, Dimension::X);
let point = Vector3D::new(4.2, 1.8, 2.2);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(cylinder.inside_naive(&point));
}
#[test]
fn not_inside_x_nopbc() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 2.0, 4.0, Dimension::X);
let point = Vector3D::new(2.9, 3.8, 2.2);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn not_inside_x_nopbc2() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 2.0, 4.0, Dimension::X);
let point = Vector3D::new(3.1, 4.6, 1.2);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_x_pbc_1() {
let cylinder = Cylinder::new([2.0, 1.0, 3.0].into(), 2.0, 3.0, Dimension::X);
let point = Vector3D::new(0.3, 1.4, 2.2);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_x_pbc_2() {
let cylinder = Cylinder::new([2.0, 1.0, 3.0].into(), 2.0, 3.0, Dimension::X);
let point = Vector3D::new(2.4, 3.8, 2.8);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_y_nopbc() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 4.0, 4.0, Dimension::Y);
let point = Vector3D::new(5.2, 3.8, 3.2);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(cylinder.inside_naive(&point));
}
#[test]
fn not_inside_y_nopbc() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 2.0, 4.0, Dimension::Y);
let point = Vector3D::new(4.2, 7.3, 2.2);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn not_inside_y_nopbc2() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 2.0, 4.0, Dimension::Y);
let point = Vector3D::new(1.1, 5.4, 3.7);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_y_pbc_1() {
let cylinder = Cylinder::new([1.0, 2.0, 3.0].into(), 2.0, 3.0, Dimension::Y);
let point = Vector3D::new(0.7, 0.8, 3.4);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_y_pbc_2() {
let cylinder = Cylinder::new([1.0, 2.0, 3.5].into(), 2.0, 3.0, Dimension::Y);
let point = Vector3D::new(3.5, 3.4, 0.0);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_z_nopbc() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 2.0, 2.0, Dimension::Z);
let point = Vector3D::new(4.0, 3.8, 4.8);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(cylinder.inside_naive(&point));
}
#[test]
fn not_inside_z_nopbc() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 2.0, 4.0, Dimension::Z);
let point = Vector3D::new(4.0, 3.8, 7.2);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn not_inside_z_nopbc2() {
let cylinder = Cylinder::new([3.0, 3.0, 3.0].into(), 2.0, 4.0, Dimension::Z);
let point = Vector3D::new(4.9, 3.7, 6.8);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_z_pbc_1() {
let cylinder = Cylinder::new([1.0, 2.0, 3.0].into(), 2.0, 3.0, Dimension::Z);
let point = Vector3D::new(1.4, 1.5, 1.5);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
#[test]
fn inside_z_pbc_2() {
let cylinder = Cylinder::new([3.0, 2.0, 3.0].into(), 2.0, 3.0, Dimension::Z);
let point = Vector3D::new(0.3, 1.5, 3.1);
let simbox = SimBox::from([4.0, 4.0, 4.0]);
assert!(cylinder.inside(&point, &simbox));
assert!(!cylinder.inside_naive(&point));
}
}
#[cfg(test)]
mod tests_triprism {
use super::*;
use float_cmp::assert_approx_eq;
#[test]
fn new_z() {
let base1 = Vector3D::new(3.0, 4.0, 2.0);
let base2 = Vector3D::new(7.0, 5.0, 2.0);
let base3 = Vector3D::new(4.0, 3.0, 2.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
assert_approx_eq!(f32, prism.get_base1().x, 3.0);
assert_approx_eq!(f32, prism.get_base1().y, 4.0);
assert_approx_eq!(f32, prism.get_base1().z, 2.0);
assert_approx_eq!(f32, prism.get_base2().x, 7.0);
assert_approx_eq!(f32, prism.get_base2().y, 5.0);
assert_approx_eq!(f32, prism.get_base2().z, 2.0);
assert_approx_eq!(f32, prism.get_base3().x, 4.0);
assert_approx_eq!(f32, prism.get_base3().y, 3.0);
assert_approx_eq!(f32, prism.get_base3().z, 2.0);
assert_approx_eq!(f32, prism.get_height(), 4.3);
assert_eq!(prism.get_orientation(), Dimension::Z);
assert_eq!(prism.get_plane(), Dimension::XY);
}
#[test]
fn new_y() {
let base1 = Vector3D::new(3.0, 3.0, 3.0);
let base2 = Vector3D::new(7.0, 3.0, 2.0);
let base3 = Vector3D::new(4.0, 3.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
assert_eq!(prism.get_orientation(), Dimension::Y);
assert_eq!(prism.get_plane(), Dimension::XZ);
}
#[test]
fn new_x() {
let base1 = Vector3D::new(5.0, 7.0, 3.0);
let base2 = Vector3D::new(5.0, 0.0, 2.0);
let base3 = Vector3D::new(5.0, 4.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
assert_eq!(prism.get_orientation(), Dimension::X);
assert_eq!(prism.get_plane(), Dimension::YZ);
}
#[test]
#[should_panic(
expected = "FATAL GROAN ERROR | TriangularPrism::new | Base of the requested TriangularPrism does not lie in xy, xz, nor yz plane."
)]
fn invalid_base_orientation() {
let base1 = Vector3D::new(3.0, 4.0, 2.0);
let base2 = Vector3D::new(7.0, 5.0, 1.8);
let base3 = Vector3D::new(4.0, 3.0, 2.0);
let _ = TriangularPrism::new(base1, base2, base3, 4.3);
}
#[test]
#[should_panic(
expected = "FATAL GROAN ERROR | TriangularPrism::new | Base of the requested TriangularPrism can not be constructed."
)]
fn invalid_base() {
let base1 = Vector3D::new(3.0, 4.0, 2.0);
let base2 = Vector3D::new(7.0, 4.0, 2.0);
let base3 = Vector3D::new(4.0, 4.0, 2.0);
let _ = TriangularPrism::new(base1, base2, base3, 4.3);
}
#[test]
fn inside_x_nopbc() {
let base1 = Vector3D::new(5.0, 7.0, 3.0);
let base2 = Vector3D::new(5.0, 0.0, 2.0);
let base3 = Vector3D::new(5.0, 4.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(9.1, 4.8, 3.6);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(prism.inside(&point, &simbox));
}
#[test]
fn not_inside_x_nopbc() {
let base1 = Vector3D::new(5.0, 7.0, 3.0);
let base2 = Vector3D::new(5.0, 0.0, 2.0);
let base3 = Vector3D::new(5.0, 4.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(9.7, 4.8, 3.6);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!prism.inside(&point, &simbox));
}
#[test]
fn inside_x_pbc() {
let base1 = Vector3D::new(5.0, 7.0, 3.0);
let base2 = Vector3D::new(5.0, 0.0, 2.0);
let base3 = Vector3D::new(5.0, 4.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(0.3, 4.8, 3.6);
let simbox = SimBox::from([8.0, 8.0, 8.0]);
assert!(prism.inside(&point, &simbox));
}
#[test]
fn inside_y_nopbc() {
let base1 = Vector3D::new(3.0, 3.0, 3.0);
let base2 = Vector3D::new(7.0, 3.0, 2.0);
let base3 = Vector3D::new(4.0, 3.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(4.8, 5.6, 3.6);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(prism.inside(&point, &simbox));
}
#[test]
fn not_inside_y_nopbc() {
let base1 = Vector3D::new(3.0, 3.0, 3.0);
let base2 = Vector3D::new(7.0, 3.0, 2.0);
let base3 = Vector3D::new(4.0, 3.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(5.5, 5.6, 3.6);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!prism.inside(&point, &simbox));
}
#[test]
fn inside_y_pbc() {
let base1 = Vector3D::new(3.0, 3.0, 3.0);
let base2 = Vector3D::new(7.0, 3.0, 2.0);
let base3 = Vector3D::new(4.0, 3.0, 5.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(4.8, 2.1, 3.6);
let simbox = SimBox::from([10.0, 5.0, 10.0]);
assert!(prism.inside(&point, &simbox));
}
#[test]
fn inside_z_nopbc() {
let base1 = Vector3D::new(3.0, 4.0, 2.0);
let base2 = Vector3D::new(7.0, 5.0, 2.0);
let base3 = Vector3D::new(4.0, 3.0, 2.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(4.8, 3.6, 2.1);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(prism.inside(&point, &simbox));
}
#[test]
fn not_inside_z_nopbc() {
let base1 = Vector3D::new(3.0, 4.0, 2.0);
let base2 = Vector3D::new(7.0, 5.0, 2.0);
let base3 = Vector3D::new(4.0, 3.0, 2.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(4.8, 3.4, 2.1);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(!prism.inside(&point, &simbox));
}
#[test]
fn inside_z_pbc() {
let base1 = Vector3D::new(3.0, 4.0, 8.0);
let base2 = Vector3D::new(7.0, 5.0, 8.0);
let base3 = Vector3D::new(4.0, 3.0, 8.0);
let prism = TriangularPrism::new(base1, base2, base3, 4.3);
let point = Vector3D::new(4.8, 3.6, 2.1);
let simbox = SimBox::from([10.0, 10.0, 10.0]);
assert!(prism.inside(&point, &simbox));
}
}