bool ConvexPolyhedron3<Real>::ComputeSilhouette (V3Array& rkTerminator, const Vector3<Real>& rkEye, const Plane3<Real>& rkPlane, const Vector3<Real>& rkU, const Vector3<Real>& rkV, V2Array& rkSilhouette) { Real fEDist = rkPlane.DistanceTo(rkEye); // assert: fEDist > 0 // closest planar point to E is K = E-dist*N Vector3<Real> kClosest = rkEye - fEDist*rkPlane.GetNormal(); // project polyhedron points onto plane for (int i = 0; i < (int)rkTerminator.size(); i++) { Vector3<Real>& rkPoint = rkTerminator[i]; Real fVDist = rkPlane.DistanceTo(rkPoint); if ( fVDist >= fEDist ) { // cannot project vertex onto plane return false; } // compute projected point Q Real fRatio = fEDist/(fEDist-fVDist); Vector3<Real> kProjected = rkEye + fRatio*(rkPoint - rkEye); // compute (x,y) so that Q = K+x*U+y*V+z*N Vector3<Real> kDiff = kProjected - kClosest; rkSilhouette.push_back(Vector2<Real>(rkU.Dot(kDiff),rkV.Dot(kDiff))); } return true; }
bool Wml::Culled (const Plane3<Real>& rkPlane, const Box3<Real>& rkBox) { Real fTmp[3] = { rkBox.Extent(0)*(rkPlane.GetNormal().Dot(rkBox.Axis(0))), rkBox.Extent(1)*(rkPlane.GetNormal().Dot(rkBox.Axis(1))), rkBox.Extent(2)*(rkPlane.GetNormal().Dot(rkBox.Axis(2))) }; Real fRadius = Math<Real>::FAbs(fTmp[0]) + Math<Real>::FAbs(fTmp[1]) + Math<Real>::FAbs(fTmp[2]); Real fPseudoDistance = rkPlane.DistanceTo(rkBox.Center()); return fPseudoDistance <= -fRadius; }
int BVaabb::WhichSide(const Plane3& plane) const { if (mAlwaysPass) return 1; Real fDistance = plane.DistanceTo(mCenter); if (fDistance <= -mRadius) { return -1; } if (fDistance >= mRadius) { return +1; } return 0; }
void PerspectiveProjectEllipsoid (const Ellipsoid3<Real>& ellipsoid, const Vector3<Real>& eye, const Plane3<Real>& plane, const Vector3<Real>& U, const Vector3<Real>& V, Vector3<Real>& P, Ellipse2<Real>& ellipse) { // Get coefficients for ellipsoid as X^T*A*X + B^T*X + C = 0. Matrix3<Real> A; Vector3<Real> B; Real C; ellipsoid.ToCoefficients(A, B, C); // Compute matrix M (see PerspectiveProjectionEllipsoid.pdf). Vector3<Real> AE = A*eye; Real EAE = eye.Dot(AE); Real BE = B.Dot(eye); Real QuadE = ((Real)4)*(EAE + BE + C); Vector3<Real> Bp2AE = B + ((Real)2)*AE; Matrix3<Real> mat = Matrix3<Real>(Bp2AE, Bp2AE) - QuadE*A; // Compute coefficients for projected ellipse. Vector3<Real> MU = mat*U; Vector3<Real> MV = mat*V; Vector3<Real> MN = mat*plane.Normal; Real DmNdE = -plane.DistanceTo(eye); P = eye + DmNdE*plane.Normal; Matrix2<Real> AOut; Vector2<Real> BOut; Real COut; AOut[0][0] = U.Dot(MU); AOut[0][1] = U.Dot(MV); AOut[1][1] = V.Dot(MV); AOut[1][0] = AOut[0][1]; BOut[0] = ((Real)2)*DmNdE*(U.Dot(MN)); BOut[1] = ((Real)2)*DmNdE*(V.Dot(MN)); COut = DmNdE*DmNdE*(plane.Normal.Dot(MN)); ellipse.FromCoefficients(AOut, BOut, COut); }
int ConvexClipper<Real>::Clip (const Plane3<Real>& plane) { // Sompute signed distances from vertices to plane. int numPositive = 0, numNegative = 0; const int numVertices = (int)mVertices.size(); for (int v = 0; v < numVertices; ++v) { Vertex& vertex = mVertices[v]; if (vertex.Visible) { vertex.Distance = plane.DistanceTo(vertex.Point); if (vertex.Distance >= mEpsilon) { ++numPositive; } else if (vertex.Distance <= -mEpsilon) { ++numNegative; vertex.Visible = false; } else { // The point is on the plane (within floating point // tolerance). vertex.Distance = (Real)0; } } } if (numPositive == 0) { // Mesh is in negative half-space, fully clipped. return -1; } if (numNegative == 0) { // Mesh is in positive half-space, fully visible. return +1; } // Clip the visible edges. const int numEdges = (int)mEdges.size(); for (int e = 0; e < numEdges; ++e) { Edge& edge = mEdges[e]; if (edge.Visible) { int v0 = edge.Vertex[0]; int v1 = edge.Vertex[1]; int f0 = edge.Face[0]; int f1 = edge.Face[1]; Face& face0 = mFaces[f0]; Face& face1 = mFaces[f1]; Real d0 = mVertices[v0].Distance; Real d1 = mVertices[v1].Distance; if (d0 <= (Real)0 && d1 <= (Real)0) { // The edge is culled. If the edge is exactly on the clip // plane, it is possible that a visible triangle shares it. // The edge will be re-added during the face loop. face0.Edges.erase(e); if (face0.Edges.empty()) { face0.Visible = false; } face1.Edges.erase(e); if (face1.Edges.empty()) { face1.Visible = false; } edge.Visible = false; continue; } if (d0 >= (Real)0 && d1 >= (Real)0) { // Face retains the edge. continue; } // The edge is split by the plane. Compute the point of // intersection. If the old edge is <V0,V1> and I is the // intersection point, the new edge is <V0,I> when d0 > 0 or // <I,V1> when d1 > 0. int vNew = (int)mVertices.size(); mVertices.push_back(Vertex()); Vertex& vertexNew = mVertices[vNew]; Vector3<Real>& point0 = mVertices[v0].Point; Vector3<Real>& point1 = mVertices[v1].Point; vertexNew.Point = point0 + (d0/(d0 - d1))*(point1 - point0); if (d0 > (Real)0) { edge.Vertex[1] = vNew; } else { edge.Vertex[0] = vNew; } } } // The mesh straddles the plane. A new convex polygonal face will be // generated. Add it now and insert edges when they are visited. int fNew = (int)mFaces.size(); mFaces.push_back(Face()); Face& faceNew = mFaces[fNew]; faceNew.Plane = plane; // Process the faces. for (int f = 0; f < fNew; ++f) { Face& face = mFaces[f]; if (face.Visible) { // Determine if the face is on the negative side, the positive // side, or split by the clipping plane. The Occurs members // are set to zero to help find the end points of the polyline // that results from clipping a face. assertion(face.Edges.size() >= 2, "Unexpected condition.\n"); std::set<int>::iterator iter = face.Edges.begin(); std::set<int>::iterator end = face.Edges.end(); while (iter != end) { int e = *iter++; Edge& edge = mEdges[e]; assertion(edge.Visible, "Unexpected condition.\n"); mVertices[edge.Vertex[0]].Occurs = 0; mVertices[edge.Vertex[1]].Occurs = 0; } int vStart, vFinal; if (GetOpenPolyline(face, vStart, vFinal)) { // Polyline is open, close it up. int eNew = (int)mEdges.size(); mEdges.push_back(Edge()); Edge& edgeNew = mEdges[eNew]; edgeNew.Vertex[0] = vStart; edgeNew.Vertex[1] = vFinal; edgeNew.Face[0] = f; edgeNew.Face[1] = fNew; // Add new edge to polygons. face.Edges.insert(eNew); faceNew.Edges.insert(eNew); } } } // Process 'faceNew' to make sure it is a simple polygon (theoretically // convex, but numerically may be slightly not convex). Floating-point // round-off errors can cause the new face from the last loop to be // needle-like with a collapse of two edges into a single edge. This // block guarantees the invariant "face always a simple polygon". Postprocess(fNew, faceNew); if (faceNew.Edges.size() < 3) { // Face is completely degenerate, remove it from mesh. mFaces.pop_back(); } return 0; }
void IntrTetrahedron3Tetrahedron3<Real>::SplitAndDecompose ( Tetrahedron3<Real> tetra, const Plane3<Real>& plane, std::vector<Tetrahedron3<Real> >& inside) { // Determine on which side of the plane the points of the tetrahedron lie. Real C[4]; int i, pos[4], neg[4], zer[4]; int positive = 0, negative = 0, zero = 0; for (i = 0; i < 4; ++i) { C[i] = plane.DistanceTo(tetra.V[i]); if (C[i] > (Real)0) { pos[positive++] = i; } else if (C[i] < (Real)0) { neg[negative++] = i; } else { zer[zero++] = i; } } // For a split to occur, one of the c_i must be positive and one must // be negative. if (negative == 0) { // Tetrahedron is completely on the positive side of plane, full clip. return; } if (positive == 0) { // Tetrahedron is completely on the negative side of plane. inside.push_back(tetra); return; } // Tetrahedron is split by plane. Determine how it is split and how to // decompose the negative-side portion into tetrahedra (6 cases). Real w0, w1, invCDiff; Vector3<Real> intp[4]; if (positive == 3) { // +++- for (i = 0; i < positive; ++i) { invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]); w0 = -C[neg[0]]*invCDiff; w1 = +C[pos[i]]*invCDiff; tetra.V[pos[i]] = w0*tetra.V[pos[i]] + w1*tetra.V[neg[0]]; } inside.push_back(tetra); } else if (positive == 2) { if (negative == 2) { // ++-- for (i = 0; i < positive; ++i) { invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]); w0 = -C[neg[0]]*invCDiff; w1 = +C[pos[i]]*invCDiff; intp[i] = w0*tetra.V[pos[i]] + w1*tetra.V[neg[0]]; } for (i = 0; i < negative; ++i) { invCDiff = ((Real)1)/(C[pos[i]] - C[neg[1]]); w0 = -C[neg[1]]*invCDiff; w1 = +C[pos[i]]*invCDiff; intp[i+2] = w0*tetra.V[pos[i]] + w1*tetra.V[neg[1]]; } tetra.V[pos[0]] = intp[2]; tetra.V[pos[1]] = intp[1]; inside.push_back(tetra); inside.push_back(Tetrahedron3<Real>(tetra.V[neg[1]], intp[3], intp[2], intp[1])); inside.push_back(Tetrahedron3<Real>(tetra.V[neg[0]], intp[0], intp[1], intp[2])); } else { // ++-0 for (i = 0; i < positive; ++i) { invCDiff = ((Real)1)/(C[pos[i]] - C[neg[0]]); w0 = -C[neg[0]]*invCDiff; w1 = +C[pos[i]]*invCDiff; tetra.V[pos[i]] = w0*tetra.V[pos[i]] + w1*tetra.V[neg[0]]; } inside.push_back(tetra); } } else if (positive == 1) { if (negative == 3) { // +--- for (i = 0; i < negative; ++i) { invCDiff = ((Real)1)/(C[pos[0]] - C[neg[i]]); w0 = -C[neg[i]]*invCDiff; w1 = +C[pos[0]]*invCDiff; intp[i] = w0*tetra.V[pos[0]] + w1*tetra.V[neg[i]]; } tetra.V[pos[0]] = intp[0]; inside.push_back(tetra); inside.push_back(Tetrahedron3<Real>(intp[0], tetra.V[neg[1]], tetra.V[neg[2]], intp[1])); inside.push_back(Tetrahedron3<Real>(tetra.V[neg[2]], intp[1], intp[2], intp[0])); } else if (negative == 2) { // +--0 for (i = 0; i < negative; ++i) { invCDiff = ((Real)1)/(C[pos[0]] - C[neg[i]]); w0 = -C[neg[i]]*invCDiff; w1 = +C[pos[0]]*invCDiff; intp[i] = w0*tetra.V[pos[0]] + w1*tetra.V[neg[i]]; } tetra.V[pos[0]] = intp[0]; inside.push_back(tetra); inside.push_back(Tetrahedron3<Real>(intp[1], tetra.V[zer[0]], tetra.V[neg[1]], intp[0])); } else { // +-00 invCDiff = ((Real)1)/(C[pos[0]] - C[neg[0]]); w0 = -C[neg[0]]*invCDiff; w1 = +C[pos[0]]*invCDiff; tetra.V[pos[0]] = w0*tetra.V[pos[0]] + w1*tetra.V[neg[0]]; inside.push_back(tetra); } } }