void findSecondPoint(const PT *pts, int i, Point2f ¢er, float &radius) { center.x = (float)(pts[0].x + pts[i].x) / 2.0f; center.y = (float)(pts[0].y + pts[i].y) / 2.0f; float dx = (float)(pts[0].x - pts[i].x); float dy = (float)(pts[0].y - pts[i].y); radius = (float)norm(Point2f(dx, dy)) / 2.0f + EPS; for (int j = 1; j < i; ++j) { dx = center.x - (float)pts[j].x; dy = center.y - (float)pts[j].y; if (norm(Point2f(dx, dy)) < radius) { continue; } else { findThirdPoint(pts, i, j, center, radius); } } }
// // Enforce delaunay on triangle t. Assume that p1 & p2 are the // endpoints to the edge that is being checked for delaunay // void enforceDelaunay(TRIANGLE *t, R_POINT *p1, R_POINT *p2, R_POINT *p3, double e, TIN_TILE *tt){ assert(t); // Since we have tiles we cannot garauntee global delaunay. We must // not enforce delaunay on boundary edges, that is edges that are on // the same boundary together. if(!(edgeOnBoundary(p1,p2,tt))){ // Find the triangle on the other side of edge p1p2 TRIANGLE *tn = whichTri(t,p1,p2,tt); // If tn is NULL then we are done, otherwise we need to check delaunay if(tn != NULL){ // Find point across from edge p1p2 in tn R_POINT *d = findThirdPoint(tn->p1,tn->p2,tn->p3,p1,p2); if(CircumCircle(d->x,d->y,p1->x,p1->y,p2->x,p2->y,p3->x,p3->y)){ edgeSwap(t,tn,p1,p3,p2,d,e,tt); } } } }
/*! * Note that the resulting triangulation will not necessarily be complex, * since it's constrained by the polygon's edges. * * Besides triangulating the polygon this method also does: * - insertion of the new polygons (triangles) at the end of * the polygon list. * - setting up marking information for the new polygons. * * \param polylist the global list of polygons * \param selfindex the index of this polygon in the global list * \return zero on success, and a negative integer if some error occured. */ int SimplePolygon::triangulate( DCTPVec2dvector &globalverts, simplepolygonvector &polylist) { #ifdef OSG_TRIANGULATE_CONVEX if( ( !is_marked ) && ( m_bConvex ) ) { // std::cerr <<"triangulating convex: " <<vertices.size() << std::endl; switch( vertices.size( ) ) { case 0: case 1: case 2: return 0; case 3: { polylist.push_back( *this ); } return 0; } unsigned int ui_prev; unsigned int ui_mid; unsigned int ui_next; const unsigned int cui_vertex_cnt = vertices.size( ); SimplePolygon cl_poly; ui_mid = 0; for( ui_prev = 1; ui_prev < cui_vertex_cnt; ++ui_prev ) { if( globalverts[ vertices[ ui_prev ] ][1] < globalverts[ vertices[ ui_mid ] ][1] ) { ui_mid = ui_prev; } else if( ( globalverts[ vertices[ ui_prev ] ][1] == globalverts[ vertices[ ui_mid ] ][1] ) && ( globalverts[ vertices[ ui_prev ] ][0] < globalverts[ vertices[ ui_mid ] ][0] ) ) { ui_mid = ui_prev; } } ui_prev = ( ui_mid + cui_vertex_cnt - 1 ) % cui_vertex_cnt; ui_next = ( ui_mid + 1 ) % cui_vertex_cnt; cl_poly.vertices.resize( 3 ); cl_poly.is_marked = is_marked; cl_poly.vertices[ 0 ] = vertices[ ui_mid ]; cl_poly.vertices[ 1 ] = vertices[ ui_next ]; cl_poly.vertices[ 2 ] = vertices[ ui_prev ]; ui_prev = ( ui_prev + cui_vertex_cnt - 1 ) % cui_vertex_cnt; ui_next = ( ui_next + 1 ) % cui_vertex_cnt; while( cl_poly.vertices[ 1 ] != cl_poly.vertices[ 2 ] ) { polylist.push_back( cl_poly ); if( globalverts[ vertices[ ui_prev ] ][1] < globalverts[ vertices[ ui_next ] ][1] ) { cl_poly.vertices[ 0 ] = cl_poly.vertices[ 2 ]; cl_poly.vertices[ 2 ] = vertices[ ui_prev ]; ui_prev = ( ui_prev + cui_vertex_cnt - 1 ) % cui_vertex_cnt; } else if( ( globalverts[ vertices[ ui_prev ] ][1] == globalverts[ vertices[ ui_next ] ][1] ) && ( globalverts[ vertices[ ui_prev ] ][0] < globalverts[ vertices[ ui_next ] ][0] ) ) { cl_poly.vertices[ 0 ] = cl_poly.vertices[ 2 ]; cl_poly.vertices[ 2 ] = vertices[ ui_prev ]; ui_prev = ( ui_prev + cui_vertex_cnt - 1 ) % cui_vertex_cnt; } else { cl_poly.vertices[ 0 ] = cl_poly.vertices[ 1 ]; cl_poly.vertices[ 1 ] = vertices[ ui_next ]; ui_next = ( ui_next + 1 ) % cui_vertex_cnt; } } return 0; } #endif // std::cerr << " triangulate in, size: " << vertices.size() << std::endl; switch( vertices.size( ) ) { case 0: case 1: case 2: return 0; case 3: { polylist.push_back( *this ); // SimplePolygon p; // p.vertices = vertices; // p.is_marked = is_marked; // std::cerr << "adding polygon of 3 vertices into the list..." << std::endl; // polylist.push_back( p ); // FIXME, this is not too elegant // std::cerr << "triangulate out!!!" << std::endl; } return 0; case 4: { const int ci_v1 = vertices[ 0 ]; const int ci_v2 = vertices[ 1 ]; const int ci_v3 = vertices[ 2 ]; const int ci_v4 = vertices[ 3 ]; const double cd_sdist1 = ( globalverts[ ci_v1 ] - globalverts[ ci_v3 ] ).squareLength( ); const double cd_sdist2 = ( globalverts[ ci_v2 ] - globalverts[ ci_v4 ] ).squareLength( ); double ad_pa[ 2 ]; double ad_pb[ 2 ]; double ad_pc[ 2 ]; double ad_pd[ 2 ]; SimplePolygon p; p.vertices.resize( 3 ); p.is_marked = is_marked; ad_pa[ 0 ] = globalverts[ ci_v1 ][0]; ad_pa[ 1 ] = globalverts[ ci_v1 ][1]; ad_pb[ 0 ] = globalverts[ ci_v2 ][0]; ad_pb[ 1 ] = globalverts[ ci_v2 ][1]; ad_pc[ 0 ] = globalverts[ ci_v3 ][0]; ad_pc[ 1 ] = globalverts[ ci_v3 ][1]; ad_pd[ 0 ] = globalverts[ ci_v4 ][0]; ad_pd[ 1 ] = globalverts[ ci_v4 ][1]; if( cd_sdist1 - cd_sdist2 < DCTP_EPS ) { /* const double cd_r1 = orient2d( ad_pa, ad_pb, ad_pc ); const double cd_r2 = orient2d( ad_pa, ad_pb, ad_pd ); if( ( ( cd_r1 <= 0.0 ) && ( cd_r2 <= 0.0 ) ) || ( ( cd_r1 >= 0.0 ) && ( cd_r2 >= 0.0 ) ) )*/ if( ( orient2d( ad_pa, ad_pb, ad_pc ) <= 0.0 ) || ( orient2d( ad_pa, ad_pd, ad_pc ) >= 0.0 ) || ( incircle( ad_pa, ad_pb, ad_pc, ad_pd ) > 0.0 ) ) { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); p.vertices[ 0 ] = ci_v2; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); // std::cerr << globalverts[ ci_v1 ] << globalverts[ ci_v2 ] << globalverts[ ci_v3 ] << globalverts[ ci_v4 ] << std::endl; } else { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v3; polylist.push_back( p ); p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); } } else { // const double cd_r1 = orient2d( ad_pc, ad_pd, ad_pa ); // const double cd_r2 = orient2d( ad_pc, ad_pd, ad_pb ); // if( ( ( cd_r1 <= 0.0 ) && ( cd_r2 <= 0.0 ) ) || // ( ( cd_r1 >= 0.0 ) && ( cd_r2 >= 0.0 ) ) ) if( ( orient2d( ad_pb, ad_pc, ad_pd ) <= 0.0 ) || ( orient2d( ad_pb, ad_pa, ad_pd ) >= 0.0 ) || ( incircle( ad_pa, ad_pb, ad_pd, ad_pc ) > 0.0 ) ) { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v3; polylist.push_back( p ); p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); // std::cerr << globalverts[ ci_v1 ] << globalverts[ ci_v2 ] << globalverts[ ci_v3 ] << globalverts[ ci_v4 ] << std::endl; } else { p.vertices[ 0 ] = ci_v1; p.vertices[ 1 ] = ci_v2; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); p.vertices[ 0 ] = ci_v2; p.vertices[ 1 ] = ci_v3; p.vertices[ 2 ] = ci_v4; polylist.push_back( p ); } } } return 0; } // recalc valid third points! v1tp = -1; validThirdPoints.resize( vertices.size( ) ); SimplePolygon poly; int i2, i3; // this is an index into the vertices[] vector int err; DCTPivector verts; //p1verts, p2verts, p3verts; int i; int j; // pseudo random (reproduces same triangulation) int offs = ( int( globalverts[ vertices[ 0 ] ][0] * vertices.size( ) ) ) % vertices.size( ); /* for( i = 0; i < vertices.size( ); ++i ) { std::cerr << globalverts[ vertices[ i ] ][0] << ","; std::cerr << globalverts[ vertices[ i ] ][1] << std::endl; }*/ for( j = 0; j < int(vertices.size()); j++ ) { i = ( j + offs ) % vertices.size( ); // v1 = vertices[ i ]; if ( i == int(vertices.size()) - 1 ) i2 = 0; //v2 = vertices [ 0 ]; else i2 = i + 1; //v2 = vertices[ i + 1 ]; err = findThirdPoint( globalverts, i, i2, i3 ); if ( err ) return err; if ( i3 >= 0 ) { // build p1 int k = i2; // !!! verts.resize( 0 ); while ( k != i3 ) { // std::cerr << " k: " << k; verts.push_back( vertices[ k ] ); k++; if ( k == int(vertices.size()) ) k = 0; } // while k verts.push_back( vertices[ k ] ); // record the last one aswell // std::cerr << " k: " << k << std::endl; poly.vertices = verts; poly.is_marked = is_marked; // std::cerr << "calling p1... " << std::endl; err = poly.triangulate( globalverts, polylist); if ( err ) return err; // build p2 verts.resize( 3 ); verts[ 0 ] = vertices[ i ]; verts[ 1 ] = vertices[ i2 ]; verts[ 2 ] = vertices[ i3 ]; poly.vertices = verts; poly.is_marked = is_marked; // std::cerr << "adding p2 to the list..." << std::endl; polylist.push_back( poly ); // build p3 k = i3; verts.resize( 0 ); while ( k != i ) { verts.push_back( vertices[ k ] ); k++; if ( k == int(vertices.size()) ) k = 0; } // while k verts.push_back( vertices[ k ] ); // record the last one aswell poly.vertices = verts; poly.is_marked = is_marked; // std::cerr << "calling p3... " << std::endl; err = poly.triangulate( globalverts, polylist ); if ( err ) return err; // std::cerr << "triangulate out!!!" << std::endl; return 0; } // if } // for i /* SWARNING << "triangulate out WITH ERROR!!!" << endLog; for( i = 0; i < vertices.size( ); ++i ) { std::cerr << globalverts[ vertices[ i ] ][0] << ","; std::cerr << globalverts[ vertices[ i ] ][1] << std::endl; }*/ // char x[ 256 ]; // gets( x ); return -1; }
// // Add triangles and distribute points when there are two collinear // triangles. Assumes that maxE is on line pa pb // void fixCollinear(R_POINT *pa, R_POINT *pb, R_POINT *pc, TRIANGLE* s, double e, R_POINT *maxError, TIN_TILE *tt, short delaunay){ assert(s && tt->pq && maxError); TRIANGLE *sp, *t1, *t2, *t3, *t4; // add 2 tris in s t1 = addTri(tt,pa, maxError, pc,NULL,whichTri(s,pa,pc,tt),NULL); assert(t1); t2 = addTri(tt,maxError, pc, pb,t1,NULL,whichTri(s,pb,pc,tt)); assert(t2); DEBUG{triangleCheck(s,t1,t2,NULL);} // Distribute points in the 2 triangles distrPoints(t1,t2,NULL,s,NULL,e,tt); DEBUG{checkPointList(t1); checkPointList(t2);} // Find other triangle Note: there may not be another triangle if s // is on the edge sp = whichTri(s,pa,pb,tt); // If there is a triangle on the other side of the collinear edge // then we need to split that triangle into two if(sp != NULL){ // Find the unknown point of the triangle on the other side of the line R_POINT *pd; pd = findThirdPoint(sp->p1,sp->p2,sp->p3,pa,pb); assert(pd); // If this triangle is in the other tile we need to make sure we // work with that tile TIN_TILE *ttn; ttn = whichTileTri(pa,pb,pd,tt); assert(ttn); assert(pointInTile(pd,ttn)); // add 2 tris adjacent to s on pa pb t3 = addTri(ttn,pa,maxError,pd,t1,whichTri(sp,pd,pa,ttn),NULL); assert(t3); t4 = addTri(ttn,pb,maxError,pd,t2,whichTri(sp,pd,pb,ttn),t3); assert(t4); DEBUG{triangleCheck(sp,t3,t4,NULL);} // 1 more tri ttn->numTris++; //If this triangle was already "done" meaning it has no more //points in it's point list > MaxE then we don't distribute points //because sp has no point list if(sp->maxE != DONE){ distrPoints(t3,t4,NULL,sp,NULL,e,ttn); //Mark triangle sp for deletion from pq before distrpoints so we //can include its maxE in the newly created triangle sp->p1p2 = sp->p1p3 = sp->p2p3 = NULL; PQ_delete(ttn->pq,sp->pqIndex); } else{ // Since distrpoints normally fixes corner we need to do it here if(sp == tt->t){ updateTinTileCorner(ttn,t3,t4,NULL); } t3->maxE = t4->maxE = DONE; t3->points = t4->points = NULL; } DEBUG{checkPointList(t3); checkPointList(t4);} removeTri(sp); // Enforce delaunay on two new edges of the new triangles if // specified if(delaunay){ // we enforce on the edge that does not have maxE as an // endpoint, so the 4th argument to enforceDelaunay should // always be the maxE point to s for that particular tri enforceDelaunay(t1,t1->p1,t1->p3,t1->p2,e,tt); enforceDelaunay(t2,t2->p2,t2->p3,t2->p1,e,tt); if(ttn == tt){ enforceDelaunay(t3,t3->p1,t3->p3,t3->p2,e,ttn); enforceDelaunay(t4,t4->p1,t4->p3,t4->p2,e,ttn); } } }