static void FaceEdgeSplicer(Face & face,int vi0,BSPNode *n) { // the face's edge starting from vertex vi0 is sliced by any incident hypeplane in the bsp if(n->isleaf) return; int vi1 = (vi0+1)%face.vertex.size(); float3 v0 = face.vertex[vi0]; float3 v1 = face.vertex[vi1]; assert(magnitude(v0-v1) > QUANTIZEDCHECK ); int f0 = PlaneTest(float4(n->xyz(), n->w), v0); int f1 = PlaneTest(float4(n->xyz(), n->w), v1); if(f0==COPLANAR && f1== COPLANAR) { // have to pass down both sides, but we have to make sure we do all subsegments generated by the first side int count = face.vertex.size(); FaceEdgeSplicer(face,vi0,n->under.get()); int k=vi0 + (face.vertex.size()-count); while(k>=vi0) { FaceEdgeSplicer(face,k,n->over.get()); k--; } } else if((f0|f1) == UNDER) { FaceEdgeSplicer(face,vi0,n->under.get()); } else if((f0|f1) == OVER) { FaceEdgeSplicer(face,vi0,n->over.get()); } else { edgesplitcount++; assert(magnitude(v0-v1) > QUANTIZEDCHECK); assert((f0|f1) == SPLIT); float3 vmid = PlaneLineIntersection(*n,v0,v1); assert(magnitude(vmid-v1) > QUANTIZEDCHECK); assert(magnitude(v0-vmid) > QUANTIZEDCHECK); int fmid = PlaneTest(float4(n->xyz(), n->w), vmid); assert(fmid==0); face.vertex.insert(face.vertex.begin() + vi0 + 1, vmid); // Insert(face.vertex, vmid, vi0 + 1); if(f0==UNDER) { FaceEdgeSplicer(face,vi0+1,n->over.get()); FaceEdgeSplicer(face,vi0 ,n->under.get()); } else { assert(f0==OVER); FaceEdgeSplicer(face,vi0+1,n->under.get()); FaceEdgeSplicer(face,vi0 ,n->over.get()); } } }
Face *NeighboringEdge(BSPNode *root,Face *face,int eid) { float3 &v0 = face->vertex[eid]; float3 &v1 = face->vertex[(eid+1)%face->vertex.size()]; assert(v0 != v1); float3 s = (v0+v1)/2.0f; float3 fnxe = cross((v1 - v0), face->xyz()); // points away from face's interior float4 p0 = *face; int f; while ((f = PlaneTest(float4(root->xyz(), root->w), s))) { root=(f==OVER)?root->over.get():root->under.get(); assert(!root->isleaf); } std::vector<BSPNode *> stack; stack.push_back(root); while(stack.size()) { BSPNode *n=Pop(stack); if(n->isleaf==OVER) continue; if(n->isleaf==UNDER) { for(unsigned int i=0;i<n->brep.size();i++) { Face *f = &n->brep[i]; if(f==face) continue; for(unsigned int j=0;j<f->vertex.size();j++) { int j1 = (j+1)%f->vertex.size(); if(magnitude(f->vertex[j]-v1)<0.001f && magnitude(f->vertex[j1]-v0)<0.001f) { NeighboringEdgeNode=n; NeighboringEdgeId=j; NeighboringEdgeFace=f; return f; } } } continue; } assert(!n->isleaf); f = PlaneTest(float4(n->xyz(), n->w), s); if(!(f&OVER)) stack.push_back(n->under.get()); if(!(f&UNDER)) stack.push_back(n->over.get()); } assert(0); return NULL; }
int SplitTest(ConvexH &convex,const btPlane &plane) { int flag=0; for(int i=0;i<convex.vertices.size();i++) { flag |= PlaneTest(plane,convex.vertices[i]); } return flag; }
void FaceSlice(Face & face,const float4 &clip) { int count=0; for(unsigned int i=0;i<face.vertex.size();i++) { unsigned int i2=(i+1)%face.vertex.size(); int vf0 = PlaneTest(clip, face.vertex[i]); int vf2 = PlaneTest(clip, face.vertex[i2]); if((vf0==OVER && vf2==UNDER)|| (vf0==UNDER && vf2==OVER ) ) { float3 vmid; vmid = PlaneLineIntersection(clip,face.vertex[i],face.vertex[i2]); assert(!PlaneTest(clip, vmid)); face.vertex.insert(face.vertex.begin() + i2, vmid); // Insert(face.vertex, vmid, i2); i=0; assert(count<2); count++; } } }
Face FaceNewQuad(const float3 &v0,const float3 &v1,const float3 &v2,const float3 &v3) { Face f; f.vertex = {v0,v1,v2,v3}; f.xyz() = normalize(cross(v1 - v0, v2 - v1) + cross(v3 - v2, v0 - v3)); f.w = -dot(f.xyz(), (v0 + v1 + v2 + v3) / 4.0f); for(auto & v : f.vertex) assert(!PlaneTest(f.plane(), v, PAPERWIDTH)); // must be coplanar FaceExtractMatVals(&f,v0,v1,v3,float2(0,0),float2(1,0),float2(0,1)); f.gu = normalize(f.gu); f.gv = normalize(f.gv); f.ot = float3(0,0,0); return f; }
Face FaceClip(Face && face,const float4 &clip) { assert(FaceSplitTest(face, clip) == SPLIT); FaceSlice(face,clip); std::vector<float3> tmp; for(unsigned int i=0;i<face.vertex.size();i++){ if (PlaneTest(clip, face.vertex[i]) != OVER) { tmp.push_back(face.vertex[i]); } } face.vertex.clear(); for (unsigned int i = 0; i<tmp.size(); i++){ face.vertex.push_back(tmp[i]); } return face; }
void Test() { TimerTest().ExecuteTest(); FoldTest().ExecuteTest(); SolidUnionTest().ExecuteTest(); BoundingSolidTest().ExecuteTest(); SolidIntersectionTest().ExecuteTest(); MaybeTest().ExecuteTest(); PlaneTest().ExecuteTest(); TransformationAdapterTest().ExecuteTest(); SphereTest().ExecuteTest(); InheritableTest().ExecuteTest(); AutoTest().ExecuteTest(); UtilitiesTest().ExecuteTest(); PolynomialTest().ExecuteTest(); ProjectionPlaneTest().ExecuteTest(); Vector3dTest().ExecuteTest(); ColorTest().ExecuteTest(); }
static void BSPClipFace(BSPNode *n,Face && face,const float3 &position,std::vector<Face> &under,std::vector<Face> &over) { if(n->isleaf==UNDER) { under.push_back(face); return; } if(n->isleaf==OVER) { over.push_back(face); return; } float4 plane(n->xyz(), n->w + dot(position, n->xyz())); int flag = FaceSplitTest(face, plane); if(flag == UNDER) { return BSPClipFace(n->under.get(),std::move(face),position,under,over); } if(flag == OVER) { return BSPClipFace(n->over.get(),std::move(face),position,under,over); } if(flag==COPLANAR) { return BSPClipFace(dot(n->xyz(), face.xyz()) > 0 ? n->under.get() : n->over.get(), std::move(face), position, under, over); } assert(flag==SPLIT); Face funder, fover; fover.xyz() = funder.xyz() = face.xyz(); fover.w = funder.w = face.w; fover.gu = funder.gu = face.gu; fover.gv = funder.gv = face.gv; fover.ot = funder.ot = face.ot; fover.matid= funder.matid= face.matid; for(unsigned int i=0;i<face.vertex.size();i++){ float3& vi = face.vertex[i]; float3& vi1= face.vertex[(i+1)%face.vertex.size()]; int vf = PlaneTest(float4(plane.xyz(), plane.w), vi); int vf1 = PlaneTest(float4(plane.xyz(), plane.w), vi1); if(vf==COPLANAR) { funder.vertex.push_back(vi); fover.vertex.push_back(vi); continue; // possible loop optimization } else if(vf==UNDER) { funder.vertex.push_back(vi); } else { assert(vf==OVER); fover.vertex.push_back(vi); } if(vf != vf1 && vf !=COPLANAR && vf1 != COPLANAR) { float3 vmid = PlaneLineIntersection(plane.xyz(), plane.w, vi, vi1); funder.vertex.push_back(vmid); fover.vertex.push_back(vmid); } } BSPClipFace(n->under.get(),std::move(funder),position,under,over); BSPClipFace(n->over.get() ,std::move(fover) ,position,under,over); }
int FaceSplitTest(const Face & face, const float4 &splitplane,float epsilon) { int flag = COPLANAR; // 0 for (const auto & v : face.vertex) flag |= PlaneTest(splitplane, v, epsilon); return flag; }