use super::*;
#[cfg(feature = "double-precision")]
type PosScalar = f64;
#[cfg(not(feature = "double-precision"))]
type PosScalar = f32;
pub fn mul_transforms(a: Transform, b: Transform) -> Transform {
Transform {
p: add(rotate_vector(a.q, b.p), a.p),
q: mul_quat(a.q, b.q),
}
}
pub fn inv_mul_transforms(a: Transform, b: Transform) -> Transform {
Transform {
p: inv_rotate_vector(a.q, sub(b.p, a.p)),
q: inv_mul_quat(a.q, b.q),
}
}
pub fn invert_transform(t: Transform) -> Transform {
Transform {
p: inv_rotate_vector(t.q, neg(t.p)),
q: conjugate(t.q),
}
}
pub fn transform_point(t: Transform, v: Vec3) -> Vec3 {
let rv = rotate_vector(t.q, v);
add(rv, t.p)
}
pub fn inv_transform_point(t: Transform, v: Vec3) -> Vec3 {
inv_rotate_vector(t.q, sub(v, t.p))
}
pub fn to_pos(v: Vec3) -> Pos {
Pos {
x: v.x as PosScalar,
y: v.y as PosScalar,
z: v.z as PosScalar,
}
}
pub fn to_vec3(p: Pos) -> Vec3 {
Vec3 {
x: p.x as f32,
y: p.y as f32,
z: p.z as f32,
}
}
#[cfg(feature = "double-precision")]
pub fn round_down_float(x: f64) -> f32 {
let f = x as f32;
if f as f64 > x {
next_after_f32(f, f32::MIN)
} else {
f
}
}
#[cfg(feature = "double-precision")]
pub fn round_up_float(x: f64) -> f32 {
let f = x as f32;
if (f as f64) < x {
next_after_f32(f, f32::MAX)
} else {
f
}
}
#[cfg(not(feature = "double-precision"))]
pub fn round_down_float(x: f64) -> f32 {
x as f32
}
#[cfg(not(feature = "double-precision"))]
pub fn round_up_float(x: f64) -> f32 {
x as f32
}
#[cfg(feature = "double-precision")]
fn next_after_f32(from: f32, to: f32) -> f32 {
if from.is_nan() || to.is_nan() {
return f32::NAN;
}
if from == to {
return to;
}
if from == 0.0 {
return if to > 0.0 {
f32::from_bits(1)
} else {
-f32::from_bits(1)
};
}
let bits = from.to_bits();
let next = if (from < to) == (from > 0.0) {
bits + 1
} else {
bits - 1
};
f32::from_bits(next)
}
pub fn sub_pos(a: Pos, b: Pos) -> Vec3 {
Vec3 {
x: (a.x - b.x) as f32,
y: (a.y - b.y) as f32,
z: (a.z - b.z) as f32,
}
}
pub fn offset_pos(p: Pos, d: Vec3) -> Pos {
Pos {
x: p.x + d.x as PosScalar,
y: p.y + d.y as PosScalar,
z: p.z + d.z as PosScalar,
}
}
pub fn lerp_position(a: Pos, b: Pos, t: f32) -> Pos {
Pos {
x: (1.0 - t) as PosScalar * a.x + t as PosScalar * b.x,
y: (1.0 - t) as PosScalar * a.y + t as PosScalar * b.y,
z: (1.0 - t) as PosScalar * a.z + t as PosScalar * b.z,
}
}
pub fn transform_world_point(t: WorldTransform, p: Vec3) -> Pos {
let r = rotate_vector(t.q, p);
Pos {
x: t.p.x + r.x as PosScalar,
y: t.p.y + r.y as PosScalar,
z: t.p.z + r.z as PosScalar,
}
}
pub fn inv_transform_world_point(t: WorldTransform, p: Pos) -> Vec3 {
let d = Vec3 {
x: (p.x - t.p.x) as f32,
y: (p.y - t.p.y) as f32,
z: (p.z - t.p.z) as f32,
};
inv_rotate_vector(t.q, d)
}
pub fn inv_mul_world_transforms(a: WorldTransform, b: WorldTransform) -> Transform {
let d = Vec3 {
x: (b.p.x - a.p.x) as f32,
y: (b.p.y - a.p.y) as f32,
z: (b.p.z - a.p.z) as f32,
};
Transform {
q: inv_mul_quat(a.q, b.q),
p: inv_rotate_vector(a.q, d),
}
}
pub fn mul_world_transforms(a: WorldTransform, b: Transform) -> WorldTransform {
let r = rotate_vector(a.q, b.p);
WorldTransform {
q: mul_quat(a.q, b.q),
p: Pos {
x: a.p.x + r.x as PosScalar,
y: a.p.y + r.y as PosScalar,
z: a.p.z + r.z as PosScalar,
},
}
}
pub fn to_relative_transform(t: WorldTransform, base: Pos) -> Transform {
Transform {
q: t.q,
p: Vec3 {
x: (t.p.x - base.x) as f32,
y: (t.p.y - base.y) as f32,
z: (t.p.z - base.z) as f32,
},
}
}
pub fn make_world_transform(t: Transform) -> WorldTransform {
WorldTransform {
p: to_pos(t.p),
q: t.q,
}
}
pub fn offset_aabb(local_box: Aabb, origin: Pos) -> Aabb {
Aabb {
lower_bound: Vec3 {
x: round_down_float(origin.x as f64 + local_box.lower_bound.x as f64),
y: round_down_float(origin.y as f64 + local_box.lower_bound.y as f64),
z: round_down_float(origin.z as f64 + local_box.lower_bound.z as f64),
},
upper_bound: Vec3 {
x: round_up_float(origin.x as f64 + local_box.upper_bound.x as f64),
y: round_up_float(origin.y as f64 + local_box.upper_bound.y as f64),
z: round_up_float(origin.z as f64 + local_box.upper_bound.z as f64),
},
}
}