use nalgebra::{Matrix3, Point3, UnitQuaternion, Vector3};
use crate::{
base::{Float, coordinate::compute_in_local},
crate_utils::{impl_parallel, impl_parallel_sum},
fields::field_triangle::local_triangle_B,
};
#[inline]
#[allow(non_snake_case)]
pub fn local_tetrahedron_B<T: Float>(
point: Point3<T>,
polarization: Vector3<T>,
mut vertices: [Vector3<T>; 4],
) -> Vector3<T> {
let v01 = vertices[1] - vertices[0];
let v02 = vertices[2] - vertices[0];
let v03 = vertices[3] - vertices[0];
let det = Matrix3::from_columns(&[v01, v02, v03]).determinant();
if det < T::zero() {
vertices.swap(2, 3);
}
let b1 = local_triangle_B(point, polarization, [vertices[0], vertices[2], vertices[1]]);
let b2 = local_triangle_B(point, polarization, [vertices[0], vertices[1], vertices[3]]);
let b3 = local_triangle_B(point, polarization, [vertices[1], vertices[2], vertices[3]]);
let b4 = local_triangle_B(point, polarization, [vertices[0], vertices[3], vertices[2]]);
let mut b_total = b1 + b2 + b3 + b4;
if let Some(mat_inv) = Matrix3::from_columns(&[
vertices[1] - vertices[0],
vertices[2] - vertices[0],
vertices[3] - vertices[0],
])
.try_inverse()
{
let p_rel = point.coords - vertices[0];
let new_p = mat_inv * p_rel;
if new_p.x >= T::zero()
&& new_p.y >= T::zero()
&& new_p.z >= T::zero()
&& new_p.x <= T::one()
&& new_p.y <= T::one()
&& new_p.z <= T::one()
&& new_p.sum() <= T::one()
{
b_total += polarization;
}
}
b_total
}
#[inline]
#[allow(non_snake_case)]
pub fn tetrahedron_B<T: Float>(
point: Point3<T>,
position: Point3<T>,
orientation: UnitQuaternion<T>,
polarization: Vector3<T>,
vertices: [Vector3<T>; 4],
) -> Vector3<T> {
compute_in_local!(
local_tetrahedron_B,
point,
position,
orientation,
(polarization, vertices),
)
}
#[allow(non_snake_case)]
pub fn tetrahedron_B_batch<T: Float>(
points: &[Point3<T>],
position: Point3<T>,
orientation: UnitQuaternion<T>,
polarization: Vector3<T>,
vertices: [Vector3<T>; 4],
out: &mut [Vector3<T>],
) {
impl_parallel!(
tetrahedron_B,
rayon_threshold: 1550, input: points,
output: out,
args: [position, orientation, polarization, vertices]
)
}
#[allow(non_snake_case)]
pub fn sum_multiple_tetrahedron_B<T: Float>(
points: &[Point3<T>],
positions: &[Point3<T>],
orientations: &[UnitQuaternion<T>],
polarizations: &[Vector3<T>],
vertices_list: &[[Vector3<T>; 4]],
out: &mut [Vector3<T>],
) {
impl_parallel_sum!(
out,
points,
15, [positions, orientations, polarizations, vertices_list],
|pos, p, o, pol, vert| tetrahedron_B(*pos, *p, *o, *pol, *vert)
)
}
#[cfg(test)]
mod tests {
use nalgebra::{point, vector};
use super::*;
#[test]
fn test_sum_multiple_tetrahedron_b() {
use crate::testing_util::impl_test_sum_multiple;
let points = &[
point![5.0, 6.0, 7.0],
point![4.0, 3.0, 2.0],
point![0.5, 0.25, 0.125],
];
let positions = &[point![1.0, 2.0, 3.0], point![0.0, 0.0, 0.0]];
let orientations = &[
UnitQuaternion::from_scaled_axis(vector![1.0, 0.6, 0.4]),
UnitQuaternion::identity(),
];
let polarizations = &[vector![0.45, 0.3, 0.15], vector![1.0, 2.0, 3.0]];
let vertices_list = &[
[
vector![0.0, 0.0, 0.0],
vector![0.0, 0.0, 1.0],
vector![1.0, 0.0, 0.0],
vector![0.0, 1.0, 0.0],
],
[
vector![-1.0, -1.0, -1.0],
vector![1.0, -1.0, -1.0],
vector![0.0, 1.0, -1.0],
vector![0.0, 0.0, 1.0],
],
];
impl_test_sum_multiple!(
sum_multiple_tetrahedron_B,
1e-15,
points,
positions,
orientations,
(polarizations, vertices_list),
|p, pos, ori, pol, vert| tetrahedron_B(p, pos, ori, pol, vert)
);
}
}