Exemple #1
0
// 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]];
}