Skip to content

Commit 3b5270d

Browse files
committed
- add sphere vs capsule and ray vs capsule functions
1 parent a93d9ee commit 3b5270d

File tree

1 file changed

+82
-14
lines changed

1 file changed

+82
-14
lines changed

src/lib.rs

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ pub fn powi<T: Float, V: FloatOps<T>>(a: V, b: i32) -> V {
128128
V::powi(a, b)
129129
}
130130

131+
/// returns a squared (raised to the power 2)
132+
pub fn sqr<T: Float, V: FloatOps<T> + Base<T>>(a: V) -> V {
133+
a * a
134+
}
135+
136+
/// returns a cubed (raised to the power 3)
137+
pub fn cube<T: Float, V: FloatOps<T> + Base<T>>(a: V) -> V {
138+
a * a * a
139+
}
140+
131141
/// returns a raised to the floating point power b
132142
pub fn powf<T: Float, V: FloatOps<T>>(a: V, b: T) -> V {
133143
V::powf(a, b)
@@ -824,6 +834,13 @@ pub fn sphere_vs_sphere<T: Float, V: VecN<T> + VecFloatOps<T>>(s1: V, r1: T, s2:
824834
d2 < r22 * r22
825835
}
826836

837+
/// returns true if the sphere or circle at centre s1 with radius r1 intsercts capsule c0-c1 with radius cr
838+
pub fn sphere_vs_capsule<T: Float + FloatOps<T>, V: VecN<T> + VecFloatOps<T> + FloatOps<T>>(s1: V, r1: T, c0: V, c1: V, cr: T) -> bool {
839+
let cp = closest_point_on_line_segment(s1, c0, c1);
840+
let r2 = sqr(r1 + cr);
841+
dist2(s1, cp) < r2
842+
}
843+
827844
/// returns ture if the aabb defined by aabb_min to aabb_max intersects the sphere (or circle) centred at s with radius r
828845
pub fn aabb_vs_sphere<T: Float, V: VecN<T> + VecFloatOps<T> + NumberOps<T>>(aabb_min: V, aabb_max: V, s: V, r: T) -> bool {
829846
let cp = closest_point_on_aabb(s, aabb_min, aabb_max);
@@ -869,6 +886,7 @@ pub fn ray_vs_sphere<T: Float + FloatOps<T> + NumberOps<T>, V: VecN<T> + VecFloa
869886

870887
/// returns the intersection point of the ray with origin r0 and direction rv with the aabb defined by aabb_min and aabb_max
871888
pub fn ray_vs_aabb<T: Number + NumberOps<T>, V: VecN<T>>(r0: V, rv: V, aabb_min: V, aabb_max: V) -> Option<V> {
889+
// http://gamedev.stackexchange.com/a/18459
872890
// min / max's from aabb axes
873891
let dirfrac = V::one() / rv;
874892
let tx = (aabb_min[0] - r0[0]) * dirfrac[0];
@@ -947,6 +965,22 @@ pub fn ray_vs_triangle<T: Float>(r0: Vec3<T>, rv: Vec3<T>, t0: Vec3<T>, t1: Vec3
947965
}
948966
}
949967

968+
/// returns the intersection point of ray wih origin r0 and direction rv against the capsule with line c0 - c1 and radius cr
969+
pub fn ray_vs_capsule<T: Float + FloatOps<T> + NumberOps<T> + SignedNumberOps<T>, V: VecN<T> + VecFloatOps<T> + SignedNumberOps<T> + FloatOps<T>>(r0: V, rv: V, c0: V, c1: V, cr: T) -> Option<V> {
970+
let sl = shortest_line_segment_between_lines(r0, rv, c0, c1);
971+
if let Some(line) = sl {
972+
if dist2(line.0, line.1) < sqr(cr) {
973+
Some(line.0)
974+
}
975+
else {
976+
None
977+
}
978+
}
979+
else {
980+
None
981+
}
982+
}
983+
950984
/// returns true if the sphere with centre s and radius r is inside the frustum defined by 6 planes packed as vec4's .xyz = normal, .w = plane distance
951985
pub fn sphere_vs_frustum<T: Number>(s: Vec3<T>, r: T, planes: &[Vec4<T>; 6]) -> bool {
952986
for p in planes.iter().take(6) {
@@ -1081,6 +1115,43 @@ pub fn shortest_line_segment_between_line_segments<T: Float + SignedNumberOps<T>
10811115
))
10821116
}
10831117

1118+
/// returns the shortest line segment between 2 lines (p1-p2) and (p3-p4) as an option tuple where .0 is the point on line segment 1 and .1 is the point on line segment 2
1119+
pub fn shortest_line_segment_between_lines<T: Float + SignedNumberOps<T> + FloatOps<T>, V: VecN<T> + SignedNumberOps<T> + FloatOps<T> + Dot<T>>(p1: V, p2: V, p3: V, p4: V) -> Option<(V, V)> {
1120+
// https://web.archive.org/web/20120404121511/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/lineline.c
1121+
1122+
let p13 = p1 - p3;
1123+
let p43 = p4 - p3;
1124+
1125+
if approx(abs(p43), V::zero(), T::small_epsilon()) {
1126+
return None;
1127+
}
1128+
1129+
let p21 = p2 - p1;
1130+
if approx(abs(p21), V::zero(), T::small_epsilon()) {
1131+
return None;
1132+
}
1133+
1134+
let d1343 = dot(p13, p43);
1135+
let d4321 = dot(p43, p21);
1136+
let d1321 = dot(p13, p21);
1137+
let d4343 = dot(p43, p43);
1138+
let d2121 = dot(p21, p21);
1139+
1140+
let denom = d2121 * d4343 - d4321 * d4321;
1141+
if abs(denom) < T::small_epsilon() {
1142+
return None;
1143+
}
1144+
1145+
let numer = d1343 * d4321 - d1321 * d4343;
1146+
let mua = numer / denom;
1147+
let mub = (d1343 + d4321 * mua) / d4343;
1148+
1149+
Some((
1150+
p1 + (p21 * mua),
1151+
p3 + (p43 * mub)
1152+
))
1153+
}
1154+
10841155
/// returns soft clipping (in a cubic fashion) of x; let m be the threshold (anything above m stays unchanged), and n the value things will take when the signal is zero
10851156
pub fn almost_identity<T: Number + Float>(x: T, m: T, n: T) -> T {
10861157
// <https://iquilezles.org/articles/functions/>
@@ -1374,12 +1445,11 @@ pub fn map_to_range<T: Float, X: Base<T>>(v: X, in_start: X, in_end: X, out_star
13741445
out_start + slope * (v - in_start)
13751446
}
13761447

1377-
// https://web.archive.org/web/20120414063459/http://local.wasp.uwa.edu.au/~pbourke//geometry/lineline3d/
1378-
13791448
// TODO:
1380-
// line_segment_between_line_segment_test
1449+
// line_segment_between_line_segment (test)
1450+
// sphere_vs_capsule (test)
1451+
// ray_vs_capsule (test)
13811452
// missing fail cases
1382-
// closest point on line seg to line seg
13831453
// projection, ndc
13841454
// projection, sc
13851455
// unprojection, ndc,
@@ -1390,18 +1460,13 @@ pub fn map_to_range<T: Float, X: Base<T>>(v: X, in_start: X, in_end: X, out_star
13901460
// mat from quat
13911461
// quat from mat
13921462

1393-
// TODO: new?
1394-
// ray_vs_capsule
1395-
// capsule_vs_sphere
1396-
// line_vs_cone
1463+
// ADDITIONS?
1464+
// obb_vs_sphere - easy
1465+
// obb_vs_aabb
1466+
// obb_vs_obb
13971467
// ray_vs_cone
13981468
// cone_vs_sphere
13991469
// cone_vs_aabb
1400-
// obb_vs_aabb
1401-
// obb_vs_sphere
1402-
// obb_vs_obb
1403-
// line_vs_sphere
1404-
// line_vs_aabb
14051470

14061471
// TODO c++
14071472
// point inside frustum
@@ -1425,4 +1490,7 @@ pub fn map_to_range<T: Float, X: Base<T>>(v: X, in_start: X, in_end: X, out_star
14251490
// point hull distance
14261491
// point poly distance
14271492
// capsule_vs_plane
1428-
// cone_vs_plane
1493+
// cone_vs_plane
1494+
// line_segment_between_line_segment
1495+
// sphere_vs_capsule
1496+
// ray_vs_capsule

0 commit comments

Comments
 (0)