#include "Polygon3.h" #include "Mesh.h" #include "ViewCellBsp.h" // TODO: erase this #include "Intersectable.h" // tolerance value for side relation #define SIDE_TOLERANCE 0.002f // TODO: Test different values #define SIDE_TOLERANCE_SQRD 0.000004f Polygon3::Polygon3(): mMaterial(NULL), mParent(NULL) {} Polygon3::Polygon3(const VertexContainer &vertices): mVertices(vertices), mMaterial(NULL), mParent(NULL) {} Polygon3::Polygon3(Intersectable *parent): mMaterial(NULL), mParent(parent) { } Polygon3::Polygon3(Face *face, Mesh *parentMesh) { VertexIndexContainer::iterator it = face->mVertexIndices.begin(); for (; it != face->mVertexIndices.end(); ++it) { mVertices.push_back(parentMesh->mVertices[*it]); mMaterial = parentMesh->mMaterial; } } Plane3 Polygon3::GetSupportingPlane() const { Vector3 v1 = mVertices[0] - mVertices[1]; Vector3 v2 = mVertices[2] - mVertices[1]; #ifdef _DEBUG Debug << "plane spanned by " << v1 << ", " << v2 << endl; #endif return Plane3(mVertices[0], mVertices[1], mVertices[2]); } void Polygon3::Split(Plane3 *partition, Polygon3 *front, Polygon3 *back) { Vector3 ptA = mVertices.back(); int sideA = partition->Side(ptA, SIDE_TOLERANCE); VertexContainer::const_iterator it; bool foundSplit = false; Vector3 prevSplitPt(ptA); // find line - plane intersections for (it = mVertices.begin(); it != mVertices.end(); ++ it) { Vector3 ptB = *it; int sideB = partition->Side(ptB, SIDE_TOLERANCE); // vertices on different sides => split if (sideB > 0) { if (sideA < 0) { //-- plane - line intersection Vector3 splitPt = partition->FindIntersection(ptA, ptB); Debug << "fpg " << splitPt << " side " << partition->Side(splitPt, SIDE_TOLERANCE) << "\nptA " << ptA << " side " << sideA << "\nptB " << ptB << " side " << sideB << " " << Distance(ptB, splitPt) << endl; if (!foundSplit || (SqrDistance(splitPt, prevSplitPt) > SIDE_TOLERANCE_SQRD)) { // add vertex to both polygons front->mVertices.push_back(splitPt); back->mVertices.push_back(splitPt); foundSplit = true; prevSplitPt = splitPt; } } front->mVertices.push_back(ptB); } else if (sideB < 0) { if (sideA > 0) { //-- plane - line intersection Vector3 splitPt = partition->FindIntersection(ptA, ptB); // if (foundSplit) Debug << "back split pt " << splitPt << " prev " << prevSplitPt << endl; if (!foundSplit || (SqrDistance(splitPt, prevSplitPt) > SIDE_TOLERANCE_SQRD)) { //Debug << "add back split vertex " << splitPt << endl; // add vertex to both polygons front->mVertices.push_back(splitPt); back->mVertices.push_back(splitPt); foundSplit = true; prevSplitPt = splitPt; }//else Debug << "reject back split vertex " << splitPt << endl; } back->mVertices.push_back(ptB); } else { // vertex on plane => add vertex to both polygons front->mVertices.push_back(ptB); back->mVertices.push_back(ptB); } ptA = ptB; sideA = sideB; } } int Polygon3::Side(const Plane3 &plane) const { int classification = ClassifyPlane(plane); if (classification == BACK_SIDE) return -1; else if (classification == FRONT_SIDE) return 1; return 0; } int Polygon3::ClassifyPlane(const Plane3 &plane) const { VertexContainer::const_iterator it; bool onFrontSide = false; bool onBackSide = false; int count = 0; // find possible line-plane intersections for (it = mVertices.begin(); it != mVertices.end(); ++ it) { int side = plane.Side(*it, SIDE_TOLERANCE); //Debug << "side: " << side << " " << plane.Distance(*it) << endl; if (side > 0) onFrontSide = true; else if (side < 0) onBackSide = true; //TODO: check if split goes through vertex if (onFrontSide && onBackSide) // split { return SPLIT; } // 3 vertices enough to decide coincident else if (((++ count) >= 3) && !onFrontSide && !onBackSide) { // Decide if plane and surface normal are same if (DotProd(plane.mNormal, GetSupportingPlane().mNormal) > 0) return COINCIDENT; // plane and polygon are coincident else return FRONT_SIDE; } } if (onBackSide) { return BACK_SIDE; } else if (onFrontSide) { return FRONT_SIDE; } // Decide if plane and surface normal are same if (DotProd(plane.mNormal, GetSupportingPlane().mNormal) > 0) return COINCIDENT; // plane and polygon are coincident else return FRONT_SIDE; } Vector3 Polygon3::Center() const { int i; Vector3 sum = mVertices[0]; for (i=1; i < mVertices.size(); i++) sum += mVertices[i]; return sum/(float)i; } void Polygon3::Scale(const float scale) { int i; Vector3 center = Center(); for (i=0; i < mVertices.size(); i++) { mVertices[i] = center + scale*(mVertices[i] - center); } } bool Polygon3::CheckValid() const { if (mVertices.size() < 3) return false; Vector3 vtx = mVertices.back(); VertexContainer::const_iterator it, it_end = mVertices.end(); for (it = mVertices.begin(); it != it_end; ++it) { if (!(SqrDistance(vtx, *it) > SIDE_TOLERANCE_SQRD)) { Debug << "Malformed vertices:\n" << *this << endl; return false; } vtx = *it; } return true; }