From 1dbde609cc22caf78f9ede5b578abc031dcb1f6b Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 20 Nov 2025 08:45:15 -0800 Subject: [PATCH 01/90] wip --- engine/physics/src/lib.rs | 3 +- engine/physics/src/minimum_difference.rs | 77 ++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 engine/physics/src/minimum_difference.rs diff --git a/engine/physics/src/lib.rs b/engine/physics/src/lib.rs index 9b7db872..56e4a458 100644 --- a/engine/physics/src/lib.rs +++ b/engine/physics/src/lib.rs @@ -1,7 +1,8 @@ mod body; -mod push_solve; mod face_crawler; mod model; +mod push_solve; +mod minimum_difference; pub mod physics; diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs new file mode 100644 index 00000000..11abdda3 --- /dev/null +++ b/engine/physics/src/minimum_difference.rs @@ -0,0 +1,77 @@ +use strafesnet_common::integer::{Planar64, Planar64Vec3}; + +use crate::model::TransformedMesh; + +// This algorithm is based on Lua code +// written by Trey Reynolds in 2021 + +// local function minimumDifference( +// queryP, radiusP, +// queryQ, radiusQ, +// exitRadius, testIntersection +// ) + +pub struct MinimumDifference{ + distance:Planar64, + p_pos:Planar64Vec3, + p_norm:Planar64Vec3, + q_pos:Planar64Vec3, + q_norm:Planar64Vec3, +} + +pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option{ + // local initialAxis = queryQ() - queryP() + // local newPoint0 = queryP(initialAxis) + // local newPoint1 = queryQ(-initialAxis) + // local direction, a0, a1, b0, b1, c0, c1, d0, d1 + + // exitRadius = testIntersection and 0 or exitRadius or 1/0 + // for _ = 1, 100 do + // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(newPoint0, newPoint1, a0, a1, b0, b1, c0, c1) + // local a, b, c, d = getRelativeSimplex(a0, a1, b0, b1, c0, c1, d0, d1) + + // if a and b and c and d then + // if testIntersection then + // return true + // end + // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) + // if norm then + // local posP, posQ = decompose(Vector3.zero, u0, u1, v0, v1, w0, w1) + // return true, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return nil + // end + + // newPoint0 = queryP(-direction) + // newPoint1 = queryQ(direction) + // local newPoint = newPoint1 - newPoint0 + + // if -direction:Dot(newPoint) > (exitRadius + radiusP + radiusQ)*direction.magnitude then + // return false + // end + + // if + // direction:Dot(newPoint - a) <= 0 or + // absDet(newPoint, a, b, c) < 1e-6 + // then + // local norm = direction.unit + // local dist = a:Dot(norm) + // local hits = -dist < radiusP + radiusQ + // if testIntersection then + // return hits + // end + // if -dist <= exitRadius + radiusP + radiusQ then + // local posP, posQ = decompose(Vector3.zero, a0, a1, b0, b1, c0, c1) + // return hits, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return false + // end + // end + + // return nil + None +} -- 2.49.1 From 73848865123ce04c4fcf651897d4b3e5c2d89fd8 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 20 Nov 2025 09:05:29 -0800 Subject: [PATCH 02/90] work --- engine/physics/src/minimum_difference.rs | 93 ++++++++++++------------ 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 11abdda3..3a776fd5 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -5,11 +5,6 @@ use crate::model::TransformedMesh; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 -// local function minimumDifference( -// queryP, radiusP, -// queryQ, radiusQ, -// exitRadius, testIntersection -// ) pub struct MinimumDifference{ distance:Planar64, @@ -19,6 +14,11 @@ pub struct MinimumDifference{ q_norm:Planar64Vec3, } +// local function minimumDifference( +// queryP, radiusP, +// queryQ, radiusQ, +// exitRadius, testIntersection +// ) pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option{ // local initialAxis = queryQ() - queryP() // local newPoint0 = queryP(initialAxis) @@ -27,51 +27,52 @@ pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option (exitRadius + radiusP + radiusQ)*direction.magnitude then - // return false - // end - - // if - // direction:Dot(newPoint - a) <= 0 or - // absDet(newPoint, a, b, c) < 1e-6 - // then - // local norm = direction.unit - // local dist = a:Dot(norm) - // local hits = -dist < radiusP + radiusQ - // if testIntersection then - // return hits - // end - // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(Vector3.zero, a0, a1, b0, b1, c0, c1) - // return hits, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return false - // end - // end + // if -direction:Dot(newPoint) > (exitRadius + radiusP + radiusQ)*direction.magnitude then + // return false + // end + // if + // direction:Dot(newPoint - a) <= 0 or + // absDet(newPoint, a, b, c) < 1e-6 + // then + // local norm = direction.unit + // local dist = a:Dot(norm) + // local hits = -dist < radiusP + radiusQ + // if testIntersection then + // return hits + // end + // if -dist <= exitRadius + radiusP + radiusQ then + // local posP, posQ = decompose(Vector3.zero, a0, a1, b0, b1, c0, c1) + // return hits, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return false + // end + panic!("quit underlining all my code!"); + } // return nil None } -- 2.49.1 From 1770ac7292364aa651700f0891abaade9de3a24e Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 20 Nov 2025 09:34:22 -0800 Subject: [PATCH 03/90] work --- engine/physics/src/minimum_difference.rs | 60 +++++++++++++++--------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 3a776fd5..74de1d3d 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -5,8 +5,35 @@ use crate::model::TransformedMesh; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 +struct PQ{ + p:Planar64Vec3, + q:Planar64Vec3, +} +type Simplex=arrayvec::ArrayVec; -pub struct MinimumDifference{ +/// Intermediate data structure containing a partially complete calculation. +/// Sometimes you only care if the meshes are intersecting, and not about the +/// exact point of intersection details. +pub struct MinimumDifference<'p,'q>{ + p:&'p TransformedMesh, + q:&'q TransformedMesh, +} +impl<'p,'q> MinimumDifference<'p,'q>{ + pub fn details(&self)->Details{ + // if testIntersection then + // return true + // end + // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) + // if norm then + // local posP, posQ = decompose(Vector3.zero, u0, u1, v0, v1, w0, w1) + // return true, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return nil + } +} +pub struct Details{ distance:Planar64, p_pos:Planar64Vec3, p_norm:Planar64Vec3, @@ -19,35 +46,23 @@ pub struct MinimumDifference{ // queryQ, radiusQ, // exitRadius, testIntersection // ) -pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option{ +pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->Option>{ // local initialAxis = queryQ() - queryP() - // local newPoint0 = queryP(initialAxis) - // local newPoint1 = queryQ(-initialAxis) + // local new_point_p = queryP(initialAxis) + // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 + let s=Simplex::from_iter([PQ{p:new_point_p,q:new_point_q}]); // exitRadius = testIntersection and 0 or exitRadius or 1/0 // for _ = 1, 100 do loop{ - // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(newPoint0, newPoint1, a0, a1, b0, b1, c0, c1) - // local a, b, c, d = getRelativeSimplex(a0, a1, b0, b1, c0, c1, d0, d1) - // if a and b and c and d then - // if testIntersection then - // return true - // end - // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) - // if norm then - // local posP, posQ = decompose(Vector3.zero, u0, u1, v0, v1, w0, w1) - // return true, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return nil + // return Some(MinimumDifference); // end - // newPoint0 = queryP(-direction) - // newPoint1 = queryQ(direction) - // local newPoint = newPoint1 - newPoint0 + // new_point_p = queryP(-direction) + // new_point_q = queryQ(direction) + // local newPoint = new_point_q - new_point_p // if -direction:Dot(newPoint) > (exitRadius + radiusP + radiusQ)*direction.magnitude then // return false @@ -71,6 +86,9 @@ pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option Date: Thu, 20 Nov 2025 09:45:55 -0800 Subject: [PATCH 04/90] work --- engine/physics/src/minimum_difference.rs | 22 +++++++++++++--------- engine/physics/src/model.rs | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 74de1d3d..c78c6fc2 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -1,6 +1,6 @@ -use strafesnet_common::integer::{Planar64, Planar64Vec3}; +use strafesnet_common::integer::{Planar64,Planar64Vec3}; -use crate::model::TransformedMesh; +use crate::model::{TransformedMesh,MeshQuery}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 @@ -15,10 +15,10 @@ type Simplex=arrayvec::ArrayVec; /// Sometimes you only care if the meshes are intersecting, and not about the /// exact point of intersection details. pub struct MinimumDifference<'p,'q>{ - p:&'p TransformedMesh, - q:&'q TransformedMesh, + p:&'p TransformedMesh<'p>, + q:&'q TransformedMesh<'q>, } -impl<'p,'q> MinimumDifference<'p,'q>{ +impl MinimumDifference<'_,'_>{ pub fn details(&self)->Details{ // if testIntersection then // return true @@ -51,14 +51,18 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 - let s=Simplex::from_iter([PQ{p:new_point_p,q:new_point_q}]); + let initial_axis=q.hint_point()-p.hint_point(); + let new_point_p=p.farthest_vert(initial_axis); + let new_point_q=q.farthest_vert(-initial_axis); + let mut simplex=Simplex::from_iter([PQ{p:new_point_p,q:new_point_q}]); // exitRadius = testIntersection and 0 or exitRadius or 1/0 // for _ = 1, 100 do loop{ // if a and b and c and d then - // return Some(MinimumDifference); - // end + if simplex.len()==4{ + return Some(MinimumDifference{p,q}); + } // new_point_p = queryP(-direction) // new_point_q = queryQ(direction) @@ -88,7 +92,7 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // end // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) - let s:Simplex = reduce_simplex() + let s:Simplex = reduce_simplex(); panic!("quit underlining all my code!"); } // return nil diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index 0665bf31..8eb14b25 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -514,7 +514,7 @@ impl TransformedMesh<'_>{ pub fn verts<'a>(&'a self)->impl Iterator>>+'a{ self.view.data.verts.iter().map(|&Vert(pos)|self.transform.vertex.transform_point3(pos)) } - fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{ + pub fn farthest_vert(&self,dir:Planar64Vec3)->SubmeshVertId{ //this happens to be well-defined. there are no virtual virtices SubmeshVertId::new( self.view.topology.verts.iter() -- 2.49.1 From 14a5a3f9642979c817403bf135d4fb5f30435d03 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 20 Nov 2025 09:49:46 -0800 Subject: [PATCH 05/90] work --- engine/physics/src/minimum_difference.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index c78c6fc2..44a2b733 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -1,13 +1,13 @@ use strafesnet_common::integer::{Planar64,Planar64Vec3}; -use crate::model::{TransformedMesh,MeshQuery}; +use crate::model::{MeshQuery,SubmeshVertId,TransformedMesh}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 struct PQ{ - p:Planar64Vec3, - q:Planar64Vec3, + p:SubmeshVertId, + q:SubmeshVertId, } type Simplex=arrayvec::ArrayVec; @@ -51,10 +51,12 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 - let initial_axis=q.hint_point()-p.hint_point(); - let new_point_p=p.farthest_vert(initial_axis); - let new_point_q=q.farthest_vert(-initial_axis); - let mut simplex=Simplex::from_iter([PQ{p:new_point_p,q:new_point_q}]); + let mut direction=q.hint_point()-p.hint_point(); + let new_point=PQ{ + p:p.farthest_vert(direction), + q:q.farthest_vert(-direction), + }; + let mut simplex=Simplex::from_iter([new_point]); // exitRadius = testIntersection and 0 or exitRadius or 1/0 // for _ = 1, 100 do @@ -67,6 +69,10 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // new_point_p = queryP(-direction) // new_point_q = queryQ(direction) // local newPoint = new_point_q - new_point_p + let new_point=PQ{ + p:p.farthest_vert(direction), + q:q.farthest_vert(-direction), + }; // if -direction:Dot(newPoint) > (exitRadius + radiusP + radiusQ)*direction.magnitude then // return false @@ -92,7 +98,7 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // end // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) - let s:Simplex = reduce_simplex(); + (direction,simplex) = reduce_simplex(); panic!("quit underlining all my code!"); } // return nil -- 2.49.1 From bc5cdc7313359ab530363253a96e944667ef8f6b Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 20 Nov 2025 09:53:56 -0800 Subject: [PATCH 06/90] work --- engine/physics/src/minimum_difference.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 44a2b733..987661c2 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -75,8 +75,9 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O }; // if -direction:Dot(newPoint) > (exitRadius + radiusP + radiusQ)*direction.magnitude then - // return false - // end + if direction.dot(new_point.point()).is_negative(){ + return None; + } // if // direction:Dot(newPoint - a) <= 0 or @@ -99,8 +100,5 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) (direction,simplex) = reduce_simplex(); - panic!("quit underlining all my code!"); } - // return nil - None } -- 2.49.1 From eed0abcc2c662f653dbc0d847bbc60998fa0c465 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 20 Nov 2025 09:59:54 -0800 Subject: [PATCH 07/90] work --- engine/physics/src/minimum_difference.rs | 40 ++++++++++++++---------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 987661c2..7c8b7e37 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -1,15 +1,12 @@ use strafesnet_common::integer::{Planar64,Planar64Vec3}; -use crate::model::{MeshQuery,SubmeshVertId,TransformedMesh}; +use crate::model::{MeshQuery,SubmeshVertId,TransformedMesh,MinkowskiVert}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 -struct PQ{ - p:SubmeshVertId, - q:SubmeshVertId, -} -type Simplex=arrayvec::ArrayVec; +use MinkowskiVert::VertVert as PQ; +type Simplex=arrayvec::ArrayVec; /// Intermediate data structure containing a partially complete calculation. /// Sometimes you only care if the meshes are intersecting, and not about the @@ -52,10 +49,10 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 let mut direction=q.hint_point()-p.hint_point(); - let new_point=PQ{ - p:p.farthest_vert(direction), - q:q.farthest_vert(-direction), - }; + let new_point=PQ( + p.farthest_vert(direction), + q.farthest_vert(-direction), + ); let mut simplex=Simplex::from_iter([new_point]); // exitRadius = testIntersection and 0 or exitRadius or 1/0 @@ -69,13 +66,13 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // new_point_p = queryP(-direction) // new_point_q = queryQ(direction) // local newPoint = new_point_q - new_point_p - let new_point=PQ{ - p:p.farthest_vert(direction), - q:q.farthest_vert(-direction), - }; + let next_point=PQ( + p.farthest_vert(direction), + q.farthest_vert(-direction), + ); // if -direction:Dot(newPoint) > (exitRadius + radiusP + radiusQ)*direction.magnitude then - if direction.dot(new_point.point()).is_negative(){ + if direction.dot(next_point.position()).is_negative(){ return None; } @@ -99,6 +96,17 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // end // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) - (direction,simplex) = reduce_simplex(); + + //push_front + if simplex.len()==simplex.capacity(){ + //this is a dead case, new_simplex never has more than 3 elements + simplex.rotate_right(1); + simplex[0]=next_point; + }else{ + simplex.push(next_point); + simplex.rotate_right(1); + } + + (direction,simplex) = reduce_simplex(simplex); } } -- 2.49.1 From f0c7677a773d58267d91e2d361c3e5c62114160b Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 20 Nov 2025 10:11:53 -0800 Subject: [PATCH 08/90] work --- engine/physics/src/minimum_difference.rs | 79 ++++++++++++++---------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 7c8b7e37..4badb97e 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -6,7 +6,13 @@ use crate::model::{MeshQuery,SubmeshVertId,TransformedMesh,MinkowskiVert}; // written by Trey Reynolds in 2021 use MinkowskiVert::VertVert as PQ; -type Simplex=arrayvec::ArrayVec; +const SIMPLEX_TETRAHEDRON:usize=4; +type Simplex=arrayvec::ArrayVec; + +enum Expanded{ + Expanded, + Unexpanded, +} /// Intermediate data structure containing a partially complete calculation. /// Sometimes you only care if the meshes are intersecting, and not about the @@ -14,20 +20,39 @@ type Simplex=arrayvec::ArrayVec; pub struct MinimumDifference<'p,'q>{ p:&'p TransformedMesh<'p>, q:&'q TransformedMesh<'q>, + expanded:Expanded, } impl MinimumDifference<'_,'_>{ pub fn details(&self)->Details{ - // if testIntersection then - // return true - // end - // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) - // if norm then - // local posP, posQ = decompose(Vector3.zero, u0, u1, v0, v1, w0, w1) - // return true, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return nil + match self.expanded{ + Expanded::Expanded=>{ + // if testIntersection then + // return hits + // end + // if -dist <= exitRadius + radiusP + radiusQ then + // local posP, posQ = decompose(Vector3.zero, a0, a1, b0, b1, c0, c1) + // return hits, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return false + Details{} + }, + Expanded::Unexpanded=>{ + // if testIntersection then + // return true + // end + // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) + // if norm then + // local posP, posQ = decompose(Vector3.zero, u0, u1, v0, v1, w0, w1) + // return true, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return nil + Details{} + }, + } } } pub struct Details{ @@ -59,47 +84,36 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // for _ = 1, 100 do loop{ // if a and b and c and d then - if simplex.len()==4{ - return Some(MinimumDifference{p,q}); + if simplex.len()==SIMPLEX_TETRAHEDRON{ + return Some(MinimumDifference::unexpanded(p,q)); } // new_point_p = queryP(-direction) // new_point_q = queryQ(direction) - // local newPoint = new_point_q - new_point_p + // local next_point = new_point_q - new_point_p let next_point=PQ( p.farthest_vert(direction), q.farthest_vert(-direction), ); - // if -direction:Dot(newPoint) > (exitRadius + radiusP + radiusQ)*direction.magnitude then + // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then if direction.dot(next_point.position()).is_negative(){ return None; } // if - // direction:Dot(newPoint - a) <= 0 or - // absDet(newPoint, a, b, c) < 1e-6 + // direction:Dot(next_point - a) <= 0 or + // absDet(next_point, a, b, c) < 1e-6 // then // local norm = direction.unit // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ - // if testIntersection then - // return hits - // end - // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(Vector3.zero, a0, a1, b0, b1, c0, c1) - // return hits, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return false + // return Some(MinimumDifference::expanded(p,q)); // end - // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) - - //push_front + // push_front if simplex.len()==simplex.capacity(){ - //this is a dead case, new_simplex never has more than 3 elements + // this is a dead case, new_simplex never has more than 3 elements simplex.rotate_right(1); simplex[0]=next_point; }else{ @@ -107,6 +121,7 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O simplex.rotate_right(1); } + // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) (direction,simplex) = reduce_simplex(simplex); } } -- 2.49.1 From ab3c693f8476436da369a239f1831bb06828196c Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 21 Nov 2025 10:17:38 -0800 Subject: [PATCH 09/90] no hold ref --- engine/physics/src/minimum_difference.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 4badb97e..f234bc71 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -17,13 +17,11 @@ enum Expanded{ /// Intermediate data structure containing a partially complete calculation. /// Sometimes you only care if the meshes are intersecting, and not about the /// exact point of intersection details. -pub struct MinimumDifference<'p,'q>{ - p:&'p TransformedMesh<'p>, - q:&'q TransformedMesh<'q>, +pub struct MinimumDifference{ expanded:Expanded, } -impl MinimumDifference<'_,'_>{ - pub fn details(&self)->Details{ +impl MinimumDifference{ + pub fn details(&self,p:&TransformedMesh,q:&TransformedMesh)->Details{ match self.expanded{ Expanded::Expanded=>{ // if testIntersection then @@ -68,7 +66,7 @@ pub struct Details{ // queryQ, radiusQ, // exitRadius, testIntersection // ) -pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->Option>{ +pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option{ // local initialAxis = queryQ() - queryP() // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) @@ -85,7 +83,7 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O loop{ // if a and b and c and d then if simplex.len()==SIMPLEX_TETRAHEDRON{ - return Some(MinimumDifference::unexpanded(p,q)); + return Some(MinimumDifference::unexpanded()); } // new_point_p = queryP(-direction) @@ -108,7 +106,7 @@ pub fn minimum_difference<'p,'q>(p:&'p TransformedMesh,q:&'q TransformedMesh)->O // local norm = direction.unit // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ - // return Some(MinimumDifference::expanded(p,q)); + // return Some(MinimumDifference::expanded()); // end // push_front -- 2.49.1 From d2ed97fcf2b2bc385a7f5e4703a24ca56bf9903b Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 21 Nov 2025 10:48:24 -0800 Subject: [PATCH 10/90] wip paste fns --- engine/physics/src/minimum_difference.rs | 260 +++++++++++++++++++++++ 1 file changed, 260 insertions(+) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index f234bc71..567454db 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -9,6 +9,266 @@ use MinkowskiVert::VertVert as PQ; const SIMPLEX_TETRAHEDRON:usize=4; type Simplex=arrayvec::ArrayVec; +/* +local function absDet(r, u, v, w) + if w then + return math.abs((u - r):Cross(v - r):Dot(w - r)) + elseif v then + return (u - r):Cross(v - r).magnitude + elseif u then + return (u - r).magnitude + else + return 1 + end +end +*/ + +/* +local function choosePerpendicularDirection(d) + local x, y, z = d.x, d.y, d.z + local best = math.min(x*x, y*y, z*z) + if x*x == best then + return Vector3.new(y*y + z*z, -x*y, -x*z) + elseif y*y == best then + return Vector3.new(-x*y, x*x + z*z, -y*z) + else + return Vector3.new(-x*z, -y*z, x*x + y*y) + end +end +*/ + +/* +local function chooseAnyDirection() + return Vector3.new(1, 0, 0) +end +*/ + +/* +local function reduceSimplex0(a0, a1) + --debug.profilebegin("reduceSimplex0") + local a = a1 - a0 + + local p = -a + + local direction = p + if direction.magnitude == 0 then + direction = chooseAnyDirection() + end + return direction, a0, a1 +end +*/ + +/* +local function reduceSimplex1(a0, a1, b0, b1) + --debug.profilebegin("reduceSimplex1") + local a = a1 - a0 + local b = b1 - b0 + + local p = -a + local u = b - a + + -- modify to take into account the radiuses + local p_u = p:Dot(u) + + if p_u >= 0 then + local direction = u:Cross(p):Cross(u) + if direction.magnitude == 0 then + direction = choosePerpendicularDirection(u) + end + -- modify the direction to take into account a0R and b0R + return direction, a0, a1, b0, b1 + end + + local direction = p + if direction.magnitude == 0 then + direction = choosePerpendicularDirection(u) + end + return direction, a0, a1 +end +*/ + +/* +local function reduceSimplex2(a0, a1, b0, b1, c0, c1) + --debug.profilebegin("reduceSimplex2") + local a = a1 - a0 + local b = b1 - b0 + local c = c1 - c0 + + local p = -a + local u = b - a + local v = c - a + + local uv = u:Cross(v) + local up = u:Cross(p) + local pv = p:Cross(v) + local uv_up = uv:Dot(up) + local uv_pv = uv:Dot(pv) + + --print("simples 2 i j", uv_up, uv_pv) + + if uv_up >= 0 and uv_pv >= 0 then + --print("and we got here??") + local uvp = uv:Dot(p) + local direction = uvp < 0 and -uv or uv + return direction, a0, a1, b0, b1, c0, c1 + end + + --print("no we got here") + + local u_u = u:Dot(u) + local v_v = v:Dot(v) + local uDist = uv_up/(u_u*v.magnitude) + local vDist = uv_pv/(v_v*u.magnitude) + local minDist2 = math.min(uDist, vDist) + + if vDist == minDist2 then + u = v + b0 = c0 + b1 = c1 + up = -pv + uv = -uv + u_u = v_v + end + + local p_u = p:Dot(u) + + if p_u >= 0 then + local direction = up:Cross(u) + --print("got here!") + if direction.magnitude == 0 then + --print("the magnitude is 0") + direction = uv + end + return direction, a0, a1, b0, b1 + end + + local direction = p + if direction.magnitude == 0 then + direction = uv + end + return direction, a0, a0 +end +*/ + +/* +-- a is always the new one +local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) + --debug.profilebegin("reduceSimplex3") + local a = a1 - a0 + local b = b1 - b0 + local c = c1 - c0 + local d = d1 - d0 + + local p = -a + local u = b - a + local v = c - a + local w = d - a + + local uv = u:Cross(v) + local vw = v:Cross(w) + local wu = w:Cross(u) + local uvw = uv:Dot(w) + local pvw = vw:Dot(p) + local upw = wu:Dot(p) + local uvp = uv:Dot(p) + + if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then + local direction = Vector3.new(0, 0, 0) + return direction, a0, a1, b0, b1, c0, c1, d0, d1 + end + + local uvwSign = uvw < 0 and -1 or uvw > 0 and 1 or 0 + local uvDist = uvp*uvwSign/uv.magnitude + local vwDist = pvw*uvwSign/vw.magnitude + local wuDist = upw*uvwSign/wu.magnitude + local minDist3 = math.min(uvDist, vwDist, wuDist) + + if vwDist == minDist3 then + u, v = v, w + b0, c0 = c0, d0 + b1, c1 = c1, d1 + uv = vw + uvp = pvw + elseif wuDist == minDist3 then + u, v = w, u + b0, c0 = d0, b0 + b1, c1 = d1, b1 + uv = wu + uvp = upw + end + + local up = u:Cross(p) + local pv = p:Cross(v) + local uv_up = uv:Dot(up) + local uv_pv = uv:Dot(pv) + + if uv_up >= 0 and uv_pv >= 0 then + local direction = uvw < 0 and uv or -uv + return direction, a0, a1, b0, b1, c0, c1 + end + + local u_u = u:Dot(u) + local v_v = v:Dot(v) + local uDist = uv_up/(u_u*v.magnitude) + local vDist = uv_pv/(v_v*u.magnitude) + local minDist2 = math.min(uDist, vDist) + + if vDist == minDist2 then + u = v + b0 = c0 + b1 = c1 + up = -pv + uv = -uv + u_u = v_v + end + + local p_u = p:Dot(u) + + if p_u >= 0 then + local direction = up:Cross(u) + if direction.magnitude == 0 then + direction = uvw < 0 and uv or -uv + end + return direction, a0, a1, b0, b1 + end + + local direction = p + if direction.magnitude == 0 then + direction = uvw < 0 and uv or -uv + end + return direction, a0, a1 +end +*/ + +/* +local function reduceSimplex(a0, a1, b0, b1, c0, c1, d0, d1) + if d0 then + return reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) + elseif c0 then + return reduceSimplex2(a0, a1, b0, b1, c0, c1) + elseif b0 then + return reduceSimplex1(a0, a1, b0, b1) + elseif a0 then + return reduceSimplex0(a0, a1) + else + error("can a simplex have 0 points?") + end +end +*/ + +fn reduce_simplex( + simplex:Simplex, +)->(Planar64Vec3,Simplex){ + match simplex.as_slice(){ + &[p0,p1,p2,p3]=>reduce_simplex_4(p0,p1,p2,p3), + &[p0,p1,p2]=>reduce_simplex_3(p0,p1,p2), + &[p0,p1]=>reduce_simplex_2(p0,p1), + &[p0]=>reduce_simplex_1(p0), + &[]=>reduce_simplex_0(), + _=>unreachable!(), + } +} + enum Expanded{ Expanded, Unexpanded, -- 2.49.1 From d00871f87f0e3061e5f0ef14e229e4b692490e86 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 21 Nov 2025 11:17:19 -0800 Subject: [PATCH 11/90] work --- engine/physics/src/minimum_difference.rs | 78 +++++++++++------------- engine/physics/src/model.rs | 2 +- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 567454db..2bf8316e 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -1,11 +1,12 @@ -use strafesnet_common::integer::{Planar64,Planar64Vec3}; +use strafesnet_common::integer::vec3; +use strafesnet_common::integer::vec3::Vector3; +use strafesnet_common::integer::{Fixed,Planar64,Planar64Vec3}; -use crate::model::{MeshQuery,SubmeshVertId,TransformedMesh,MinkowskiVert}; +use crate::model::{MeshQuery, MinkowskiMesh, MinkowskiVert, SubmeshVertId}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 -use MinkowskiVert::VertVert as PQ; const SIMPLEX_TETRAHEDRON:usize=4; type Simplex=arrayvec::ArrayVec; @@ -22,6 +23,16 @@ local function absDet(r, u, v, w) end end */ +fn simplex_abs_det_is_zero(simplex:&Simplex)->bool{ + match simplex.as_slice(){ + &[p0,p1,p2,p3]=>(p1-p0).cross(p2-p0).dot(p3-p0)==Fixed::ZERO, + &[p0,p1,p2]=>(p1-p0).cross(p2-p0)==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])}, + &[p0,p1]=>p1-p0==vec3::ZERO, + &[p0]=>1==0, + &[]=>1==0, + _=>unreachable!(), + } +} /* local function choosePerpendicularDirection(d) @@ -240,22 +251,6 @@ local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) end */ -/* -local function reduceSimplex(a0, a1, b0, b1, c0, c1, d0, d1) - if d0 then - return reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) - elseif c0 then - return reduceSimplex2(a0, a1, b0, b1, c0, c1) - elseif b0 then - return reduceSimplex1(a0, a1, b0, b1) - elseif a0 then - return reduceSimplex0(a0, a1) - else - error("can a simplex have 0 points?") - end -end -*/ - fn reduce_simplex( simplex:Simplex, )->(Planar64Vec3,Simplex){ @@ -281,14 +276,14 @@ pub struct MinimumDifference{ expanded:Expanded, } impl MinimumDifference{ - pub fn details(&self,p:&TransformedMesh,q:&TransformedMesh)->Details{ + pub fn details(&self,mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Details{ match self.expanded{ Expanded::Expanded=>{ // if testIntersection then // return hits // end // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(Vector3.zero, a0, a1, b0, b1, c0, c1) + // local posP, posQ = decompose(rel_pos, a0, a1, b0, b1, c0, c1) // return hits, -dist - radiusP - radiusQ, // posP - radiusP*norm, -norm, // posQ + radiusQ*norm, norm @@ -302,7 +297,7 @@ impl MinimumDifference{ // end // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) // if norm then - // local posP, posQ = decompose(Vector3.zero, u0, u1, v0, v1, w0, w1) + // local posP, posQ = decompose(rel_pos, u0, u1, v0, v1, w0, w1) // return true, -dist - radiusP - radiusQ, // posP - radiusP*norm, -norm, // posQ + radiusQ*norm, norm @@ -326,16 +321,13 @@ pub struct Details{ // queryQ, radiusQ, // exitRadius, testIntersection // ) -pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option{ +pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Option{ // local initialAxis = queryQ() - queryP() // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 - let mut direction=q.hint_point()-p.hint_point(); - let new_point=PQ( - p.farthest_vert(direction), - q.farthest_vert(-direction), - ); + let mut direction=mesh.hint_point()+rel_pos; + let new_point=mesh.farthest_vert(direction); let mut simplex=Simplex::from_iter([new_point]); // exitRadius = testIntersection and 0 or exitRadius or 1/0 @@ -343,32 +335,19 @@ pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option (exitRadius + radiusP + radiusQ)*direction.magnitude then - if direction.dot(next_point.position()).is_negative(){ + if direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ return None; } - // if - // direction:Dot(next_point - a) <= 0 or - // absDet(next_point, a, b, c) < 1e-6 - // then - // local norm = direction.unit - // local dist = a:Dot(norm) - // local hits = -dist < radiusP + radiusQ - // return Some(MinimumDifference::expanded()); - // end - // push_front if simplex.len()==simplex.capacity(){ // this is a dead case, new_simplex never has more than 3 elements @@ -379,6 +358,17 @@ pub fn minimum_difference(p:&TransformedMesh,q:&TransformedMesh)->Option{ mesh1, } } - fn farthest_vert(&self,dir:Planar64Vec3)->MinkowskiVert{ + pub fn farthest_vert(&self,dir:Planar64Vec3)->MinkowskiVert{ MinkowskiVert::VertVert(self.mesh0.farthest_vert(dir),self.mesh1.farthest_vert(-dir)) } fn next_transition_vert(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Fixed<2,64>,infinity_dir:Planar64Vec3,point:Planar64Vec3)->Transition{ -- 2.49.1 From 978659e8c6b78da9483863100edabf3e80471c19 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 21 Nov 2025 11:23:32 -0800 Subject: [PATCH 12/90] work --- engine/physics/src/minimum_difference.rs | 34 +++++++++++++++++------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 2bf8316e..3e1e32e0 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -23,13 +23,29 @@ local function absDet(r, u, v, w) end end */ -fn simplex_abs_det_is_zero(simplex:&Simplex)->bool{ +fn simplex_abs_det_is_zero(mesh:&MinkowskiMesh,simplex:&Simplex)->bool{ match simplex.as_slice(){ - &[p0,p1,p2,p3]=>(p1-p0).cross(p2-p0).dot(p3-p0)==Fixed::ZERO, - &[p0,p1,p2]=>(p1-p0).cross(p2-p0)==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])}, - &[p0,p1]=>p1-p0==vec3::ZERO, - &[p0]=>1==0, - &[]=>1==0, + &[p0,p1,p2,p3]=>{ + let p0=mesh.vert(p0); + let p1=mesh.vert(p1); + let p2=mesh.vert(p2); + let p3=mesh.vert(p3); + (p1-p0).cross(p2-p0).dot(p3-p0)==Fixed::ZERO + }, + &[p0,p1,p2]=>{ + const P128V3_ZERO:Vector3>=Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO]); + let p0=mesh.vert(p0); + let p1=mesh.vert(p1); + let p2=mesh.vert(p2); + (p1-p0).cross(p2-p0)==P128V3_ZERO + }, + &[p0,p1]=>{ + let p0=mesh.vert(p0); + let p1=mesh.vert(p1); + p1-p0==vec3::ZERO + }, + &[_p0]=>false,// 1 == 0 + &[]=>false, _=>unreachable!(), } } @@ -283,7 +299,7 @@ impl MinimumDifference{ // return hits // end // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(rel_pos, a0, a1, b0, b1, c0, c1) + // local posP, posQ = decompose(-rel_pos, a0, a1, b0, b1, c0, c1) // return hits, -dist - radiusP - radiusQ, // posP - radiusP*norm, -norm, // posQ + radiusQ*norm, norm @@ -297,7 +313,7 @@ impl MinimumDifference{ // end // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) // if norm then - // local posP, posQ = decompose(rel_pos, u0, u1, v0, v1, w0, w1) + // local posP, posQ = decompose(-rel_pos, u0, u1, v0, v1, w0, w1) // return true, -dist - radiusP - radiusQ, // posP - radiusP*norm, -norm, // posQ + radiusQ*norm, norm @@ -362,7 +378,7 @@ pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Option Date: Fri, 21 Nov 2025 12:12:29 -0800 Subject: [PATCH 13/90] work --- engine/physics/src/minimum_difference.rs | 146 ++++++++++++++--------- 1 file changed, 90 insertions(+), 56 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 3e1e32e0..d3ed774e 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -2,7 +2,7 @@ use strafesnet_common::integer::vec3; use strafesnet_common::integer::vec3::Vector3; use strafesnet_common::integer::{Fixed,Planar64,Planar64Vec3}; -use crate::model::{MeshQuery, MinkowskiMesh, MinkowskiVert, SubmeshVertId}; +use crate::model::{MeshQuery,MinkowskiMesh,MinkowskiVert,SubmeshVertId}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 @@ -63,56 +63,103 @@ local function choosePerpendicularDirection(d) end end */ +fn choose_perpendicular_direction(d:Planar64Vec3)->Planar64Vec3{ + let x=d.x.abs(); + let y=d.y.abs(); + let z=d.z.abs(); + match x.min(y).min(z){ + min if min==x=>Vector3::new([y*y+z*z,-x*y,-x*z]).wrap_1(), + min if min==y=>Vector3::new([-x*y,x*x+z*z,-y*z]).wrap_1(), + min if min==z=>Vector3::new([-x*z,-y*z,x*x+y*y]).wrap_1(), + _=>unreachable!(), + } +} -/* -local function chooseAnyDirection() - return Vector3.new(1, 0, 0) -end -*/ +const fn choose_any_direction()->Planar64Vec3{ + vec3::X +} -/* -local function reduceSimplex0(a0, a1) - --debug.profilebegin("reduceSimplex0") - local a = a1 - a0 +fn reduce_simplex( + mesh:&MinkowskiMesh, + mut simplex:Simplex, +)->(Planar64Vec3,Simplex){ + match simplex.len(){ + 0=>(choose_any_direction(),simplex), + // local function reduceSimplex0(a0, a1) + 1=>{ + // --debug.profilebegin("reduceSimplex0") + // local a = a1 - a0 + let p0=mesh.vert(simplex[0]); - local p = -a + // local p = -a + let p=-p0; - local direction = p - if direction.magnitude == 0 then - direction = chooseAnyDirection() - end - return direction, a0, a1 -end -*/ + // local direction = p + let mut direction=p; -/* -local function reduceSimplex1(a0, a1, b0, b1) - --debug.profilebegin("reduceSimplex1") - local a = a1 - a0 - local b = b1 - b0 + // if direction.magnitude == 0 then + // direction = chooseAnyDirection() + if direction==vec3::ZERO{ + direction=choose_any_direction(); + } - local p = -a - local u = b - a + // return direction, a0, a1 + (direction,simplex) + }, + // local function reduceSimplex1(a0, a1, b0, b1) + 2=>{ + // --debug.profilebegin("reduceSimplex1") + // local a = a1 - a0 + // local b = b1 - b0 + let p0=mesh.vert(simplex[0]); + let p1=mesh.vert(simplex[1]); - -- modify to take into account the radiuses - local p_u = p:Dot(u) + // local p = -a + // local u = b - a + let p=-p0; + let u=p1-p0; - if p_u >= 0 then - local direction = u:Cross(p):Cross(u) - if direction.magnitude == 0 then - direction = choosePerpendicularDirection(u) - end - -- modify the direction to take into account a0R and b0R - return direction, a0, a1, b0, b1 - end + // -- modify to take into account the radiuses + // local p_u = p:Dot(u) + let p_u=p.dot(u); - local direction = p - if direction.magnitude == 0 then - direction = choosePerpendicularDirection(u) - end - return direction, a0, a1 -end -*/ + // if p_u >= 0 then + if !p_u.is_negative(){ + // local direction = u:Cross(p):Cross(u) + let mut direction=u.cross(p).cross(u); + + // if direction.magnitude == 0 then + if direction==Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO]){ + return (choose_perpendicular_direction(u),simplex); + } + + // -- modify the direction to take into account a0R and b0R + // return direction, a0, a1, b0, b1 + return (direction.narrow_1().unwrap(),simplex) + } + + simplex.pop(); + + // local direction = p + let mut direction=p; + + // if direction.magnitude == 0 then + if direction==vec3::ZERO{ + direction=choose_perpendicular_direction(u); + } + + // return direction, a0, a1 + (direction,simplex) + }, + 3=>{ + (_,_) + }, + 4=>{ + (_,_) + }, + _=>unreachable!(), + } +} /* local function reduceSimplex2(a0, a1, b0, b1, c0, c1) @@ -267,19 +314,6 @@ local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) end */ -fn reduce_simplex( - simplex:Simplex, -)->(Planar64Vec3,Simplex){ - match simplex.as_slice(){ - &[p0,p1,p2,p3]=>reduce_simplex_4(p0,p1,p2,p3), - &[p0,p1,p2]=>reduce_simplex_3(p0,p1,p2), - &[p0,p1]=>reduce_simplex_2(p0,p1), - &[p0]=>reduce_simplex_1(p0), - &[]=>reduce_simplex_0(), - _=>unreachable!(), - } -} - enum Expanded{ Expanded, Unexpanded, @@ -386,6 +420,6 @@ pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Option Date: Fri, 21 Nov 2025 12:39:17 -0800 Subject: [PATCH 14/90] work --- engine/physics/src/minimum_difference.rs | 163 +++++++++++++---------- 1 file changed, 96 insertions(+), 67 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index d3ed774e..6d8785e3 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -33,11 +33,10 @@ fn simplex_abs_det_is_zero(mesh:&MinkowskiMesh,simplex:&Simplex)->bool{ (p1-p0).cross(p2-p0).dot(p3-p0)==Fixed::ZERO }, &[p0,p1,p2]=>{ - const P128V3_ZERO:Vector3>=Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO]); let p0=mesh.vert(p0); let p1=mesh.vert(p1); let p2=mesh.vert(p2); - (p1-p0).cross(p2-p0)==P128V3_ZERO + (p1-p0).cross(p2-p0)==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])} }, &[p0,p1]=>{ let p0=mesh.vert(p0); @@ -129,7 +128,7 @@ fn reduce_simplex( let mut direction=u.cross(p).cross(u); // if direction.magnitude == 0 then - if direction==Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO]){ + if direction==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])}{ return (choose_perpendicular_direction(u),simplex); } @@ -151,8 +150,101 @@ fn reduce_simplex( // return direction, a0, a1 (direction,simplex) }, + // local function reduceSimplex2(a0, a1, b0, b1, c0, c1) 3=>{ - (_,_) + // --debug.profilebegin("reduceSimplex2") + // local a = a1 - a0 + // local b = b1 - b0 + // local c = c1 - c0 + let p0=mesh.vert(simplex[0]); + let p1=mesh.vert(simplex[1]); + let p2=mesh.vert(simplex[2]); + + // local p = -a + // local u = b - a + // local v = c - a + let p=-p0; + let mut u=p1-p0; + let v=p2-p0; + + // local uv = u:Cross(v) + // local up = u:Cross(p) + // local pv = p:Cross(v) + // local uv_up = uv:Dot(up) + // local uv_pv = uv:Dot(pv) + let mut uv=u.cross(v); + let mut up=u.cross(p); + let pv=p.cross(v); + let uv_up=uv.dot(up); + let uv_pv=uv.dot(pv); + + // if uv_up >= 0 and uv_pv >= 0 then + if !uv_up.is_negative()&&!uv_pv.is_negative(){ + // local uvp = uv:Dot(p) + let uvp=uv.dot(p); + + // local direction = uvp < 0 and -uv or uv + let direction=if uvp.is_negative(){ + -uv + }else{ + uv + }; + + // return direction, a0, a1, b0, b1, c0, c1 + return (direction.narrow_1().unwrap(),simplex) + } + + // local u_u = u:Dot(u) + // local v_v = v:Dot(v) + // local uDist = uv_up/(u_u*v.magnitude) + // local vDist = uv_pv/(v_v*u.magnitude) + // local minDist2 = math.min(uDist, vDist) + let u_u=u.dot(u); + let v_v=v.dot(v); + let u_dist=uv_up*(v_v*u.length()); + let v_dist=uv_pv*(u_u*v.length()); + + // if vDist == minDist2 then + if v_dist= 0 then + if !p_u.is_negative(){ + // local direction = up:Cross(u) + let direction=up.cross(u); + // if direction.magnitude == 0 then + if direction==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])}{ + // direction = uv + return (uv.narrow_1().unwrap(),simplex) + } + + // return direction, a0, a1, b0, b1 + return (direction.narrow_1().unwrap(),simplex) + } + + simplex.pop(); + + // local direction = p + let direction=p; + // if direction.magnitude == 0 then + if direction==vec3::ZERO{ + // direction = uv + return (uv.narrow_1().unwrap(),simplex) + } + // return direction, a0, a0 + (direction,simplex) }, 4=>{ (_,_) @@ -161,69 +253,6 @@ fn reduce_simplex( } } -/* -local function reduceSimplex2(a0, a1, b0, b1, c0, c1) - --debug.profilebegin("reduceSimplex2") - local a = a1 - a0 - local b = b1 - b0 - local c = c1 - c0 - - local p = -a - local u = b - a - local v = c - a - - local uv = u:Cross(v) - local up = u:Cross(p) - local pv = p:Cross(v) - local uv_up = uv:Dot(up) - local uv_pv = uv:Dot(pv) - - --print("simples 2 i j", uv_up, uv_pv) - - if uv_up >= 0 and uv_pv >= 0 then - --print("and we got here??") - local uvp = uv:Dot(p) - local direction = uvp < 0 and -uv or uv - return direction, a0, a1, b0, b1, c0, c1 - end - - --print("no we got here") - - local u_u = u:Dot(u) - local v_v = v:Dot(v) - local uDist = uv_up/(u_u*v.magnitude) - local vDist = uv_pv/(v_v*u.magnitude) - local minDist2 = math.min(uDist, vDist) - - if vDist == minDist2 then - u = v - b0 = c0 - b1 = c1 - up = -pv - uv = -uv - u_u = v_v - end - - local p_u = p:Dot(u) - - if p_u >= 0 then - local direction = up:Cross(u) - --print("got here!") - if direction.magnitude == 0 then - --print("the magnitude is 0") - direction = uv - end - return direction, a0, a1, b0, b1 - end - - local direction = p - if direction.magnitude == 0 then - direction = uv - end - return direction, a0, a0 -end -*/ - /* -- a is always the new one local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) -- 2.49.1 From 03b72301a3140035adfc44b93509f59db1cc4fe8 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 21 Nov 2025 12:44:50 -0800 Subject: [PATCH 15/90] eugh --- engine/physics/src/minimum_difference.rs | 190 ++++++++++++----------- 1 file changed, 100 insertions(+), 90 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 6d8785e3..098d735e 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -246,103 +246,113 @@ fn reduce_simplex( // return direction, a0, a0 (direction,simplex) }, + // local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) 4=>{ + // --debug.profilebegin("reduceSimplex3") + // local a = a1 - a0 + // local b = b1 - b0 + // local c = c1 - c0 + // local d = d1 - d0 + let p0=mesh.vert(simplex[0]); + let p1=mesh.vert(simplex[1]); + let p2=mesh.vert(simplex[2]); + let p3=mesh.vert(simplex[3]); + + // local p = -a + // local u = b - a + // local v = c - a + // local w = d - a + let p=-p0; + let u=p1-p0; + let v=p2-p0; + let w=p3-p0; + + // local uv = u:Cross(v) + // local vw = v:Cross(w) + // local wu = w:Cross(u) + // local uvw = uv:Dot(w) + // local pvw = vw:Dot(p) + // local upw = wu:Dot(p) + // local uvp = uv:Dot(p) + let uv = u.cross(v); + let vw = v.cross(w); + let wu = w.cross(u); + let uv_w = uv.dot(w); + let pv_w = vw.dot(p); + let up_w = wu.dot(p); + let uv_p = uv.dot(p); + + // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then + // local direction = Vector3.new(0, 0, 0) + // return direction, a0, a1, b0, b1, c0, c1, d0, d1 + // end + + // local uvwSign = uvw < 0 and -1 or uvw > 0 and 1 or 0 + // local uvDist = uvp*uvwSign/uv.magnitude + // local vwDist = pvw*uvwSign/vw.magnitude + // local wuDist = upw*uvwSign/wu.magnitude + // local minDist3 = math.min(uvDist, vwDist, wuDist) + + // if vwDist == minDist3 then + // u, v = v, w + // b0, c0 = c0, d0 + // b1, c1 = c1, d1 + // uv = vw + // uvp = pvw + // elseif wuDist == minDist3 then + // u, v = w, u + // b0, c0 = d0, b0 + // b1, c1 = d1, b1 + // uv = wu + // uvp = upw + // end + + // local up = u:Cross(p) + // local pv = p:Cross(v) + // local uv_up = uv:Dot(up) + // local uv_pv = uv:Dot(pv) + + // if uv_up >= 0 and uv_pv >= 0 then + // local direction = uvw < 0 and uv or -uv + // return direction, a0, a1, b0, b1, c0, c1 + // end + + // local u_u = u:Dot(u) + // local v_v = v:Dot(v) + // local uDist = uv_up/(u_u*v.magnitude) + // local vDist = uv_pv/(v_v*u.magnitude) + // local minDist2 = math.min(uDist, vDist) + + // if vDist == minDist2 then + // u = v + // b0 = c0 + // b1 = c1 + // up = -pv + // uv = -uv + // u_u = v_v + // end + + // local p_u = p:Dot(u) + + // if p_u >= 0 then + // local direction = up:Cross(u) + // if direction.magnitude == 0 then + // direction = uvw < 0 and uv or -uv + // end + // return direction, a0, a1, b0, b1 + // end + + // local direction = p + // if direction.magnitude == 0 then + // direction = uvw < 0 and uv or -uv + // end + // return direction, a0, a1 (_,_) }, _=>unreachable!(), } } -/* --- a is always the new one -local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) - --debug.profilebegin("reduceSimplex3") - local a = a1 - a0 - local b = b1 - b0 - local c = c1 - c0 - local d = d1 - d0 - - local p = -a - local u = b - a - local v = c - a - local w = d - a - - local uv = u:Cross(v) - local vw = v:Cross(w) - local wu = w:Cross(u) - local uvw = uv:Dot(w) - local pvw = vw:Dot(p) - local upw = wu:Dot(p) - local uvp = uv:Dot(p) - - if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then - local direction = Vector3.new(0, 0, 0) - return direction, a0, a1, b0, b1, c0, c1, d0, d1 - end - - local uvwSign = uvw < 0 and -1 or uvw > 0 and 1 or 0 - local uvDist = uvp*uvwSign/uv.magnitude - local vwDist = pvw*uvwSign/vw.magnitude - local wuDist = upw*uvwSign/wu.magnitude - local minDist3 = math.min(uvDist, vwDist, wuDist) - - if vwDist == minDist3 then - u, v = v, w - b0, c0 = c0, d0 - b1, c1 = c1, d1 - uv = vw - uvp = pvw - elseif wuDist == minDist3 then - u, v = w, u - b0, c0 = d0, b0 - b1, c1 = d1, b1 - uv = wu - uvp = upw - end - - local up = u:Cross(p) - local pv = p:Cross(v) - local uv_up = uv:Dot(up) - local uv_pv = uv:Dot(pv) - - if uv_up >= 0 and uv_pv >= 0 then - local direction = uvw < 0 and uv or -uv - return direction, a0, a1, b0, b1, c0, c1 - end - - local u_u = u:Dot(u) - local v_v = v:Dot(v) - local uDist = uv_up/(u_u*v.magnitude) - local vDist = uv_pv/(v_v*u.magnitude) - local minDist2 = math.min(uDist, vDist) - - if vDist == minDist2 then - u = v - b0 = c0 - b1 = c1 - up = -pv - uv = -uv - u_u = v_v - end - - local p_u = p:Dot(u) - - if p_u >= 0 then - local direction = up:Cross(u) - if direction.magnitude == 0 then - direction = uvw < 0 and uv or -uv - end - return direction, a0, a1, b0, b1 - end - - local direction = p - if direction.magnitude == 0 then - direction = uvw < 0 and uv or -uv - end - return direction, a0, a1 -end -*/ - enum Expanded{ Expanded, Unexpanded, -- 2.49.1 From 91636747d4ebe87fad9ebba7a9909e39fef1ce5b Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Fri, 21 Nov 2025 12:46:54 -0800 Subject: [PATCH 16/90] idea --- engine/physics/src/minimum_difference.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 098d735e..b171b386 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -8,6 +8,11 @@ use crate::model::{MeshQuery,MinkowskiMesh,MinkowskiVert,SubmeshVertId}; // written by Trey Reynolds in 2021 const SIMPLEX_TETRAHEDRON:usize=4; +// TODO: consider using an enum? +// enum Simplex{ +// Simplex1([Vert;1]), +// Simplex2([Vert;2]), +// } type Simplex=arrayvec::ArrayVec; /* -- 2.49.1 From f9ed33073eb60933301cb064324dde57d4bc2593 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Sat, 22 Nov 2025 08:52:02 -0800 Subject: [PATCH 17/90] zero --- engine/physics/src/minimum_difference.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index b171b386..834b71db 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -46,7 +46,7 @@ fn simplex_abs_det_is_zero(mesh:&MinkowskiMesh,simplex:&Simplex)->bool{ &[p0,p1]=>{ let p0=mesh.vert(p0); let p1=mesh.vert(p1); - p1-p0==vec3::ZERO + p1-p0==vec3::zero() }, &[_p0]=>false,// 1 == 0 &[]=>false, @@ -103,7 +103,7 @@ fn reduce_simplex( // if direction.magnitude == 0 then // direction = chooseAnyDirection() - if direction==vec3::ZERO{ + if direction==vec3::zero(){ direction=choose_any_direction(); } @@ -148,7 +148,7 @@ fn reduce_simplex( let mut direction=p; // if direction.magnitude == 0 then - if direction==vec3::ZERO{ + if direction==vec3::zero(){ direction=choose_perpendicular_direction(u); } @@ -230,7 +230,7 @@ fn reduce_simplex( // local direction = up:Cross(u) let direction=up.cross(u); // if direction.magnitude == 0 then - if direction==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])}{ + if direction==vec3::zero(){ // direction = uv return (uv.narrow_1().unwrap(),simplex) } @@ -244,7 +244,7 @@ fn reduce_simplex( // local direction = p let direction=p; // if direction.magnitude == 0 then - if direction==vec3::ZERO{ + if direction==vec3::zero(){ // direction = uv return (uv.narrow_1().unwrap(),simplex) } -- 2.49.1 From e1dac67aa0f6e682feb75e0e4458a2c043565ee4 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 10:40:27 -0800 Subject: [PATCH 18/90] notes --- engine/physics/src/minimum_difference.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 834b71db..0ef37155 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -373,9 +373,14 @@ impl MinimumDifference{ pub fn details(&self,mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Details{ match self.expanded{ Expanded::Expanded=>{ + // local norm = direction.unit + // local dist = a:Dot(norm) + // local hits = -dist < radiusP + radiusQ // if testIntersection then // return hits // end + // NOTE: if hits is true, this if statement necessarily evaluates to true. + // i.e. hits implies this statement // if -dist <= exitRadius + radiusP + radiusQ then // local posP, posQ = decompose(-rel_pos, a0, a1, b0, b1, c0, c1) // return hits, -dist - radiusP - radiusQ, @@ -457,9 +462,6 @@ pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Option Date: Mon, 24 Nov 2025 11:24:40 -0800 Subject: [PATCH 19/90] work --- engine/physics/src/minimum_difference.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 0ef37155..cd5adb3b 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -288,9 +288,15 @@ fn reduce_simplex( let uv_p = uv.dot(p); // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then - // local direction = Vector3.new(0, 0, 0) - // return direction, a0, a1, b0, b1, c0, c1, d0, d1 - // end + // TODO: reduce this + if (pv_w.is_zero()||pv_w.is_negative()^uv_w.is_negative()) + ||(up_w.is_zero()||up_w.is_negative()^uv_w.is_negative()) + ||(uv_p.is_zero()||uv_p.is_negative()^uv_w.is_negative()){ + // origin is contained, this is a positive detection + // local direction = Vector3.new(0, 0, 0) + // return direction, a0, a1, b0, b1, c0, c1, d0, d1 + return (vec3::zero(),simplex); + } // local uvwSign = uvw < 0 and -1 or uvw > 0 and 1 or 0 // local uvDist = uvp*uvwSign/uv.magnitude -- 2.49.1 From 2c1fa5da223f3fe2d54d47900304dfeb452b4329 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 11:33:33 -0800 Subject: [PATCH 20/90] work --- engine/physics/src/minimum_difference.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index cd5adb3b..8902e612 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -288,10 +288,9 @@ fn reduce_simplex( let uv_p = uv.dot(p); // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then - // TODO: reduce this - if (pv_w.is_zero()||pv_w.is_negative()^uv_w.is_negative()) - ||(up_w.is_zero()||up_w.is_negative()^uv_w.is_negative()) - ||(uv_p.is_zero()||uv_p.is_negative()^uv_w.is_negative()){ + if !pv_w.div_sign(uv_w).is_negative() + ||!up_w.div_sign(uv_w).is_negative() + ||!uv_p.div_sign(uv_w).is_negative(){ // origin is contained, this is a positive detection // local direction = Vector3.new(0, 0, 0) // return direction, a0, a1, b0, b1, c0, c1, d0, d1 @@ -303,6 +302,10 @@ fn reduce_simplex( // local vwDist = pvw*uvwSign/vw.magnitude // local wuDist = upw*uvwSign/wu.magnitude // local minDist3 = math.min(uvDist, vwDist, wuDist) + let uv_dist=uv_p.mul_sign(uv_w)*vw.length()*wu.length(); + let vw_dist=pv_w.mul_sign(uv_w)*wu.length()*uv.length(); + let wu_dist=up_w.mul_sign(uv_w)*uv.length()*vw.length(); + let min_dist=uv_dist.min(vw_dist).min(wu_dist); // if vwDist == minDist3 then // u, v = v, w -- 2.49.1 From 6160872469f22319d4cf8a65f18c44b69ef0c09d Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 11:40:52 -0800 Subject: [PATCH 21/90] work --- engine/physics/src/minimum_difference.rs | 38 ++++++++++++++---------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 8902e612..51c664d2 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -268,8 +268,8 @@ fn reduce_simplex( // local v = c - a // local w = d - a let p=-p0; - let u=p1-p0; - let v=p2-p0; + let mut u=p1-p0; + let mut v=p2-p0; let w=p3-p0; // local uv = u:Cross(v) @@ -279,13 +279,13 @@ fn reduce_simplex( // local pvw = vw:Dot(p) // local upw = wu:Dot(p) // local uvp = uv:Dot(p) - let uv = u.cross(v); + let mut uv = u.cross(v); let vw = v.cross(w); let wu = w.cross(u); let uv_w = uv.dot(w); let pv_w = vw.dot(p); let up_w = wu.dot(p); - let uv_p = uv.dot(p); + let mut uv_p = uv.dot(p); // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then if !pv_w.div_sign(uv_w).is_negative() @@ -308,18 +308,26 @@ fn reduce_simplex( let min_dist=uv_dist.min(vw_dist).min(wu_dist); // if vwDist == minDist3 then - // u, v = v, w - // b0, c0 = c0, d0 - // b1, c1 = c1, d1 - // uv = vw - // uvp = pvw + if vw_dist==min_dist{ + (u,v)=(v,w); + uv=vw; + uv_p=pv_w; + // b0, c0 = c0, d0 + // b1, c1 = c1, d1 + simplex[1]=simplex[2]; + simplex[2]=simplex[3]; // elseif wuDist == minDist3 then - // u, v = w, u - // b0, c0 = d0, b0 - // b1, c1 = d1, b1 - // uv = wu - // uvp = upw - // end + }else if wu_dist==min_dist{ + (u,v)=(w,u); + uv=wu; + uv_p=up_w; + // b0, c0 = d0, b0 + // b1, c1 = d1, b1 + simplex[2]=simplex[1]; + simplex[1]=simplex[3]; + } + + simplex.pop(); // local up = u:Cross(p) // local pv = p:Cross(v) -- 2.49.1 From be05fd108a9ac4a9c64733028b3dc33603a95489 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 11:53:08 -0800 Subject: [PATCH 22/90] work --- engine/physics/src/minimum_difference.rs | 82 ++++++++++++++++++------ 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 51c664d2..c951debd 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -130,7 +130,7 @@ fn reduce_simplex( // if p_u >= 0 then if !p_u.is_negative(){ // local direction = u:Cross(p):Cross(u) - let mut direction=u.cross(p).cross(u); + let direction=u.cross(p).cross(u); // if direction.magnitude == 0 then if direction==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])}{ @@ -204,7 +204,7 @@ fn reduce_simplex( // local uDist = uv_up/(u_u*v.magnitude) // local vDist = uv_pv/(v_v*u.magnitude) // local minDist2 = math.min(uDist, vDist) - let u_u=u.dot(u); + let mut u_u=u.dot(u); let v_v=v.dot(v); let u_dist=uv_up*(v_v*u.length()); let v_dist=uv_pv*(u_u*v.length()); @@ -333,43 +333,83 @@ fn reduce_simplex( // local pv = p:Cross(v) // local uv_up = uv:Dot(up) // local uv_pv = uv:Dot(pv) + let mut up = u.cross(p); + let pv = p.cross(v); + let uv_up = uv.dot(up); + let uv_pv = uv.dot(pv); // if uv_up >= 0 and uv_pv >= 0 then - // local direction = uvw < 0 and uv or -uv - // return direction, a0, a1, b0, b1, c0, c1 - // end + if !uv_up.is_negative()&&!uv_pv.is_negative(){ + // local direction = uvw < 0 and uv or -uv + // return direction, a0, a1, b0, b1, c0, c1 + if uv_w.is_negative(){ + return (uv.narrow_1().unwrap(),simplex); + }else{ + return (-uv.narrow_1().unwrap(),simplex); + } + } // local u_u = u:Dot(u) // local v_v = v:Dot(v) // local uDist = uv_up/(u_u*v.magnitude) // local vDist = uv_pv/(v_v*u.magnitude) // local minDist2 = math.min(uDist, vDist) + let mut u_u=u.dot(u); + let v_v=v.dot(v); + let u_dist=uv_up*(v_v*u.length()); + let v_dist=uv_pv*(u_u*v.length()); // if vDist == minDist2 then - // u = v - // b0 = c0 - // b1 = c1 - // up = -pv - // uv = -uv - // u_u = v_v - // end + if v_dist= 0 then - // local direction = up:Cross(u) - // if direction.magnitude == 0 then - // direction = uvw < 0 and uv or -uv - // end - // return direction, a0, a1, b0, b1 - // end + if !p_u.is_negative(){ + // local direction = up:Cross(u) + let direction=up.cross(u); + // if direction.magnitude == 0 then + if direction==vec3::zero(){ + // direction = uvw < 0 and uv or -uv + // return direction, a0, a1, b0, b1 + if uv_w.is_negative(){ + return (uv.narrow_1().unwrap(),simplex); + }else{ + return (-uv.narrow_1().unwrap(),simplex); + } + } + + // return direction, a0, a1, b0, b1 + return (direction.narrow_1().unwrap(),simplex) + } + + simplex.pop(); // local direction = p + let direction=p; // if direction.magnitude == 0 then - // direction = uvw < 0 and uv or -uv - // end + if direction==vec3::zero(){ + // direction = uvw < 0 and uv or -uv + if uv_w.is_negative(){ + return (uv.narrow_1().unwrap(),simplex); + }else{ + return (-uv.narrow_1().unwrap(),simplex); + } + } + // return direction, a0, a1 - (_,_) + (direction,simplex) }, _=>unreachable!(), } -- 2.49.1 From 8a9db203fa5a3e78397d86ae38da272477a4bb44 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 11:55:21 -0800 Subject: [PATCH 23/90] remove unused --- engine/physics/src/minimum_difference.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index c951debd..2ddf9031 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -204,7 +204,7 @@ fn reduce_simplex( // local uDist = uv_up/(u_u*v.magnitude) // local vDist = uv_pv/(v_v*u.magnitude) // local minDist2 = math.min(uDist, vDist) - let mut u_u=u.dot(u); + let u_u=u.dot(u); let v_v=v.dot(v); let u_dist=uv_up*(v_v*u.length()); let v_dist=uv_pv*(u_u*v.length()); @@ -214,7 +214,7 @@ fn reduce_simplex( u=v; up=-pv; uv=-uv; - u_u=v_v; + // u_u=v_v; // unused // b0 = c0 // b1 = c1 simplex[1]=simplex[2]; @@ -285,7 +285,7 @@ fn reduce_simplex( let uv_w = uv.dot(w); let pv_w = vw.dot(p); let up_w = wu.dot(p); - let mut uv_p = uv.dot(p); + let uv_p = uv.dot(p); // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then if !pv_w.div_sign(uv_w).is_negative() @@ -311,7 +311,7 @@ fn reduce_simplex( if vw_dist==min_dist{ (u,v)=(v,w); uv=vw; - uv_p=pv_w; + // uv_p=pv_w; // unused // b0, c0 = c0, d0 // b1, c1 = c1, d1 simplex[1]=simplex[2]; @@ -320,7 +320,7 @@ fn reduce_simplex( }else if wu_dist==min_dist{ (u,v)=(w,u); uv=wu; - uv_p=up_w; + // uv_p=up_w; // unused // b0, c0 = d0, b0 // b1, c1 = d1, b1 simplex[2]=simplex[1]; @@ -354,7 +354,7 @@ fn reduce_simplex( // local uDist = uv_up/(u_u*v.magnitude) // local vDist = uv_pv/(v_v*u.magnitude) // local minDist2 = math.min(uDist, vDist) - let mut u_u=u.dot(u); + let u_u=u.dot(u); let v_v=v.dot(v); let u_dist=uv_up*(v_v*u.length()); let v_dist=uv_pv*(u_u*v.length()); @@ -364,7 +364,7 @@ fn reduce_simplex( u=v; up=-pv; uv=-uv; - u_u=v_v; + // u_u=v_v; // unused // b0 = c0 // b1 = c1 simplex[1]=simplex[2]; -- 2.49.1 From 4fdd254f2acc2b2b5929b091dc899262ffccfba8 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 12:06:24 -0800 Subject: [PATCH 24/90] remove is more clear --- engine/physics/src/minimum_difference.rs | 29 ++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 2ddf9031..b6c5df0c 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -142,7 +142,7 @@ fn reduce_simplex( return (direction.narrow_1().unwrap(),simplex) } - simplex.pop(); + simplex.remove(1); // local direction = p let mut direction=p; @@ -217,11 +217,11 @@ fn reduce_simplex( // u_u=v_v; // unused // b0 = c0 // b1 = c1 - simplex[1]=simplex[2]; + simplex.remove(1); + }else{ + simplex.remove(2); } - simplex.pop(); - // local p_u = p:Dot(u) let p_u=p.dot(u); @@ -239,7 +239,7 @@ fn reduce_simplex( return (direction.narrow_1().unwrap(),simplex) } - simplex.pop(); + simplex.remove(1); // local direction = p let direction=p; @@ -314,8 +314,7 @@ fn reduce_simplex( // uv_p=pv_w; // unused // b0, c0 = c0, d0 // b1, c1 = c1, d1 - simplex[1]=simplex[2]; - simplex[2]=simplex[3]; + simplex.remove(1); // elseif wuDist == minDist3 then }else if wu_dist==min_dist{ (u,v)=(w,u); @@ -323,12 +322,14 @@ fn reduce_simplex( // uv_p=up_w; // unused // b0, c0 = d0, b0 // b1, c1 = d1, b1 + // before [a,b,c,d] simplex[2]=simplex[1]; - simplex[1]=simplex[3]; + simplex.swap_remove(1); + // after [a,d,b] + }else{ + simplex.remove(2); } - simplex.pop(); - // local up = u:Cross(p) // local pv = p:Cross(v) // local uv_up = uv:Dot(up) @@ -367,11 +368,11 @@ fn reduce_simplex( // u_u=v_v; // unused // b0 = c0 // b1 = c1 - simplex[1]=simplex[2]; + simplex.remove(1); + }else{ + simplex.remove(2); } - simplex.pop(); - // local p_u = p:Dot(u) let p_u=p.dot(u); @@ -394,7 +395,7 @@ fn reduce_simplex( return (direction.narrow_1().unwrap(),simplex) } - simplex.pop(); + simplex.remove(1); // local direction = p let direction=p; -- 2.49.1 From df7bee6cd19ae0ab00633de5e683e623b3078b62 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 12:12:17 -0800 Subject: [PATCH 25/90] details later --- engine/physics/src/minimum_difference.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index b6c5df0c..fd3541f0 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -466,11 +466,11 @@ impl MinimumDifference{ } } pub struct Details{ - distance:Planar64, - p_pos:Planar64Vec3, - p_norm:Planar64Vec3, - q_pos:Planar64Vec3, - q_norm:Planar64Vec3, + // distance:Planar64, + // p_pos:Planar64Vec3, + // p_norm:Planar64Vec3, + // q_pos:Planar64Vec3, + // q_norm:Planar64Vec3, } // local function minimumDifference( -- 2.49.1 From 4470e88d7b0493e79701916235e720dbba207a8a Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 12:21:17 -0800 Subject: [PATCH 26/90] refactor calculation result --- engine/physics/src/minimum_difference.rs | 39 +++++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index fd3541f0..3a57336e 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -416,21 +416,23 @@ fn reduce_simplex( } } -enum Expanded{ - Expanded, - Unexpanded, -} - /// Intermediate data structure containing a partially complete calculation. /// Sometimes you only care if the meshes are intersecting, and not about the /// exact point of intersection details. -pub struct MinimumDifference{ - expanded:Expanded, +pub enum MinimumDifference{ + Expanded{}, + Unexpanded{}, } impl MinimumDifference{ - pub fn details(&self,mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Details{ - match self.expanded{ - Expanded::Expanded=>{ + fn expanded()->Option{ + unimplemented!() + } + fn unexpanded()->Self{ + unimplemented!() + } + pub fn topology(self,mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Topology{ + match self{ + Self::Expanded{}=>{ // local norm = direction.unit // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ @@ -446,9 +448,9 @@ impl MinimumDifference{ // posQ + radiusQ*norm, norm // end // return false - Details{} + Topology{} }, - Expanded::Unexpanded=>{ + Self::Unexpanded{}=>{ // if testIntersection then // return true // end @@ -460,11 +462,18 @@ impl MinimumDifference{ // posQ + radiusQ*norm, norm // end // return nil - Details{} + Topology{} }, } } } +pub struct Topology{ +} +impl Topology{ + pub fn details(self)->Details{ + unimplemented!() + } +} pub struct Details{ // distance:Planar64, // p_pos:Planar64Vec3, @@ -492,7 +501,7 @@ pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->OptionOption Date: Mon, 24 Nov 2025 13:28:12 -0800 Subject: [PATCH 27/90] insane trait just to remove if statements --- engine/physics/src/minimum_difference.rs | 124 +++++++++++++---------- 1 file changed, 70 insertions(+), 54 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 3a57336e..3f72b246 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -419,58 +419,11 @@ fn reduce_simplex( /// Intermediate data structure containing a partially complete calculation. /// Sometimes you only care if the meshes are intersecting, and not about the /// exact point of intersection details. -pub enum MinimumDifference{ - Expanded{}, - Unexpanded{}, -} -impl MinimumDifference{ - fn expanded()->Option{ - unimplemented!() - } - fn unexpanded()->Self{ - unimplemented!() - } - pub fn topology(self,mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Topology{ - match self{ - Self::Expanded{}=>{ - // local norm = direction.unit - // local dist = a:Dot(norm) - // local hits = -dist < radiusP + radiusQ - // if testIntersection then - // return hits - // end - // NOTE: if hits is true, this if statement necessarily evaluates to true. - // i.e. hits implies this statement - // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(-rel_pos, a0, a1, b0, b1, c0, c1) - // return hits, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return false - Topology{} - }, - Self::Unexpanded{}=>{ - // if testIntersection then - // return true - // end - // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) - // if norm then - // local posP, posQ = decompose(-rel_pos, u0, u1, v0, v1, w0, w1) - // return true, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return nil - Topology{} - }, - } - } -} pub struct Topology{ + simplex:Simplex, } impl Topology{ - pub fn details(self)->Details{ + pub fn details(self,mesh:&MinkowskiMesh)->Details{ unimplemented!() } } @@ -482,12 +435,75 @@ pub struct Details{ // q_norm:Planar64Vec3, } +trait Return{ + /// are we just testing for intersection + const IS_FAST:bool; + const FAST_FAIL:Self::Output; + type Output; + fn expanded(simplex:Simplex)->Self::Output; + fn unexpanded(simplex:Simplex)->Self::Output; +} +struct ReturnIntersect; +struct ReturnTopology; +impl Return for ReturnIntersect{ + type Output=bool; + const IS_FAST:bool=true; + const FAST_FAIL:Self::Output=false; + fn expanded(simplex:Simplex)->Self::Output{ + // local norm = direction.unit + // local dist = a:Dot(norm) + // local hits = -dist < radiusP + radiusQ + // return hits + unimplemented!() + } + fn unexpanded(_simplex:Simplex)->Self::Output{ + // intersection is guaranteed at this point + true + } +} +impl Return for ReturnTopology{ + type Output=Topology; + const IS_FAST:bool=false; + // this value is irrelevant and will never be returned! + const FAST_FAIL:Self::Output=Topology{simplex:Simplex::new_const()}; + fn expanded(simplex:Simplex)->Self::Output{ + // NOTE: if hits is true, this if statement necessarily evaluates to true. + // i.e. hits implies this statement + // if -dist <= exitRadius + radiusP + radiusQ then + // local posP, posQ = decompose(-rel_pos, a0, a1, b0, b1, c0, c1) + // return hits, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return false + unimplemented!() + } + fn unexpanded(simplex:Simplex)->Self::Output{ + // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) + // if norm then + // local posP, posQ = decompose(-rel_pos, u0, u1, v0, v1, w0, w1) + // return true, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return nil + unimplemented!() + } +} + +pub fn point_in_mesh(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->bool{ + minimum_difference::(mesh,rel_pos) +} +pub fn get_closest_fev(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Topology{ + minimum_difference::(mesh,rel_pos) +} + // local function minimumDifference( // queryP, radiusP, // queryQ, radiusQ, // exitRadius, testIntersection // ) -pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Option{ +fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->R::Output{ // local initialAxis = queryQ() - queryP() // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) @@ -501,7 +517,7 @@ pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->OptionOption (exitRadius + radiusP + radiusQ)*direction.magnitude then - if direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ - return None; + if R::IS_FAST&&direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ + return R::FAST_FAIL; } // push_front @@ -529,7 +545,7 @@ pub fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Option Date: Mon, 24 Nov 2025 13:41:08 -0800 Subject: [PATCH 28/90] switch trait to closures --- engine/physics/src/minimum_difference.rs | 120 +++++++++++------------ 1 file changed, 57 insertions(+), 63 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 3f72b246..2493650b 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -435,67 +435,55 @@ pub struct Details{ // q_norm:Planar64Vec3, } -trait Return{ - /// are we just testing for intersection - const IS_FAST:bool; - const FAST_FAIL:Self::Output; - type Output; - fn expanded(simplex:Simplex)->Self::Output; - fn unexpanded(simplex:Simplex)->Self::Output; -} -struct ReturnIntersect; -struct ReturnTopology; -impl Return for ReturnIntersect{ - type Output=bool; - const IS_FAST:bool=true; - const FAST_FAIL:Self::Output=false; - fn expanded(simplex:Simplex)->Self::Output{ - // local norm = direction.unit - // local dist = a:Dot(norm) - // local hits = -dist < radiusP + radiusQ - // return hits - unimplemented!() - } - fn unexpanded(_simplex:Simplex)->Self::Output{ - // intersection is guaranteed at this point - true - } -} -impl Return for ReturnTopology{ - type Output=Topology; - const IS_FAST:bool=false; - // this value is irrelevant and will never be returned! - const FAST_FAIL:Self::Output=Topology{simplex:Simplex::new_const()}; - fn expanded(simplex:Simplex)->Self::Output{ - // NOTE: if hits is true, this if statement necessarily evaluates to true. - // i.e. hits implies this statement - // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(-rel_pos, a0, a1, b0, b1, c0, c1) - // return hits, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return false - unimplemented!() - } - fn unexpanded(simplex:Simplex)->Self::Output{ - // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) - // if norm then - // local posP, posQ = decompose(-rel_pos, u0, u1, v0, v1, w0, w1) - // return true, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return nil - unimplemented!() - } -} - pub fn point_in_mesh(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->bool{ - minimum_difference::(mesh,rel_pos) + minimum_difference::(mesh,rel_pos, + // expanded + |_simplex|{ + // local norm = direction.unit + // local dist = a:Dot(norm) + // local hits = -dist < radiusP + radiusQ + // return hits + unimplemented!() + }, + // unexpanded + |_simplex|{ + // intersection is guaranteed at this point + true + }, + // fast_fail value + false + ) } pub fn get_closest_fev(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Topology{ - minimum_difference::(mesh,rel_pos) + minimum_difference::(mesh,rel_pos, + // expanded + |_simplex|{ + // NOTE: if hits is true, this if statement necessarily evaluates to true. + // i.e. hits implies this statement + // if -dist <= exitRadius + radiusP + radiusQ then + // local posP, posQ = decompose(-rel_pos, a0, a1, b0, b1, c0, c1) + // return hits, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return false + unimplemented!() + }, + // unexpanded + |_simplex|{ + // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) + // if norm then + // local posP, posQ = decompose(-rel_pos, u0, u1, v0, v1, w0, w1) + // return true, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return nil + unimplemented!() + }, + // fast_fail value is irrelevant and will never be returned! + Topology{simplex:Simplex::new_const()} + ) } // local function minimumDifference( @@ -503,7 +491,13 @@ pub fn get_closest_fev(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Topology{ // queryQ, radiusQ, // exitRadius, testIntersection // ) -fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->R::Output{ +fn minimum_difference( + mesh:&MinkowskiMesh, + rel_pos:Planar64Vec3, + expanded:impl Fn(Simplex)->T, + unexpanded:impl Fn(Simplex)->T, + fast_fail:T, +)->T{ // local initialAxis = queryQ() - queryP() // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) @@ -517,7 +511,7 @@ fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->R::Ou loop{ // if a and b and c and d then if simplex.len()==SIMPLEX_TETRAHEDRON{ - return R::unexpanded(simplex); + return unexpanded(simplex); } // new_point_p = queryP(-direction) @@ -526,8 +520,8 @@ fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->R::Ou let next_point=mesh.farthest_vert(direction); // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then - if R::IS_FAST&&direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ - return R::FAST_FAIL; + if ENABLE_FAST_FAIL&&direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ + return fast_fail; } // push_front @@ -545,7 +539,7 @@ fn minimum_difference(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->R::Ou // absDet(next_point, a, b, c) < 1e-6 if !direction.dot(mesh.vert(simplex[0])-mesh.vert(simplex[1])).is_positive() ||simplex_abs_det_is_zero(mesh,&simplex){ - return R::expanded(simplex); + return expanded(simplex); } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) -- 2.49.1 From 96cdd684d1e796f63135a3072bcc646bbc958a1c Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 13:54:18 -0800 Subject: [PATCH 29/90] stuff --- engine/physics/src/minimum_difference.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 2493650b..357510b7 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -417,7 +417,7 @@ fn reduce_simplex( } /// Intermediate data structure containing a partially complete calculation. -/// Sometimes you only care if the meshes are intersecting, and not about the +/// Sometimes you only care about the topology, and not about the /// exact point of intersection details. pub struct Topology{ simplex:Simplex, @@ -436,7 +436,8 @@ pub struct Details{ } pub fn point_in_mesh(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->bool{ - minimum_difference::(mesh,rel_pos, + const ENABLE_FAST_FAIL:bool=true; + minimum_difference::(mesh,rel_pos, // expanded |_simplex|{ // local norm = direction.unit @@ -455,7 +456,8 @@ pub fn point_in_mesh(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->bool{ ) } pub fn get_closest_fev(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Topology{ - minimum_difference::(mesh,rel_pos, + const ENABLE_FAST_FAIL:bool=false; + minimum_difference::(mesh,rel_pos, // expanded |_simplex|{ // NOTE: if hits is true, this if statement necessarily evaluates to true. -- 2.49.1 From e4966b037febe1358dcc303fbc668f1bb53263d0 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 13:58:11 -0800 Subject: [PATCH 30/90] names --- engine/physics/src/minimum_difference.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 357510b7..32b40686 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -435,9 +435,9 @@ pub struct Details{ // q_norm:Planar64Vec3, } -pub fn point_in_mesh(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->bool{ +pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ const ENABLE_FAST_FAIL:bool=true; - minimum_difference::(mesh,rel_pos, + minimum_difference::(mesh,point, // expanded |_simplex|{ // local norm = direction.unit @@ -455,9 +455,9 @@ pub fn point_in_mesh(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->bool{ false ) } -pub fn get_closest_fev(mesh:&MinkowskiMesh,rel_pos:Planar64Vec3)->Topology{ +pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ const ENABLE_FAST_FAIL:bool=false; - minimum_difference::(mesh,rel_pos, + minimum_difference::(mesh,point, // expanded |_simplex|{ // NOTE: if hits is true, this if statement necessarily evaluates to true. -- 2.49.1 From ee50f8dc1e23602a0ab520001fea69a1aa652cdd Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 14:07:34 -0800 Subject: [PATCH 31/90] refine naming --- engine/physics/src/minimum_difference.rs | 65 +++++++++++++----------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 32b40686..d59c37ae 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -416,6 +416,18 @@ fn reduce_simplex( } } +// local function expand( +// queryP, queryQ, +// vertA0, vertA1, +// vertB0, vertB1, +// vertC0, vertC1, +// vertD0, vertD1, +// accuracy +// ) +fn refine_to_exact(mesh:&MinkowskiMesh,simplex:Simplex)->Simplex{ + unimplemented!() +} + /// Intermediate data structure containing a partially complete calculation. /// Sometimes you only care about the topology, and not about the /// exact point of intersection details. @@ -423,7 +435,17 @@ pub struct Topology{ simplex:Simplex, } impl Topology{ - pub fn details(self,mesh:&MinkowskiMesh)->Details{ + /// Returns None if the point is intersecting the mesh. + pub fn closest_point_details(self,mesh:&MinkowskiMesh)->Option
{ + // NOTE: if hits is true, this if statement necessarily evaluates to true. + // i.e. hits implies this statement + // if -dist <= exitRadius + radiusP + radiusQ then + // local posP, posQ = decompose(-point, a0, a1, b0, b1, c0, c1) + // return hits, -dist - radiusP - radiusQ, + // posP - radiusP*norm, -norm, + // posQ + radiusQ*norm, norm + // end + // return false unimplemented!() } } @@ -438,7 +460,7 @@ pub struct Details{ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ const ENABLE_FAST_FAIL:bool=true; minimum_difference::(mesh,point, - // expanded + // exact |_simplex|{ // local norm = direction.unit // local dist = a:Dot(norm) @@ -446,7 +468,7 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ // return hits unimplemented!() }, - // unexpanded + // approximate |_simplex|{ // intersection is guaranteed at this point true @@ -458,30 +480,13 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ const ENABLE_FAST_FAIL:bool=false; minimum_difference::(mesh,point, - // expanded - |_simplex|{ - // NOTE: if hits is true, this if statement necessarily evaluates to true. - // i.e. hits implies this statement - // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(-rel_pos, a0, a1, b0, b1, c0, c1) - // return hits, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return false - unimplemented!() - }, - // unexpanded - |_simplex|{ + // exact + |simplex|Topology{simplex}, + // approximate + |simplex|{ // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) - // if norm then - // local posP, posQ = decompose(-rel_pos, u0, u1, v0, v1, w0, w1) - // return true, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return nil - unimplemented!() + let simplex=refine_to_exact(mesh,simplex); + Topology{simplex} }, // fast_fail value is irrelevant and will never be returned! Topology{simplex:Simplex::new_const()} @@ -496,8 +501,8 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ fn minimum_difference( mesh:&MinkowskiMesh, rel_pos:Planar64Vec3, - expanded:impl Fn(Simplex)->T, - unexpanded:impl Fn(Simplex)->T, + exact:impl Fn(Simplex)->T, + approximate:impl Fn(Simplex)->T, fast_fail:T, )->T{ // local initialAxis = queryQ() - queryP() @@ -513,7 +518,7 @@ fn minimum_difference( loop{ // if a and b and c and d then if simplex.len()==SIMPLEX_TETRAHEDRON{ - return unexpanded(simplex); + return approximate(simplex); } // new_point_p = queryP(-direction) @@ -541,7 +546,7 @@ fn minimum_difference( // absDet(next_point, a, b, c) < 1e-6 if !direction.dot(mesh.vert(simplex[0])-mesh.vert(simplex[1])).is_positive() ||simplex_abs_det_is_zero(mesh,&simplex){ - return expanded(simplex); + return exact(simplex); } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) -- 2.49.1 From 0048306236eb562ced85982d9dfe01e7debec503 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 14:18:06 -0800 Subject: [PATCH 32/90] more naming things --- engine/physics/src/minimum_difference.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index d59c37ae..0334b6c4 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -460,7 +460,7 @@ pub struct Details{ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ const ENABLE_FAST_FAIL:bool=true; minimum_difference::(mesh,point, - // exact + // on_exact |_simplex|{ // local norm = direction.unit // local dist = a:Dot(norm) @@ -468,7 +468,7 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ // return hits unimplemented!() }, - // approximate + // on_intersecting |_simplex|{ // intersection is guaranteed at this point true @@ -480,9 +480,9 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ const ENABLE_FAST_FAIL:bool=false; minimum_difference::(mesh,point, - // exact + // on_exact |simplex|Topology{simplex}, - // approximate + // on_intersecting |simplex|{ // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) let simplex=refine_to_exact(mesh,simplex); @@ -501,9 +501,9 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ fn minimum_difference( mesh:&MinkowskiMesh, rel_pos:Planar64Vec3, - exact:impl Fn(Simplex)->T, - approximate:impl Fn(Simplex)->T, - fast_fail:T, + on_exact:impl Fn(Simplex)->T, + on_intersecting:impl Fn(Simplex)->T, + on_fast_fail:T, )->T{ // local initialAxis = queryQ() - queryP() // local new_point_p = queryP(initialAxis) @@ -518,7 +518,9 @@ fn minimum_difference( loop{ // if a and b and c and d then if simplex.len()==SIMPLEX_TETRAHEDRON{ - return approximate(simplex); + // Enough information to conclude that the meshes are intersecting. + // Topology information is computed if needed. + return on_intersecting(simplex); } // new_point_p = queryP(-direction) @@ -528,7 +530,7 @@ fn minimum_difference( // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then if ENABLE_FAST_FAIL&&direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ - return fast_fail; + return on_fast_fail; } // push_front @@ -546,7 +548,8 @@ fn minimum_difference( // absDet(next_point, a, b, c) < 1e-6 if !direction.dot(mesh.vert(simplex[0])-mesh.vert(simplex[1])).is_positive() ||simplex_abs_det_is_zero(mesh,&simplex){ - return exact(simplex); + // Found enough information to compute the exact closest point. + return on_exact(simplex); } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) -- 2.49.1 From d93e55867873f7ca562f9deddf224681ac3cc91c Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 14:33:57 -0800 Subject: [PATCH 33/90] fast fail fn --- engine/physics/src/minimum_difference.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 0334b6c4..25e368ff 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -474,7 +474,7 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ true }, // fast_fail value - false + ||false ) } pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ @@ -489,7 +489,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ Topology{simplex} }, // fast_fail value is irrelevant and will never be returned! - Topology{simplex:Simplex::new_const()} + ||unreachable!() ) } @@ -503,7 +503,7 @@ fn minimum_difference( rel_pos:Planar64Vec3, on_exact:impl Fn(Simplex)->T, on_intersecting:impl Fn(Simplex)->T, - on_fast_fail:T, + on_fast_fail:impl FnOnce()->T, )->T{ // local initialAxis = queryQ() - queryP() // local new_point_p = queryP(initialAxis) @@ -530,7 +530,7 @@ fn minimum_difference( // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then if ENABLE_FAST_FAIL&&direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ - return on_fast_fail; + return on_fast_fail(); } // push_front -- 2.49.1 From d1c13757e019b9e4bb69e883ba40bb1fb07a5f8d Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 24 Nov 2025 14:34:05 -0800 Subject: [PATCH 34/90] FnOnce --- engine/physics/src/minimum_difference.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 25e368ff..dfedb5d7 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -501,8 +501,8 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ fn minimum_difference( mesh:&MinkowskiMesh, rel_pos:Planar64Vec3, - on_exact:impl Fn(Simplex)->T, - on_intersecting:impl Fn(Simplex)->T, + on_exact:impl FnOnce(Simplex)->T, + on_intersecting:impl FnOnce(Simplex)->T, on_fast_fail:impl FnOnce()->T, )->T{ // local initialAxis = queryQ() - queryP() -- 2.49.1 From e514c27675fa01e5f4f28bee507fd1e7f19d4297 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 08:14:19 -0800 Subject: [PATCH 35/90] reduce min dist bit width --- engine/physics/src/minimum_difference.rs | 68 +++++++++++++----------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index dfedb5d7..485e6870 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -204,10 +204,8 @@ fn reduce_simplex( // local uDist = uv_up/(u_u*v.magnitude) // local vDist = uv_pv/(v_v*u.magnitude) // local minDist2 = math.min(uDist, vDist) - let u_u=u.dot(u); - let v_v=v.dot(v); - let u_dist=uv_up*(v_v*u.length()); - let v_dist=uv_pv*(u_u*v.length()); + let u_dist=uv_up*v.length(); + let v_dist=uv_pv*u.length(); // if vDist == minDist2 then if v_dist Date: Tue, 25 Nov 2025 08:14:23 -0800 Subject: [PATCH 36/90] work --- engine/physics/src/minimum_difference.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 485e6870..271e901e 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -133,7 +133,7 @@ fn reduce_simplex( let direction=u.cross(p).cross(u); // if direction.magnitude == 0 then - if direction==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])}{ + if direction==vec3::zero(){ return (choose_perpendicular_direction(u),simplex); } -- 2.49.1 From e777b89c6ddedcfc0ab58d13d07c52966ab4a4bf Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 08:32:56 -0800 Subject: [PATCH 37/90] rename variable --- engine/physics/src/minimum_difference.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 271e901e..0dcc95b4 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -472,7 +472,7 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ // return hits unimplemented!() }, - // on_intersecting + // on_escape |_simplex|{ // intersection is guaranteed at this point true @@ -486,7 +486,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ minimum_difference::(mesh,point, // on_exact |simplex|Topology{simplex}, - // on_intersecting + // on_escape |simplex|{ // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) let simplex=refine_to_exact(mesh,simplex); @@ -506,7 +506,7 @@ fn minimum_difference( mesh:&MinkowskiMesh, rel_pos:Planar64Vec3, on_exact:impl FnOnce(Simplex)->T, - on_intersecting:impl FnOnce(Simplex)->T, + on_escape:impl FnOnce(Simplex)->T, on_fast_fail:impl FnOnce()->T, )->T{ // local initialAxis = queryQ() - queryP() @@ -524,7 +524,7 @@ fn minimum_difference( if simplex.len()==SIMPLEX_TETRAHEDRON{ // Enough information to conclude that the meshes are intersecting. // Topology information is computed if needed. - return on_intersecting(simplex); + return on_escape(simplex); } // new_point_p = queryP(-direction) -- 2.49.1 From de54bcfc36e10459aa00180c356b534b0ef91582 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 08:33:10 -0800 Subject: [PATCH 38/90] implement contains_point --- engine/physics/src/minimum_difference.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 0dcc95b4..d602801b 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -465,12 +465,12 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ const ENABLE_FAST_FAIL:bool=true; minimum_difference::(mesh,point, // on_exact - |_simplex|{ + |simplex,direction|{ // local norm = direction.unit // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ // return hits - unimplemented!() + mesh.vert(simplex[1]).dot(direction).is_negative() }, // on_escape |_simplex|{ @@ -485,7 +485,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ const ENABLE_FAST_FAIL:bool=false; minimum_difference::(mesh,point, // on_exact - |simplex|Topology{simplex}, + |simplex,_direction|Topology{simplex}, // on_escape |simplex|{ // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) @@ -505,7 +505,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ fn minimum_difference( mesh:&MinkowskiMesh, rel_pos:Planar64Vec3, - on_exact:impl FnOnce(Simplex)->T, + on_exact:impl FnOnce(Simplex,Planar64Vec3)->T, on_escape:impl FnOnce(Simplex)->T, on_fast_fail:impl FnOnce()->T, )->T{ @@ -553,7 +553,7 @@ fn minimum_difference( if !direction.dot(mesh.vert(simplex[0])-mesh.vert(simplex[1])).is_positive() ||simplex_abs_det_is_zero(mesh,&simplex){ // Found enough information to compute the exact closest point. - return on_exact(simplex); + return on_exact(simplex,direction); } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) -- 2.49.1 From 069db75d3ae9b4c3a6fb12284f6f153b6c9c384b Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 08:34:46 -0800 Subject: [PATCH 39/90] use min diff --- engine/physics/src/model.rs | 18 ++++-------------- engine/physics/src/physics.rs | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index 9ecbe0f4..fd02f9f4 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -815,20 +815,10 @@ impl MinkowskiMesh<'_>{ } best_edge } - fn infinity_in(&self,infinity_body:Body)->Option<(MinkowskiFace,GigaTime)>{ - let infinity_fev=self.infinity_fev(-infinity_body.velocity,infinity_body.position); - // Bound::Included means that the surface of the mesh is included in the mesh - infinity_fev.crawl(self,&infinity_body,Bound::Unbounded,Bound::Included(&infinity_body.time)).hit() - } - pub fn is_point_in_mesh(&self,point:Planar64Vec3)->bool{ - let infinity_body=Body::new(point,vec3::Y,vec3::zero(),Time::ZERO); - //movement must escape the mesh forwards and backwards in time, - //otherwise the point is not inside the mesh - self.infinity_in(infinity_body) - .is_some_and(|_| - self.infinity_in(-infinity_body) - .is_some() - ) + pub fn contains_point(&self,point:Planar64Vec3)->bool{ + let contains_point=crate::minimum_difference::contains_point(self,point); + println!("contains_point={contains_point}"); + contains_point } } impl MeshQuery for MinkowskiMesh<'_>{ diff --git a/engine/physics/src/physics.rs b/engine/physics/src/physics.rs index baeb5a92..069735e1 100644 --- a/engine/physics/src/physics.rs +++ b/engine/physics/src/physics.rs @@ -1277,7 +1277,7 @@ fn recalculate_touching( //no checks are needed because of the time limits. let model_mesh=models.mesh(convex_mesh_id); let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh()); - if minkowski.is_point_in_mesh(body.position){ + if minkowski.contains_point(body.position){ match convex_mesh_id.model_id{ //being inside of contact objects is an invalid physics state //but the physics isn't advanced enough to do anything about it yet -- 2.49.1 From 8a1ab4e03c17266368d27ab694b0bb779cbbccbc Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:00:13 -0800 Subject: [PATCH 40/90] fix wrong --- engine/physics/src/minimum_difference.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index d602801b..418a8933 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -470,7 +470,7 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ // return hits - mesh.vert(simplex[1]).dot(direction).is_negative() + mesh.vert(simplex[1]).dot(direction).is_positive() }, // on_escape |_simplex|{ -- 2.49.1 From 1b833ef6b3463444ecdc4cd5a5942f012b33fece Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:00:23 -0800 Subject: [PATCH 41/90] fix degenerate case --- engine/physics/src/minimum_difference.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 418a8933..1738fa6c 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -514,6 +514,10 @@ fn minimum_difference( // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 let mut direction=mesh.hint_point()+rel_pos; + // degenerate case + if direction==vec3::zero(){ + direction=choose_any_direction(); + } let new_point=mesh.farthest_vert(direction); let mut simplex=Simplex::from_iter([new_point]); -- 2.49.1 From 6621e369f2bc9adaba9e691697314b22934c1672 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:09:46 -0800 Subject: [PATCH 42/90] include relative point --- engine/physics/src/minimum_difference.rs | 33 ++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 1738fa6c..a6c467dd 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -84,8 +84,9 @@ const fn choose_any_direction()->Planar64Vec3{ } fn reduce_simplex( - mesh:&MinkowskiMesh, mut simplex:Simplex, + mesh:&MinkowskiMesh, + point:Planar64Vec3, )->(Planar64Vec3,Simplex){ match simplex.len(){ 0=>(choose_any_direction(),simplex), @@ -93,7 +94,7 @@ fn reduce_simplex( 1=>{ // --debug.profilebegin("reduceSimplex0") // local a = a1 - a0 - let p0=mesh.vert(simplex[0]); + let p0=mesh.vert(simplex[0])+point; // local p = -a let p=-p0; @@ -115,8 +116,8 @@ fn reduce_simplex( // --debug.profilebegin("reduceSimplex1") // local a = a1 - a0 // local b = b1 - b0 - let p0=mesh.vert(simplex[0]); - let p1=mesh.vert(simplex[1]); + let p0=mesh.vert(simplex[0])+point; + let p1=mesh.vert(simplex[1])+point; // local p = -a // local u = b - a @@ -161,9 +162,9 @@ fn reduce_simplex( // local a = a1 - a0 // local b = b1 - b0 // local c = c1 - c0 - let p0=mesh.vert(simplex[0]); - let p1=mesh.vert(simplex[1]); - let p2=mesh.vert(simplex[2]); + let p0=mesh.vert(simplex[0])+point; + let p1=mesh.vert(simplex[1])+point; + let p2=mesh.vert(simplex[2])+point; // local p = -a // local u = b - a @@ -256,10 +257,10 @@ fn reduce_simplex( // local b = b1 - b0 // local c = c1 - c0 // local d = d1 - d0 - let p0=mesh.vert(simplex[0]); - let p1=mesh.vert(simplex[1]); - let p2=mesh.vert(simplex[2]); - let p3=mesh.vert(simplex[3]); + let p0=mesh.vert(simplex[0])+point; + let p1=mesh.vert(simplex[1])+point; + let p2=mesh.vert(simplex[2])+point; + let p3=mesh.vert(simplex[3])+point; // local p = -a // local u = b - a @@ -470,7 +471,7 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ // return hits - mesh.vert(simplex[1]).dot(direction).is_positive() + (mesh.vert(simplex[1])+point).dot(direction).is_positive() }, // on_escape |_simplex|{ @@ -504,7 +505,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ // ) fn minimum_difference( mesh:&MinkowskiMesh, - rel_pos:Planar64Vec3, + point:Planar64Vec3, on_exact:impl FnOnce(Simplex,Planar64Vec3)->T, on_escape:impl FnOnce(Simplex)->T, on_fast_fail:impl FnOnce()->T, @@ -513,7 +514,7 @@ fn minimum_difference( // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 - let mut direction=mesh.hint_point()+rel_pos; + let mut direction=mesh.hint_point()+point; // degenerate case if direction==vec3::zero(){ direction=choose_any_direction(); @@ -537,7 +538,7 @@ fn minimum_difference( let next_point=mesh.farthest_vert(direction); // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then - if ENABLE_FAST_FAIL&&direction.dot(mesh.vert(next_point)+rel_pos).is_negative(){ + if ENABLE_FAST_FAIL&&direction.dot(mesh.vert(next_point)+point).is_negative(){ return on_fast_fail(); } @@ -561,6 +562,6 @@ fn minimum_difference( } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) - (direction,simplex)=reduce_simplex(mesh,simplex); + (direction,simplex)=reduce_simplex(simplex,mesh,point); } } -- 2.49.1 From 2483abe2adef3166fb96a949ed3d6adc8a3a5ec7 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:12:22 -0800 Subject: [PATCH 43/90] work --- engine/physics/src/minimum_difference.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index a6c467dd..cb38536e 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -1,8 +1,8 @@ use strafesnet_common::integer::vec3; use strafesnet_common::integer::vec3::Vector3; -use strafesnet_common::integer::{Fixed,Planar64,Planar64Vec3}; +use strafesnet_common::integer::{Fixed,Planar64Vec3}; -use crate::model::{MeshQuery,MinkowskiMesh,MinkowskiVert,SubmeshVertId}; +use crate::model::{MeshQuery,MinkowskiMesh,MinkowskiVert}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 @@ -41,7 +41,7 @@ fn simplex_abs_det_is_zero(mesh:&MinkowskiMesh,simplex:&Simplex)->bool{ let p0=mesh.vert(p0); let p1=mesh.vert(p1); let p2=mesh.vert(p2); - (p1-p0).cross(p2-p0)==const{Vector3::new([Fixed::ZERO,Fixed::ZERO,Fixed::ZERO])} + (p1-p0).cross(p2-p0)==vec3::zero() }, &[p0,p1]=>{ let p0=mesh.vert(p0); -- 2.49.1 From dd7a636fa929cc0b0194eb90b2889f3595db0be4 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:15:18 -0800 Subject: [PATCH 44/90] careful relative point opti --- engine/physics/src/minimum_difference.rs | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index cb38536e..2b8929c3 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -94,10 +94,10 @@ fn reduce_simplex( 1=>{ // --debug.profilebegin("reduceSimplex0") // local a = a1 - a0 - let p0=mesh.vert(simplex[0])+point; + let p0=mesh.vert(simplex[0]); // local p = -a - let p=-p0; + let p=-(p0+point); // local direction = p let mut direction=p; @@ -116,12 +116,12 @@ fn reduce_simplex( // --debug.profilebegin("reduceSimplex1") // local a = a1 - a0 // local b = b1 - b0 - let p0=mesh.vert(simplex[0])+point; - let p1=mesh.vert(simplex[1])+point; + let p0=mesh.vert(simplex[0]); + let p1=mesh.vert(simplex[1]); // local p = -a // local u = b - a - let p=-p0; + let p=-(p0+point); let u=p1-p0; // -- modify to take into account the radiuses @@ -162,14 +162,14 @@ fn reduce_simplex( // local a = a1 - a0 // local b = b1 - b0 // local c = c1 - c0 - let p0=mesh.vert(simplex[0])+point; - let p1=mesh.vert(simplex[1])+point; - let p2=mesh.vert(simplex[2])+point; + let p0=mesh.vert(simplex[0]); + let p1=mesh.vert(simplex[1]); + let p2=mesh.vert(simplex[2]); // local p = -a // local u = b - a // local v = c - a - let p=-p0; + let p=-(p0+point); let mut u=p1-p0; let v=p2-p0; @@ -257,16 +257,16 @@ fn reduce_simplex( // local b = b1 - b0 // local c = c1 - c0 // local d = d1 - d0 - let p0=mesh.vert(simplex[0])+point; - let p1=mesh.vert(simplex[1])+point; - let p2=mesh.vert(simplex[2])+point; - let p3=mesh.vert(simplex[3])+point; + let p0=mesh.vert(simplex[0]); + let p1=mesh.vert(simplex[1]); + let p2=mesh.vert(simplex[2]); + let p3=mesh.vert(simplex[3]); // local p = -a // local u = b - a // local v = c - a // local w = d - a - let p=-p0; + let p=-(p0+point); let mut u=p1-p0; let mut v=p2-p0; let w=p3-p0; -- 2.49.1 From d0c38a6e66976796936b5ac7afa162da5d462c4b Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:15:25 -0800 Subject: [PATCH 45/90] style --- engine/physics/src/minimum_difference.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 2b8929c3..9a2fa52b 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -278,13 +278,13 @@ fn reduce_simplex( // local pvw = vw:Dot(p) // local upw = wu:Dot(p) // local uvp = uv:Dot(p) - let mut uv = u.cross(v); - let vw = v.cross(w); - let wu = w.cross(u); - let uv_w = uv.dot(w); - let pv_w = vw.dot(p); - let up_w = wu.dot(p); - let uv_p = uv.dot(p); + let mut uv=u.cross(v); + let vw=v.cross(w); + let wu=w.cross(u); + let uv_w=uv.dot(w); + let pv_w=vw.dot(p); + let up_w=wu.dot(p); + let uv_p=uv.dot(p); // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then if !pv_w.div_sign(uv_w).is_negative() @@ -341,10 +341,10 @@ fn reduce_simplex( // local pv = p:Cross(v) // local uv_up = uv:Dot(up) // local uv_pv = uv:Dot(pv) - let mut up = u.cross(p); - let pv = p.cross(v); - let uv_up = uv.dot(up); - let uv_pv = uv.dot(pv); + let mut up=u.cross(p); + let pv=p.cross(v); + let uv_up=uv.dot(up); + let uv_pv=uv.dot(pv); // if uv_up >= 0 and uv_pv >= 0 then if !uv_up.is_negative()&&!uv_pv.is_negative(){ -- 2.49.1 From 570d33a030eeedcddc186712d5d28402fb5ee0f5 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:22:46 -0800 Subject: [PATCH 46/90] rename --- engine/physics/src/minimum_difference.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 9a2fa52b..ea567a0f 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -28,7 +28,7 @@ local function absDet(r, u, v, w) end end */ -fn simplex_abs_det_is_zero(mesh:&MinkowskiMesh,simplex:&Simplex)->bool{ +fn simplex_det_is_zero(mesh:&MinkowskiMesh,simplex:&Simplex)->bool{ match simplex.as_slice(){ &[p0,p1,p2,p3]=>{ let p0=mesh.vert(p0); @@ -556,7 +556,7 @@ fn minimum_difference( // direction:Dot(next_point - a) <= 0 or // absDet(next_point, a, b, c) < 1e-6 if !direction.dot(mesh.vert(simplex[0])-mesh.vert(simplex[1])).is_positive() - ||simplex_abs_det_is_zero(mesh,&simplex){ + ||simplex_det_is_zero(mesh,&simplex){ // Found enough information to compute the exact closest point. return on_exact(simplex,direction); } -- 2.49.1 From af1374906b6259f1def59f4e4f0e8e2d6af73e25 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:32:09 -0800 Subject: [PATCH 47/90] fix algorithm --- engine/physics/src/minimum_difference.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index ea567a0f..3e52ccf9 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -521,6 +521,7 @@ fn minimum_difference( } let new_point=mesh.farthest_vert(direction); let mut simplex=Simplex::from_iter([new_point]); + (direction,simplex)=reduce_simplex(simplex,mesh,point); // exitRadius = testIntersection and 0 or exitRadius or 1/0 // for _ = 1, 100 do @@ -535,7 +536,7 @@ fn minimum_difference( // new_point_p = queryP(-direction) // new_point_q = queryQ(direction) // local next_point = new_point_q - new_point_p - let next_point=mesh.farthest_vert(direction); + let next_point=mesh.farthest_vert(-direction); // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then if ENABLE_FAST_FAIL&&direction.dot(mesh.vert(next_point)+point).is_negative(){ -- 2.49.1 From 0c8cf02287a262d77e4468bb864a04df532789ef Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 09:49:30 -0800 Subject: [PATCH 48/90] simplify perp --- engine/physics/src/minimum_difference.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 3e52ccf9..3371ccf8 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -71,11 +71,12 @@ fn choose_perpendicular_direction(d:Planar64Vec3)->Planar64Vec3{ let x=d.x.abs(); let y=d.y.abs(); let z=d.z.abs(); - match x.min(y).min(z){ - min if min==x=>Vector3::new([y*y+z*z,-x*y,-x*z]).wrap_1(), - min if min==y=>Vector3::new([-x*y,x*x+z*z,-y*z]).wrap_1(), - min if min==z=>Vector3::new([-x*z,-y*z,x*x+y*y]).wrap_1(), - _=>unreachable!(), + if x Date: Tue, 25 Nov 2025 11:12:45 -0800 Subject: [PATCH 49/90] refactor using Simplex enum --- engine/physics/src/minimum_difference.rs | 332 ++++++++++++++--------- 1 file changed, 197 insertions(+), 135 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 3371ccf8..d0bb56db 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -7,13 +7,36 @@ use crate::model::{MeshQuery,MinkowskiMesh,MinkowskiVert}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 -const SIMPLEX_TETRAHEDRON:usize=4; -// TODO: consider using an enum? -// enum Simplex{ -// Simplex1([Vert;1]), -// Simplex2([Vert;2]), -// } -type Simplex=arrayvec::ArrayVec; +type Simplex=[MinkowskiVert;N]; +enum Simplex1_3{ + Simplex1(Simplex<1>), + Simplex2(Simplex<2>), + Simplex3(Simplex<3>), +} +impl Simplex1_3{ + fn push_front(self,v:MinkowskiVert)->Simplex2_4{ + match self{ + Simplex1_3::Simplex1([v0])=>Simplex2_4::Simplex2([v,v0]), + Simplex1_3::Simplex2([v0,v1])=>Simplex2_4::Simplex3([v,v0,v1]), + Simplex1_3::Simplex3([v0,v1,v2])=>Simplex2_4::Simplex4([v,v0,v1,v2]), + } + } +} +enum Simplex2_4{ + Simplex2(Simplex<2>), + Simplex3(Simplex<3>), + Simplex4(Simplex<4>), +} +impl core::ops::Index for Simplex2_4{ + type Output=MinkowskiVert; + fn index(&self,index:usize)->&Self::Output{ + match self{ + Simplex2_4::Simplex2(s)=>&s[index], + Simplex2_4::Simplex3(s)=>&s[index], + Simplex2_4::Simplex4(s)=>&s[index], + } + } +} /* local function absDet(r, u, v, w) @@ -28,29 +51,28 @@ local function absDet(r, u, v, w) end end */ -fn simplex_det_is_zero(mesh:&MinkowskiMesh,simplex:&Simplex)->bool{ - match simplex.as_slice(){ - &[p0,p1,p2,p3]=>{ - let p0=mesh.vert(p0); - let p1=mesh.vert(p1); - let p2=mesh.vert(p2); - let p3=mesh.vert(p3); - (p1-p0).cross(p2-p0).dot(p3-p0)==Fixed::ZERO - }, - &[p0,p1,p2]=>{ - let p0=mesh.vert(p0); - let p1=mesh.vert(p1); - let p2=mesh.vert(p2); - (p1-p0).cross(p2-p0)==vec3::zero() - }, - &[p0,p1]=>{ - let p0=mesh.vert(p0); - let p1=mesh.vert(p1); - p1-p0==vec3::zero() - }, - &[_p0]=>false,// 1 == 0 - &[]=>false, - _=>unreachable!(), +impl Simplex2_4{ + fn det_is_zero(&self,mesh:&MinkowskiMesh)->bool{ + match self{ + &Self::Simplex4([p0,p1,p2,p3])=>{ + let p0=mesh.vert(p0); + let p1=mesh.vert(p1); + let p2=mesh.vert(p2); + let p3=mesh.vert(p3); + (p1-p0).cross(p2-p0).dot(p3-p0)==Fixed::ZERO + }, + &Self::Simplex3([p0,p1,p2])=>{ + let p0=mesh.vert(p0); + let p1=mesh.vert(p1); + let p2=mesh.vert(p2); + (p1-p0).cross(p2-p0)==vec3::zero() + }, + &Self::Simplex2([p0,p1])=>{ + let p0=mesh.vert(p0); + let p1=mesh.vert(p1); + p1-p0==vec3::zero() + } + } } } @@ -84,41 +106,52 @@ const fn choose_any_direction()->Planar64Vec3{ vec3::X } -fn reduce_simplex( - mut simplex:Simplex, +fn reduce1( + simplex:Simplex<1>, mesh:&MinkowskiMesh, point:Planar64Vec3, -)->(Planar64Vec3,Simplex){ - match simplex.len(){ - 0=>(choose_any_direction(),simplex), - // local function reduceSimplex0(a0, a1) - 1=>{ - // --debug.profilebegin("reduceSimplex0") - // local a = a1 - a0 - let p0=mesh.vert(simplex[0]); +)->(Planar64Vec3,Simplex1_3){ + // --debug.profilebegin("reduceSimplex0") + // local a = a1 - a0 + let p0=mesh.vert(simplex[0]); - // local p = -a - let p=-(p0+point); + // local p = -a + let p=-(p0+point); - // local direction = p - let mut direction=p; + // local direction = p + let mut direction=p; - // if direction.magnitude == 0 then - // direction = chooseAnyDirection() - if direction==vec3::zero(){ - direction=choose_any_direction(); - } + // if direction.magnitude == 0 then + // direction = chooseAnyDirection() + if direction==vec3::zero(){ + direction=choose_any_direction(); + } - // return direction, a0, a1 - (direction,simplex) - }, + // return direction, a0, a1 + (direction,Simplex1_3::Simplex1(simplex)) +} + +enum Reduce{ + Escape(Simplex<4>), + Reduced{ + dir:Planar64Vec3, + simplex:Simplex1_3, + } +} + +fn reduce( + simplex:Simplex2_4, + mesh:&MinkowskiMesh, + point:Planar64Vec3, +)->Reduce{ + match simplex{ // local function reduceSimplex1(a0, a1, b0, b1) - 2=>{ + Simplex2_4::Simplex2([v0,v1])=>{ // --debug.profilebegin("reduceSimplex1") // local a = a1 - a0 // local b = b1 - b0 - let p0=mesh.vert(simplex[0]); - let p1=mesh.vert(simplex[1]); + let p0=mesh.vert(v0); + let p1=mesh.vert(v1); // local p = -a // local u = b - a @@ -136,36 +169,43 @@ fn reduce_simplex( // if direction.magnitude == 0 then if direction==vec3::zero(){ - return (choose_perpendicular_direction(u),simplex); + return Reduce::Reduced{ + dir:choose_perpendicular_direction(u), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; } // -- modify the direction to take into account a0R and b0R // return direction, a0, a1, b0, b1 - return (direction.narrow_1().unwrap(),simplex) + return Reduce::Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; } - simplex.remove(1); - // local direction = p - let mut direction=p; + let mut dir=p; // if direction.magnitude == 0 then - if direction==vec3::zero(){ - direction=choose_perpendicular_direction(u); + if dir==vec3::zero(){ + dir=choose_perpendicular_direction(u); } // return direction, a0, a1 - (direction,simplex) + Reduce::Reduced{ + dir, + simplex:Simplex1_3::Simplex1([v0]), + } }, // local function reduceSimplex2(a0, a1, b0, b1, c0, c1) - 3=>{ + Simplex2_4::Simplex3([v0,mut v1,v2])=>{ // --debug.profilebegin("reduceSimplex2") // local a = a1 - a0 // local b = b1 - b0 // local c = c1 - c0 - let p0=mesh.vert(simplex[0]); - let p1=mesh.vert(simplex[1]); - let p2=mesh.vert(simplex[2]); + let p0=mesh.vert(v0); + let p1=mesh.vert(v1); + let p2=mesh.vert(v2); // local p = -a // local u = b - a @@ -198,7 +238,10 @@ fn reduce_simplex( }; // return direction, a0, a1, b0, b1, c0, c1 - return (direction.narrow_1().unwrap(),simplex) + return Reduce::Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex3([v0,v1,v2]), + }; } // local u_u = u:Dot(u) @@ -214,12 +257,9 @@ fn reduce_simplex( u=v; up=-pv; uv=-uv; - // u_u=v_v; // unused // b0 = c0 // b1 = c1 - simplex.remove(1); - }else{ - simplex.remove(2); + v1=v2; } // local p_u = p:Dot(u) @@ -232,36 +272,46 @@ fn reduce_simplex( // if direction.magnitude == 0 then if direction==vec3::zero(){ // direction = uv - return (uv.narrow_1().unwrap(),simplex) + return Reduce::Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; } // return direction, a0, a1, b0, b1 - return (direction.narrow_1().unwrap(),simplex) + return Reduce::Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; } - simplex.remove(1); - // local direction = p - let direction=p; + let dir=p; // if direction.magnitude == 0 then - if direction==vec3::zero(){ + if dir==vec3::zero(){ // direction = uv - return (uv.narrow_1().unwrap(),simplex) + return Reduce::Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex1([v0]), + }; } // return direction, a0, a0 - (direction,simplex) + Reduce::Reduced{ + dir, + simplex:Simplex1_3::Simplex1([v0]), + } }, // local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) - 4=>{ + Simplex2_4::Simplex4([v0,mut v1,mut v2,v3])=>{ // --debug.profilebegin("reduceSimplex3") // local a = a1 - a0 // local b = b1 - b0 // local c = c1 - c0 // local d = d1 - d0 - let p0=mesh.vert(simplex[0]); - let p1=mesh.vert(simplex[1]); - let p2=mesh.vert(simplex[2]); - let p3=mesh.vert(simplex[3]); + let p0=mesh.vert(v0); + let p1=mesh.vert(v1); + let p2=mesh.vert(v2); + let p3=mesh.vert(v3); // local p = -a // local u = b - a @@ -294,7 +344,7 @@ fn reduce_simplex( // origin is contained, this is a positive detection // local direction = Vector3.new(0, 0, 0) // return direction, a0, a1, b0, b1, c0, c1, d0, d1 - return (vec3::zero(),simplex); + return Reduce::Escape([v0,v1,v2,v3]); } // local uvwSign = uvw < 0 and -1 or uvw > 0 and 1 or 0 @@ -317,9 +367,9 @@ fn reduce_simplex( // uv_p=pv_w; // unused // b0, c0 = c0, d0 // b1, c1 = c1, d1 - simplex.remove(1); + (v1,v2)=(v2,v3); }else{ - simplex.remove(2); + v2=v3; } }else{ // elseif wuDist == minDist3 then @@ -330,11 +380,10 @@ fn reduce_simplex( // b0, c0 = d0, b0 // b1, c1 = d1, b1 // before [a,b,c,d] - simplex[2]=simplex[1]; - simplex.swap_remove(1); + (v1,v2)=(v3,v1); // after [a,d,b] }else{ - simplex.remove(2); + v2=v3; } } @@ -352,9 +401,15 @@ fn reduce_simplex( // local direction = uvw < 0 and uv or -uv // return direction, a0, a1, b0, b1, c0, c1 if uv_w.is_negative(){ - return (uv.narrow_1().unwrap(),simplex); + return Reduce::Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex3([v0,v1,v2]), + }; }else{ - return (-uv.narrow_1().unwrap(),simplex); + return Reduce::Reduced{ + dir:-uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex3([v0,v1,v2]), + }; } } @@ -371,12 +426,9 @@ fn reduce_simplex( u=v; up=-pv; uv=-uv; - // u_u=v_v; // unused // b0 = c0 // b1 = c1 - simplex.remove(1); - }else{ - simplex.remove(2); + v1=v2; } // local p_u = p:Dot(u) @@ -391,34 +443,49 @@ fn reduce_simplex( // direction = uvw < 0 and uv or -uv // return direction, a0, a1, b0, b1 if uv_w.is_negative(){ - return (uv.narrow_1().unwrap(),simplex); + return Reduce::Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; }else{ - return (-uv.narrow_1().unwrap(),simplex); + return Reduce::Reduced{ + dir:-uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; } } // return direction, a0, a1, b0, b1 - return (direction.narrow_1().unwrap(),simplex) + return Reduce::Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; } - simplex.remove(1); - // local direction = p - let direction=p; + let dir=p; // if direction.magnitude == 0 then - if direction==vec3::zero(){ + if dir==vec3::zero(){ // direction = uvw < 0 and uv or -uv if uv_w.is_negative(){ - return (uv.narrow_1().unwrap(),simplex); + return Reduce::Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex1([v0]), + }; }else{ - return (-uv.narrow_1().unwrap(),simplex); + return Reduce::Reduced{ + dir:-uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex1([v0]), + }; } } // return direction, a0, a1 - (direction,simplex) + Reduce::Reduced{ + dir, + simplex:Simplex1_3::Simplex1([v0]), + } }, - _=>unreachable!(), } } @@ -430,7 +497,7 @@ fn reduce_simplex( // vertD0, vertD1, // accuracy // ) -fn refine_to_exact(mesh:&MinkowskiMesh,simplex:Simplex)->Simplex{ +fn refine_to_exact(mesh:&MinkowskiMesh,simplex:Simplex<4>)->Simplex2_4{ unimplemented!() } @@ -438,7 +505,7 @@ fn refine_to_exact(mesh:&MinkowskiMesh,simplex:Simplex)->Simplex{ /// Sometimes you only care about the topology, and not about the /// exact point of intersection details. pub struct Topology{ - simplex:Simplex, + simplex:Simplex2_4, } impl Topology{ /// Returns None if the point is intersecting the mesh. @@ -507,8 +574,8 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ fn minimum_difference( mesh:&MinkowskiMesh, point:Planar64Vec3, - on_exact:impl FnOnce(Simplex,Planar64Vec3)->T, - on_escape:impl FnOnce(Simplex)->T, + on_exact:impl FnOnce(Simplex2_4,Planar64Vec3)->T, + on_escape:impl FnOnce(Simplex<4>)->T, on_fast_fail:impl FnOnce()->T, )->T{ // local initialAxis = queryQ() - queryP() @@ -521,49 +588,44 @@ fn minimum_difference( direction=choose_any_direction(); } let new_point=mesh.farthest_vert(direction); - let mut simplex=Simplex::from_iter([new_point]); - (direction,simplex)=reduce_simplex(simplex,mesh,point); + let (mut direction,mut simplex_small)=reduce1([new_point],mesh,point); // exitRadius = testIntersection and 0 or exitRadius or 1/0 // for _ = 1, 100 do loop{ - // if a and b and c and d then - if simplex.len()==SIMPLEX_TETRAHEDRON{ - // Enough information to conclude that the meshes are intersecting. - // Topology information is computed if needed. - return on_escape(simplex); - } - // new_point_p = queryP(-direction) // new_point_q = queryQ(direction) // local next_point = new_point_q - new_point_p let next_point=mesh.farthest_vert(-direction); + let next_pos=mesh.vert(next_point); // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then - if ENABLE_FAST_FAIL&&direction.dot(mesh.vert(next_point)+point).is_negative(){ + if ENABLE_FAST_FAIL&&direction.dot(next_pos+point).is_negative(){ return on_fast_fail(); } - // push_front - if simplex.len()==simplex.capacity(){ - // this is a dead case, new_simplex never has more than 3 elements - simplex.rotate_right(1); - simplex[0]=next_point; - }else{ - simplex.push(next_point); - simplex.rotate_right(1); - } + let simplex_big=simplex_small.push_front(next_point); // if // direction:Dot(next_point - a) <= 0 or // absDet(next_point, a, b, c) < 1e-6 - if !direction.dot(mesh.vert(simplex[0])-mesh.vert(simplex[1])).is_positive() - ||simplex_det_is_zero(mesh,&simplex){ + if !direction.dot(next_pos-mesh.vert(simplex_big[1])).is_positive() + ||simplex_big.det_is_zero(mesh){ // Found enough information to compute the exact closest point. - return on_exact(simplex,direction); + return on_exact(simplex_big,direction); } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) - (direction,simplex)=reduce_simplex(simplex,mesh,point); + match reduce(simplex_big,mesh,point){ + Reduce::Escape(simplex)=>{ + // Enough information to conclude that the meshes are intersecting. + // Topology information is computed if needed. + return on_escape(simplex); + }, + Reduce::Reduced{dir,simplex}=>{ + direction=dir; + simplex_small=simplex; + }, + } } } -- 2.49.1 From 492e72c1bc92546559aab0baa2030f156f11dcf9 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 11:35:11 -0800 Subject: [PATCH 50/90] deconstruct --- engine/physics/src/minimum_difference.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index d0bb56db..7476129d 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -107,13 +107,13 @@ const fn choose_any_direction()->Planar64Vec3{ } fn reduce1( - simplex:Simplex<1>, + [v0]:Simplex<1>, mesh:&MinkowskiMesh, point:Planar64Vec3, )->(Planar64Vec3,Simplex1_3){ // --debug.profilebegin("reduceSimplex0") // local a = a1 - a0 - let p0=mesh.vert(simplex[0]); + let p0=mesh.vert(v0); // local p = -a let p=-(p0+point); @@ -128,7 +128,7 @@ fn reduce1( } // return direction, a0, a1 - (direction,Simplex1_3::Simplex1(simplex)) + (direction,Simplex1_3::Simplex1([v0])) } enum Reduce{ -- 2.49.1 From ca40e650609242ca682cd588e1a2299fb77389f4 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 11:43:47 -0800 Subject: [PATCH 51/90] split reduce --- engine/physics/src/minimum_difference.rs | 716 ++++++++++++----------- 1 file changed, 368 insertions(+), 348 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 7476129d..0e867f0d 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -131,12 +131,370 @@ fn reduce1( (direction,Simplex1_3::Simplex1([v0])) } +// local function reduceSimplex1(a0, a1, b0, b1) +fn reduce2( + [v0,v1]:Simplex<2>, + mesh:&MinkowskiMesh, + point:Planar64Vec3, +)->Reduced{ + // --debug.profilebegin("reduceSimplex1") + // local a = a1 - a0 + // local b = b1 - b0 + let p0=mesh.vert(v0); + let p1=mesh.vert(v1); + + // local p = -a + // local u = b - a + let p=-(p0+point); + let u=p1-p0; + + // -- modify to take into account the radiuses + // local p_u = p:Dot(u) + let p_u=p.dot(u); + + // if p_u >= 0 then + if !p_u.is_negative(){ + // local direction = u:Cross(p):Cross(u) + let direction=u.cross(p).cross(u); + + // if direction.magnitude == 0 then + if direction==vec3::zero(){ + return Reduced{ + dir:choose_perpendicular_direction(u), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; + } + + // -- modify the direction to take into account a0R and b0R + // return direction, a0, a1, b0, b1 + return Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; + } + + // local direction = p + let mut dir=p; + + // if direction.magnitude == 0 then + if dir==vec3::zero(){ + dir=choose_perpendicular_direction(u); + } + + // return direction, a0, a1 + Reduced{ + dir, + simplex:Simplex1_3::Simplex1([v0]), + } +} + +// local function reduceSimplex2(a0, a1, b0, b1, c0, c1) +fn reduce3( + [v0,mut v1,v2]:Simplex<3>, + mesh:&MinkowskiMesh, + point:Planar64Vec3, +)->Reduced{ + // --debug.profilebegin("reduceSimplex2") + // local a = a1 - a0 + // local b = b1 - b0 + // local c = c1 - c0 + let p0=mesh.vert(v0); + let p1=mesh.vert(v1); + let p2=mesh.vert(v2); + + // local p = -a + // local u = b - a + // local v = c - a + let p=-(p0+point); + let mut u=p1-p0; + let v=p2-p0; + + // local uv = u:Cross(v) + // local up = u:Cross(p) + // local pv = p:Cross(v) + // local uv_up = uv:Dot(up) + // local uv_pv = uv:Dot(pv) + let mut uv=u.cross(v); + let mut up=u.cross(p); + let pv=p.cross(v); + let uv_up=uv.dot(up); + let uv_pv=uv.dot(pv); + + // if uv_up >= 0 and uv_pv >= 0 then + if !uv_up.is_negative()&&!uv_pv.is_negative(){ + // local uvp = uv:Dot(p) + let uvp=uv.dot(p); + + // local direction = uvp < 0 and -uv or uv + let direction=if uvp.is_negative(){ + -uv + }else{ + uv + }; + + // return direction, a0, a1, b0, b1, c0, c1 + return Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex3([v0,v1,v2]), + }; + } + + // local u_u = u:Dot(u) + // local v_v = v:Dot(v) + // local uDist = uv_up/(u_u*v.magnitude) + // local vDist = uv_pv/(v_v*u.magnitude) + // local minDist2 = math.min(uDist, vDist) + let u_dist=uv_up*v.length(); + let v_dist=uv_pv*u.length(); + + // if vDist == minDist2 then + if v_dist= 0 then + if !p_u.is_negative(){ + // local direction = up:Cross(u) + let direction=up.cross(u); + // if direction.magnitude == 0 then + if direction==vec3::zero(){ + // direction = uv + return Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; + } + + // return direction, a0, a1, b0, b1 + return Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }; + } + + // local direction = p + let dir=p; + // if direction.magnitude == 0 then + if dir==vec3::zero(){ + // direction = uv + return Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex1([v0]), + }; + } + // return direction, a0, a0 + Reduced{ + dir, + simplex:Simplex1_3::Simplex1([v0]), + } +} + +// local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) +fn reduce4( + [v0,mut v1,mut v2,v3]:Simplex<4>, + mesh:&MinkowskiMesh, + point:Planar64Vec3, +)->Reduce{ + // --debug.profilebegin("reduceSimplex3") + // local a = a1 - a0 + // local b = b1 - b0 + // local c = c1 - c0 + // local d = d1 - d0 + let p0=mesh.vert(v0); + let p1=mesh.vert(v1); + let p2=mesh.vert(v2); + let p3=mesh.vert(v3); + + // local p = -a + // local u = b - a + // local v = c - a + // local w = d - a + let p=-(p0+point); + let mut u=p1-p0; + let mut v=p2-p0; + let w=p3-p0; + + // local uv = u:Cross(v) + // local vw = v:Cross(w) + // local wu = w:Cross(u) + // local uvw = uv:Dot(w) + // local pvw = vw:Dot(p) + // local upw = wu:Dot(p) + // local uvp = uv:Dot(p) + let mut uv=u.cross(v); + let vw=v.cross(w); + let wu=w.cross(u); + let uv_w=uv.dot(w); + let pv_w=vw.dot(p); + let up_w=wu.dot(p); + let uv_p=uv.dot(p); + + // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then + if !pv_w.div_sign(uv_w).is_negative() + ||!up_w.div_sign(uv_w).is_negative() + ||!uv_p.div_sign(uv_w).is_negative(){ + // origin is contained, this is a positive detection + // local direction = Vector3.new(0, 0, 0) + // return direction, a0, a1, b0, b1, c0, c1, d0, d1 + return Reduce::Escape([v0,v1,v2,v3]); + } + + // local uvwSign = uvw < 0 and -1 or uvw > 0 and 1 or 0 + // local uvDist = uvp*uvwSign/uv.magnitude + // local vwDist = pvw*uvwSign/vw.magnitude + // local wuDist = upw*uvwSign/wu.magnitude + // local minDist3 = math.min(uvDist, vwDist, wuDist) + let uv_dist=uv_p.mul_sign(uv_w); + let vw_dist=pv_w.mul_sign(uv_w); + let wu_dist=up_w.mul_sign(uv_w); + let wu_len=wu.length(); + let uv_len=uv.length(); + let vw_len=vw.length(); + + if vw_dist*wu_len= 0 and uv_pv >= 0 then + if !uv_up.is_negative()&&!uv_pv.is_negative(){ + // local direction = uvw < 0 and uv or -uv + // return direction, a0, a1, b0, b1, c0, c1 + if uv_w.is_negative(){ + return Reduce::Reduced(Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex3([v0,v1,v2]), + }); + }else{ + return Reduce::Reduced(Reduced{ + dir:-uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex3([v0,v1,v2]), + }); + } + } + + // local u_u = u:Dot(u) + // local v_v = v:Dot(v) + // local uDist = uv_up/(u_u*v.magnitude) + // local vDist = uv_pv/(v_v*u.magnitude) + // local minDist2 = math.min(uDist, vDist) + let u_dist=uv_up*v.length(); + let v_dist=uv_pv*u.length(); + + // if vDist == minDist2 then + if v_dist= 0 then + if !p_u.is_negative(){ + // local direction = up:Cross(u) + let direction=up.cross(u); + // if direction.magnitude == 0 then + if direction==vec3::zero(){ + // direction = uvw < 0 and uv or -uv + // return direction, a0, a1, b0, b1 + if uv_w.is_negative(){ + return Reduce::Reduced(Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }); + }else{ + return Reduce::Reduced(Reduced{ + dir:-uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }); + } + } + + // return direction, a0, a1, b0, b1 + return Reduce::Reduced(Reduced{ + dir:direction.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex2([v0,v1]), + }); + } + + // local direction = p + let dir=p; + // if direction.magnitude == 0 then + if dir==vec3::zero(){ + // direction = uvw < 0 and uv or -uv + if uv_w.is_negative(){ + return Reduce::Reduced(Reduced{ + dir:uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex1([v0]), + }); + }else{ + return Reduce::Reduced(Reduced{ + dir:-uv.narrow_1().unwrap(), + simplex:Simplex1_3::Simplex1([v0]), + }); + } + } + + // return direction, a0, a1 + Reduce::Reduced(Reduced{ + dir, + simplex:Simplex1_3::Simplex1([v0]), + }) +} + +struct Reduced{ + dir:Planar64Vec3, + simplex:Simplex1_3, +} + enum Reduce{ Escape(Simplex<4>), - Reduced{ - dir:Planar64Vec3, - simplex:Simplex1_3, - } + Reduced(Reduced), } fn reduce( @@ -145,347 +503,9 @@ fn reduce( point:Planar64Vec3, )->Reduce{ match simplex{ - // local function reduceSimplex1(a0, a1, b0, b1) - Simplex2_4::Simplex2([v0,v1])=>{ - // --debug.profilebegin("reduceSimplex1") - // local a = a1 - a0 - // local b = b1 - b0 - let p0=mesh.vert(v0); - let p1=mesh.vert(v1); - - // local p = -a - // local u = b - a - let p=-(p0+point); - let u=p1-p0; - - // -- modify to take into account the radiuses - // local p_u = p:Dot(u) - let p_u=p.dot(u); - - // if p_u >= 0 then - if !p_u.is_negative(){ - // local direction = u:Cross(p):Cross(u) - let direction=u.cross(p).cross(u); - - // if direction.magnitude == 0 then - if direction==vec3::zero(){ - return Reduce::Reduced{ - dir:choose_perpendicular_direction(u), - simplex:Simplex1_3::Simplex2([v0,v1]), - }; - } - - // -- modify the direction to take into account a0R and b0R - // return direction, a0, a1, b0, b1 - return Reduce::Reduced{ - dir:direction.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex2([v0,v1]), - }; - } - - // local direction = p - let mut dir=p; - - // if direction.magnitude == 0 then - if dir==vec3::zero(){ - dir=choose_perpendicular_direction(u); - } - - // return direction, a0, a1 - Reduce::Reduced{ - dir, - simplex:Simplex1_3::Simplex1([v0]), - } - }, - // local function reduceSimplex2(a0, a1, b0, b1, c0, c1) - Simplex2_4::Simplex3([v0,mut v1,v2])=>{ - // --debug.profilebegin("reduceSimplex2") - // local a = a1 - a0 - // local b = b1 - b0 - // local c = c1 - c0 - let p0=mesh.vert(v0); - let p1=mesh.vert(v1); - let p2=mesh.vert(v2); - - // local p = -a - // local u = b - a - // local v = c - a - let p=-(p0+point); - let mut u=p1-p0; - let v=p2-p0; - - // local uv = u:Cross(v) - // local up = u:Cross(p) - // local pv = p:Cross(v) - // local uv_up = uv:Dot(up) - // local uv_pv = uv:Dot(pv) - let mut uv=u.cross(v); - let mut up=u.cross(p); - let pv=p.cross(v); - let uv_up=uv.dot(up); - let uv_pv=uv.dot(pv); - - // if uv_up >= 0 and uv_pv >= 0 then - if !uv_up.is_negative()&&!uv_pv.is_negative(){ - // local uvp = uv:Dot(p) - let uvp=uv.dot(p); - - // local direction = uvp < 0 and -uv or uv - let direction=if uvp.is_negative(){ - -uv - }else{ - uv - }; - - // return direction, a0, a1, b0, b1, c0, c1 - return Reduce::Reduced{ - dir:direction.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex3([v0,v1,v2]), - }; - } - - // local u_u = u:Dot(u) - // local v_v = v:Dot(v) - // local uDist = uv_up/(u_u*v.magnitude) - // local vDist = uv_pv/(v_v*u.magnitude) - // local minDist2 = math.min(uDist, vDist) - let u_dist=uv_up*v.length(); - let v_dist=uv_pv*u.length(); - - // if vDist == minDist2 then - if v_dist= 0 then - if !p_u.is_negative(){ - // local direction = up:Cross(u) - let direction=up.cross(u); - // if direction.magnitude == 0 then - if direction==vec3::zero(){ - // direction = uv - return Reduce::Reduced{ - dir:uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex2([v0,v1]), - }; - } - - // return direction, a0, a1, b0, b1 - return Reduce::Reduced{ - dir:direction.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex2([v0,v1]), - }; - } - - // local direction = p - let dir=p; - // if direction.magnitude == 0 then - if dir==vec3::zero(){ - // direction = uv - return Reduce::Reduced{ - dir:uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex1([v0]), - }; - } - // return direction, a0, a0 - Reduce::Reduced{ - dir, - simplex:Simplex1_3::Simplex1([v0]), - } - }, - // local function reduceSimplex3(a0, a1, b0, b1, c0, c1, d0, d1) - Simplex2_4::Simplex4([v0,mut v1,mut v2,v3])=>{ - // --debug.profilebegin("reduceSimplex3") - // local a = a1 - a0 - // local b = b1 - b0 - // local c = c1 - c0 - // local d = d1 - d0 - let p0=mesh.vert(v0); - let p1=mesh.vert(v1); - let p2=mesh.vert(v2); - let p3=mesh.vert(v3); - - // local p = -a - // local u = b - a - // local v = c - a - // local w = d - a - let p=-(p0+point); - let mut u=p1-p0; - let mut v=p2-p0; - let w=p3-p0; - - // local uv = u:Cross(v) - // local vw = v:Cross(w) - // local wu = w:Cross(u) - // local uvw = uv:Dot(w) - // local pvw = vw:Dot(p) - // local upw = wu:Dot(p) - // local uvp = uv:Dot(p) - let mut uv=u.cross(v); - let vw=v.cross(w); - let wu=w.cross(u); - let uv_w=uv.dot(w); - let pv_w=vw.dot(p); - let up_w=wu.dot(p); - let uv_p=uv.dot(p); - - // if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then - if !pv_w.div_sign(uv_w).is_negative() - ||!up_w.div_sign(uv_w).is_negative() - ||!uv_p.div_sign(uv_w).is_negative(){ - // origin is contained, this is a positive detection - // local direction = Vector3.new(0, 0, 0) - // return direction, a0, a1, b0, b1, c0, c1, d0, d1 - return Reduce::Escape([v0,v1,v2,v3]); - } - - // local uvwSign = uvw < 0 and -1 or uvw > 0 and 1 or 0 - // local uvDist = uvp*uvwSign/uv.magnitude - // local vwDist = pvw*uvwSign/vw.magnitude - // local wuDist = upw*uvwSign/wu.magnitude - // local minDist3 = math.min(uvDist, vwDist, wuDist) - let uv_dist=uv_p.mul_sign(uv_w); - let vw_dist=pv_w.mul_sign(uv_w); - let wu_dist=up_w.mul_sign(uv_w); - let wu_len=wu.length(); - let uv_len=uv.length(); - let vw_len=vw.length(); - - if vw_dist*wu_len= 0 and uv_pv >= 0 then - if !uv_up.is_negative()&&!uv_pv.is_negative(){ - // local direction = uvw < 0 and uv or -uv - // return direction, a0, a1, b0, b1, c0, c1 - if uv_w.is_negative(){ - return Reduce::Reduced{ - dir:uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex3([v0,v1,v2]), - }; - }else{ - return Reduce::Reduced{ - dir:-uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex3([v0,v1,v2]), - }; - } - } - - // local u_u = u:Dot(u) - // local v_v = v:Dot(v) - // local uDist = uv_up/(u_u*v.magnitude) - // local vDist = uv_pv/(v_v*u.magnitude) - // local minDist2 = math.min(uDist, vDist) - let u_dist=uv_up*v.length(); - let v_dist=uv_pv*u.length(); - - // if vDist == minDist2 then - if v_dist= 0 then - if !p_u.is_negative(){ - // local direction = up:Cross(u) - let direction=up.cross(u); - // if direction.magnitude == 0 then - if direction==vec3::zero(){ - // direction = uvw < 0 and uv or -uv - // return direction, a0, a1, b0, b1 - if uv_w.is_negative(){ - return Reduce::Reduced{ - dir:uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex2([v0,v1]), - }; - }else{ - return Reduce::Reduced{ - dir:-uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex2([v0,v1]), - }; - } - } - - // return direction, a0, a1, b0, b1 - return Reduce::Reduced{ - dir:direction.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex2([v0,v1]), - }; - } - - // local direction = p - let dir=p; - // if direction.magnitude == 0 then - if dir==vec3::zero(){ - // direction = uvw < 0 and uv or -uv - if uv_w.is_negative(){ - return Reduce::Reduced{ - dir:uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex1([v0]), - }; - }else{ - return Reduce::Reduced{ - dir:-uv.narrow_1().unwrap(), - simplex:Simplex1_3::Simplex1([v0]), - }; - } - } - - // return direction, a0, a1 - Reduce::Reduced{ - dir, - simplex:Simplex1_3::Simplex1([v0]), - } - }, + Simplex2_4::Simplex2(simplex)=>Reduce::Reduced(reduce2(simplex,mesh,point)), + Simplex2_4::Simplex3(simplex)=>Reduce::Reduced(reduce3(simplex,mesh,point)), + Simplex2_4::Simplex4(simplex)=>reduce4(simplex,mesh,point), } } @@ -622,9 +642,9 @@ fn minimum_difference( // Topology information is computed if needed. return on_escape(simplex); }, - Reduce::Reduced{dir,simplex}=>{ - direction=dir; - simplex_small=simplex; + Reduce::Reduced(reduced)=>{ + direction=reduced.dir; + simplex_small=reduced.simplex; }, } } -- 2.49.1 From 9c4c14c5dc9827df8e23c6c145062fb0e4f601af Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 11:43:58 -0800 Subject: [PATCH 52/90] reduce member fn --- engine/physics/src/minimum_difference.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 0e867f0d..c7218f25 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -497,15 +497,13 @@ enum Reduce{ Reduced(Reduced), } -fn reduce( - simplex:Simplex2_4, - mesh:&MinkowskiMesh, - point:Planar64Vec3, -)->Reduce{ - match simplex{ - Simplex2_4::Simplex2(simplex)=>Reduce::Reduced(reduce2(simplex,mesh,point)), - Simplex2_4::Simplex3(simplex)=>Reduce::Reduced(reduce3(simplex,mesh,point)), - Simplex2_4::Simplex4(simplex)=>reduce4(simplex,mesh,point), +impl Simplex2_4{ + fn reduce(self,mesh:&MinkowskiMesh,point:Planar64Vec3)->Reduce{ + match self{ + Self::Simplex2(simplex)=>Reduce::Reduced(reduce2(simplex,mesh,point)), + Self::Simplex3(simplex)=>Reduce::Reduced(reduce3(simplex,mesh,point)), + Self::Simplex4(simplex)=>reduce4(simplex,mesh,point), + } } } @@ -636,7 +634,7 @@ fn minimum_difference( } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) - match reduce(simplex_big,mesh,point){ + match simplex_big.reduce(mesh,point){ Reduce::Escape(simplex)=>{ // Enough information to conclude that the meshes are intersecting. // Topology information is computed if needed. -- 2.49.1 From b8be1690920dff18eb2878938e909833926aefdf Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 11:50:40 -0800 Subject: [PATCH 53/90] use struct --- engine/physics/src/minimum_difference.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index c7218f25..62d14879 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -110,7 +110,7 @@ fn reduce1( [v0]:Simplex<1>, mesh:&MinkowskiMesh, point:Planar64Vec3, -)->(Planar64Vec3,Simplex1_3){ +)->Reduced{ // --debug.profilebegin("reduceSimplex0") // local a = a1 - a0 let p0=mesh.vert(v0); @@ -119,16 +119,19 @@ fn reduce1( let p=-(p0+point); // local direction = p - let mut direction=p; + let mut dir=p; // if direction.magnitude == 0 then // direction = chooseAnyDirection() - if direction==vec3::zero(){ - direction=choose_any_direction(); + if dir==vec3::zero(){ + dir=choose_any_direction(); } // return direction, a0, a1 - (direction,Simplex1_3::Simplex1([v0])) + Reduced{ + dir, + simplex:Simplex1_3::Simplex1([v0]), + } } // local function reduceSimplex1(a0, a1, b0, b1) @@ -606,7 +609,7 @@ fn minimum_difference( direction=choose_any_direction(); } let new_point=mesh.farthest_vert(direction); - let (mut direction,mut simplex_small)=reduce1([new_point],mesh,point); + let Reduced{dir:mut direction,simplex:mut simplex_small}=reduce1([new_point],mesh,point); // exitRadius = testIntersection and 0 or exitRadius or 1/0 // for _ = 1, 100 do -- 2.49.1 From 6448d7cc575190b4d245fe307462c47e48c63fe3 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 12:12:33 -0800 Subject: [PATCH 54/90] put comment back in --- engine/physics/src/minimum_difference.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 62d14879..6f63d4ca 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -638,6 +638,7 @@ fn minimum_difference( // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) match simplex_big.reduce(mesh,point){ + // if a and b and c and d then Reduce::Escape(simplex)=>{ // Enough information to conclude that the meshes are intersecting. // Topology information is computed if needed. -- 2.49.1 From 7e7839f4aa160654f01f642662a57839e96220cc Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 25 Nov 2025 15:25:03 -0800 Subject: [PATCH 55/90] remove indexing --- engine/physics/src/minimum_difference.rs | 31 ++++++++++-------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 6f63d4ca..538bb0e5 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -27,16 +27,6 @@ enum Simplex2_4{ Simplex3(Simplex<3>), Simplex4(Simplex<4>), } -impl core::ops::Index for Simplex2_4{ - type Output=MinkowskiVert; - fn index(&self,index:usize)->&Self::Output{ - match self{ - Simplex2_4::Simplex2(s)=>&s[index], - Simplex2_4::Simplex3(s)=>&s[index], - Simplex2_4::Simplex4(s)=>&s[index], - } - } -} /* local function absDet(r, u, v, w) @@ -555,12 +545,12 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ const ENABLE_FAST_FAIL:bool=true; minimum_difference::(mesh,point, // on_exact - |simplex,direction|{ + |last_pos,direction|{ // local norm = direction.unit // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ // return hits - (mesh.vert(simplex[1])+point).dot(direction).is_positive() + (last_pos+point).dot(direction).is_positive() }, // on_escape |_simplex|{ @@ -575,7 +565,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ const ENABLE_FAST_FAIL:bool=false; minimum_difference::(mesh,point, // on_exact - |simplex,_direction|Topology{simplex}, + |_last_pos,_direction|unimplemented!(), // on_escape |simplex|{ // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) @@ -595,7 +585,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ fn minimum_difference( mesh:&MinkowskiMesh, point:Planar64Vec3, - on_exact:impl FnOnce(Simplex2_4,Planar64Vec3)->T, + on_exact:impl FnOnce(Planar64Vec3,Planar64Vec3)->T, on_escape:impl FnOnce(Simplex<4>)->T, on_fast_fail:impl FnOnce()->T, )->T{ @@ -608,8 +598,10 @@ fn minimum_difference( if direction==vec3::zero(){ direction=choose_any_direction(); } - let new_point=mesh.farthest_vert(direction); - let Reduced{dir:mut direction,simplex:mut simplex_small}=reduce1([new_point],mesh,point); + let last_point=mesh.farthest_vert(direction); + // this represents the 'a' value in the commented code + let mut last_pos=mesh.vert(last_point); + let Reduced{dir:mut direction,simplex:mut simplex_small}=reduce1([last_point],mesh,point); // exitRadius = testIntersection and 0 or exitRadius or 1/0 // for _ = 1, 100 do @@ -630,10 +622,10 @@ fn minimum_difference( // if // direction:Dot(next_point - a) <= 0 or // absDet(next_point, a, b, c) < 1e-6 - if !direction.dot(next_pos-mesh.vert(simplex_big[1])).is_positive() + if !direction.dot(next_pos-last_pos).is_positive() ||simplex_big.det_is_zero(mesh){ // Found enough information to compute the exact closest point. - return on_exact(simplex_big,direction); + return on_exact(last_pos,direction); } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) @@ -649,5 +641,8 @@ fn minimum_difference( simplex_small=reduced.simplex; }, } + + // next loop this will be a + last_pos=next_pos; } } -- 2.49.1 From 5641e9a26f42c96c2c28d4b60a30c636dd65305c Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Wed, 26 Nov 2025 09:45:03 -0800 Subject: [PATCH 56/90] physics: derive Eq for Minkowski FEV --- engine/physics/src/model.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index fd02f9f4..cb18c596 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -572,7 +572,7 @@ impl MeshQuery for TransformedMesh<'_>{ //(face,vertex) //(edge,edge) //(vertex,face) -#[derive(Clone,Copy,Debug)] +#[derive(Clone,Copy,Debug,Eq,PartialEq)] pub enum MinkowskiVert{ VertVert(SubmeshVertId,SubmeshVertId), } @@ -591,7 +591,7 @@ impl UndirectedEdge for MinkowskiEdge{ } } } -#[derive(Clone,Copy,Debug)] +#[derive(Clone,Copy,Debug,Eq,PartialEq)] pub enum MinkowskiDirectedEdge{ VertEdge(SubmeshVertId,SubmeshDirectedEdgeId), EdgeVert(SubmeshDirectedEdgeId,SubmeshVertId), -- 2.49.1 From da718e4bd22add6733101dfcea02d9e1568e1ae2 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 27 Nov 2025 09:54:17 -0800 Subject: [PATCH 57/90] rename variable --- engine/physics/src/minimum_difference.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 538bb0e5..5cdf9228 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -593,12 +593,12 @@ fn minimum_difference( // local new_point_p = queryP(initialAxis) // local new_point_q = queryQ(-initialAxis) // local direction, a0, a1, b0, b1, c0, c1, d0, d1 - let mut direction=mesh.hint_point()+point; + let mut initial_axis=mesh.hint_point()+point; // degenerate case - if direction==vec3::zero(){ - direction=choose_any_direction(); + if initial_axis==vec3::zero(){ + initial_axis=choose_any_direction(); } - let last_point=mesh.farthest_vert(direction); + let last_point=mesh.farthest_vert(initial_axis); // this represents the 'a' value in the commented code let mut last_pos=mesh.vert(last_point); let Reduced{dir:mut direction,simplex:mut simplex_small}=reduce1([last_point],mesh,point); -- 2.49.1 From 5e14a85d845cd1defbef02526034a542341705c7 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Wed, 26 Nov 2025 12:30:06 -0800 Subject: [PATCH 58/90] make hint_point consistent with vert --- engine/physics/src/model.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index cb18c596..ddced6fc 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -858,8 +858,7 @@ impl MeshQuery for MinkowskiMesh<'_>{ } } fn hint_point(&self)->Planar64Vec3{ - self.mesh1.transform.vertex.translation- - self.mesh0.transform.vertex.translation + self.mesh0.transform.vertex.translation-self.mesh1.transform.vertex.translation } fn face_edges(&self,face_id:MinkowskiFace)->impl AsRef<[MinkowskiDirectedEdge]>{ match face_id{ -- 2.49.1 From f90436f0cc569eaa7422d1bb2df93f7e76965610 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 27 Nov 2025 09:59:56 -0800 Subject: [PATCH 59/90] negate minkowski input to minimum_difference --- engine/physics/src/minimum_difference.rs | 10 ++++++---- engine/physics/src/model.rs | 12 ++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index 5cdf9228..a04cbf8b 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -543,7 +543,8 @@ pub struct Details{ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ const ENABLE_FAST_FAIL:bool=true; - minimum_difference::(mesh,point, + // TODO: remove mesh negation + minimum_difference::(&-mesh,point, // on_exact |last_pos,direction|{ // local norm = direction.unit @@ -563,7 +564,8 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ } pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ const ENABLE_FAST_FAIL:bool=false; - minimum_difference::(mesh,point, + // TODO: remove mesh negation + minimum_difference::(&-mesh,point, // on_exact |_last_pos,_direction|unimplemented!(), // on_escape @@ -598,7 +600,7 @@ fn minimum_difference( if initial_axis==vec3::zero(){ initial_axis=choose_any_direction(); } - let last_point=mesh.farthest_vert(initial_axis); + let last_point=mesh.farthest_vert(-initial_axis); // this represents the 'a' value in the commented code let mut last_pos=mesh.vert(last_point); let Reduced{dir:mut direction,simplex:mut simplex_small}=reduce1([last_point],mesh,point); @@ -609,7 +611,7 @@ fn minimum_difference( // new_point_p = queryP(-direction) // new_point_q = queryQ(direction) // local next_point = new_point_q - new_point_p - let next_point=mesh.farthest_vert(-direction); + let next_point=mesh.farthest_vert(direction); let next_pos=mesh.vert(next_point); // if -direction:Dot(next_point) > (exitRadius + radiusP + radiusQ)*direction.magnitude then diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index ddced6fc..8d801d00 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -439,7 +439,7 @@ impl TryFrom<&model::Mesh> for PhysicsMesh{ } } -#[derive(Debug)] +#[derive(Debug,Clone,Copy)] pub struct PhysicsMeshView<'a>{ data:&'a PhysicsMeshData, topology:&'a PhysicsMeshTopology, @@ -496,7 +496,7 @@ impl PhysicsMeshTransform{ } } -#[derive(Debug)] +#[derive(Debug,Clone,Copy)] pub struct TransformedMesh<'a>{ view:PhysicsMeshView<'a>, transform:&'a PhysicsMeshTransform, @@ -645,6 +645,14 @@ pub fn into_giga_time(time:Time,relative_to:Time)->GigaTime{ Ratio::new(r.num.widen_4(),r.den.widen_4()) } +// TODO: remove this +impl<'a> core::ops::Neg for &MinkowskiMesh<'a>{ + type Output=MinkowskiMesh<'a>; + fn neg(self)->Self::Output{ + MinkowskiMesh::minkowski_sum(self.mesh1,self.mesh0) + } +} + impl MinkowskiMesh<'_>{ pub fn minkowski_sum<'a>(mesh0:TransformedMesh<'a>,mesh1:TransformedMesh<'a>)->MinkowskiMesh<'a>{ MinkowskiMesh{ -- 2.49.1 From 9d04df4894c8135952b2b2abd4937b2674ae0768 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 27 Nov 2025 10:59:33 -0800 Subject: [PATCH 60/90] convert to fev using dumbest algorithm possible --- engine/physics/src/minimum_difference.rs | 63 ++++++++++++++++++++---- engine/physics/src/model.rs | 11 ++++- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index a04cbf8b..e947f354 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -2,12 +2,13 @@ use strafesnet_common::integer::vec3; use strafesnet_common::integer::vec3::Vector3; use strafesnet_common::integer::{Fixed,Planar64Vec3}; -use crate::model::{MeshQuery,MinkowskiMesh,MinkowskiVert}; +use crate::model::{DirectedEdge,FEV,MeshQuery,MinkowskiMesh,MinkowskiVert}; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 type Simplex=[MinkowskiVert;N]; +#[derive(Clone,Copy)] enum Simplex1_3{ Simplex1(Simplex<1>), Simplex2(Simplex<2>), @@ -546,7 +547,7 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ // TODO: remove mesh negation minimum_difference::(&-mesh,point, // on_exact - |last_pos,direction|{ + |_simplex,last_pos,direction|{ // local norm = direction.unit // local dist = a:Dot(norm) // local hits = -dist < radiusP + radiusQ @@ -562,17 +563,61 @@ pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ ||false ) } -pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ +#[derive(Debug)] +pub struct OhNoes; +pub fn closest_fev_not_inside<'a>(mesh:&MinkowskiMesh<'a>,point:Planar64Vec3)->Option>,OhNoes>>{ const ENABLE_FAST_FAIL:bool=false; // TODO: remove mesh negation minimum_difference::(&-mesh,point, // on_exact - |_last_pos,_direction|unimplemented!(), + |simplex,_last_pos,_direction|{ + // Convert simplex to FEV + // Vertices must be inverted since the mesh is inverted + Some(match simplex{ + Simplex1_3::Simplex1([v0])=>Ok(FEV::Vert(-v0)), + Simplex1_3::Simplex2([v0,v1])=>{ + // invert + let (v0,v1)=(-v0,-v1); + // dumbest stupidest brute force search + let v0e=mesh.vert_edges(v0); + for &v0e in v0e.as_ref(){ + // check opposite vertex to see if it is v1 + if mesh.edge_verts(v0e.as_undirected()).as_ref()[v0e.parity() as usize]==v1{ + return Some(Ok(FEV::Edge(v0e.as_undirected()))); + } + } + Err(OhNoes) + }, + Simplex1_3::Simplex3([v0,v1,v2])=>{ + // invert + let (v0,v1,v2)=(-v0,-v1,-v2); + // dumbest stupidest brute force search + let v0e=mesh.vert_edges(v0); + for &v0e in v0e.as_ref(){ + // check opposite vertex to see if it is v1 + if mesh.edge_verts(v0e.as_undirected()).as_ref()[v0e.parity() as usize]==v1{ + // check if a vertex of the face is v2 + let ef=mesh.edge_faces(v0e.as_undirected()); + for &ef in ef.as_ref(){ + let fe=mesh.face_edges(ef); + for e in fe.as_ref(){ + if mesh.edge_verts(e.as_undirected()).as_ref()[e.parity() as usize]==v2{ + return Some(Ok(FEV::Face(ef))); + } + } + } + } + } + Err(OhNoes) + }, + }) + }, // on_escape - |simplex|{ + |_simplex|{ + // intersection is guaranteed at this point // local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5) - let simplex=refine_to_exact(mesh,simplex); - Topology{simplex} + // let simplex=refine_to_exact(mesh,simplex); + None }, // fast_fail value is irrelevant and will never be returned! ||unreachable!() @@ -587,7 +632,7 @@ pub fn closest_fev(mesh:&MinkowskiMesh,point:Planar64Vec3)->Topology{ fn minimum_difference( mesh:&MinkowskiMesh, point:Planar64Vec3, - on_exact:impl FnOnce(Planar64Vec3,Planar64Vec3)->T, + on_exact:impl FnOnce(Simplex1_3,Planar64Vec3,Planar64Vec3)->T, on_escape:impl FnOnce(Simplex<4>)->T, on_fast_fail:impl FnOnce()->T, )->T{ @@ -627,7 +672,7 @@ fn minimum_difference( if !direction.dot(next_pos-last_pos).is_positive() ||simplex_big.det_is_zero(mesh){ // Found enough information to compute the exact closest point. - return on_exact(last_pos,direction); + return on_exact(simplex_small,last_pos,direction); } // direction, a0, a1, b0, b1, c0, c1, d0, d1 = reduceSimplex(new_point_p, new_point_q, a0, a1, b0, b1, c0, c1) diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index 8d801d00..3d9d042c 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -576,7 +576,16 @@ impl MeshQuery for TransformedMesh<'_>{ pub enum MinkowskiVert{ VertVert(SubmeshVertId,SubmeshVertId), } -#[derive(Clone,Copy,Debug)] +// TODO: remove this +impl core::ops::Neg for MinkowskiVert{ + type Output=Self; + fn neg(self)->Self::Output{ + match self{ + MinkowskiVert::VertVert(v0,v1)=>MinkowskiVert::VertVert(v1,v0), + } + } +} +#[derive(Clone,Copy,Debug,Eq,PartialEq)] pub enum MinkowskiEdge{ VertEdge(SubmeshVertId,SubmeshEdgeId), EdgeVert(SubmeshEdgeId,SubmeshVertId), -- 2.49.1 From f3b02bba9267bfe8f1ced39f04c81c4ee14f027e Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 27 Nov 2025 11:52:16 -0800 Subject: [PATCH 61/90] use new algorithm --- engine/physics/src/face_crawler.rs | 6 - engine/physics/src/minimum_difference.rs | 41 ------- engine/physics/src/model.rs | 143 ++--------------------- 3 files changed, 8 insertions(+), 182 deletions(-) diff --git a/engine/physics/src/face_crawler.rs b/engine/physics/src/face_crawler.rs index a012fd17..44cfb914 100644 --- a/engine/physics/src/face_crawler.rs +++ b/engine/physics/src/face_crawler.rs @@ -21,12 +21,6 @@ impl CrawlResult{ CrawlResult::Hit(face,time)=>Some((face,time)), } } - pub fn miss(self)->Option>{ - match self{ - CrawlResult::Miss(fev)=>Some(fev), - CrawlResult::Hit(_,_)=>None, - } - } } // TODO: move predict_collision_face_out algorithm in here or something diff --git a/engine/physics/src/minimum_difference.rs b/engine/physics/src/minimum_difference.rs index e947f354..05a1181f 100644 --- a/engine/physics/src/minimum_difference.rs +++ b/engine/physics/src/minimum_difference.rs @@ -501,47 +501,6 @@ impl Simplex2_4{ } } -// local function expand( -// queryP, queryQ, -// vertA0, vertA1, -// vertB0, vertB1, -// vertC0, vertC1, -// vertD0, vertD1, -// accuracy -// ) -fn refine_to_exact(mesh:&MinkowskiMesh,simplex:Simplex<4>)->Simplex2_4{ - unimplemented!() -} - -/// Intermediate data structure containing a partially complete calculation. -/// Sometimes you only care about the topology, and not about the -/// exact point of intersection details. -pub struct Topology{ - simplex:Simplex2_4, -} -impl Topology{ - /// Returns None if the point is intersecting the mesh. - pub fn closest_point_details(self,mesh:&MinkowskiMesh)->Option
{ - // NOTE: if hits is true, this if statement necessarily evaluates to true. - // i.e. hits implies this statement - // if -dist <= exitRadius + radiusP + radiusQ then - // local posP, posQ = decompose(-point, a0, a1, b0, b1, c0, c1) - // return hits, -dist - radiusP - radiusQ, - // posP - radiusP*norm, -norm, - // posQ + radiusQ*norm, norm - // end - // return false - unimplemented!() - } -} -pub struct Details{ - // distance:Planar64, - // p_pos:Planar64Vec3, - // p_norm:Planar64Vec3, - // q_pos:Planar64Vec3, - // q_norm:Planar64Vec3, -} - pub fn contains_point(mesh:&MinkowskiMesh,point:Planar64Vec3)->bool{ const ENABLE_FAST_FAIL:bool=true; // TODO: remove mesh negation diff --git a/engine/physics/src/model.rs b/engine/physics/src/model.rs index 3d9d042c..5b61b73c 100644 --- a/engine/physics/src/model.rs +++ b/engine/physics/src/model.rs @@ -637,17 +637,6 @@ pub struct MinkowskiMesh<'a>{ mesh1:TransformedMesh<'a>, } -//infinity fev algorithm state transition -#[derive(Debug)] -enum Transition{ - Done,//found closest vert, no edges are better - Vert(MinkowskiVert),//transition to vert -} -enum EV{ - Vert(MinkowskiVert), - Edge(MinkowskiEdge), -} - pub type GigaTime=Ratio,Fixed<4,128>>; pub fn into_giga_time(time:Time,relative_to:Time)->GigaTime{ let r=(time-relative_to).to_ratio(); @@ -672,137 +661,21 @@ impl MinkowskiMesh<'_>{ pub fn farthest_vert(&self,dir:Planar64Vec3)->MinkowskiVert{ MinkowskiVert::VertVert(self.mesh0.farthest_vert(dir),self.mesh1.farthest_vert(-dir)) } - fn next_transition_vert(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Fixed<2,64>,infinity_dir:Planar64Vec3,point:Planar64Vec3)->Transition{ - let mut best_transition=Transition::Done; - for &directed_edge_id in self.vert_edges(vert_id).as_ref(){ - let edge_n=self.directed_edge_n(directed_edge_id); - //is boundary uncrossable by a crawl from infinity - let edge_verts=self.edge_verts(directed_edge_id.as_undirected()); - //select opposite vertex - let test_vert_id=edge_verts.as_ref()[directed_edge_id.parity() as usize]; - //test if it's closer - let diff=point-self.vert(test_vert_id); - if edge_n.dot(infinity_dir).is_zero(){ - let distance_squared=diff.dot(diff); - if distance_squared<*best_distance_squared{ - best_transition=Transition::Vert(test_vert_id); - *best_distance_squared=distance_squared; - } - } - } - best_transition - } - fn final_ev(&self,vert_id:MinkowskiVert,best_distance_squared:&mut Fixed<2,64>,infinity_dir:Planar64Vec3,point:Planar64Vec3)->EV{ - let mut best_transition=EV::Vert(vert_id); - let diff=point-self.vert(vert_id); - for &directed_edge_id in self.vert_edges(vert_id).as_ref(){ - let edge_n=self.directed_edge_n(directed_edge_id); - //is boundary uncrossable by a crawl from infinity - //check if time of collision is outside Time::MIN..Time::MAX - if edge_n.dot(infinity_dir).is_zero(){ - let d=edge_n.dot(diff); - //test the edge - let edge_nn=edge_n.dot(edge_n); - if !d.is_negative()&&d<=edge_nn{ - let distance_squared={ - let c=diff.cross(edge_n); - //wrap for speed - (c.dot(c)/edge_nn).divide().wrap_2() - }; - if distance_squared<=*best_distance_squared{ - best_transition=EV::Edge(directed_edge_id.as_undirected()); - *best_distance_squared=distance_squared; - } - } - } - } - best_transition - } - fn crawl_boundaries(&self,mut vert_id:MinkowskiVert,infinity_dir:Planar64Vec3,point:Planar64Vec3)->EV{ - let mut best_distance_squared={ - let diff=point-self.vert(vert_id); - diff.dot(diff) - }; - loop{ - match self.next_transition_vert(vert_id,&mut best_distance_squared,infinity_dir,point){ - Transition::Done=>return self.final_ev(vert_id,&mut best_distance_squared,infinity_dir,point), - Transition::Vert(new_vert_id)=>vert_id=new_vert_id, - } - } - } - /// This function drops a vertex down to an edge or a face if the path from infinity did not cross any vertex-edge boundaries but the point is supposed to have already crossed a boundary down from a vertex - fn infinity_fev(&self,infinity_dir:Planar64Vec3,point:Planar64Vec3)->FEV::>{ - //start on any vertex - //cross uncrossable vertex-edge boundaries until you find the closest vertex or edge - //cross edge-face boundary if it's uncrossable - match self.crawl_boundaries(self.farthest_vert(infinity_dir),infinity_dir,point){ - //if a vert is returned, it is the closest point to the infinity point - EV::Vert(vert_id)=>FEV::Vert(vert_id), - EV::Edge(edge_id)=>{ - //cross to face if the boundary is not crossable and we are on the wrong side - let edge_n=self.edge_n(edge_id); - // point is multiplied by two because vert_sum sums two vertices. - let delta_pos=point*2-{ - let &[v0,v1]=self.edge_verts(edge_id).as_ref(); - self.vert(v0)+self.vert(v1) - }; - for (i,&face_id) in self.edge_faces(edge_id).as_ref().iter().enumerate(){ - let face_n=self.face_nd(face_id).0; - //edge-face boundary nd, n facing out of the face towards the edge - let boundary_n=face_n.cross(edge_n)*(i as i64*2-1); - let boundary_d=boundary_n.dot(delta_pos); - //check if time of collision is outside Time::MIN..Time::MAX - //infinity_dir can always be treated as a velocity - if !boundary_d.is_positive()&&boundary_n.dot(infinity_dir).is_zero(){ - //both faces cannot pass this condition, return early if one does. - return FEV::Face(face_id); - } - } - FEV::Edge(edge_id) - }, - } - } - // TODO: fundamentally improve this algorithm. - // All it needs to do is find the closest point on the mesh - // and return the FEV which the point resides on. - // - // What it actually does is use the above functions to trace a ray in from infinity, - // crawling the closest point along the mesh surface until the ray reaches - // the starting point to discover the final FEV. - // - // The actual collision prediction probably does a single test - // and then immediately returns with 0 FEV transitions on average, - // because of the strict time_limit constraint. - // - // Most of the calculation time is just calculating the starting point - // for the "actual" crawling algorithm below (predict_collision_{in|out}). - fn closest_fev_not_inside(&self,mut infinity_body:Body,start_time:Bound<&Time>)->Option>>{ - infinity_body.infinity_dir().and_then(|dir|{ - let infinity_fev=self.infinity_fev(-dir,infinity_body.position); - //a line is simpler to solve than a parabola - infinity_body.velocity=dir; - infinity_body.acceleration=vec3::zero(); - //crawl in from negative infinity along a tangent line to get the closest fev - infinity_fev.crawl(self,&infinity_body,Bound::Unbounded,start_time).miss() - }) - } pub fn predict_collision_in(&self,relative_body:&Body,range:impl RangeBounds