use cgmath;
use super::float;
use std::ops;
pub type Float = f32;
pub type FSize = u32;
pub type Point2f = cgmath::Point2<Float>;
pub type Point3f = cgmath::Point3<Float>;
pub type Vector2f = cgmath::Vector2<Float>;
pub type Vector3f = cgmath::Vector3<Float>;
pub type Vector4f = cgmath::Vector4<Float>;
pub type Matrix2f = cgmath::Matrix2<Float>;
pub type Matrix3f = cgmath::Matrix3<Float>;
pub type Matrix4f = cgmath::Matrix4<Float>;
pub type Basis3f = cgmath::Basis3<Float>;
pub use cgmath::{Point2, Point3, Vector2, Vector3, Vector4, Basis3, BaseNum, BaseFloat, Matrix4, PartialOrd, Deg, Rad, ApproxEq};
pub use cgmath::prelude::*;
#[derive(Debug, Copy, Clone)]
pub struct EFloat {
pub value: Float,
pub err: Float,
}
impl EFloat {
#[inline]
pub fn lower_bound(self) -> Float {
float::next_down(self.value - self.err)
}
#[inline]
pub fn upper_bound(self) -> Float {
float::next_up(self.value + self.err)
}
}
impl From<Float> for EFloat {
#[inline]
fn from(f: Float) -> EFloat {
EFloat{
value: f, err: 0. as Float,
}
}
}
impl From<EFloat> for Float {
#[inline]
fn from(f: EFloat) -> Float {
f.value
}
}
impl ops::Add for EFloat {
type Output = EFloat;
#[inline]
fn add(self, rhs: EFloat) -> EFloat {
let value = self.value + rhs.value;
let errsum = self.err + rhs.err;
EFloat{
value,
err: (value.abs() + errsum) * float::eb_term(1. as Float) + errsum
}
}
}
impl ops::Sub for EFloat {
type Output = EFloat;
#[inline]
fn sub(self, rhs: EFloat) -> EFloat {
let value = self.value - rhs.value;
let errsum = (self.err - rhs.err).abs();
EFloat{
value,
err: (value.abs() + errsum) * float::eb_term(1. as Float) + errsum
}
}
}
impl ops::Mul for EFloat {
type Output = EFloat;
#[inline]
fn mul(self, rhs: EFloat) -> EFloat {
let value = self.value * rhs.value;
let errsum = (self.err*rhs.value + rhs.err*self.value + self.err*rhs.err).abs();
EFloat{
value,
err: (value.abs() + errsum) * float::eb_term(1. as Float) + errsum
}
}
}
impl ops::Div for EFloat {
type Output = EFloat;
#[inline]
fn div(self, rhs: EFloat) -> EFloat {
let value = self.value / rhs.value;
let errsum = self.err / rhs.value.abs();
EFloat{
value,
err: (value.abs() + errsum) * float::eb_term(1. as Float) + errsum
}
}
}
#[derive(Copy, Clone, PartialEq)]
pub struct Sphericalf {
pub theta: Float,
pub phi: Float,
}
impl Sphericalf {
#[inline]
pub fn new(theta: Float, phi: Float) -> Sphericalf {
Sphericalf{
theta: theta, phi: phi
}
}
#[inline]
pub fn from<T, P>(theta: T, phi: P) -> Sphericalf
where T: Into<Rad<Float>>,
P: Into<Rad<Float>>,
{
Sphericalf{
theta: theta.into().0, phi: phi.into().0
}
}
#[inline]
pub fn from_vec(v: Vector3f) -> Sphericalf {
Sphericalf::new(
Sphericalf::theta_from_vec(v),
Sphericalf::phi_from_vec(v)
)
}
#[inline]
pub fn to_vec(&self) -> Vector3f {
let sintheta = self.theta.sin();
let costheta = self.theta.cos();
let sinphi = self.phi.sin();
let cosphi = self.phi.cos();
Vector3f::new(
sintheta * cosphi,
sintheta * sinphi,
costheta
)
}
#[inline]
pub fn to_vec_in(&self, basis: &Basis3f) -> Vector3f {
let vlocal = self.to_vec();
basis.as_ref() * vlocal
}
#[inline]
pub fn theta_from_vec(v: Vector3f) -> Float {
#[cfg(debug)]
{
assert_ulps_eq!(v.normalize(), 1.0 as Float);
}
let z = float::clamp(v.z, -1.0 as Float, 1.0 as Float);
z.acos()
}
#[inline]
pub fn phi_from_vec(v: Vector3f) -> Float {
#[cfg(debug)]
{
assert_ulps_eq!(v.normalize(), 1.0 as Float);
}
let ret = v.y.atan2(v.x);
if ret < 0.0 as Float {
ret + float::pi() * 2.0 as Float
} else {
ret
}
}
}
pub mod normal {
use super::*;
#[inline]
pub fn cos_theta(norm: Vector3f) -> Float {
norm.z
}
#[inline]
pub fn cos2_theta(norm: Vector3f) -> Float {
norm.z * norm.z
}
#[inline]
pub fn sin2_theta(norm: Vector3f) -> Float {
((1.0 as Float) - cos2_theta(norm)).abs()
}
#[inline]
pub fn sin_theta(norm: Vector3f) -> Float {
sin2_theta(norm).sqrt()
}
#[inline]
pub fn tan_theta(norm: Vector3f) -> Float {
sin_theta(norm)/cos_theta(norm)
}
#[inline]
pub fn tan2_theta(norm: Vector3f) -> Float {
sin2_theta(norm)/cos2_theta(norm)
}
#[inline]
pub fn cos_phi(norm: Vector3f) -> Float {
let sin_theta = sin_theta(norm);
if sin_theta == 0.0 as Float {
1.0 as Float
} else {
float::clamp(norm.x / sin_theta, -1.0 as Float, 1.0 as Float)
}
}
pub fn sin_phi(norm: Vector3f) -> Float {
let sin_theta = sin_theta(norm);
if sin_theta == 0.0 as Float {
0.0 as Float
} else {
float::clamp(norm.y / sin_theta, -1.0 as Float, 1.0 as Float)
}
}
#[inline]
pub fn cos2_phi(norm: Vector3f) -> Float {
cos_phi(norm).powi(2)
}
#[inline]
pub fn sin2_phi(norm: Vector3f) -> Float {
sin_phi(norm).powi(2)
}
#[inline]
pub fn cos_dphi(n0: Vector3f, n1: Vector3f) -> Float {
float::clamp(
(n0.x * n1.x + n0.y * n1.y) / (
(n0.x * n0.x + n0.y * n0.y) * (n1.x * n1.x + n1.y * n1.y)
).sqrt(),
-1.0 as Float,
1.0 as Float
)
}
#[inline]
pub fn reflect(wo: Vector3f, n: Vector3f) -> Vector3f {
-wo + 2.0 as Float * wo.dot(n) * n
}
#[inline]
pub fn refract(wo: Vector3f, n: Vector3f, eta: Float) -> Option<Vector3f> {
let cos_theta = wo.dot(n);
debug_assert!(cos_theta > 0. as Float);
let sin2_theta = 1. as Float - cos_theta * cos_theta;
let sin2_thetat = eta * eta * sin2_theta.max(0. as Float);
if sin2_thetat >= 1. as Float {
None
} else {
let cos_thetat = (1. as Float - sin2_thetat).sqrt();
Some(
-eta * wo + (eta*cos_theta - cos_thetat)*n
)
}
}
#[inline]
pub fn get_basis_from(dir: Vector3f) -> (Vector3f, Vector3f) {
let mut up = Vector3f::new(0. as Float, 0. as Float, 1. as Float);
if relative_eq!(up, dir) {
up = Vector3f::new(0. as Float, 1. as Float, 0. as Float);
};
let u = up.cross(dir).normalize();
let v = dir.cross(u).normalize();
(u, v)
}
}