// This is a horrible function but it is intended to be a brute force // solution and not efficient or elegant. void QuarticTriangulator::triangulate( const std::vector<ControlPoint> &points, Triangulation &result ) { bool bGoodTriangle; int n = points.size(); // Just iterate through all possible triangles and keep the good ones. for( int i = 0; i < n; ++i ) { Point A( points[i].point.getX(), points[i].point.getY() ); for( int j = 0; j < n; ++j ) { if( j != i ) { Point B( points[j].point.getX(), points[j].point.getY() ); for( int k = 0; k < n; ++k ) { if( k != i && k != j ) { Point C( points[k].point.getX(), points[k].point.getY() ); Triangle triangle( A, B, C ); Circle circumCircle( triangle ); bGoodTriangle = true; for( int c = 0; c < n; ++c ) { if( c != i && c != j && c != k ) { Point D( points[c].point.getX(), points[c].point.getY() ); if( circumCircle.encloses( D ) ) { bGoodTriangle = false; break; } } } // end for c if( bGoodTriangle ) { Tri t; t.a = i; t.b = j; t.c = k; t.triangle = triangle; result.push_back( t ); } } } // end for k } } // end for j } // end for i // Do final check and fix any problems. // This isn't actually necessary, but I'm leaving it commented in // case I want to run tests in the future. /* Triangulation old( result ); bool isAllGood; result.clear(); for( int m = 0; m < old.size(); ++m ) { Circle C( old[m].triangle ); isAllGood = true; for( int n = 0; n < points.size(); ++n ) { Point P( points[n].point.getX(), points[n].point.getY() ); if( n != old[m].a && n != old[m].b && n != old[m].c && C.encloses( P ) ) { isAllGood = false; break; } } if( isAllGood ) { result.push_back( old[m] ); } else { printf( "Removed One\n" ); } } */ return; } // end function triangulate
static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e) { static const float EPS = 1e-5f; int* edge = &edges[e*4]; // Cache s and t. int s,t; if (edge[2] == UNDEF) { s = edge[0]; t = edge[1]; } else if (edge[3] == UNDEF) { s = edge[1]; t = edge[0]; } else { // Edge already completed. return; } // Find best point on left of edge. int pt = npts; float c[3] = {0,0,0}; float r = -1; for (int u = 0; u < npts; ++u) { if (u == s || u == t) continue; if (vcross2(&pts[s*3], &pts[t*3], &pts[u*3]) > EPS) { if (r < 0) { // The circle is not updated yet, do it now. pt = u; circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); continue; } const float d = vdist2(c, &pts[u*3]); const float tol = 0.001f; if (d > r*(1+tol)) { // Outside current circumcircle, skip. continue; } else if (d < r*(1-tol)) { // Inside safe circumcircle, update circle. pt = u; circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); } else { // Inside epsilon circum circle, do extra tests to make sure the edge is valid. // s-u and t-u cannot overlap with s-pt nor t-pt if they exists. if (overlapEdges(pts, edges, nedges, s,u)) continue; if (overlapEdges(pts, edges, nedges, t,u)) continue; // Edge is valid. pt = u; circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); } } } // Add new triangle or update edge info if s-t is on hull. if (pt < npts) { // Update face information of edge being completed. updateLeftFace(&edges[e*4], s, t, nfaces); // Add new edge or update face info of old edge. e = findEdge(edges, nedges, pt, s); if (e == UNDEF) addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, UNDEF); else updateLeftFace(&edges[e*4], pt, s, nfaces); // Add new edge or update face info of old edge. e = findEdge(edges, nedges, t, pt); if (e == UNDEF) addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, UNDEF); else updateLeftFace(&edges[e*4], t, pt, nfaces); nfaces++; } else { updateLeftFace(&edges[e*4], s, t, HULL); } }
// Based on Paul Bourke's triangulate.c // http://astronomy.swin.edu.au/~pbourke/terrain/triangulate/triangulate.c static void delaunay(const int nv, float *verts, rcIntArray& idx, rcIntArray& tris, rcIntArray& edges) { // Sort vertices idx.resize(nv); for (int i = 0; i < nv; ++i) idx[i] = i; #ifdef WIN32 qsort_s(&idx[0], idx.size(), sizeof(int), ptcmp, verts); #else qsort_r(&idx[0], idx.size(), sizeof(int), verts, ptcmp); #endif // Find the maximum and minimum vertex bounds. // This is to allow calculation of the bounding triangle float xmin = verts[0]; float ymin = verts[2]; float xmax = xmin; float ymax = ymin; for (int i = 1; i < nv; ++i) { xmin = rcMin(xmin, verts[i*3+0]); xmax = rcMax(xmax, verts[i*3+0]); ymin = rcMin(ymin, verts[i*3+2]); ymax = rcMax(ymax, verts[i*3+2]); } float dx = xmax - xmin; float dy = ymax - ymin; float dmax = (dx > dy) ? dx : dy; float xmid = (xmax + xmin) / 2.0f; float ymid = (ymax + ymin) / 2.0f; // Set up the supertriangle // This is a triangle which encompasses all the sample points. // The supertriangle coordinates are added to the end of the // vertex list. The supertriangle is the first triangle in // the triangle list. float sv[3*3]; sv[0] = xmid - 20 * dmax; sv[1] = 0; sv[2] = ymid - dmax; sv[3] = xmid; sv[4] = 0; sv[5] = ymid + 20 * dmax; sv[6] = xmid + 20 * dmax; sv[7] = 0; sv[8] = ymid - dmax; tris.push(-3); tris.push(-2); tris.push(-1); tris.push(0); // not completed for (int i = 0; i < nv; ++i) { const float xp = verts[idx[i]*3+0]; const float yp = verts[idx[i]*3+2]; edges.resize(0); // Set up the edge buffer. // If the point (xp,yp) lies inside the circumcircle then the // three edges of that triangle are added to the edge buffer // and that triangle is removed. for (int j = 0; j < tris.size()/4; ++j) { int* t = &tris[j*4]; if (t[3]) // completed? continue; const float* v1 = t[0] < 0 ? &sv[(t[0]+3)*3] : &verts[idx[t[0]]*3]; const float* v2 = t[1] < 0 ? &sv[(t[1]+3)*3] : &verts[idx[t[1]]*3]; const float* v3 = t[2] < 0 ? &sv[(t[2]+3)*3] : &verts[idx[t[2]]*3]; float xc,yc,rsqr; int inside = circumCircle(xp,yp, v1[0],v1[2], v2[0],v2[2], v3[0],v3[2], xc,yc,rsqr); if (xc < xp && rcSqr(xp-xc) > rsqr) t[3] = 1; if (inside) { // Collect triangle edges. edges.push(t[0]); edges.push(t[1]); edges.push(t[1]); edges.push(t[2]); edges.push(t[2]); edges.push(t[0]); // Remove triangle j. t[0] = tris[tris.size()-4]; t[1] = tris[tris.size()-3]; t[2] = tris[tris.size()-2]; t[3] = tris[tris.size()-1]; tris.resize(tris.size()-4); j--; } } // Remove duplicate edges. const int ne = edges.size()/2; for (int j = 0; j < ne-1; ++j) { for (int k = j+1; k < ne; ++k) { // Dupe?, make null. if ((edges[j*2+0] == edges[k*2+1]) && (edges[j*2+1] == edges[k*2+0])) { edges[j*2+0] = 0; edges[j*2+1] = 0; edges[k*2+0] = 0; edges[k*2+1] = 0; } } } // Form new triangles for the current point // Skipping over any null. // All edges are arranged in clockwise order. for (int j = 0; j < ne; ++j) { if (edges[j*2+0] == edges[j*2+1]) continue; tris.push(edges[j*2+0]); tris.push(edges[j*2+1]); tris.push(i); tris.push(0); // not completed } } // Remove triangles with supertriangle vertices // These are triangles which have a vertex number greater than nv for (int i = 0; i < tris.size()/4; ++i) { int* t = &tris[i*4]; if (t[0] < 0 || t[1] < 0 || t[2] < 0) { t[0] = tris[tris.size()-4]; t[1] = tris[tris.size()-3]; t[2] = tris[tris.size()-2]; t[3] = tris[tris.size()-1]; tris.resize(tris.size()-4); i--; } } // Triangle vertices are pointing to sorted vertices, remap indices. for (int i = 0; i < tris.size(); ++i) tris[i] = idx[tris[i]]; }