strafe-client/src/face_crawler.rs

119 lines
4.3 KiB
Rust
Raw Normal View History

2023-10-26 04:31:53 +00:00
use crate::physics::Body;
2023-10-26 23:18:32 +00:00
use crate::model_physics::{VirtualMesh,FEV,FaceId};
2023-10-27 02:38:37 +00:00
use crate::integer::{Time,Planar64,Planar64Vec3};
use crate::zeroes::zeroes2;
2023-10-26 04:31:53 +00:00
2023-10-26 04:22:28 +00:00
struct State{
fev:FEV,
2023-10-27 02:38:34 +00:00
time:Time,
2023-10-26 04:22:28 +00:00
}
enum Transition{
Miss,
2023-10-27 02:38:34 +00:00
Next(FEV,Time),
2023-10-26 04:22:28 +00:00
Hit(FaceId,Time),
}
2023-10-26 04:31:53 +00:00
impl State{
2023-10-26 22:51:47 +00:00
fn next_transition(&self,mesh:&VirtualMesh,body:&Body,time_limit:Time)->Transition{
2023-10-26 04:31:53 +00:00
//conflicting derivative means it crosses in the wrong direction.
2023-10-26 22:51:47 +00:00
//if the transition time is equal to an already tested transition, do not replace the current best.
let mut best_time=time_limit;
let mut best_transtition=Transition::Miss;
2023-10-26 22:51:47 +00:00
match &self.fev{
&FEV::Face(face_id)=>{
//test own face collision time, ignoring roots with zero or conflicting derivative
//n=face.normal d=face.dot
//n.a t^2+n.v t+n.p-d==0
let (n,d)=mesh.face_nd(face_id);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Hit(face_id,t);
}
}
//test each edge collision time, ignoring roots with zero or conflicting derivative
for &(edge_id,test_face_id) in mesh.face_edges(face_id){
let (n,d)=mesh.face_nd(test_face_id);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::Edge(edge_id),t);
break;
}
}
}
2023-10-26 22:51:47 +00:00
//if none:
2023-10-26 04:31:53 +00:00
},
&FEV::Edge(edge_id)=>{
//test each face collision time, ignoring roots with zero or conflicting derivative
for &test_face_id in mesh.edge_side_faces(edge_id){
let (n,d)=mesh.face_nd(test_face_id);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::Face(test_face_id),t);
break;
}
}
}
//test each vertex collision time, ignoring roots with zero or conflicting derivative
for &(vert_id,test_face_id) in mesh.edge_ends(edge_id){
let (n,d)=mesh.face_nd(test_face_id);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::Vert(vert_id),t);
break;
}
}
}
2023-10-26 22:51:47 +00:00
//if none:
2023-10-26 04:31:53 +00:00
},
&FEV::Vert(vertex_id)=>{
//test each edge collision time, ignoring roots with zero or conflicting derivative
for &(edge_id,test_face_id) in mesh.vert_edges(vertex_id){
let (n,d)=mesh.face_nd(test_face_id);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
if self.time<t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::Edge(edge_id),t);
break;
}
}
}
2023-10-26 22:51:47 +00:00
//if none:
2023-10-26 04:31:53 +00:00
},
}
best_transtition
2023-10-26 04:31:53 +00:00
}
}
2023-10-26 23:18:32 +00:00
pub fn predict_collision(mesh:&VirtualMesh,relative_body:&Body,time_limit:Time)->Option<(FaceId,Time)>{
let mut state=State{
fev:mesh.closest_fev(relative_body.position),
2023-10-27 02:38:37 +00:00
time:relative_body.time,
2023-10-26 23:18:32 +00:00
};
//it would be possible to write down the point of closest approach...
loop{
match state.next_transition(mesh,relative_body,time_limit){
Transition::Miss=>return None,
2023-10-27 02:38:37 +00:00
Transition::Next(fev,time)=>(state.fev,state.time)=(fev,time),
Transition::Hit(face,time)=>return Some((face,time)),
2023-10-26 04:31:53 +00:00
}
}
}
2023-10-27 03:52:38 +00:00
pub fn predict_collision_end(mesh:&VirtualMesh,relative_body:&Body,time_limit:Time,c:&crate::physics::RelativeCollision)->Option<(FaceId,Time)>{
//imagine the mesh without the collision face
//no algorithm needed, there is only one state and three cases (Face,Edge,None)
//determine when it passes an edge ("sliding off" case) or if it leaves the surface directly
//the state can be constructed from the RelativeCollision directly
None
}