#[cfg(test)]
mod tests;
use crate::real::Real;
use crate::{Error, Result};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SweptFaces<R> {
lo: [R; 4],
hi: [R; 4],
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Interior {
Joined,
Separated,
}
impl<R: Real> SweptFaces<R> {
pub fn new(lo: [R; 4], hi: [R; 4]) -> Result<Self> {
let faces = Self { lo, hi };
if faces.denominator(R::ZERO) == R::ZERO || faces.denominator(R::ONE) == R::ZERO {
return Err(Error::DegenerateSweep);
}
Ok(faces)
}
#[must_use]
pub fn denominator(&self, t: R) -> R {
let at = |v: &[R; 4]| v[0] + v[2] - v[1] - v[3];
at(&self.lo) + (at(&self.hi) - at(&self.lo)) * t
}
#[must_use]
pub fn numerator(&self, t: R) -> R {
let s = R::ONE - t;
let v = |k: usize| self.lo[k] * s + self.hi[k] * t;
v(0) * v(2) - v(1) * v(3)
}
#[must_use]
pub fn saddle(&self, t: R) -> R {
self.numerator(t) / self.denominator(t)
}
#[must_use]
pub fn saddle_position(&self, t: R) -> [R; 2] {
let s = R::ONE - t;
let v = |k: usize| self.lo[k] * s + self.hi[k] * t;
let d = self.denominator(t);
[(v(0) - v(3)) / d, (v(0) - v(1)) / d]
}
#[must_use]
pub fn pole(&self) -> Option<R> {
let (d0, d1) = (self.denominator(R::ZERO), self.denominator(R::ONE));
if (d0 < R::ZERO) == (d1 < R::ZERO) {
return None;
}
let t = d0 / (d0 - d1);
if t > R::ZERO && t < R::ONE {
Some(t)
} else {
None
}
}
#[must_use]
pub fn test(&self) -> Interior {
let mut breaks = [R::ZERO; 3];
let mut count = 0;
for t in self.numerator_roots().chain(self.pole()) {
if t > R::ZERO && t < R::ONE {
breaks[count] = t;
count += 1;
}
}
let breaks = &mut breaks[..count];
for i in 1..breaks.len() {
let mut j = i;
while j > 0 && breaks[j - 1] > breaks[j] {
breaks.swap(j - 1, j);
j -= 1;
}
}
let half = R::ONE / (R::ONE + R::ONE);
if self.saddle(R::ZERO) > R::ZERO || self.saddle(R::ONE) > R::ZERO {
return Interior::Joined;
}
let mut previous = R::ZERO;
for k in 0..=breaks.len() {
let next = breaks.get(k).copied().unwrap_or(R::ONE);
let mid = (previous + next) * half;
if mid > previous && mid < next && self.saddle(mid) > R::ZERO {
return Interior::Joined;
}
previous = next;
}
Interior::Separated
}
fn numerator_roots(&self) -> impl Iterator<Item = R> {
let d = |k: usize| self.hi[k] - self.lo[k];
let a = d(0) * d(2) - d(1) * d(3);
let b = self.lo[2] * d(0) + self.lo[0] * d(2) - self.lo[3] * d(1) - self.lo[1] * d(3);
let c = self.lo[0] * self.lo[2] - self.lo[1] * self.lo[3];
let mut roots = [R::ZERO; 2];
let mut count = 0;
if a == R::ZERO {
if b != R::ZERO {
roots[0] = -c / b;
count = 1;
}
} else {
let two = R::ONE + R::ONE;
let disc = b * b - two * two * a * c;
if disc >= R::ZERO {
let root = disc.sqrt();
roots[0] = (-b - root) / (two * a);
roots[1] = (-b + root) / (two * a);
count = 2;
}
}
roots.into_iter().take(count)
}
}
#[cfg(test)]
pub(super) fn chernyaev_numerator_test<R: Real>(faces: &SweptFaces<R>) -> Interior {
let d = |k: usize| faces.hi[k] - faces.lo[k];
let a = d(0) * d(2) - d(1) * d(3);
let b = faces.lo[2] * d(0) + faces.lo[0] * d(2) - faces.lo[3] * d(1) - faces.lo[1] * d(3);
let two = R::ONE + R::ONE;
let mut positive = faces.numerator(R::ZERO) > R::ZERO || faces.numerator(R::ONE) > R::ZERO;
if a < R::ZERO {
let vertex = -b / (two * a);
if vertex > R::ZERO && vertex < R::ONE {
positive = positive || faces.numerator(vertex) > R::ZERO;
}
}
if positive {
Interior::Joined
} else {
Interior::Separated
}
}