Skip to content

Commit bd8c82b

Browse files
committed
- add line segment between line segments function and test
1 parent 02ca597 commit bd8c82b

File tree

2 files changed

+100
-6
lines changed

2 files changed

+100
-6
lines changed

src/lib.rs

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,17 @@ pub fn point_inside_polygon<T: Float>(p: Vec2<T>, poly: &Vec<Vec2<T>>) -> bool {
679679
c
680680
}
681681

682+
/// returns true if the point p is inside the frustum defined by 6 planes packed as vec4's .xyz = normal, .w = plane distance
683+
pub fn point_inside_frustum<T: Number>(p: Vec3<T>, planes: &[Vec4<T>; 6]) -> bool {
684+
for plane in planes.iter().take(6) {
685+
let d = dot(p, Vec3::from(*plane)) + plane.w;
686+
if d > T::zero() {
687+
return false;
688+
}
689+
}
690+
true
691+
}
692+
682693
/// returns the classification of the 3D aabb defined as aabb_min to aabb_max vs the plane defined by point on plane x and normal n
683694
pub fn aabb_vs_plane<T: SignedNumber + SignedNumberOps<T>>(aabb_min: Vec3<T>, aabb_max: Vec3<T>, x: Vec3<T>, n: Vec3<T>) -> Classification {
684695
let e = (aabb_max - aabb_min) / T::two();
@@ -936,7 +947,7 @@ pub fn ray_vs_triangle<T: Float>(r0: Vec3<T>, rv: Vec3<T>, t0: Vec3<T>, t1: Vec3
936947
}
937948
}
938949

