2023-11-30 09:51:17 +00:00
|
|
|
use crate::physics::Body;
|
2024-09-11 22:58:13 +00:00
|
|
|
use crate::model_physics::{GigaTime,FEV,MeshQuery,DirectedEdge,MinkowskiMesh,MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert};
|
|
|
|
use strafesnet_common::integer::{Time,Fixed,Ratio};
|
2023-11-30 09:51:17 +00:00
|
|
|
|
2024-09-11 22:58:13 +00:00
|
|
|
#[derive(Debug)]
|
2023-11-30 09:51:17 +00:00
|
|
|
enum Transition<F,E:DirectedEdge,V>{
|
|
|
|
Miss,
|
2024-09-11 22:58:13 +00:00
|
|
|
Next(FEV<F,E,V>,GigaTime),
|
|
|
|
Hit(F,GigaTime),
|
2023-11-30 09:51:17 +00:00
|
|
|
}
|
|
|
|
|
2024-09-11 22:58:13 +00:00
|
|
|
type MinkowskiFEV=FEV<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
|
|
|
|
type MinkowskiTransition=Transition<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
|
|
|
|
|
|
|
|
fn next_transition(fev:&MinkowskiFEV,body_time:GigaTime,mesh:&MinkowskiMesh,body:&Body,mut best_time:GigaTime)->MinkowskiTransition{
|
2023-11-30 09:51:17 +00:00
|
|
|
//conflicting derivative means it crosses in the wrong direction.
|
|
|
|
//if the transition time is equal to an already tested transition, do not replace the current best.
|
2024-09-11 22:58:13 +00:00
|
|
|
let mut best_transition=MinkowskiTransition::Miss;
|
2023-11-30 09:51:17 +00:00
|
|
|
match fev{
|
2024-09-11 22:58:13 +00:00
|
|
|
&MinkowskiFEV::Face(face_id)=>{
|
2023-11-30 09:51:17 +00:00
|
|
|
//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);
|
2023-12-02 10:02:51 +00:00
|
|
|
//TODO: use higher precision d value?
|
|
|
|
//use the mesh transform translation instead of baking it into the d value.
|
2024-09-11 22:58:13 +00:00
|
|
|
for dt in Fixed::<4,128>::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
|
|
|
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
|
|
|
best_time=dt;
|
|
|
|
best_transition=MinkowskiTransition::Hit(face_id,dt);
|
2023-11-30 09:51:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
|
|
|
for &directed_edge_id in mesh.face_edges(face_id).iter(){
|
|
|
|
let edge_n=mesh.directed_edge_n(directed_edge_id);
|
|
|
|
let n=n.cross(edge_n);
|
|
|
|
let verts=mesh.edge_verts(directed_edge_id.as_undirected());
|
|
|
|
//WARNING: d is moved out of the *2 block because of adding two vertices!
|
2024-09-11 22:58:13 +00:00
|
|
|
//WARNING: precision is swept under the rug!
|
|
|
|
for dt in Fixed::<4,128>::zeroes2(n.dot(body.position*2-(mesh.vert(verts[0])+mesh.vert(verts[1]))).fix_4(),n.dot(body.velocity).fix_4()*2,n.dot(body.acceleration).fix_4()){
|
|
|
|
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
|
|
|
best_time=dt;
|
|
|
|
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Edge(directed_edge_id.as_undirected()),dt);
|
2023-11-30 09:51:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//if none:
|
|
|
|
},
|
2024-09-11 22:58:13 +00:00
|
|
|
&MinkowskiFEV::Edge(edge_id)=>{
|
2023-11-30 09:51:17 +00:00
|
|
|
//test each face collision time, ignoring roots with zero or conflicting derivative
|
|
|
|
let edge_n=mesh.edge_n(edge_id);
|
|
|
|
let edge_verts=mesh.edge_verts(edge_id);
|
2023-12-02 09:58:18 +00:00
|
|
|
let delta_pos=body.position*2-(mesh.vert(edge_verts[0])+mesh.vert(edge_verts[1]));
|
2023-11-30 09:51:17 +00:00
|
|
|
for (i,&edge_face_id) in mesh.edge_faces(edge_id).iter().enumerate(){
|
|
|
|
let face_n=mesh.face_nd(edge_face_id).0;
|
|
|
|
//edge_n gets parity from the order of edge_faces
|
|
|
|
let n=face_n.cross(edge_n)*((i as i64)*2-1);
|
|
|
|
//WARNING yada yada d *2
|
2024-09-11 22:58:13 +00:00
|
|
|
for dt in Fixed::<4,128>::zeroes2(n.dot(delta_pos).fix_4(),n.dot(body.velocity).fix_4()*2,n.dot(body.acceleration).fix_4()){
|
|
|
|
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
|
|
|
best_time=dt;
|
|
|
|
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Face(edge_face_id),dt);
|
2023-11-30 09:51:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//test each vertex collision time, ignoring roots with zero or conflicting derivative
|
|
|
|
for (i,&vert_id) in edge_verts.iter().enumerate(){
|
|
|
|
//vertex normal gets parity from vert index
|
|
|
|
let n=edge_n*(1-2*(i as i64));
|
2024-09-11 22:58:13 +00:00
|
|
|
for dt in Fixed::<2,64>::zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
|
|
|
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
|
|
|
let dt=Ratio::new(dt.num.fix_4(),dt.den.fix_4());
|
|
|
|
best_time=dt;
|
|
|
|
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Vert(vert_id),dt);
|
2023-11-30 09:51:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//if none:
|
|
|
|
},
|
2024-09-11 22:58:13 +00:00
|
|
|
&MinkowskiFEV::Vert(vert_id)=>{
|
2023-11-30 09:51:17 +00:00
|
|
|
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
|
|
|
for &directed_edge_id in mesh.vert_edges(vert_id).iter(){
|
|
|
|
//edge is directed away from vertex, but we want the dot product to turn out negative
|
|
|
|
let n=-mesh.directed_edge_n(directed_edge_id);
|
2024-09-11 22:58:13 +00:00
|
|
|
for dt in Fixed::<2,64>::zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
|
|
|
if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
|
|
|
|
let dt=Ratio::new(dt.num.fix_4(),dt.den.fix_4());
|
|
|
|
best_time=dt;
|
|
|
|
best_transition=MinkowskiTransition::Next(MinkowskiFEV::Edge(directed_edge_id.as_undirected()),dt);
|
2023-11-30 09:51:17 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//if none:
|
|
|
|
},
|
|
|
|
}
|
2024-09-11 22:58:13 +00:00
|
|
|
best_transition
|
2023-11-30 09:51:17 +00:00
|
|
|
}
|
|
|
|
pub enum CrawlResult<F,E:DirectedEdge,V>{
|
|
|
|
Miss(FEV<F,E,V>),
|
2024-09-11 22:58:13 +00:00
|
|
|
Hit(F,GigaTime),
|
2023-11-30 09:51:17 +00:00
|
|
|
}
|
2024-09-11 22:58:13 +00:00
|
|
|
type MinkowskiCrawlResult=CrawlResult<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
|
|
|
|
pub fn crawl_fev(mut fev:MinkowskiFEV,mesh:&MinkowskiMesh,relative_body:&Body,start_time:Time,time_limit:Time)->MinkowskiCrawlResult{
|
|
|
|
let mut body_time={
|
|
|
|
let r=(start_time-relative_body.time).to_ratio();
|
|
|
|
Ratio::new(r.num.fix_4(),r.den.fix_4())
|
|
|
|
};
|
|
|
|
let time_limit={
|
|
|
|
let r=(time_limit-relative_body.time).to_ratio();
|
|
|
|
Ratio::new(r.num.fix_4(),r.den.fix_4())
|
|
|
|
};
|
2023-11-30 09:51:17 +00:00
|
|
|
for _ in 0..20{
|
2024-09-11 22:58:13 +00:00
|
|
|
match next_transition(&fev,body_time,mesh,relative_body,time_limit){
|
2023-11-30 09:51:17 +00:00
|
|
|
Transition::Miss=>return CrawlResult::Miss(fev),
|
2024-09-11 22:58:13 +00:00
|
|
|
Transition::Next(next_fev,next_time)=>(fev,body_time)=(next_fev,next_time),
|
2023-11-30 09:51:17 +00:00
|
|
|
Transition::Hit(face,time)=>return CrawlResult::Hit(face,time),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//TODO: fix all bugs
|
2024-02-15 08:21:21 +00:00
|
|
|
//println!("Too many iterations! Using default behaviour instead of crashing...");
|
2023-11-30 09:51:17 +00:00
|
|
|
CrawlResult::Miss(fev)
|
|
|
|
}
|