do face crawler

This commit is contained in:
Quaternions 2024-09-16 13:03:50 -07:00
parent 215dfab8a9
commit 4556bc8741

View File

@ -1,31 +1,32 @@
use crate::physics::Body; use crate::physics::Body;
use crate::model_physics::{FEV,MeshQuery,DirectedEdge}; use crate::model_physics::{FEV,MeshQuery,DirectedEdge,MinkowskiMesh,MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert};
use strafesnet_common::integer::{Time,Fixed,Planar64}; use strafesnet_common::integer::{Time,Fixed,Ratio};
enum Transition<F,E:DirectedEdge,V>{ enum Transition<F,E:DirectedEdge,V>{
Miss, Miss,
Next(FEV<F,E,V>,Time), Next(FEV<F,E,V>,Ratio<Fixed<4,128>,Fixed<4,128>>),
Hit(F,Time), Hit(F,Ratio<Fixed<4,128>,Fixed<4,128>>),
} }
fn next_transition<F:Copy,E:Copy+DirectedEdge,V:Copy>(fev:&FEV<F,E,V>,time:Time,mesh:&impl MeshQuery<F,E,V>,body:&Body,time_limit:Time)->Transition<F,E,V>{ type MinkowskiFEV=FEV<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
type MinkowskiTransition=Transition<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
fn next_transition(fev:&MinkowskiFEV,body_time:Ratio<Fixed<4,128>,Fixed<4,128>>,mesh:&MinkowskiMesh,body:&Body,mut best_time:Ratio<Fixed<4,128>,Fixed<4,128>>)->MinkowskiTransition{
//conflicting derivative means it crosses in the wrong direction. //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. //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=MinkowskiTransition::Miss;
let mut best_transtition=Transition::Miss;
match fev{ match fev{
&FEV::<F,E,V>::Face(face_id)=>{ &MinkowskiFEV::Face(face_id)=>{
//test own face collision time, ignoring roots with zero or conflicting derivative //test own face collision time, ignoring roots with zero or conflicting derivative
//n=face.normal d=face.dot //n=face.normal d=face.dot
//n.a t^2+n.v t+n.p-d==0 //n.a t^2+n.v t+n.p-d==0
let (n,d)=mesh.face_nd(face_id); let (n,d)=mesh.face_nd(face_id);
//TODO: use higher precision d value? //TODO: use higher precision d value?
//use the mesh transform translation instead of baking it into the d value. //use the mesh transform translation instead of baking it into the d value.
for t in Fixed::<2,64>::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ for dt in Fixed::<4,128>::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t); if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t)).is_negative(){ best_time=dt;
best_time=t; best_transtition=MinkowskiTransition::Hit(face_id,dt);
best_transtition=Transition::Hit(face_id,t);
break; break;
} }
} }
@ -35,18 +36,18 @@ enum Transition<F,E:DirectedEdge,V>{
let n=n.cross(edge_n); let n=n.cross(edge_n);
let verts=mesh.edge_verts(directed_edge_id.as_undirected()); let verts=mesh.edge_verts(directed_edge_id.as_undirected());
//WARNING: d is moved out of the *2 block because of adding two vertices! //WARNING: d is moved out of the *2 block because of adding two vertices!
for t in zeroes2(n.dot(body.position*2-(mesh.vert(verts[0])+mesh.vert(verts[1]))),n.dot(body.velocity)*2,n.dot(body.acceleration)){ //WARNING: precision is swept under the rug!
let t=body.time+Time::from(t); 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 time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t)).is_negative(){ if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
best_time=t; best_time=dt;
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t); best_transtition=MinkowskiTransition::Next(MinkowskiFEV::Edge(directed_edge_id.as_undirected()),dt);
break; break;
} }
} }
} }
//if none: //if none:
}, },
&FEV::<F,E,V>::Edge(edge_id)=>{ &MinkowskiFEV::Edge(edge_id)=>{
//test each face collision time, ignoring roots with zero or conflicting derivative //test each face collision time, ignoring roots with zero or conflicting derivative
let edge_n=mesh.edge_n(edge_id); let edge_n=mesh.edge_n(edge_id);
let edge_verts=mesh.edge_verts(edge_id); let edge_verts=mesh.edge_verts(edge_id);
@ -56,11 +57,10 @@ enum Transition<F,E:DirectedEdge,V>{
//edge_n gets parity from the order of edge_faces //edge_n gets parity from the order of edge_faces
let n=face_n.cross(edge_n)*((i as i64)*2-1); let n=face_n.cross(edge_n)*((i as i64)*2-1);
//WARNING yada yada d *2 //WARNING yada yada d *2
for t in zeroes2(n.dot(delta_pos),n.dot(body.velocity)*2,n.dot(body.acceleration)){ 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()){
let t=body.time+Time::from(t); if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t)).is_negative(){ best_time=dt;
best_time=t; best_transtition=MinkowskiTransition::Next(MinkowskiFEV::Face(edge_face_id),dt);
best_transtition=Transition::Next(FEV::<F,E,V>::Face(edge_face_id),t);
break; break;
} }
} }
@ -69,27 +69,27 @@ enum Transition<F,E:DirectedEdge,V>{
for (i,&vert_id) in edge_verts.iter().enumerate(){ for (i,&vert_id) in edge_verts.iter().enumerate(){
//vertex normal gets parity from vert index //vertex normal gets parity from vert index
let n=edge_n*(1-2*(i as i64)); let n=edge_n*(1-2*(i as i64));
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ 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)){
let t=body.time+Time::from(t); if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t)).is_negative(){ let dt=Ratio::new(dt.num.fix_4(),dt.den.fix_4());
best_time=t; best_time=dt;
best_transtition=Transition::Next(FEV::<F,E,V>::Vert(vert_id),t); best_transtition=MinkowskiTransition::Next(MinkowskiFEV::Vert(vert_id),dt);
break; break;
} }
} }
} }
//if none: //if none:
}, },
&FEV::<F,E,V>::Vert(vert_id)=>{ &MinkowskiFEV::Vert(vert_id)=>{
//test each edge collision time, ignoring roots with zero or conflicting derivative //test each edge collision time, ignoring roots with zero or conflicting derivative
for &directed_edge_id in mesh.vert_edges(vert_id).iter(){ 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 //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); let n=-mesh.directed_edge_n(directed_edge_id);
for t in zeroes2((n.dot(body.position-mesh.vert(vert_id)))*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ 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)){
let t=body.time+Time::from(t); if body_time.le_ratio(dt)&&dt.lt_ratio(best_time)&&n.dot(body.extrapolated_velocity_ratio_dt(dt)).is_negative(){
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t)).is_negative(){ let dt=Ratio::new(dt.num.fix_4(),dt.den.fix_4());
best_time=t; best_time=dt;
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t); best_transtition=MinkowskiTransition::Next(MinkowskiFEV::Edge(directed_edge_id.as_undirected()),dt);
break; break;
} }
} }
@ -101,14 +101,22 @@ enum Transition<F,E:DirectedEdge,V>{
} }
pub enum CrawlResult<F,E:DirectedEdge,V>{ pub enum CrawlResult<F,E:DirectedEdge,V>{
Miss(FEV<F,E,V>), Miss(FEV<F,E,V>),
Hit(F,Time), Hit(F,Ratio<Fixed<4,128>,Fixed<4,128>>),
} }
pub fn crawl_fev<F:Copy,E:Copy+DirectedEdge,V:Copy>(mut fev:FEV<F,E,V>,mesh:&impl MeshQuery<F,E,V>,relative_body:&Body,start_time:Time,time_limit:Time)->CrawlResult<F,E,V>{ type MinkowskiCrawlResult=CrawlResult<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>;
let mut time=start_time; 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())
};
for _ in 0..20{ for _ in 0..20{
match next_transition(&fev,time,mesh,relative_body,time_limit){ match next_transition(&fev,body_time,mesh,relative_body,time_limit){
Transition::Miss=>return CrawlResult::Miss(fev), Transition::Miss=>return CrawlResult::Miss(fev),
Transition::Next(next_fev,next_time)=>(fev,time)=(next_fev,next_time), Transition::Next(next_fev,next_time)=>(fev,body_time)=(next_fev,next_time),
Transition::Hit(face,time)=>return CrawlResult::Hit(face,time), Transition::Hit(face,time)=>return CrawlResult::Hit(face,time),
} }
} }