// // http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml list<Polygon> Triangulate(const Polygon& poly) { int n = poly.points.size(); int *verts = new int[n]; list<Polygon> polys; for (int i = 0; i < n; i++) { verts[i] = i; } int remaining = n; int v = remaining - 1; int count = 2*remaining; while (remaining > 2) { if (count <= 0) { Debug("Failed to triangulate polygon"); return {}; } count--; int u, w; u = v; if (u >= remaining) u = 0; v = u + 1; if (v >= remaining) v = 0; w = v + 1; if (w >= remaining) w = 0; if (IsEar(poly, u, v, w, remaining, verts)) { int a, b, c; a = verts[u]; b = verts[v]; c = verts[w]; Polygon tri; tri.points.push_back(poly[a]); tri.points.push_back(poly[b]); tri.points.push_back(poly[c]); polys.push_back(tri); for (int s = v, t = v + 1; t < remaining; s++, t++) { verts[s] = verts[t]; } remaining--; count = 2 * remaining; } } delete [] verts; return polys; }
void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) { Vector tu, tv; srf->TangentsAt(0.5, 0.5, &tu, &tv); double s = sqrt(tu.MagSquared() + tv.MagSquared()); // We would like to apply our tolerances in xyz; but that would be a lot // of work, so at least scale the epsilon semi-reasonably. That's // perfect for square planes, less perfect for anything else. double scaledEps = LENGTH_EPS / s; int i; // Clean the original contour by removing any zero-length edges. l.ClearTags(); for(i = 1; i < l.n; i++) { if((l.elem[i].p).Equals(l.elem[i-1].p)) { l.elem[i].tag = 1; } } l.RemoveTagged(); // Now calculate the ear-ness of each vertex for(i = 0; i < l.n; i++) { (l.elem[i]).ear = IsEar(i, scaledEps) ? SPoint::EAR : SPoint::NOT_EAR; } bool toggle = false; while(l.n > 3) { // Some points may have changed ear-ness, so recalculate for(i = 0; i < l.n; i++) { if(l.elem[i].ear == SPoint::UNKNOWN) { (l.elem[i]).ear = IsEar(i, scaledEps) ? SPoint::EAR : SPoint::NOT_EAR; } } int bestEar = -1; double bestChordTol = VERY_POSITIVE; // Alternate the starting position so we generate strip-like // triangulations instead of fan-like toggle = !toggle; int offset = toggle ? -1 : 0; for(i = 0; i < l.n; i++) { int ear = WRAP(i+offset, l.n); if(l.elem[ear].ear == SPoint::EAR) { if(srf->degm == 1 && srf->degn == 1) { // This is a plane; any ear is a good ear. bestEar = ear; break; } // If we are triangulating a curved surface, then try to // clip ears that have a small chord tolerance from the // surface. Vector prev = l.elem[WRAP((i+offset-1), l.n)].p, next = l.elem[WRAP((i+offset+1), l.n)].p; double tol = srf->ChordToleranceForEdge(prev, next); if(tol < bestChordTol - scaledEps) { bestEar = ear; bestChordTol = tol; } if(bestChordTol < 0.1*SS.ChordTolMm()) { break; } } } if(bestEar < 0) { dbp("couldn't find an ear! fail"); return; } ClipEarInto(m, bestEar, scaledEps); } ClipEarInto(m, 0, scaledEps); // add the last triangle }
TriangulateEC<Real>::TriangulateEC (int iQuantity, const Vector2<Real>* akPosition, Query::Type eQueryType, Real fEpsilon, int*& raiIndex) { assert(iQuantity >= 3 && akPosition); if (eQueryType == Query::QT_FILTERED) { assert((Real)0.0 <= fEpsilon && fEpsilon <= (Real)1.0); } Vector2<Real>* akSPosition = 0; Vector2<Real> kMin, kMax, kRange; Real fScale; int i; switch (eQueryType) { case Query::QT_INT64: // Transform the vertices to the square [0,2^{20}]^2. Vector2<Real>::ComputeExtremes(iQuantity,akPosition,kMin,kMax); kRange = kMax - kMin; fScale = (kRange[0] >= kRange[1] ? kRange[0] : kRange[1]); fScale *= (Real)(1 << 20); akSPosition = WM4_NEW Vector2<Real>[iQuantity]; for (i = 0; i < iQuantity; i++) { akSPosition[i] = (akPosition[i] - kMin)*fScale; } m_pkQuery = WM4_NEW Query2Int64<Real>(iQuantity,akSPosition); break; case Query::QT_INTEGER: // Transform the vertices to the square [0,2^{24}]^2. Vector2<Real>::ComputeExtremes(iQuantity,akPosition,kMin,kMax); kRange = kMax - kMin; fScale = (kRange[0] >= kRange[1] ? kRange[0] : kRange[1]); fScale *= (Real)(1 << 24); akSPosition = WM4_NEW Vector2<Real>[iQuantity]; for (i = 0; i < iQuantity; i++) { akSPosition[i] = (akPosition[i] - kMin)*fScale; } m_pkQuery = WM4_NEW Query2TInteger<Real>(iQuantity,akSPosition); break; case Query::QT_REAL: // Transform the vertices to the square [0,1]^2. Vector2<Real>::ComputeExtremes(iQuantity,akPosition,kMin,kMax); kRange = kMax - kMin; fScale = (kRange[0] >= kRange[1] ? kRange[0] : kRange[1]); akSPosition = WM4_NEW Vector2<Real>[iQuantity]; for (i = 0; i < iQuantity; i++) { akSPosition[i] = (akPosition[i] - kMin)*fScale; } m_pkQuery = WM4_NEW Query2<Real>(iQuantity,akSPosition); break; case Query::QT_RATIONAL: // No transformation of the input data. m_pkQuery = WM4_NEW Query2TRational<Real>(iQuantity,akPosition); break; case Query::QT_FILTERED: // No transformation of the input data. m_pkQuery = WM4_NEW Query2Filtered<Real>(iQuantity,akPosition, fEpsilon); break; } int iQm1 = iQuantity - 1; raiIndex = WM4_NEW int[3*iQm1]; int* piIndex = raiIndex; m_akVertex = WM4_NEW Vertex[iQuantity]; m_iCFirst = -1; m_iCLast = -1; m_iRFirst = -1; m_iRLast = -1; m_iEFirst = -1; m_iELast = -1; // Create a circular list of the polygon vertices for dynamic removal of // vertices. Keep track of two linear sublists, one for the convex // vertices and one for the reflex vertices. This is an O(N) process // where N is the number of polygon vertices. for (i = 0; i <= iQm1; i++) { // link the vertices Vertex& rkV = V(i); rkV.VPrev = (i > 0 ? i-1 : iQm1); rkV.VNext = (i < iQm1 ? i+1 : 0); // link the convex/reflex vertices if (IsConvex(i)) { InsertAfterC(i); } else { InsertAfterR(i); } } if (m_iRFirst == -1) { // polygon is convex, just triangle fan it for (i = 1; i < iQm1; i++) { *piIndex++ = 0; *piIndex++ = i; *piIndex++ = i+1; } return; } // Identify the ears and build a circular list of them. Let V0, V1, and // V2 be consecutive vertices forming a triangle T. The vertex V1 is an // ear if no other vertices of the polygon lie inside T. Although it is // enough to show that V1 is not an ear by finding at least one other // vertex inside T, it is sufficient to search only the reflex vertices. // This is an O(C*R) process where C is the number of convex vertices and // R is the number of reflex vertices, N = C+R. The order is O(N^2), for // example when C = R = N/2. for (i = m_iCFirst; i != -1; i = V(i).SNext) { if (IsEar(i)) { InsertEndE(i); } } V(m_iEFirst).EPrev = m_iELast; V(m_iELast).ENext = m_iEFirst; // Remove the ears, one at a time. while (true) { // add triangle of ear to output int iVPrev = V(m_iEFirst).VPrev; int iVNext = V(m_iEFirst).VNext; *piIndex++ = iVPrev; *piIndex++ = m_iEFirst; *piIndex++ = iVNext; // remove the vertex corresponding to the ear RemoveV(m_iEFirst); if (--iQuantity == 3) { // Only one triangle remains, just remove the ear and copy it. RemoveE(); iVPrev = V(m_iEFirst).VPrev; iVNext = V(m_iEFirst).VNext; *piIndex++ = iVPrev; *piIndex++ = m_iEFirst; *piIndex++ = iVNext; break; } // removal of the ear can cause an adjacent vertex to become an ear bool bWasReflex; Vertex& rkVPrev = V(iVPrev); if (!rkVPrev.IsEar) { bWasReflex = !rkVPrev.IsConvex; if (IsConvex(iVPrev)) { if (bWasReflex) { RemoveR(iVPrev); } if (IsEar(iVPrev)) { InsertBeforeE(iVPrev); } } } Vertex& rkVNext = V(iVNext); if (!rkVNext.IsEar) { bWasReflex = !rkVNext.IsConvex; if (IsConvex(iVNext)) { if (bWasReflex) { RemoveR(iVNext); } if (IsEar(iVNext)) { InsertAfterE(iVNext); } } } // remove the ear RemoveE(); } WM4_DELETE[] akSPosition; WM4_DELETE m_pkQuery; }