939-
/// returns true if the sphere with centre s and radius r is inside the furstum defined by 6 planes packed as vec4's .xyz = normal, .w = plane distance
950+
/// 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
940951
pub fn sphere_vs_frustum<T: Number>(s: Vec3<T>, r: T, planes: &[Vec4<T>; 6]) -> bool {
941952
for p in planes.iter().take(6) {
942953
let d = dot(s, Vec3::from(*p)) + p.w;
@@ -947,7 +958,7 @@ pub fn sphere_vs_frustum<T: Number>(s: Vec3<T>, r: T, planes: &[Vec4<T>; 6]) ->
947958
true
948959
}
949960

950-
/// returns true if the aabb defined by aabb_pos (centre) and aabb_extent is inside the furstum defined by 6 planes packed as vec4's .xyz = normal, .w = plane distance
961+
/// returns true if the aabb defined by aabb_pos (centre) and aabb_extent is inside the frustum defined by 6 planes packed as vec4's .xyz = normal, .w = plane distance
951962
pub fn aabb_vs_frustum<T: SignedNumber + SignedNumberOps<T>>(aabb_pos: Vec3<T>, aabb_extent: Vec3<T>, planes: &[Vec4<T>; 6]) -> bool {
952963
let mut inside = true;
953964
for p in planes.iter().take(6) {
@@ -990,7 +1001,7 @@ pub fn line_segment_vs_line_segment<T: Float + SignedNumberOps<T> + FloatOps<T>>
9901001
}
9911002

9921003
/// returns the intersection point if the infinite line l1-l2 intersects with s1-s2
993-
pub fn line_vs_line<T: Float + SignedNumberOps<T> + FloatOps<T>>(l1: Vec3<T>, l2: Vec3<T>, s1: Vec3<T>, s2: Vec3<T>) -> Option<Vec3<T>> {
1004+
pub fn line_vs_line<T: Float + SignedNumberOps<T> + FloatOps<T>>(l1: Vec3<T>, l2: Vec3<T>, s1: Vec3<T>, s2: Vec3<T>) -> Option<Vec3<T>> {
9941005
let da = l2 - l1;
9951006
let db = s2 - s1;
9961007
let dc = s1 - l1;
@@ -1033,6 +1044,43 @@ pub fn ray_vs_line_segment<T: Float + SignedNumberOps<T> + FloatOps<T>>(r0: Vec3
10331044
}
10341045
}
10351046

1047+
/// returns the shortest line segment between 2 line segments (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
1048+
pub fn shortest_line_segment_between_line_segments<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)> {
1049+
// https://web.archive.org/web/20120404121511/http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/lineline.c
1050+
1051+
let p13 = p1 - p3;
1052+
let p43 = p4 - p3;
1053+
1054+
if approx(abs(p43), V::zero(), T::small_epsilon()) {
1055+
return None;
1056+
}
1057+
1058+
let p21 = p2 - p1;
1059+
if approx(abs(p21), V::zero(), T::small_epsilon()) {
1060+
return None;
1061+
}
1062+
1063+
let d1343 = dot(p13, p43);
1064+
let d4321 = dot(p43, p21);
1065+
let d1321 = dot(p13, p21);
1066+
let d4343 = dot(p43, p43);
1067+
let d2121 = dot(p21, p21);
1068+
1069+
let denom = d2121 * d4343 - d4321 * d4321;
1070+
if abs(denom) < T::small_epsilon() {
1071+
return None;
1072+
}
1073+
1074+
let numer = d1343 * d4321 - d1321 * d4343;
1075+
let mua = numer / denom;
1076+
let mub = (d1343 + d4321 * mua) / d4343;
1077+
1078+
Some((
1079+
p1 + (p21 * mua),
1080+
p3 + (p43 * mub)
1081+
))
1082+
}
1083+
10361084
/// 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
10371085
pub fn almost_identity<T: Number + Float>(x: T, m: T, n: T) -> T {
10381086
// <https://iquilezles.org/articles/functions/>
@@ -1326,9 +1374,11 @@ pub fn map_to_range<T: Float, X: Base<T>>(v: X, in_start: X, in_end: X, out_star
13261374
out_start + slope * (v - in_start)
13271375
}
13281376

1329-
// TODO: tests
1377+
// https://web.archive.org/web/20120414063459/http://local.wasp.uwa.edu.au/~pbourke//geometry/lineline3d/
1378+
1379+
// TODO:
13301380
// missing fail cases
1331-
// ray triangle (test)
1381+
// closest point on line seg to line seg
13321382
// projection, ndc
13331383
// projection, sc
13341384
// unprojection, ndc,
@@ -1340,18 +1390,20 @@ pub fn map_to_range<T: Float, X: Base<T>>(v: X, in_start: X, in_end: X, out_star
13401390
// quat from mat
13411391

13421392
// TODO: new?
1393+
// ray_vs_capsule
1394+
// capsule_vs_sphere
13431395
// line_vs_cone
13441396
// ray_vs_cone
13451397
// cone_vs_sphere
13461398
// cone_vs_aabb
1347-
// capsule_vs_sphere
13481399
// obb_vs_aabb
13491400
// obb_vs_sphere
13501401
// obb_vs_obb
13511402
// line_vs_sphere
13521403
// line_vs_aabb
13531404

13541405
// TODO c++
1406+
// point inside frustum
13551407
// point inside cone test has no passes
13561408
// point plane distance
13571409
// point sphere distance

tests/tests.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,34 @@ fn point_inside_obb_test() {
17571757
assert_eq!(result, false);
17581758
}
17591759

1760+
#[test]
1761+
fn point_inside_frustum_test() {
1762+
let planes = Mat4f::new(
1763+
0.85501, 1.45179e-08, 0.467094, 0.0,
1764+
0.39811, 1.52002, -0.728735, 0.0,
1765+
0.420904, -0.479617, -0.770459, 60.004,
1766+
0.420736, -0.479426, -0.770151, 60.0
1767+
).get_frustum_planes();
1768+
1769+
// inside
1770+
let pos = vec3f(-5.0, 5.0, 50.0);
1771+
let result = point_inside_frustum(pos, &planes);
1772+
assert_eq!(result, false);
1773+
1774+
let pos = vec3f(-8.76, -8.04, 5.3);
1775+
let result = point_inside_frustum(pos, &planes);
1776+
assert_eq!(result, false);
1777+
1778+
// outside
1779+
let pos = vec3f(4.85, 7.45, 2.28);
1780+
let result = point_inside_frustum(pos, &planes);
1781+
assert_eq!(result, false);
1782+
1783+
let pos = vec3f(0.0100002, 1.53, -2.92);
1784+
let result = point_inside_frustum(pos, &planes);
1785+
assert_eq!(result, false);
1786+
}
1787+
17601788
#[test]
17611789
fn plane_distance_test() {
17621790
let x = vec3f(-1.22, 9.23, 7.09);
@@ -2648,6 +2676,20 @@ fn ray_vs_line_segment_test() {
26482676
assert_eq!(t, -10.0);
26492677
}
26502678

2679+
#[test]
2680+
fn line_segment_between_line_segment_test() {
2681+
let l1 = Vec2f::new(-100.0, 0.0);
2682+
let l2 = Vec2f::new(100.0, 0.0);
2683+
let l3 = Vec2f::new(-100.0, 10.0);
2684+
let l4 = Vec2f::new(100.0, 10.0);
2685+
let result = shortest_line_segment_between_line_segments(l1, l2, l3, l4);
2686+
assert_eq!(result.is_some(), true);
2687+
if let Some((p1, p2)) = result {
2688+
assert_eq!(p1, Vec2f::new(0.0, 0.0));
2689+
assert_eq!(p2, Vec2f::new(0.0, 10.0));
2690+
}
2691+
}
2692+
26512693
#[test]
26522694
fn utils() {
26532695
// TODO: quilez... these were to just test compilation

0 commit comments

Comments
 (0)