void GeometryTerrain::addTerrain(const int& size_, const float& octaves_, const float& height_, float* RGBFloats_, const float& scale2_, const float& persistance_) { for (int z = 0; z < size_; ++z) { for (int x = 0; x < size_; ++x) { glm::vec4 colourBottom(RGBFloats_[0], RGBFloats_[1], RGBFloats_[2], 1.0f); glm::vec4 colourTop(RGBFloats_[3], RGBFloats_[4], RGBFloats_[5], 1.0f); float temp_height = octave_noise_2d(octaves_, persistance_, scale2_, x, z); points[x][z] = glm::vec3(x, height_ * temp_height, z); glm::vec4 newcolour = glm::lerp(colourBottom, colourTop, temp_height); //gen colour based on Y height colours[x][z] = newcolour; } } //create the triangles from the points for (int z = 0; z < size_ - 1; ++z) { for (int x = 0; x < size_ - 1; ++x) { addTri(TriType::TRI_TERRAIN, points[x][z], points[x][z+1], points[x+1][z+1], colours[x][z], 0); addTri(TriType::TRI_TERRAIN, points[x][z], points[x + 1][z + 1], points[x + 1][z], colours[x][z], 1); } } }
void Patch::addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d) { QVector3D norm = QVector3D::normal(a, b, c); if (sm == Smooth) { addTri(a, b, c, norm); addTri(a, c, d, norm); } else { // If faceted share the two common vertices addTri(a, b, c, norm); int k = geom->vertices.count(); geom->appendSmooth(a, norm, k); geom->appendSmooth(c, norm, k); geom->appendFaceted(d, norm); count += 3; } }
void GeometryTerrain::addCube(glm::vec3& position_, const float& size_) { glm::vec3 pos2 = position_; glm::vec3 pos3 = position_; glm::vec4 colour = glm::vec4(1,1,1,1); pos2.y += 1; pos3.x += 1; addTri(TRI_PLAIN, position_, pos2, pos3, colour, 0); }
void Mesh::addFace(VertexList<Vertex>* vertexList, const Face& face) { if (face.type == Quad) addQuad(vertexList, face); else addTri(vertexList, face); }
NxF32 computeConcavityVolume(NxU32 vcount_hull, const NxF32 *vertices_hull, NxU32 tcount_hull, const NxU32 *indices_hull, NxU32 vcount_mesh, const NxF32 *vertices_mesh, NxU32 tcount_mesh, const NxU32 *indices_mesh) { NxF32 total_volume = 0; #if SHOW_DEBUG NVSHARE::gRenderDebug->pushRenderState(); NVSHARE::gRenderDebug->setCurrentDisplayTime(150.0f); #endif iRayCast *cast_hull = createRayCast(vertices_hull,tcount_hull,indices_hull); iRayCast *cast_mesh = createRayCast(vertices_mesh,tcount_mesh,indices_mesh); const NxU32 *indices = indices_mesh; #if 0 static NxU32 index = 0; NxU32 i = index++; indices = &indices[i*3]; #else for (NxU32 i=0; i<tcount_mesh; i++) #endif { NxU32 i1 = indices[0]; NxU32 i2 = indices[1]; NxU32 i3 = indices[2]; const NxF32 *p1 = &vertices_mesh[i1*3]; const NxF32 *p2 = &vertices_mesh[i2*3]; const NxF32 *p3 = &vertices_mesh[i3*3]; NxF32 normal[3]; NxF32 d = fm_computePlane(p3,p2,p1,normal); NxF32 vertices[6*3]; vertices[0] = p1[0]; vertices[1] = p1[1]; vertices[2] = p1[2]; vertices[3] = p2[0]; vertices[4] = p2[1]; vertices[5] = p2[2]; vertices[6] = p3[0]; vertices[7] = p3[1]; vertices[8] = p3[2]; NxF32 midPoint[3]; midPoint[0] = (p1[0]+p2[0]+p3[0])/3; midPoint[1] = (p1[1]+p2[1]+p3[1])/3; midPoint[2] = (p1[2]+p2[2]+p3[2])/3; fm_lerp(midPoint,p1,&vertices[0],0.9999f); fm_lerp(midPoint,p2,&vertices[3],0.9999f); fm_lerp(midPoint,p3,&vertices[6],0.9999f); NxF32 *_p1 = &vertices[3*3]; NxF32 *_p2 = &vertices[4*3]; NxF32 *_p3 = &vertices[5*3]; NxU32 hitCount = 0; if ( raycast(&vertices[0],normal, _p1,cast_hull,cast_mesh) ) hitCount++; if ( raycast(&vertices[3],normal, _p2,cast_hull,cast_mesh) ) hitCount++; if ( raycast(&vertices[6],normal, _p3,cast_hull,cast_mesh) ) hitCount++; // form triangle mesh! if ( hitCount == 3 ) { NxU32 tcount = 0; NxU32 tindices[8*3]; addTri(tindices,2,1,0,tcount); addTri(tindices,3,4,5,tcount); addTri(tindices,0,3,2,tcount); addTri(tindices,2,3,5,tcount); addTri(tindices,1,3,0,tcount); addTri(tindices,4,3,1,tcount); addTri(tindices,5,4,1,tcount); addTri(tindices,2,5,1,tcount); NxF32 volume = fm_computeMeshVolume(vertices,tcount,tindices); total_volume+=volume; #if SHOW_DEBUG NVSHARE::gRenderDebug->setCurrentColor(0x0000FF,0xFFFFFF); NVSHARE::gRenderDebug->addToCurrentState(NVSHARE::DebugRenderState::SolidWireShaded); for (NxU32 i=0; i<tcount; i++) { NxU32 i1 = tindices[i*3+0]; NxU32 i2 = tindices[i*3+1]; NxU32 i3 = tindices[i*3+2]; const NxF32 *p1 = &vertices[i1*3]; const NxF32 *p2 = &vertices[i2*3]; const NxF32 *p3 = &vertices[i3*3]; NVSHARE::gRenderDebug->DebugTri(p1,p2,p3); } #endif } indices+=3; } #if SHOW_DEBUG NVSHARE::gRenderDebug->popRenderState(); #endif releaseRayCast(cast_hull); releaseRayCast(cast_mesh); return total_volume; }
bool createBox(NxVec3 &dimensions,NxuGeometry &g,const NxMat34 *localPose, float shrink,unsigned int maxV) { g.reset(); g.mVertices = new float[8 *3]; g.mVcount = 8; g.mTcount = 12; g.mIndices = new unsigned int[12 *3]; float bmin[3]; float bmax[3]; bmin[0] = -dimensions.x*shrink; bmin[1] = -dimensions.y*shrink; bmin[2] = -dimensions.z*shrink; bmax[0] = dimensions.x*shrink; bmax[1] = dimensions.y*shrink; bmax[2] = dimensions.z*shrink; set(g.mVertices, 0, bmin[0], bmin[1], bmin[2], localPose); set(g.mVertices, 1, bmax[0], bmin[1], bmin[2], localPose); set(g.mVertices, 2, bmax[0], bmax[1], bmin[2], localPose); set(g.mVertices, 3, bmin[0], bmax[1], bmin[2], localPose); set(g.mVertices, 4, bmin[0], bmin[1], bmax[2], localPose); set(g.mVertices, 5, bmax[0], bmin[1], bmax[2], localPose); set(g.mVertices, 6, bmax[0], bmax[1], bmax[2], localPose); set(g.mVertices, 7, bmin[0], bmax[1], bmax[2], localPose); unsigned int *indices = g.mIndices; indices = addTri(0, 3, 2, indices); indices = addTri(0, 2, 1, indices); indices = addTri(2, 6, 5, indices); indices = addTri(1, 2, 5, indices); indices = addTri(6, 7, 4, indices); indices = addTri(5, 6, 4, indices); indices = addTri(4, 7, 3, indices); indices = addTri(4, 3, 0, indices); indices = addTri(5, 4, 0, indices); indices = addTri(5, 0, 1, indices); indices = addTri(3, 7, 6, indices); indices = addTri(2, 3, 6, indices); return true; }
void calcConvexDecomposition(unsigned int vcount, const float *vertices, unsigned int tcount, const unsigned int *indices, ConvexDecompInterface *callback, float masterVolume, unsigned int depth) { float plane[4]; bool split = false; if ( depth < MAXDEPTH ) { float volume; float c = computeConcavity( vcount, vertices, tcount, indices, callback, plane, volume ); if ( depth == 0 ) { masterVolume = volume; } float percent = (c*100.0f)/masterVolume; if ( percent > CONCAVE_PERCENT ) // if great than 5% of the total volume is concave, go ahead and keep splitting. { split = true; } } if ( depth >= MAXDEPTH || !split ) { #if 1 HullResult result; HullLibrary hl; HullDesc desc; desc.SetHullFlag(QF_TRIANGLES); desc.mVcount = vcount; desc.mVertices = vertices; desc.mVertexStride = sizeof(float)*3; HullError ret = hl.CreateConvexHull(desc,result); if ( ret == QE_OK ) { ConvexResult r(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices); callback->ConvexDecompResult(r); } #else static unsigned int colors[8] = { 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0xFF8040 }; static int count = 0; count++; if ( count == 8 ) count = 0; assert( count >= 0 && count < 8 ); unsigned int color = colors[count]; const unsigned int *source = indices; for (unsigned int i=0; i<tcount; i++) { unsigned int i1 = *source++; unsigned int i2 = *source++; unsigned int i3 = *source++; FaceTri t(vertices, i1, i2, i3 ); callback->ConvexDebugTri( t.mP1.Ptr(), t.mP2.Ptr(), t.mP3.Ptr(), color ); } #endif return; } UintVector ifront; UintVector iback; VertexLookup vfront = Vl_createVertexLookup(); VertexLookup vback = Vl_createVertexLookup(); bool showmesh = false; #if SHOW_MESH showmesh = true; #endif if ( 0 ) { showmesh = true; for (float x=-1; x<1; x+=0.10f) { for (float y=0; y<1; y+=0.10f) { for (float z=-1; z<1; z+=0.04f) { float d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3]; Vector3d p(x,y,z); if ( d >= 0 ) callback->ConvexDebugPoint(p.Ptr(), 0.02f, 0x00FF00); else callback->ConvexDebugPoint(p.Ptr(), 0.02f, 0xFF0000); } } } } if ( 1 ) { // ok..now we are going to 'split' all of the input triangles against this plane! const unsigned int *source = indices; for (unsigned int i=0; i<tcount; i++) { unsigned int i1 = *source++; unsigned int i2 = *source++; unsigned int i3 = *source++; FaceTri t(vertices, i1, i2, i3 ); Vector3d front[4]; Vector3d back[4]; unsigned int fcount=0; unsigned int bcount=0; PlaneTriResult result; result = planeTriIntersection(plane,t.mP1.Ptr(),sizeof(Vector3d),0.00001f,front[0].Ptr(),fcount,back[0].Ptr(),bcount ); if( fcount > 4 || bcount > 4 ) { result = planeTriIntersection(plane,t.mP1.Ptr(),sizeof(Vector3d),0.00001f,front[0].Ptr(),fcount,back[0].Ptr(),bcount ); } switch ( result ) { case PTR_FRONT: assert( fcount == 3 ); if ( showmesh ) callback->ConvexDebugTri( front[0].Ptr(), front[1].Ptr(), front[2].Ptr(), 0x00FF00 ); #if MAKE_MESH addTri( vfront, ifront, front[0], front[1], front[2] ); #endif break; case PTR_BACK: assert( bcount == 3 ); if ( showmesh ) callback->ConvexDebugTri( back[0].Ptr(), back[1].Ptr(), back[2].Ptr(), 0xFFFF00 ); #if MAKE_MESH addTri( vback, iback, back[0], back[1], back[2] ); #endif break; case PTR_SPLIT: assert( fcount >= 3 && fcount <= 4); assert( bcount >= 3 && bcount <= 4); #if MAKE_MESH addTri( vfront, ifront, front[0], front[1], front[2] ); addTri( vback, iback, back[0], back[1], back[2] ); if ( fcount == 4 ) { addTri( vfront, ifront, front[0], front[2], front[3] ); } if ( bcount == 4 ) { addTri( vback, iback, back[0], back[2], back[3] ); } #endif if ( showmesh ) { callback->ConvexDebugTri( front[0].Ptr(), front[1].Ptr(), front[2].Ptr(), 0x00D000 ); callback->ConvexDebugTri( back[0].Ptr(), back[1].Ptr(), back[2].Ptr(), 0xD0D000 ); if ( fcount == 4 ) { callback->ConvexDebugTri( front[0].Ptr(), front[2].Ptr(), front[3].Ptr(), 0x00D000 ); } if ( bcount == 4 ) { callback->ConvexDebugTri( back[0].Ptr(), back[2].Ptr(), back[3].Ptr(), 0xD0D000 ); } } break; } } unsigned int fsize = ifront.size()/3; unsigned int bsize = iback.size()/3; // ok... here we recursively call if ( ifront.size() ) { unsigned int vcount = Vl_getVcount(vfront); const float *vertices = Vl_getVertices(vfront); unsigned int tcount = ifront.size()/3; calcConvexDecomposition(vcount, vertices, tcount, &ifront[0], callback, masterVolume, depth+1); } ifront.clear(); Vl_releaseVertexLookup(vfront); if ( iback.size() ) { unsigned int vcount = Vl_getVcount(vback); const float *vertices = Vl_getVertices(vback); unsigned int tcount = iback.size()/3; calcConvexDecomposition(vcount, vertices, tcount, &iback[0], callback, masterVolume, depth+1); } iback.clear(); Vl_releaseVertexLookup(vback); } }
float getVolume(ConvexDecompInterface *callback) const { unsigned int indices[8*3]; unsigned int tcount = 0; addTri(indices,0,1,2,tcount); addTri(indices,3,4,5,tcount); addTri(indices,0,3,4,tcount); addTri(indices,0,4,1,tcount); addTri(indices,1,4,5,tcount); addTri(indices,1,5,2,tcount); addTri(indices,0,3,5,tcount); addTri(indices,0,5,2,tcount); const float *vertices = mP1.Ptr(); if ( callback ) { unsigned int color = getDebugColor(); #if 0 Vector3d d1 = mNear1; Vector3d d2 = mNear2; Vector3d d3 = mNear3; callback->ConvexDebugPoint(mP1.Ptr(),0.01f,0x00FF00); callback->ConvexDebugPoint(mP2.Ptr(),0.01f,0x00FF00); callback->ConvexDebugPoint(mP3.Ptr(),0.01f,0x00FF00); callback->ConvexDebugPoint(d1.Ptr(),0.01f,0xFF0000); callback->ConvexDebugPoint(d2.Ptr(),0.01f,0xFF0000); callback->ConvexDebugPoint(d3.Ptr(),0.01f,0xFF0000); callback->ConvexDebugTri(mP1.Ptr(), d1.Ptr(), d1.Ptr(),0x00FF00); callback->ConvexDebugTri(mP2.Ptr(), d2.Ptr(), d2.Ptr(),0x00FF00); callback->ConvexDebugTri(mP3.Ptr(), d3.Ptr(), d3.Ptr(),0x00FF00); #else for (unsigned int i=0; i<tcount; i++) { unsigned int i1 = indices[i*3+0]; unsigned int i2 = indices[i*3+1]; unsigned int i3 = indices[i*3+2]; const float *p1 = &vertices[ i1*3 ]; const float *p2 = &vertices[ i2*3 ]; const float *p3 = &vertices[ i3*3 ]; callback->ConvexDebugTri(p1,p2,p3,color); } #endif } float v = computeMeshVolume(mP1.Ptr(), tcount, indices ); return v; }
// // Refine a grid into a TIN_TILgE with error < e // void refineTile(TIN_TILE *tt, double e, short delaunay, short useNodata) { BOOL complete; // is maxE < e complete = 0; TRIANGLE *t1, *t2, *t3, *s; int refineCount = 0; // Read points for initial two triangles into a file initTilePoints(tt,e,useNodata); // While there still is a triangle with max error > e while(PQ_extractMin(tt->pq, &s)){ // Triangles should no longer be marked for deletion since they // are being deleted from the PQ if(s->p1p2 == NULL && s->p1p3 == NULL && s->p2p3 == NULL){ printf(strcat("skipping deleted triangle: err=",ELEV_TYPE_PRINT_CHAR), s->maxErrorValue); fflush(stdout); assert(0); removeTri(s); } assert(s); refineCount++; // malloc the point with max error as it will become a corner R_POINT* maxError = (R_POINT*)malloc(sizeof(R_POINT)); assert(maxError); maxError->x = s->maxE->x; maxError->y = s->maxE->y; maxError->z = s->maxE->z; // Add point to the correct point pointer array assert(tt->bPointsCount < tt->ncols && tt->rPointsCount < tt->nrows && tt->bPointsCount < (tt->ncols * tt->nrows)-(tt->ncols + tt->nrows)); if(maxError->x == (tt->iOffset + tt->nrows-1) ){ tt->bPoints[tt->bPointsCount]=maxError; tt->bPointsCount++; } else if(maxError->y == (tt->jOffset + tt->ncols-1) ){ tt->rPoints[tt->rPointsCount]=maxError; tt->rPointsCount++; } else{ tt->points[tt->pointsCount]=maxError; tt->pointsCount++; } // Debug - print the point being added #ifdef REFINE_DEBUG { TRIANGLE *snext; R_POINT err = findError(s->maxE->x, s->maxE->y, s->maxE->z, s); printf("Point (%6d,%6d,%6d) error=%10ld \t", s->maxE->x, s->maxE->y, s->maxE->z, err ); printTriangleCoords(s); fflush(stdout); if(err != s->maxErrorValue){ printf("Died err= %ld maxE= %ld \n",err,s->maxErrorValue); exit(1); } PQ_min(tt->pq, &snext); assert(s->maxErrorValue >= snext->maxErrorValue); } #endif // Check for collinear points. We make the valid assumption that // MaxE cannot be collinear with > 1 tri int area12,area13,area23; area12 = areaSign(s->p1, s->p2, maxError); area13 = areaSign(s->p1, maxError, s->p3); area23 = areaSign(maxError, s->p2, s->p3); // If p1 p2 is collinear with MaxE if (!area12){ fixCollinear(s->p1,s->p2,s->p3,s,e,maxError,tt,delaunay); tt->numTris++; } else if (!area13){ fixCollinear(s->p1,s->p3,s->p2,s,e,maxError,tt,delaunay); tt->numTris++; } else if (!area23){ fixCollinear(s->p2,s->p3,s->p1,s,e,maxError,tt,delaunay); tt->numTris++; } else { // add three new triangles t1 = addTri(tt,s->p1, s->p2, maxError,s->p1p2,NULL,NULL); t2 = addTri(tt,s->p1, maxError, s->p3,t1,s->p1p3,NULL); t3 = addTri(tt,maxError, s->p2, s->p3,t1,t2,s->p2p3); DEBUG{triangleCheck(s,t1,t2,t3);} tt->numTris += 2; // create poinlists from the original tri (this will yeild the max error) distrPoints(t1,t2,t3,s,NULL,e,tt); DEBUG{checkPointList(t1);checkPointList(t2);checkPointList(t3);} // Enforce delaunay on three 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->p2,t1->p3,e,tt); enforceDelaunay(t2,t2->p1,t2->p3,t2->p2,e,tt); enforceDelaunay(t3,t3->p2,t3->p3,t3->p1,e,tt); } } // remove original tri removeTri(s); //DEBUG{printTin(tt);} extern int displayValid; displayValid = 0; } s = tt->t; // The number of points added is equal to the number of refine loops tt->numPoints += refineCount; /* The number of points should be equal to the sum of all points arrays (one center and possible 4 boundary). Since the arrays have overlap of corner points we subtract the overlaps */ int pts = 0; pts = tt->pointsCount + tt->rPointsCount + tt->bPointsCount - 1; if(tt->top != NULL) pts += tt->top->bPointsCount - 2; if(tt->left != NULL) pts += tt->left->rPointsCount - 2; //assert(tt->numPoints == pts); fix // Sort the point arrays for future use and binary searching qsort(tt->rPoints,tt->rPointsCount,sizeof(R_POINT*),(void *)QS_compPoints); qsort(tt->bPoints,tt->bPointsCount,sizeof(R_POINT*),(void *)QS_compPoints); qsort(tt->points,tt->pointsCount,sizeof(R_POINT*),(void *)QS_compPoints); // We are done with the pq PQ_free(tt->pq); }
// // Swap the common edge between two triangles t1 and t2. The common // edge should always be edge ac, abc are part of t1 and acd are part // of t2. // void edgeSwap(TRIANGLE *t1, TRIANGLE *t2, R_POINT *a, R_POINT *b, R_POINT *c, R_POINT *d, double e, TIN_TILE *tt){ // Common edge must be ac assert(isEndPoint(t1,a) && isEndPoint(t1,b) && isEndPoint(t1,c) && isEndPoint(t2,a) && isEndPoint(t2,c) && isEndPoint(t2,d)); assert(a != b && a != c && a != d && b != c && b != d && c != d); assert(t1 != t2); // Add the two new triangles with the swapped edge TRIANGLE *tn1, *tn2; tn1 = addTri(tt,a, b, d,whichTri(t1,a,b,tt),whichTri(t2,a,d,tt),NULL); tn2 = addTri(tt,c, b, d,whichTri(t1,c,b,tt),whichTri(t2,c,d,tt),tn1); assert(isEndPoint(tn1,a) && isEndPoint(tn1,b) && isEndPoint(tn1,d) && isEndPoint(tn2,b) && isEndPoint(tn2,c) && isEndPoint(tn2,d)); assert(tn1->p2p3 == tn2 && tn2->p2p3 == tn1); if(tn1->p1p2 != NULL) assert(whichTri(tn1->p1p2,a,b,tt) == tn1); if(tn1->p1p3 != NULL) assert(whichTri(tn1->p1p3,a,d,tt) == tn1); if(tn2->p1p2 != NULL) assert(whichTri(tn2->p1p2,c,b,tt) == tn2); if(tn2->p1p3 != NULL) assert(whichTri(tn2->p1p3,c,d,tt) == tn2); // Debug DEBUG{ printf("EdgeSwap: \n"); printTriangle(t1); printTriangle(t2); printTriangle(tn1); printTriangle(tn2); } // Distribute point list from t1 and t2 to tn1 and tn2. Distribute // points requires that the fourth argument (s) be a valid triangle // with a point list so we must check that t1 and t2 are not already // done and thus do not have a point list. If at least one does then // call distribute points with s = the trinagle with the valid point // list. If both are done then the newly created triangles are done // tooand need to be marked accordingly if(t1->maxE != DONE && t2->maxE != DONE) distrPoints(tn1,tn2,NULL,t1,t2,e,tt); else if(t1->maxE != DONE){ distrPoints(tn1,tn2,NULL,t1,NULL,e,tt); } else if(t2->maxE != DONE){ distrPoints(tn1,tn2,NULL,t2,NULL,e,tt); } else{ tn1->maxE = tn2->maxE = DONE; tn1->points = tn2->points= NULL; } // Update the corner if the corner is being swapped. Distrpoints // will not always catch this so it must be done here if(t1 == tt->t || t2 == tt->t){ updateTinTileCorner(tt,tn1,tn2,NULL); } // mark triangles for deletion from the PQ t1->p1p2 = t1->p1p3 = t1->p2p3 = NULL; t2->p1p2 = t2->p1p3 = t2->p2p3 = NULL; PQ_delete(tt->pq,t1->pqIndex); PQ_delete(tt->pq,t2->pqIndex); removeTri(t1); removeTri(t2); DEBUG{checkPointList(tn1); checkPointList(tn2);} // We have created two different triangles, we need to check // delaunay on their 2 edges enforceDelaunay(tn1,a,d,b,e,tt); enforceDelaunay(tn2,c,d,b,e,tt); }
// // Initialize TIN structure, returns a pointer to lower left tri. This // will not initialize the points in the triangles, just the two // staring triangles. Points will be added later in refinement. // TIN_TILE* initTinTile(TIN_TILE *tt,TIN_TILE *leftTile, TIN_TILE *topTile, TRIANGLE *leftTri, TRIANGLE *topTri, R_POINT *nw, R_POINT *sw, R_POINT *ne, int iOffset, int jOffset, short useNodata, TIN *tin){ // Create a pointer to the lower left tri in the tin TRIANGLE *first, *second; // Create a PQ of the error of the triangles. We want to give the PQ // an initial size which is the lowest power of 2 which will fit all // the triangles in a tile (3 * numPoints in tile) = (3 * tin->tl *tin->tl) // // If TL is larger than 4000 then we are probably running untiled // and we should start the pq small and just let it grow as needed unsigned int initPQSize = 1048576; if(tin->tl < 4000) initPQSize = (unsigned int) pow(2,ceil(log10(3 * tin->tl * tin->tl) /log10(2))); tt->pq = PQ_initialize( initPQSize ); // Set Offset tt->iOffset = iOffset; tt->jOffset = jOffset; // Set neighbors tt->top = topTile; tt->left = leftTile; // Number of triangles and points tt->numTris = 2; tt->numPoints = 4; // Point neighbors to me pointNeighborTileTo(tt,DIR_BOTTOM,topTile); pointNeighborTileTo(tt,DIR_RIGHT,leftTile); // We need to create at least 1 and up to 4 corner points for the // intial triangulation. They have incorrect z value for now and // will be updated later if(nw == NULL){ nw = (R_POINT*)malloc(sizeof(R_POINT)); nw->x=iOffset; nw->y=jOffset; nw->z=0; } if(ne == NULL){ ne = (R_POINT*)malloc(sizeof(R_POINT)); ne->x=iOffset; ne->y=tt->ncols-1+jOffset; ne->z=0; } if(sw == NULL){ sw = (R_POINT*)malloc(sizeof(R_POINT)); sw->x=tt->nrows-1+iOffset; sw->y=jOffset; sw->z=0; } R_POINT *se = (R_POINT*)malloc(sizeof(R_POINT)); se->x=tt->nrows-1+iOffset; se->y=tt->ncols-1+jOffset; se->z=0; // Store the 4 corner points for later reference tt->nw = nw; tt->ne = ne; tt->sw = sw; tt->se = se; assert(pointOnBoundary(nw,tt) && pointOnBoundary(ne,tt) && pointOnBoundary(sw,tt) && pointOnBoundary(se,tt) ); // Create the first two triangles. tt->t = first = addTri(tt,nw,sw,se,leftTri,NULL,NULL); second = addTri(tt,nw,ne,se,topTri,first,NULL); assert(tt->t); assert(first); assert(second); // Point the tins lower left corner to sw tt->v = sw; // Lower left edge nw-sw gets stored in tin tt->e.t1 = NULL; tt->e.t2 = NULL; tt->e.p1 = nw; tt->e.p2 = sw; tt->e.type = IN; return tt; }
// // Add the points two the two initial triangles of a Tin tile from // file. Also add points from neighbor boundary arrays to the // triangulation to have boundary consistancy // TIN_TILE *initTilePoints(TIN_TILE *tt, double e, short useNodata){ // First two tris TRIANGLE *first = tt->t; TRIANGLE *second = tt->t->p1p3; // Get back to the beginning of the tile data file rewind(tt->gridFile); // Now build list of points in the triangle // Create a dummy tail for both point lists first->points = Q_init(); second->points = Q_init(); first->maxE = DONE; second->maxE = DONE; // Build the two point lists register int row, col; ELEV_TYPE maxE_first=0; ELEV_TYPE maxE_second=0; ELEV_TYPE tempE = 0; R_POINT temp; // iterate through all points and distribute them to the // two triangles for(row=0;row<tt->nrows;row++) { temp.x=row+tt->iOffset; for(col=0;col<tt->ncols;col++) { temp.y=col+tt->jOffset; fread(&temp.z,sizeof(ELEV_TYPE), 1, tt->gridFile); // Only set Z values for corner points since they already exist if(row==0 && col==0){ tt->nw->z = temp.z; continue; } if(row==0 && col==tt->ncols-1){ tt->ne->z = temp.z; continue; } if(row==tt->nrows-1 && col==tt->ncols-1){ tt->se->z = temp.z; continue; } if(row==tt->nrows-1 && col==0){ tt->sw->z = temp.z; continue; } //Ignore edge points if internal tile if(tt->iOffset != 0 && row == 0) continue; if(tt->jOffset != 0 && col == 0) continue; //Skip nodata or change it to min-1 if(temp.z == tt->nodata){ if(!useNodata) continue; else temp.z = tt->min-1; } // Add to the first triangle's list if(inTri2D(first->p1, first->p2, first->p3, &temp)) { Q_insert_elem_head(first->points, temp); //Update max error tempE = findError(temp.x,temp.y,temp.z,first); if (tempE > maxE_first) { maxE_first = tempE; assert(Q_first(first->points)); // store pointer to triangle w/ max err first->maxE = &Q_first(first->points)->e; first->maxErrorValue = tempE; } } // Add to the second triangle's list else { assert(inTri2D(second->p1, second->p2, second->p3, &temp)); Q_insert_elem_head(second->points, temp); //Update max error tempE = findError(temp.x,temp.y,temp.z,second); if (tempE > maxE_second) { maxE_second = tempE; assert(Q_first(second->points)); // store pointer to triangle w/ max err second->maxE = &Q_first(second->points)->e; second->maxErrorValue = tempE; } } }//for col }//for row //end distribute points among initial triangles DEBUG {checkPointList(first); checkPointList(second);} // First triangle has no points with error > e, mark as done if (first->maxE == DONE){ Q_free_queue(first->points); first->points = NULL; first->maxErrorValue = 0; } // Insert max error point into the PQ else PQ_insert(tt->pq,first); // Second triangle has no points with error > e, mark as done if (second->maxE == DONE){ Q_free_queue(second->points); second->points = NULL; second->maxErrorValue = 0; } // Insert max error point into the PQ else PQ_insert(tt->pq,second); // Initialize point pointer arrays // At most points can have (tl*tl)-2*tl points in it // At most bPoints and rPoints can have tl points tt->points = (R_POINT **)malloc( ((tt->nrows * tt->ncols) - (tt->nrows + tt->ncols)) * sizeof(R_POINT*)); tt->bPoints = (R_POINT **)malloc( tt->ncols * sizeof(R_POINT*)); tt->rPoints = (R_POINT **)malloc( tt->nrows * sizeof(R_POINT*)); // Add points to point pointer array tt->points[0]=tt->nw;//nw tt->bPoints[0]=tt->sw;//sw tt->bPoints[1]=tt->se;//se tt->rPoints[0]=tt->ne;//ne tt->rPoints[1]=tt->se;//se tt->pointsCount = 1; tt->bPointsCount = 2; tt->rPointsCount = 2; // // Add boundary points to the triangulation // int i; COORD_TYPE prevX = 0,prevY = 0; TRIANGLE *t1,*t2, *s, *sp; s = tt->t; sp = tt->t->p1p3; if(tt->left != NULL){ // The first & last point in this array are corner points for this // tile so we ignore them for(i = 1; i < tt->left->rPointsCount-1; i++){ assert(s && tt->pq && tt->left->rPoints[i]); assert(prevX <= tt->left->rPoints[i]->x && prevY <= tt->left->rPoints[i]->y); assert(tt->left->rPoints[i] != tt->nw && tt->left->rPoints[i] != tt->ne && tt->left->rPoints[i] != tt->sw && tt->left->rPoints[i] != tt->se); // add 2 tris in s t1 = addTri(tt, s->p1, tt->left->rPoints[i], s->p3, NULL,whichTri(s,s->p1,s->p3,tt),NULL); assert(t1); t2 = addTri(tt, tt->left->rPoints[i], s->p2, s->p3, NULL,t1,whichTri(s,s->p2,s->p3,tt)); assert(t2); // Verify that t1 and t2 are really inside s triangleCheck(s,t1,t2,NULL); // Distribute points in the 2 triangles if(s->maxE != DONE){ s->p1p2 = s->p1p3 = s->p2p3 = NULL; distrPoints(t1,t2,NULL,s,NULL,e,tt); //Mark triangle s for deletion from pq before distrpoints so we //can include its maxE in the newly created triangle PQ_delete(tt->pq,s->pqIndex); } else{ // Since distrpoints normally fixes corner we need to do it here if(s == tt->t){ updateTinTileCorner(tt,t1,t2,NULL); } t1->maxE = t2->maxE = DONE; t1->points = t2->points = NULL; } removeTri(s); tt->numTris++; tt->numPoints++; // Now split the next lowest boundary triangle s = t2; // Should we enforce Delaunay here? prevX = tt->left->rPoints[i]->x; prevY = tt->left->rPoints[i]->y; } } if(tt->top != NULL){ // The first & last point in this array are corner points for this // tile so we ignore them s = sp; prevX = prevY = 0; for(i = 1; i < tt->top->bPointsCount-1; i++){ assert(s && tt->pq && tt->top->bPoints[i]); assert(prevX <= tt->top->bPoints[i]->x && prevY <= tt->top->bPoints[i]->y); // add 2 tris in s t1 = addTri(tt, s->p1, tt->top->bPoints[i], s->p3, NULL,whichTri(s,s->p1,s->p3,tt),NULL); assert(t1); t2 = addTri(tt, tt->top->bPoints[i], s->p2, s->p3, NULL,t1,whichTri(s,s->p2,s->p3,tt)); assert(t2); // Verify that t1 and t2 are really inside s triangleCheck(s,t1,t2,NULL); // Distribute points in the 2 triangles if(s->maxE != DONE){ distrPoints(t1,t2,NULL,s,NULL,e,tt); //Mark triangle sp for deletion from pq before distrpoints so we //can include its maxE in the newly created triangle s->p1p2 = s->p1p3 = s->p2p3 = NULL; PQ_delete(tt->pq,s->pqIndex); } else{ // Since distrpoints normally fixes corner we need to do it here if(s == tt->t){ updateTinTileCorner(tt,t1,t2,NULL); } t1->maxE = t2->maxE = DONE; t1->points = t2->points = NULL; } removeTri(s); tt->numTris++; tt->numPoints++; // Now split the next lowest boundary triangle s = t2; // Should we enforce Delaunay here? prevX = tt->top->bPoints[i]->x; prevY = tt->top->bPoints[i]->y; } } return tt; }
// // 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); } } }
/* mkPoly: * Construct simple polygon from shortest path from t to s in g. * dad gives the indices of the triangles on path. * sx used to store index of s in points. * index of t is always 0 */ static tripoly_t *mkPoly(router_t * rtr, int *dad, int s, int t, pointf p_s, pointf p_t, int *sx) { tripoly_t *ps; int nxt; ipair p; int nt = 0; side_t *side1; side_t *side2; int i, idx; int cnt1 = 0; int cnt2 = 0; pointf *pts; pointf *pps; /* maps vertex index used in router_t to vertex index used in tripoly */ Dt_t *vmap; tri **trim; /* count number of triangles in path */ for (nxt = dad[t]; nxt != s; nxt = dad[nxt]) nt++; side1 = N_NEW(nt + 4, side_t); side2 = N_NEW(nt + 4, side_t); nxt = dad[t]; p = edgeToSeg(rtr->tg, nxt, t); side1[cnt1].ts = addTri(-1, p.j, NULL); side1[cnt1++].v = p.i; side2[cnt2].ts = addTri(-1, p.i, NULL); side2[cnt2++].v = p.j; t = nxt; for (nxt = dad[t]; nxt >= 0; nxt = dad[nxt]) { p = edgeToSeg(rtr->tg, t, nxt); if (p.i == side1[cnt1 - 1].v) { side1[cnt1 - 1].ts = addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts); side2[cnt2 - 1].ts = addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts); side2[cnt2].ts = addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL); side2[cnt2++].v = p.j; } else if (p.i == side2[cnt2 - 1].v) { side1[cnt1 - 1].ts = addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts); side2[cnt2 - 1].ts = addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts); side1[cnt1].ts = addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL); side1[cnt1++].v = p.j; } else if (p.j == side1[cnt1 - 1].v) { side1[cnt1 - 1].ts = addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts); side2[cnt2 - 1].ts = addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts); side2[cnt2].ts = addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL); side2[cnt2++].v = p.i; } else { side1[cnt1 - 1].ts = addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts); side2[cnt2 - 1].ts = addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts); side1[cnt1].ts = addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL); side1[cnt1++].v = p.i; } t = nxt; } side1[cnt1 - 1].ts = addTri(-2, side2[cnt2 - 1].v, side1[cnt1 - 1].ts); side2[cnt2 - 1].ts = addTri(-2, side1[cnt1 - 1].v, side2[cnt2 - 1].ts); /* store points in pts starting with t in 0, * then side1, then s, then side2 */ vmap = dtopen(&ipairdisc, Dtoset); vmapAdd(vmap, -1, 0); vmapAdd(vmap, -2, cnt1 + 1); pps = pts = N_GNEW(nt + 4, pointf); trim = N_NEW(nt + 4, tri *); *pps++ = p_t; idx = 1; for (i = 0; i < cnt1; i++) { vmapAdd(vmap, side1[i].v, idx); *pps++ = rtr->ps[side1[i].v]; trim[idx++] = side1[i].ts; } *pps++ = p_s; idx++; for (i = cnt2 - 1; i >= 0; i--) { vmapAdd(vmap, side2[i].v, idx); *pps++ = rtr->ps[side2[i].v]; trim[idx++] = side2[i].ts; } for (i = 0; i < nt + 4; i++) { mapTri(vmap, trim[i]); } ps = NEW(tripoly_t); ps->poly.pn = nt + 4; /* nt triangles gives nt+2 points plus s and t */ ps->poly.ps = pts; ps->triMap = trim; free (side1); free (side2); dtclose(vmap); *sx = cnt1 + 1; /* index of s in ps */ return ps; }