2023-10-26 04:31:53 +00:00
|
|
|
use crate::physics::Body;
|
2023-11-17 00:56:34 +00:00
|
|
|
use crate::model_physics::{FEV,MeshQuery,DirectedEdge};
|
2023-11-16 04:30:20 +00:00
|
|
|
use crate::integer::{Time,Planar64};
|
2023-10-27 02:38:37 +00:00
|
|
|
use crate::zeroes::zeroes2;
|
2023-10-26 04:31:53 +00:00
|
|
|
|
2023-11-17 00:56:34 +00:00
|
|
|
enum Transition<F,E:DirectedEdge,V>{
|
2023-10-26 04:22:28 +00:00
|
|
|
Miss,
|
2023-10-27 21:18:50 +00:00
|
|
|
Next(FEV<F,E,V>,Time),
|
|
|
|
Hit(F,Time),
|
2023-10-26 04:22:28 +00:00
|
|
|
}
|
2023-10-26 04:31:53 +00:00
|
|
|
|
2023-11-17 01:03:12 +00:00
|
|
|
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>{
|
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.
|
2023-10-27 02:37:59 +00:00
|
|
|
let mut best_time=time_limit;
|
|
|
|
let mut best_transtition=Transition::Miss;
|
2023-11-16 04:32:10 +00:00
|
|
|
match fev{
|
2023-10-27 21:18:50 +00:00
|
|
|
&FEV::<F,E,V>::Face(face_id)=>{
|
2023-10-27 02:37:59 +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);
|
|
|
|
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);
|
2023-11-17 22:57:16 +00:00
|
|
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
2023-10-27 02:37:59 +00:00
|
|
|
best_time=t;
|
|
|
|
best_transtition=Transition::Hit(face_id,t);
|
2023-11-18 02:40:11 +00:00
|
|
|
break;
|
2023-10-27 02:37:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
2023-11-17 00:56:34 +00:00
|
|
|
for &directed_edge_id in mesh.face_edges(face_id).iter(){
|
|
|
|
let edge_n=mesh.directed_edge_n(directed_edge_id);
|
2023-11-18 01:54:21 +00:00
|
|
|
let n=n.cross(edge_n);
|
2023-11-17 00:56:34 +00:00
|
|
|
let verts=mesh.edge_verts(directed_edge_id.as_undirected());
|
|
|
|
let d=n.dot(mesh.vert(verts[0]))+n.dot(mesh.vert(verts[1]));
|
|
|
|
//WARNING: d is moved out of the *2 block because of adding two vertices!
|
|
|
|
for t in zeroes2(n.dot(body.position)*2-d,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
2023-10-27 02:37:59 +00:00
|
|
|
let t=body.time+Time::from(t);
|
2023-11-17 22:57:16 +00:00
|
|
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
2023-10-27 02:37:59 +00:00
|
|
|
best_time=t;
|
2023-11-17 00:56:34 +00:00
|
|
|
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
2023-10-27 02:37:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-26 22:51:47 +00:00
|
|
|
//if none:
|
2023-10-26 04:31:53 +00:00
|
|
|
},
|
2023-10-27 21:18:50 +00:00
|
|
|
&FEV::<F,E,V>::Edge(edge_id)=>{
|
2023-10-27 02:37:59 +00:00
|
|
|
//test each face collision time, ignoring roots with zero or conflicting derivative
|
2023-11-16 03:48:13 +00:00
|
|
|
let edge_n=mesh.edge_n(edge_id);
|
2023-11-22 02:17:46 +00:00
|
|
|
let edge_verts=mesh.edge_verts(edge_id);
|
2023-11-17 00:56:34 +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=edge_n.cross(face_n)*((i as i64)*2-1);
|
2023-11-22 02:17:46 +00:00
|
|
|
let d=n.dot(mesh.vert(edge_verts[0]))+n.dot(mesh.vert(edge_verts[1]));
|
2023-11-17 00:56:34 +00:00
|
|
|
//WARNING yada yada d *2
|
|
|
|
for t in zeroes2((n.dot(body.position))*2-d,n.dot(body.velocity)*2,n.dot(body.acceleration)){
|
2023-10-27 02:37:59 +00:00
|
|
|
let t=body.time+Time::from(t);
|
2023-11-17 22:57:16 +00:00
|
|
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
2023-10-27 02:37:59 +00:00
|
|
|
best_time=t;
|
2023-11-17 00:56:34 +00:00
|
|
|
best_transtition=Transition::Next(FEV::<F,E,V>::Face(edge_face_id),t);
|
2023-10-27 02:37:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//test each vertex collision time, ignoring roots with zero or conflicting derivative
|
2023-11-01 22:08:27 +00:00
|
|
|
let n=mesh.edge_n(edge_id);
|
2023-11-17 00:56:34 +00:00
|
|
|
for (i,&vert_id) in mesh.edge_verts(edge_id).iter().enumerate(){
|
|
|
|
//vertex normal gets parity from vert index
|
|
|
|
let n=n*(1-2*(i as i64));
|
2023-11-01 22:08:27 +00:00
|
|
|
let d=n.dot(mesh.vert(vert_id));
|
2023-10-27 02:37:59 +00:00
|
|
|
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);
|
2023-11-17 22:57:16 +00:00
|
|
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
2023-10-27 02:37:59 +00:00
|
|
|
best_time=t;
|
2023-10-27 21:18:50 +00:00
|
|
|
best_transtition=Transition::Next(FEV::<F,E,V>::Vert(vert_id),t);
|
2023-10-27 02:37:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-26 22:51:47 +00:00
|
|
|
//if none:
|
2023-10-26 04:31:53 +00:00
|
|
|
},
|
2023-11-01 22:08:27 +00:00
|
|
|
&FEV::<F,E,V>::Vert(vert_id)=>{
|
2023-10-27 02:37:59 +00:00
|
|
|
//test each edge collision time, ignoring roots with zero or conflicting derivative
|
2023-11-17 00:56:34 +00:00
|
|
|
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);
|
2023-11-01 22:08:27 +00:00
|
|
|
let d=n.dot(mesh.vert(vert_id));
|
2023-10-27 02:37:59 +00:00
|
|
|
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);
|
2023-11-17 22:57:16 +00:00
|
|
|
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
|
2023-10-27 02:37:59 +00:00
|
|
|
best_time=t;
|
2023-11-17 00:56:34 +00:00
|
|
|
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
|
2023-10-27 02:37:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-26 22:51:47 +00:00
|
|
|
//if none:
|
2023-10-26 04:31:53 +00:00
|
|
|
},
|
|
|
|
}
|
2023-10-27 02:37:59 +00:00
|
|
|
best_transtition
|
2023-10-26 04:31:53 +00:00
|
|
|
}
|
2023-11-17 23:26:35 +00:00
|
|
|
pub enum CrawlResult<F,E:DirectedEdge,V>{
|
|
|
|
Miss(FEV<F,E,V>),
|
|
|
|
Hit(F,Time),
|
|
|
|
}
|
|
|
|
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>{
|
2023-11-17 03:18:07 +00:00
|
|
|
let mut time=start_time;
|
2023-10-26 23:18:32 +00:00
|
|
|
loop{
|
2023-11-17 01:03:12 +00:00
|
|
|
match next_transition(&fev,time,mesh,relative_body,time_limit){
|
2023-11-17 23:26:35 +00:00
|
|
|
Transition::Miss=>return CrawlResult::Miss(fev),
|
2023-11-16 04:32:10 +00:00
|
|
|
Transition::Next(next_fev,next_time)=>(fev,time)=(next_fev,next_time),
|
2023-11-17 23:26:35 +00:00
|
|
|
Transition::Hit(face,time)=>return CrawlResult::Hit(face,time),
|
2023-10-26 04:31:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|