use super::*;
pub fn arbitrary_perp(v: Vec3) -> Vec3 {
let p = if v.x < -0.5 || 0.5 < v.x {
let a = 0.67;
let b = -0.42;
Vec3 {
x: a * v.y + b * v.z,
y: -a * v.x,
z: -b * v.x,
}
} else if v.y < -0.5 || 0.5 < v.y {
let a = 0.67;
let c = -0.42;
Vec3 {
x: a * v.y,
y: -a * v.x + c * v.z,
z: -c * v.y,
}
} else {
debug_assert!(v.z < -0.5 || 0.5 < v.z);
let a = 0.67;
let b = -0.42;
Vec3 {
x: a * v.z,
y: b * v.z,
z: -a * v.x - b * v.y,
}
};
debug_assert!(length_squared(p) > 0.1);
debug_assert!(abs_float(dot(p, v)) < 100.0 * f32::EPSILON);
normalize(p)
}
pub fn scalar_triple_product(a: Vec3, b: Vec3, c: Vec3) -> f32 {
let d = Vec3 {
x: b.y * c.z - b.z * c.y,
y: b.z * c.x - b.x * c.z,
z: b.x * c.y - b.y * c.x,
};
a.x * d.x + a.y * d.y + a.z * d.z
}
pub const SQRT3: f32 = 1.732050808;
pub const BOUNDS3_EMPTY: Aabb = Aabb {
lower_bound: Vec3 {
x: f32::MAX,
y: f32::MAX,
z: f32::MAX,
},
upper_bound: Vec3 {
x: -f32::MAX,
y: -f32::MAX,
z: -f32::MAX,
},
};
pub fn align_up8(x: usize) -> usize {
(x + 7) & !7
}
pub fn modified_cross(a: Vec3, b: Vec3) -> Vec3 {
Vec3 {
x: a.y * b.z + a.z * b.y,
y: a.z * b.x + a.x * b.z,
z: a.x * b.y + a.y * b.x,
}
}
pub fn dot2(v1: Vec2, v2: Vec2) -> f32 {
v1.x * v2.x + v1.y * v2.y
}
pub fn length2(v: Vec2) -> f32 {
dot2(v, v).sqrt()
}
pub fn length_squared2(v: Vec2) -> f32 {
dot2(v, v)
}
pub fn add2(a: Vec2, b: Vec2) -> Vec2 {
Vec2 {
x: a.x + b.x,
y: a.y + b.y,
}
}
pub fn sub2(a: Vec2, b: Vec2) -> Vec2 {
Vec2 {
x: a.x - b.x,
y: a.y - b.y,
}
}
pub fn mul_sv2(s: f32, v: Vec2) -> Vec2 {
Vec2 {
x: s * v.x,
y: s * v.y,
}
}
pub fn cross2(a: Vec2, b: Vec2) -> f32 {
a.x * b.y - a.y * b.x
}
pub fn distance_squared2(a: Vec2, b: Vec2) -> f32 {
let dx = b.x - a.x;
let dy = b.y - a.y;
dx * dx + dy * dy
}
pub fn make_normal_from_points(point1: Vec3, point2: Vec3, point3: Vec3) -> Vec3 {
normalize(cross(sub(point2, point1), sub(point3, point1)))
}
pub fn max_element_index(v: Vec3) -> i32 {
if v.x < v.y {
if v.y < v.z {
2
} else {
1
}
} else if v.x < v.z {
2
} else {
0
}
}
pub fn major_axis(v: Vec3) -> i32 {
max_element_index(v)
}
pub fn get_by_index(v: Vec3, index: i32) -> f32 {
debug_assert!((0..3).contains(&index));
match index {
0 => v.x,
1 => v.y,
2 => v.z,
_ => unreachable!(),
}
}
pub fn signed_volume(v1: Vec3, v2: Vec3, v3: Vec3, p: Vec3) -> f32 {
let e1 = sub(v2, v1);
let e2 = sub(v3, v1);
let n = cross(e1, e2);
dot(n, sub(p, v1))
}
pub const TWO_PI: f32 = 6.283185307;
pub fn make_diagonal_matrix(a: f32, b: f32, c: f32) -> Matrix3 {
Matrix3 {
cx: Vec3 {
x: a,
y: 0.0,
z: 0.0,
},
cy: Vec3 {
x: 0.0,
y: b,
z: 0.0,
},
cz: Vec3 {
x: 0.0,
y: 0.0,
z: c,
},
}
}
pub fn is_within_segments(result: &SegmentDistanceResult) -> bool {
(0.0 <= result.fraction1 && result.fraction1 <= 1.0)
&& (0.0 <= result.fraction2 && result.fraction2 <= 1.0)
}
pub fn make_plane_from_normal_and_point(normal: Vec3, point: Vec3) -> Plane {
Plane {
normal,
offset: dot(normal, point),
}
}
pub fn make_plane_from_points(point1: Vec3, point2: Vec3, point3: Vec3) -> Plane {
let mut plane = Plane {
normal: cross(sub(point2, point1), sub(point3, point1)),
offset: 0.0,
};
plane.normal = normalize(plane.normal);
plane.offset = dot(plane.normal, point1);
plane
}
pub fn transform_plane(transform: Transform, plane: Plane) -> Plane {
let normal = rotate_vector(transform.q, plane.normal);
Plane {
normal,
offset: plane.offset + dot(normal, transform.p),
}
}
pub fn plane_separation(plane: Plane, point: Vec3) -> f32 {
dot(plane.normal, point) - plane.offset
}
pub fn rotate_inertia(q: Quat, central_inertia: Matrix3) -> Matrix3 {
let rotation_matrix = make_matrix_from_quat(q);
mul_mm(
rotation_matrix,
mul_mm(central_inertia, transpose(rotation_matrix)),
)
}
pub fn box_inertia(mass: f32, min: Vec3, max: Vec3) -> Matrix3 {
let delta = sub(max, min);
let ixx = mass * (delta.y * delta.y + delta.z * delta.z) / 12.0;
let iyy = mass * (delta.x * delta.x + delta.z * delta.z) / 12.0;
let izz = mass * (delta.x * delta.x + delta.y * delta.y) / 12.0;
make_diagonal_matrix(ixx, iyy, izz)
}
pub fn sphere_inertia(mass: f32, radius: f32) -> Matrix3 {
let i = 0.4 * mass * radius * radius;
make_diagonal_matrix(i, i, i)
}
pub fn cylinder_inertia(mass: f32, radius: f32, height: f32) -> Matrix3 {
let ixx = mass * (3.0 * radius * radius + height * height) / 12.0;
let iyy = 0.5 * mass * radius * radius;
make_diagonal_matrix(ixx, iyy, ixx)
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Triangle {
pub vertices: [Vec3; 3],
pub i1: i32,
pub i2: i32,
pub i3: i32,
pub flags: i32,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TrianglePoint {
pub point: Vec3,
pub feature: crate::manifold::TriangleFeature,
}
pub fn closest_point_on_triangle(a: Vec3, b: Vec3, c: Vec3, q: Vec3) -> TrianglePoint {
use crate::manifold::TriangleFeature;
let ab = sub(b, a);
let ac = sub(c, a);
let aq = sub(q, a);
let d1 = dot(ab, aq);
let d2 = dot(ac, aq);
if d1 <= 0.0 && d2 <= 0.0 {
return TrianglePoint {
point: a,
feature: TriangleFeature::Vertex1,
};
}
let bq = sub(q, b);
let d3 = dot(ab, bq);
let d4 = dot(ac, bq);
if d3 > 0.0 && d4 <= d3 {
return TrianglePoint {
point: b,
feature: TriangleFeature::Vertex2,
};
}
let vc = d1 * d4 - d3 * d2;
if vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0 {
let t = d1 / (d1 - d3);
return TrianglePoint {
point: mul_add(a, t, ab),
feature: TriangleFeature::Edge1,
};
}
let cq = sub(q, c);
let d5 = dot(ab, cq);
let d6 = dot(ac, cq);
if d6 >= 0.0 && d5 <= d6 {
return TrianglePoint {
point: c,
feature: TriangleFeature::Vertex3,
};
}
let vb = d5 * d2 - d1 * d6;
if vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0 {
let t = d2 / (d2 - d6);
return TrianglePoint {
point: mul_add(a, t, ac),
feature: TriangleFeature::Edge3,
};
}
let va = d3 * d6 - d5 * d4;
if va <= 0.0 && d4 >= d3 && d5 >= d6 {
let bc = sub(c, b);
let t = (d4 - d3) / ((d4 - d3) + (d5 - d6));
return TrianglePoint {
point: mul_add(b, t, bc),
feature: TriangleFeature::Edge2,
};
}
let t1 = vb / (va + vb + vc);
let t2 = vc / (va + vb + vc);
let mut p = mul_add(a, t1, ab);
p = mul_add(p, t2, ac);
TrianglePoint {
point: p,
feature: TriangleFeature::TriangleFace,
}
}