mod cast;
mod gjk;
mod toi;
mod types;
pub use cast::shape_cast;
pub use gjk::shape_distance;
pub use toi::time_of_impact;
pub use types::{
DistanceInput, DistanceOutput, SegmentDistanceResult, ShapeCastPairInput, ShapeProxy, Simplex,
SimplexCache, SimplexVertex, Sweep, ToiInput, ToiOutput, ToiState,
};
use crate::hull::MAX_POLYGON_VERTICES;
use crate::math_functions::{
add, clamp_float, distance_squared, dot, min_int, mul_add, mul_sv, normalize_rot,
rotate_vector, sub, transform_point, Rot, Transform, Vec2,
};
pub fn get_sweep_transform(sweep: &Sweep, time: f32) -> Transform {
let mut xf = Transform {
p: add(mul_sv(1.0 - time, sweep.c1), mul_sv(time, sweep.c2)),
q: normalize_rot(Rot {
c: (1.0 - time) * sweep.q1.c + time * sweep.q2.c,
s: (1.0 - time) * sweep.q1.s + time * sweep.q2.s,
}),
};
xf.p = sub(xf.p, rotate_vector(xf.q, sweep.local_center));
xf
}
pub fn segment_distance(p1: Vec2, q1: Vec2, p2: Vec2, q2: Vec2) -> SegmentDistanceResult {
let mut result = SegmentDistanceResult::default();
let d1 = sub(q1, p1);
let d2 = sub(q2, p2);
let r = sub(p1, p2);
let dd1 = dot(d1, d1);
let dd2 = dot(d2, d2);
let rd1 = dot(r, d1);
let rd2 = dot(r, d2);
let eps_sqr = f32::EPSILON * f32::EPSILON;
if dd1 < eps_sqr || dd2 < eps_sqr {
if dd1 >= eps_sqr {
result.fraction1 = clamp_float(-rd1 / dd1, 0.0, 1.0);
result.fraction2 = 0.0;
} else if dd2 >= eps_sqr {
result.fraction1 = 0.0;
result.fraction2 = clamp_float(rd2 / dd2, 0.0, 1.0);
} else {
result.fraction1 = 0.0;
result.fraction2 = 0.0;
}
} else {
let d12 = dot(d1, d2);
let denominator = dd1 * dd2 - d12 * d12;
let mut f1 = 0.0;
if denominator != 0.0 {
f1 = clamp_float((d12 * rd2 - rd1 * dd2) / denominator, 0.0, 1.0);
}
let mut f2 = (d12 * f1 + rd2) / dd2;
if f2 < 0.0 {
f2 = 0.0;
f1 = clamp_float(-rd1 / dd1, 0.0, 1.0);
} else if f2 > 1.0 {
f2 = 1.0;
f1 = clamp_float((d12 - rd1) / dd1, 0.0, 1.0);
}
result.fraction1 = f1;
result.fraction2 = f2;
}
result.closest1 = mul_add(p1, result.fraction1, d1);
result.closest2 = mul_add(p2, result.fraction2, d2);
result.distance_squared = distance_squared(result.closest1, result.closest2);
result
}
pub fn make_proxy(points: &[Vec2], radius: f32) -> ShapeProxy {
let count = min_int(points.len() as i32, MAX_POLYGON_VERTICES as i32);
let mut proxy = ShapeProxy {
points: [Vec2::default(); MAX_POLYGON_VERTICES],
count,
radius,
};
proxy.points[..count as usize].copy_from_slice(&points[..count as usize]);
proxy
}
pub fn make_offset_proxy(
points: &[Vec2],
radius: f32,
position: Vec2,
rotation: Rot,
) -> ShapeProxy {
let count = min_int(points.len() as i32, MAX_POLYGON_VERTICES as i32);
let transform = Transform {
p: position,
q: rotation,
};
let mut proxy = ShapeProxy {
points: [Vec2::default(); MAX_POLYGON_VERTICES],
count,
radius,
};
for (dst, src) in proxy.points[..count as usize]
.iter_mut()
.zip(&points[..count as usize])
{
*dst = transform_point(transform, *src);
}
proxy
}