Files
fdtd-coremem/src/geom/vec.rs
Colin d8ae766099 Add a bunch of .round()s before conversions
Previously this was leading to inconsistencies when using f32 v.s. f64
2020-12-17 15:09:53 -08:00

348 lines
7.2 KiB
Rust

use crate::flt::{Flt, Real};
use super::Vec3u;
use serde::{Serialize, Deserialize};
use std::convert::From;
use std::iter::Sum;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub};
fn round(f: Real) -> Real {
Real::from_inner(f.into_inner().round())
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct Vec2 {
pub x: Real,
pub y: Real,
}
impl Add for Vec2 {
type Output = Vec2;
fn add(self, other: Vec2) -> Vec2 {
let mut ret = self.clone();
ret += other;
ret
}
}
impl AddAssign for Vec2 {
fn add_assign(&mut self, other: Vec2) {
self.x += other.x;
self.y += other.y;
}
}
impl Neg for Vec2 {
type Output = Vec2;
fn neg(self) -> Vec2 {
Vec2 {
x: -self.x,
y: -self.y,
}
}
}
impl Sub for Vec2 {
type Output = Vec2;
fn sub(self, other: Vec2) -> Vec2 {
self + (-other)
}
}
impl Mul<Flt> for Vec2 {
type Output = Vec2;
fn mul(self, s: Flt) -> Vec2 {
Vec2 {
x: self.x * s,
y: self.y * s,
}
}
}
impl Into<(Flt, Flt)> for Vec2 {
fn into(self) -> (Flt, Flt) {
(self.x(), self.y())
}
}
impl Into<(Real, Real)> for Vec2 {
fn into(self) -> (Real, Real) {
(self.x, self.y)
}
}
impl Vec2 {
pub fn new(x: Flt, y: Flt) -> Self {
Self {
x: x.into(),
y: y.into(),
}
}
pub fn x(&self) -> Flt {
self.x.into()
}
pub fn y(&self) -> Flt {
self.y.into()
}
pub fn round(&self) -> Vec2 {
Vec2 {
x: round(self.x),
y: round(self.y),
}
}
pub fn distance_sq(&self, other: Self) -> Flt {
(*self - other).mag_sq()
}
pub fn mag_sq(&self) -> Flt {
(self.x*self.x + self.y*self.y).into()
}
pub fn mag(&self) -> Flt {
self.mag_sq().sqrt()
}
pub fn with_mag(&self, new_mag: Flt) -> Vec2 {
if new_mag == 0.0 {
// avoid div-by-zero if self.mag() == 0 and new_mag == 0
Vec2::new(0.0, 0.0)
} else {
let scale = Real::from_inner(new_mag) / self.mag();
self.clone() * scale.into_inner()
}
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Vec3 {
pub(crate) x: Real,
pub(crate) y: Real,
pub(crate) z: Real,
}
impl Vec3 {
pub fn new(x: Flt, y: Flt, z: Flt) -> Self {
Self {
x: x.into(),
y: y.into(),
z: z.into()
}
}
pub fn unit() -> Self {
Self::new(1.0, 1.0, 1.0)
}
pub fn zero() -> Self {
Self::new(0.0, 0.0, 0.0)
}
pub fn x(&self) -> Flt {
self.x.into()
}
pub fn y(&self) -> Flt {
self.y.into()
}
pub fn z(&self) -> Flt {
self.z.into()
}
pub fn xy(&self) -> Vec2 {
Vec2::new(self.x(), self.y())
}
pub fn mag(&self) -> Flt {
let Vec3 { x, y, z } = *self;
(x*x + y*y + z*z).into_inner().sqrt()
}
pub fn component_sum(&self) -> Flt {
(self.x + self.y + self.z).into()
}
pub fn dot(&self, other: Self) -> Flt {
self.elem_mul(other).component_sum()
}
pub fn cross(&self, other: Self) -> Self {
// det( i j k |
// | s.x s.y s.z |
// | o.x o.y o.z )
let x = self.y * other.z - other.y * self.z;
let y = other.z * self.z - self.x * other.z;
let z = self.x * other.y - other.x * self.y;
Self { x, y, z }
}
/// Perform element-wise multiplication with `other`.
pub fn elem_mul(&self, other: Self) -> Self {
Self {
x: self.x * other.x,
y: self.y * other.y,
z: self.z * other.z,
}
}
/// Perform element-wise division with `other`.
pub fn elem_div(&self, other: Self) -> Self {
Self {
x: self.x / other.x,
y: self.y / other.y,
z: self.z / other.z,
}
}
pub fn with_mag(&self, new_mag: Flt) -> Vec3 {
if new_mag == 0.0 {
// avoid div-by-zero if self.mag() == 0 and new_mag == 0
Self::zero()
} else {
let scale = Real::from_inner(new_mag) / self.mag();
self.clone() * scale.into_inner()
}
}
/// Normalizes to 1.0 length, unless it's the zero vector, in which case length remains zero.
pub fn norm(&self) -> Vec3 {
if *self == Self::zero() {
*self
} else {
self.with_mag(1.0)
}
}
pub fn round(&self) -> Vec3 {
Self::new(self.x().round(), self.y().round(), self.z().round())
}
}
impl Into<(Flt, Flt, Flt)> for Vec3 {
fn into(self) -> (Flt, Flt, Flt) {
(self.x(), self.y(), self.z())
}
}
impl From<(Flt, Flt, Flt)> for Vec3 {
fn from((x, y, z): (Flt, Flt, Flt)) -> Self {
Self::new(x, y, z)
}
}
impl From<(Real, Real, Real)> for Vec3 {
fn from((x, y, z): (Real, Real, Real)) -> Self {
Self { x, y, z }
}
}
impl From<Vec3u> for Vec3 {
fn from(v: Vec3u) -> Self {
Self::new(v.x() as _, v.y() as _, v.z() as _)
}
}
impl AddAssign for Vec3 {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
self.y += other.y;
self.z += other.z;
}
}
impl Add for Vec3 {
type Output = Self;
fn add(self, other: Self) -> Self {
let mut work = self.clone();
work += other;
work
}
}
impl Sub for Vec3 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z,
}
}
}
impl Neg for Vec3 {
type Output = Self;
fn neg(self) -> Self {
Self {
x: -self.x,
y: -self.y,
z: -self.z,
}
}
}
impl MulAssign<Real> for Vec3 {
fn mul_assign(&mut self, other: Real) {
self.x *= other;
self.y *= other;
self.z *= other;
}
}
impl Mul<Real> for Vec3 {
type Output = Self;
fn mul(self, other: Real) -> Self {
let mut work = self.clone();
work *= other;
work
}
}
impl MulAssign<Flt> for Vec3 {
fn mul_assign(&mut self, other: Flt) {
self.x *= other;
self.y *= other;
self.z *= other;
}
}
impl Mul<Flt> for Vec3 {
type Output = Self;
fn mul(self, other: Flt) -> Self {
let mut work = self.clone();
work *= other;
work
}
}
impl DivAssign<Real> for Vec3 {
fn div_assign(&mut self, other: Real) {
*self *= Real::from_inner(1.0) / other;
}
}
impl Div<Real> for Vec3 {
type Output = Self;
fn div(self, other: Real) -> Self {
let mut work = self.clone();
work /= other;
work
}
}
impl DivAssign<Flt> for Vec3 {
fn div_assign(&mut self, other: Flt) {
*self *= 1.0 / other;
}
}
impl Div<Flt> for Vec3 {
type Output = Self;
fn div(self, other: Flt) -> Self {
let mut work = self.clone();
work /= other;
work
}
}
impl Sum for Vec3 {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::default(), |a, b| a + b)
}
}