From 71d221581f34b3913fdb3b8c80d4cff09cb4988a Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 16 Nov 2023 16:56:34 -0800 Subject: [PATCH] DirectedEdge trait (huge) --- src/face_crawler.rs | 51 ++++++------ src/model_physics.rs | 183 +++++++++++++++++++++++-------------------- 2 files changed, 126 insertions(+), 108 deletions(-) diff --git a/src/face_crawler.rs b/src/face_crawler.rs index 386a387..41de9ec 100644 --- a/src/face_crawler.rs +++ b/src/face_crawler.rs @@ -1,15 +1,15 @@ use crate::physics::Body; -use crate::model_physics::{FEV,MeshQuery}; +use crate::model_physics::{FEV,MeshQuery,DirectedEdge}; use crate::integer::{Time,Planar64}; use crate::zeroes::zeroes2; -enum Transition{ +enum Transition{ Miss, Next(FEV,Time), Hit(F,Time), } - pub fn next_transition_body(fev:&FEV,time:Time,mesh:&impl MeshQuery,body:&Body,time_limit:Time)->Transition{ + pub fn next_transition_body(fev:&FEV,time:Time,mesh:&impl MeshQuery,body:&Body,time_limit:Time)->Transition{ //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. let mut best_time=time_limit; @@ -28,18 +28,17 @@ enum Transition{ } } //test each edge collision time, ignoring roots with zero or conflicting derivative - for &edge_id in mesh.face_edges(face_id).iter(){ - //this needs to be directed edge! - todo!(); - let edge_n=mesh.edge_n(edge_id); - let n=n.cross(edge_n); - //picking a vert randomly is terrible - let d=n.dot(mesh.vert(mesh.edge_verts(edge_id)[0])); - for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ + for &directed_edge_id in mesh.face_edges(face_id).iter(){ + let edge_n=mesh.directed_edge_n(directed_edge_id); + let n=edge_n.cross(n); + 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)){ let t=body.time+Time::from(t); if time::Edge(edge_id),t); + best_transtition=Transition::Next(FEV::::Edge(directed_edge_id.as_undirected()),t); break; } } @@ -49,22 +48,27 @@ enum Transition{ &FEV::::Edge(edge_id)=>{ //test each face collision time, ignoring roots with zero or conflicting derivative let edge_n=mesh.edge_n(edge_id); - for &test_face_id in mesh.edge_faces(edge_id).iter(){ - let face_n=mesh.face_nd(test_face_id).0; - let n=edge_n.cross(face_n); - let d=n.dot(mesh.vert(mesh.edge_verts(edge_id)[0])); - for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ + 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); + let verts=mesh.edge_verts(edge_id); + let d=n.dot(mesh.vert(verts[0]))+n.dot(mesh.vert(verts[1])); + //WARNING yada yada d *2 + for t in zeroes2((n.dot(body.position))*2-d,n.dot(body.velocity)*2,n.dot(body.acceleration)){ let t=body.time+Time::from(t); if time::Face(test_face_id),t); + best_transtition=Transition::Next(FEV::::Face(edge_face_id),t); break; } } } //test each vertex collision time, ignoring roots with zero or conflicting derivative let n=mesh.edge_n(edge_id); - for &vert_id in mesh.edge_verts(edge_id).iter(){ + 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)); let d=n.dot(mesh.vert(vert_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); @@ -79,14 +83,15 @@ enum Transition{ }, &FEV::::Vert(vert_id)=>{ //test each edge collision time, ignoring roots with zero or conflicting derivative - for &edge_id in mesh.vert_edges(vert_id).iter(){ - let n=mesh.edge_n(edge_id); + 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); let d=n.dot(mesh.vert(vert_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 time::Edge(edge_id),t); + best_transtition=Transition::Next(FEV::::Edge(directed_edge_id.as_undirected()),t); break; } } @@ -96,7 +101,7 @@ enum Transition{ } best_transtition } -pub fn crawl_fev_body(mut fev:FEV,mesh:&impl MeshQuery,relative_body:&Body,time_limit:Time)->Option<(F,Time)>{ +pub fn crawl_fev_body(mut fev:FEV,mesh:&impl MeshQuery,relative_body:&Body,time_limit:Time)->Option<(F,Time)>{ let mut time=relative_body.time; loop{ match next_transition_body(&fev,time,mesh,relative_body,time_limit){ diff --git a/src/model_physics.rs b/src/model_physics.rs index ba6fa7c..26086d8 100644 --- a/src/model_physics.rs +++ b/src/model_physics.rs @@ -6,28 +6,34 @@ pub struct VertId(usize); #[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] pub struct EdgeId(usize); impl EdgeId{ - fn as_directed_edge_id(&self,parity:bool)->DirectedEdgeId{ + fn as_directed(&self,parity:bool)->DirectedEdgeId{ DirectedEdgeId(self.0|((parity as usize)<<(usize::BITS-1))) } } +pub trait DirectedEdge{ + type UndirectedEdge; + fn as_undirected(&self)->Self::UndirectedEdge; + fn parity(&self)->bool; +} /// DirectedEdgeId refers to an EdgeId when undirected. #[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] pub struct DirectedEdgeId(usize); -impl DirectedEdgeId{ - fn as_edge_id(&self)->EdgeId{ +impl DirectedEdge for DirectedEdgeId{ + type UndirectedEdge=EdgeId; + fn as_undirected(&self)->EdgeId{ EdgeId(self.0&!(1<<(usize::BITS-1))) } - fn signum(&self)->isize{ - ((self.0&(1<<(usize::BITS-1))!=0) as isize)*2-1 + fn parity(&self)->bool{ + self.0&(1<<(usize::BITS-1))!=0 } } #[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] pub struct FaceId(usize); //Vertex <-> Edge <-> Face -> Collide -pub enum FEV{ +pub enum FEV{ Face(F), - Edge(E), + Edge(E::UndirectedEdge), Vert(V), } @@ -42,8 +48,25 @@ impl Face{ } } struct Vert(Planar64Vec3); +pub trait MeshQuery{ + fn edge_n(&self,edge_id:EDGE::UndirectedEdge)->Planar64Vec3{ + let verts=self.edge_verts(edge_id); + self.vert(verts[1].clone())-self.vert(verts[0].clone()) + } + fn directed_edge_n(&self,directed_edge_id:EDGE)->Planar64Vec3{ + let verts=self.edge_verts(directed_edge_id.as_undirected()); + (self.vert(verts[1].clone())-self.vert(verts[0].clone()))*((directed_edge_id.parity() as i64)*2-1) + } + fn vert(&self,vert_id:VERT)->Planar64Vec3; + fn face_nd(&self,face_id:FACE)->(Planar64Vec3,Planar64); + fn face_edges(&self,face_id:FACE)->Cow>; + fn edge_faces(&self,edge_id:EDGE::UndirectedEdge)->Cow<[FACE;2]>; + fn edge_verts(&self,edge_id:EDGE::UndirectedEdge)->Cow<[VERT;2]>; + fn vert_edges(&self,vert_id:VERT)->Cow>; + fn vert_faces(&self,vert_id:VERT)->Cow>; +} struct FaceRefs{ - edges:Vec, + edges:Vec, //verts:Vec, } struct EdgeRefs{ @@ -87,7 +110,7 @@ impl EdgeRefGuy{ self.0[i]=face_id; } } -struct FaceRefGuy(Vec); +struct FaceRefGuy(Vec); #[derive(Default)] struct EdgePool{ edge_guys:Vec<(EdgeIdGuy,EdgeRefGuy)>, @@ -139,12 +162,12 @@ impl From<&crate::model::IndexedModel> for PhysicsMesh{ //index edges & face into vertices { let vert_ref_guy=unsafe{vert_ref_guys.get_unchecked_mut(vert0_id)}; - vert_ref_guy.edges.insert(edge_id.as_directed_edge_id(!is_sorted)); + vert_ref_guy.edges.insert(edge_id.as_directed(!is_sorted)); vert_ref_guy.faces.insert(face_id); - unsafe{vert_ref_guys.get_unchecked_mut(vert1_id)}.edges.insert(edge_id.as_directed_edge_id(is_sorted)); + unsafe{vert_ref_guys.get_unchecked_mut(vert1_id)}.edges.insert(edge_id.as_directed(is_sorted)); } - //return edge_id - edge_id + //return directed_edge_id + edge_id.as_directed(is_sorted) }).collect(); //choose precision loss randomly idk normal=normal/len as i64; @@ -176,32 +199,12 @@ impl From<&crate::model::IndexedModel> for PhysicsMesh{ } } -pub trait MeshQuery{ - fn edge_n(&self,edge_id:EDGE)->Planar64Vec3{ - let verts=self.edge_verts(edge_id); - self.vert(verts[1].clone())-self.vert(verts[0].clone()) - } - fn vert(&self,vert_id:VERT)->Planar64Vec3; - fn face_nd(&self,face_id:FACE)->(Planar64Vec3,Planar64); - fn face_edges(&self,face_id:FACE)->Cow>; - fn edge_faces(&self,edge_id:EDGE)->Cow<[FACE;2]>; - fn edge_verts(&self,edge_id:EDGE)->Cow<[VERT;2]>; - fn vert_edges(&self,vert_id:VERT)->Cow>; - fn vert_faces(&self,vert_id:VERT)->Cow>; -} impl PhysicsMesh{ pub fn verts<'a>(&'a self)->impl Iterator+'a{ self.verts.iter().map(|Vert(pos)|*pos) } - fn vert_directed_edges(&self,vert_id:VertId)->Cow>{ - Cow::Borrowed(&self.vert_topology[vert_id.0].edges) - } - fn directed_edge_n(&self,directed_edge_id:DirectedEdgeId)->Planar64Vec3{ - let verts=self.edge_verts(directed_edge_id.as_edge_id()); - (self.vert(verts[1].clone())-self.vert(verts[0].clone()))*(directed_edge_id.signum() as i64) - } } -impl MeshQuery for PhysicsMesh{ +impl MeshQuery for PhysicsMesh{ fn face_nd(&self,face_id:FaceId)->(Planar64Vec3,Planar64){ (self.faces[face_id.0].normal,self.faces[face_id.0].dot) } @@ -209,7 +212,7 @@ impl MeshQuery for PhysicsMesh{ fn vert(&self,vert_id:VertId)->Planar64Vec3{ self.verts[vert_id.0].0 } - fn face_edges(&self,face_id:FaceId)->Cow>{ + fn face_edges(&self,face_id:FaceId)->Cow>{ Cow::Borrowed(&self.face_topology[face_id.0].edges) } fn edge_faces(&self,edge_id:EdgeId)->Cow<[FaceId;2]>{ @@ -218,9 +221,8 @@ impl MeshQuery for PhysicsMesh{ fn edge_verts(&self,edge_id:EdgeId)->Cow<[VertId;2]>{ Cow::Borrowed(&self.edge_topology[edge_id.0].verts) } - fn vert_edges(&self,vert_id:VertId)->Cow>{ - //not poggers - Cow::Owned(self.vert_topology[vert_id.0].edges.iter().map(|directed_edge_id|directed_edge_id.as_edge_id()).collect()) + fn vert_edges(&self,vert_id:VertId)->Cow>{ + Cow::Borrowed(&self.vert_topology[vert_id.0].edges) } fn vert_faces(&self,vert_id:VertId)->Cow>{ Cow::Borrowed(&self.vert_topology[vert_id.0].faces) @@ -257,16 +259,8 @@ impl TransformedMesh<'_>{ } best_vert } - #[inline] - fn vert_directed_edges(&self,vert_id:VertId)->Cow>{ - self.mesh.vert_directed_edges(vert_id) - } - #[inline] - fn directed_edge_n(&self,directed_edge_id:DirectedEdgeId)->Planar64Vec3{ - self.mesh.directed_edge_n(directed_edge_id) - } } -impl MeshQuery for TransformedMesh<'_>{ +impl MeshQuery for TransformedMesh<'_>{ fn face_nd(&self,face_id:FaceId)->(Planar64Vec3,Planar64){ let (n,d)=self.mesh.face_nd(face_id); let transformed_n=*self.normal_transform*n; @@ -277,7 +271,7 @@ impl MeshQuery for TransformedMesh<'_>{ self.transform.transform_point3(self.mesh.vert(vert_id)) } #[inline] - fn face_edges(&self,face_id:FaceId)->Cow>{ + fn face_edges(&self,face_id:FaceId)->Cow>{ self.mesh.face_edges(face_id) } #[inline] @@ -289,7 +283,7 @@ impl MeshQuery for TransformedMesh<'_>{ self.mesh.edge_verts(edge_id) } #[inline] - fn vert_edges(&self,vert_id:VertId)->Cow>{ + fn vert_edges(&self,vert_id:VertId)->Cow>{ self.mesh.vert_edges(vert_id) } #[inline] @@ -307,15 +301,36 @@ enum MinkowskiVert{ VertVert(VertId,VertId), } #[derive(Clone,Copy)] -enum MinkowskiEdge{ +pub enum MinkowskiEdge{ VertEdge(VertId,EdgeId), EdgeVert(EdgeId,VertId), //EdgeEdge when edges are parallel } +#[derive(Clone,Copy)] +enum MinkowskiDirectedEdge{ + VertEdge(VertId,DirectedEdgeId), + EdgeVert(DirectedEdgeId,VertId), + //EdgeEdge when edges are parallel +} +impl DirectedEdge for MinkowskiDirectedEdge{ + type UndirectedEdge=MinkowskiEdge; + fn as_undirected(&self)->Self::UndirectedEdge{ + match self{ + MinkowskiDirectedEdge::VertEdge(v0,e1)=>MinkowskiEdge::VertEdge(*v0,e1.as_undirected()), + MinkowskiDirectedEdge::EdgeVert(e0,v1)=>MinkowskiEdge::EdgeVert(e0.as_undirected(),*v1), + } + } + fn parity(&self)->bool{ + match self{ + MinkowskiDirectedEdge::VertEdge(_,e) + |MinkowskiDirectedEdge::EdgeVert(e,_)=>e.parity(), + } + } +} #[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] pub enum MinkowskiFace{ VertFace(VertId,FaceId), - EdgeEdge(EdgeId,EdgeId), + EdgeEdge(EdgeId,EdgeId,bool), FaceVert(FaceId,VertId), //EdgeFace //FaceEdge @@ -337,11 +352,11 @@ impl MinkowskiMesh<'_>{ fn farthest_vert(&self,dir:Planar64Vec3)->MinkowskiVert{ MinkowskiVert::VertVert(self.mesh0.farthest_vert(dir),self.mesh1.farthest_vert(-dir)) } - fn closest_fev(&self,point:Planar64Vec3)->FEV{ + fn closest_fev(&self,point:Planar64Vec3)->FEV{ //put some genius code right here instead of this //assume that point is outside the mesh and nonzero //find vertex on mesh0 farthest in point direction - let fev=FEV::::Vert(self.farthest_vert(point)); + let fev=FEV::::Vert(self.farthest_vert(point)); crate::face_crawler::crawl_fev_dot(fev,self,point) } pub fn predict_collision_in(&self,relative_body:&crate::physics::Body,time_limit:crate::integer::Time)->Option<(MinkowskiFace,crate::integer::Time)>{ @@ -353,31 +368,32 @@ impl MinkowskiMesh<'_>{ let mut best_time=time_limit; let mut best_edge=None; let face_n=self.face_nd(contact_face_id).0; - for &edge_id in self.face_edges(contact_face_id).iter(){ - let edge_n=self.edge_n(edge_id); + for &directed_edge_id in self.face_edges(contact_face_id).iter(){ + let edge_n=self.directed_edge_n(directed_edge_id); let n=face_n.cross(edge_n); - //picking a vert randomly is terrible - let d=n.dot(self.vert(self.edge_verts(edge_id)[0])); - for t in crate::zeroes::zeroes2((n.dot(relative_body.position)-d)*2,n.dot(relative_body.velocity)*2,n.dot(relative_body.acceleration)){ + let verts=self.edge_verts(directed_edge_id.as_undirected()); + let d=n.dot(self.vert(verts[0]))+n.dot(self.vert(verts[1])); + //WARNING! d outside of *2 + for t in crate::zeroes::zeroes2((n.dot(relative_body.position))*2-d,n.dot(relative_body.velocity)*2,n.dot(relative_body.acceleration)){ let t=relative_body.time+crate::integer::Time::from(t); if relative_body.time for MinkowskiMesh<'_>{ +impl MeshQuery for MinkowskiMesh<'_>{ fn face_nd(&self,face_id:MinkowskiFace)->(Planar64Vec3,Planar64){ match face_id{ MinkowskiFace::VertFace(v0,f1)=>{ let (n,d)=self.mesh1.face_nd(f1); (-n,d-n.dot(self.mesh0.vert(v0))) }, - MinkowskiFace::EdgeEdge(e0,e1)=>{ + MinkowskiFace::EdgeEdge(e0,e1,parity)=>{ let edge0_n=self.mesh0.edge_n(e0); let edge1_n=self.mesh1.edge_n(e1); let &[e0v0,e0v1]=self.mesh0.edge_verts(e0).borrow(); @@ -385,8 +401,7 @@ impl MeshQuery for MinkowskiMesh<'_>{ let n=edge0_n.cross(edge1_n); let e0d=n.dot(self.mesh0.vert(e0v0)+self.mesh0.vert(e0v1)); let e1d=n.dot(self.mesh0.vert(e1v0)+self.mesh0.vert(e1v1)); - let sign=e0d.signum_i64(); - (n*(sign*2),(e0d-e1d)*sign) + (n*(parity as i64*4-2),(e0d-e1d)*(parity as i64*2-1)) }, MinkowskiFace::FaceVert(f0,v1)=>{ let (n,d)=self.mesh0.face_nd(f0); @@ -401,27 +416,27 @@ impl MeshQuery for MinkowskiMesh<'_>{ }, } } - fn face_edges(&self,face_id:MinkowskiFace)->Cow>{ + fn face_edges(&self,face_id:MinkowskiFace)->Cow>{ match face_id{ MinkowskiFace::VertFace(v0,f1)=>{ Cow::Owned(self.mesh1.face_edges(f1).iter().map(|&edge_id1|{ - MinkowskiEdge::VertEdge(v0,edge_id1) + MinkowskiDirectedEdge::VertEdge(v0,edge_id1) }).collect()) }, - MinkowskiFace::EdgeEdge(e0,e1)=>{ + MinkowskiFace::EdgeEdge(e0,e1,parity)=>{ let e0v=self.mesh0.edge_verts(e0); let e1v=self.mesh1.edge_verts(e1); //could sort this if ordered edges are needed Cow::Owned(vec![ - MinkowskiEdge::VertEdge(e0v[0],e1), - MinkowskiEdge::VertEdge(e0v[1],e1), - MinkowskiEdge::EdgeVert(e0,e1v[0]), - MinkowskiEdge::EdgeVert(e0,e1v[1]), + MinkowskiDirectedEdge::VertEdge(e0v[0],e1.as_directed(parity)), + MinkowskiDirectedEdge::EdgeVert(e0.as_directed(parity),e1v[0]), + MinkowskiDirectedEdge::VertEdge(e0v[1],e1.as_directed(!parity)), + MinkowskiDirectedEdge::EdgeVert(e0.as_directed(!parity),e1v[1]), ]) }, MinkowskiFace::FaceVert(f0,v1)=>{ Cow::Owned(self.mesh0.face_edges(f0).iter().map(|&edge_id0|{ - MinkowskiEdge::EdgeVert(edge_id0,v1) + MinkowskiDirectedEdge::EdgeVert(edge_id0,v1) }).collect()) }, } @@ -430,13 +445,12 @@ impl MeshQuery for MinkowskiMesh<'_>{ match edge_id{ MinkowskiEdge::VertEdge(v0,e1)=>{ let e1f=self.mesh1.edge_faces(e1); - Cow::Owned([(e1f[0],e1f[1]),(e1f[1],e1f[0])].map(|(edge_face_id1,other_edge_face_id1)|{ + Cow::Owned([(e1f[0],e1f[1],true),(e1f[1],e1f[0],false)].map(|(edge_face_id1,other_edge_face_id1,face_parity)|{ let mut best_edge=None; let mut best_d=Planar64::MAX; let edge_face1_n=self.mesh1.face_nd(edge_face_id1).0; let other_edge_face1_n=self.mesh1.face_nd(other_edge_face_id1).0; - let v0e=self.mesh0.vert_directed_edges(v0); - for &directed_edge_id0 in v0e.iter(){ + for &directed_edge_id0 in self.mesh0.vert_edges(v0).iter(){ let edge0_n=self.mesh0.directed_edge_n(directed_edge_id0); if edge_face1_n.dot(edge0_n) for MinkowskiMesh<'_>{ } best_edge.map_or( MinkowskiFace::VertFace(v0,edge_face_id1), - |directed_edge_id0|MinkowskiFace::EdgeEdge(directed_edge_id0.as_edge_id(),e1) + |directed_edge_id0|MinkowskiFace::EdgeEdge(directed_edge_id0.as_undirected(),e1,directed_edge_id0.parity()^face_parity) ) })) }, MinkowskiEdge::EdgeVert(e0,v1)=>{ let e0f=self.mesh0.edge_faces(e0); - Cow::Owned([(e0f[0],e0f[1]),(e0f[1],e0f[0])].map(|(edge_face_id0,other_edge_face_id0)|{ + Cow::Owned([(e0f[0],e0f[1],true),(e0f[1],e0f[0],false)].map(|(edge_face_id0,other_edge_face_id0,face_parity)|{ let mut best_edge=None; let mut best_d=Planar64::MAX; let edge_face0_n=self.mesh0.face_nd(edge_face_id0).0; let other_edge_face0_n=self.mesh0.face_nd(other_edge_face_id0).0; - let v1e=self.mesh1.vert_directed_edges(v1); - for &directed_edge_id1 in v1e.iter(){ + for &directed_edge_id1 in self.mesh1.vert_edges(v1).iter(){ let edge1_n=self.mesh1.directed_edge_n(directed_edge_id1); if edge_face0_n.dot(edge1_n) for MinkowskiMesh<'_>{ } best_edge.map_or( MinkowskiFace::FaceVert(edge_face_id0,v1), - |directed_edge_id1|MinkowskiFace::EdgeEdge(e0,directed_edge_id1.as_edge_id()) + |directed_edge_id1|MinkowskiFace::EdgeEdge(e0,directed_edge_id1.as_undirected(),directed_edge_id1.parity()^face_parity) ) })) }, @@ -492,24 +505,24 @@ impl MeshQuery for MinkowskiMesh<'_>{ }, } } - fn vert_edges(&self,vert_id:MinkowskiVert)->Cow>{ + fn vert_edges(&self,vert_id:MinkowskiVert)->Cow>{ match vert_id{ MinkowskiVert::VertVert(v0,v1)=>{ let mut edges=Vec::new(); - let v0e=self.mesh0.vert_directed_edges(v0); + let v0e=self.mesh0.vert_edges(v0); let v1f=self.mesh1.vert_faces(v1); for &directed_edge_id in v0e.iter(){ let n=self.mesh0.directed_edge_n(directed_edge_id); if v1f.iter().all(|&face_id|n.dot(self.mesh1.face_nd(face_id).0)