//determines if this polygon lies entirely within a single plane bool CEditPoly::IsCoplanar() { //run through all the points, projecting them onto the normal. The //value should be relatively the same for all the points if(NumVerts() < 4) { //if we have 3 or less points, we mathmatically have to be coplanar, so just bail to //prevent mathmatical errors from causing problems return true; } //the epsilon value that we allow points to stray from the plane static const float kfPlaneEpsilon = 0.01f; LTVector vNormal = Normal(); CReal fDist = m_pBrush->m_Points[Index(0)].Dot(Normal()); for(uint32 nCurrPt = 1; nCurrPt < NumVerts(); nCurrPt++) { CReal fTestDist = m_pBrush->m_Points[Index(nCurrPt)].Dot(Normal()); fTestDist -= fDist; if((fTestDist < -kfPlaneEpsilon) || (fTestDist > kfPlaneEpsilon)) { return false; } } return true; }
void CBasePoly::GetCenterPoint( CVector ¢erPt ) { centerPt.Init( 0.0f, 0.0f, 0.0f ); for(uint32 i=0; i < NumVerts(); i++ ) centerPt += Pt(i); centerPt /= (CReal)NumVerts(); }
/** Copy all the vertices and triangle of another TIN to this one. This is a simple join. No attempt is made to share vertices or any other integration. It is further assumed that the two TINs have compatible coordinate systems. */ void vtTin::AppendFrom(const vtTin *pTin) { const size_t verts = pTin->NumVerts(); const size_t tris = pTin->NumTris(); // Preallocate (for efficiency) m_vert.SetMaxSize(m_vert.GetSize() + verts + 1); m_z.reserve(m_vert.GetSize() + verts + 1); m_tri.reserve(m_tri.size() + (tris*3) + 1); // Remember the starting point for vertex indices const int base = NumVerts(); // Simple, naive copy of vertices and triangles DPoint2 p; float z; for (size_t i = 0; i < verts; i++) { pTin->GetVert(i, p, z); AddVert(p, z); } for (size_t i = 0; i < tris; i++) { const int *tri = pTin->GetAtTri(i); AddTri(base+tri[0], base+tri[1], base+tri[2]); } ComputeExtents(); }
int CDispInfo::ApplyTerrainMod_Speculative( ITerrainMod *pMod, CSpeculativeTerrainModVert *pSpeculativeVerts, int nMaxVerts ) { int nModified = 0; if( nMaxVerts == 0 ) return 0; int nVerts = NumVerts(); for( int iVert=0; iVert < nVerts; iVert++ ) { if( m_AllowedVerts.Get( iVert ) ) { pSpeculativeVerts[nModified].m_vNew = m_Verts[iVert].m_vPos; Vector &vOriginalPos = m_Verts[iVert].m_vOriginalPos; if( pMod->ApplyMod( pSpeculativeVerts[nModified].m_vNew, vOriginalPos ) ) { pSpeculativeVerts[nModified].m_vOriginal = vOriginalPos; pSpeculativeVerts[nModified].m_vCurrent = m_Verts[iVert].m_vPos; ++nModified; if( nModified >= nMaxVerts ) break; } } } return nModified; }
/** * Write the TIN to a TIN (.itf) file (VTP-defined format). */ bool vtTin::Write(const char *fname, bool progress_callback(int)) const { FILE *fp = vtFileOpen(fname, "wb"); if (!fp) return false; char *wkt; OGRErr err = m_proj.exportToWkt(&wkt); if (err != OGRERR_NONE) { fclose(fp); return false; } int proj_len = strlen(wkt); int data_start = 5 + 4 + 4 + 4 + + 4 + proj_len + 32 + 4 + 4; int i; int verts = NumVerts(); int tris = NumTris(); fwrite("tin02", 5, 1, fp); // version 2 fwrite(&verts, 4, 1, fp); fwrite(&tris, 4, 1, fp); fwrite(&data_start, 4, 1, fp); fwrite(&proj_len, 4, 1, fp); fwrite(wkt, proj_len, 1, fp); OGRFree(wkt); // version 2 of the format has extents: left, top, right, bottom, min z, max h fwrite(&m_EarthExtents.left, sizeof(double), 4, fp); fwrite(&m_fMinHeight, sizeof(float), 1, fp); fwrite(&m_fMaxHeight, sizeof(float), 1, fp); // room for future extention: you can add fields here, as long as you // increase the data_start offset above accordingly // count progress int count = 0, total = verts + tris; // write verts for (i = 0; i < verts; i++) { fwrite(&m_vert[i].x, 8, 2, fp); // 2 doubles fwrite(&m_z[i], 4, 1, fp); // 1 float if (progress_callback && (++count % 100) == 0) progress_callback(count * 99 / total); } // write tris for (i = 0; i < tris; i++) { fwrite(&m_tri[i*3], 4, 3, fp); // 3 ints if (progress_callback && (++count % 100) == 0) progress_callback(count * 99 / total); } fclose(fp); return true; }
/** * Because the TIN triangles refer to their vertices by index, it's possible * to have some vertices which are not referenced. Find and remove those * vertices. * \return The number of unused vertices removed. */ int vtTin::RemoveUnusedVertices() { size_t verts = NumVerts(); std::vector<bool> used; used.resize(verts, false); // Flag all the vertices that are used size_t tris = NumTris(); for (size_t i = 0; i < tris; i++) { used[m_tri[i*3]] = true; used[m_tri[i*3+1]] = true; used[m_tri[i*3+2]] = true; } // Remove all the vertices that weren't flagged int count = 0; for (size_t i = 0; i < verts;) { if (!used[i]) { // Remove vertex RemVert(i); used.erase(used.begin()+i); verts--; count++; } else i++; } return count; }
//determines the surface area of the polygon CReal CEditPoly::GetSurfaceArea() { //accumulate the area occupied by each triangle CReal fArea = 0.0f; uint32 nNumPts = NumVerts(); //safety first... if(nNumPts < 3) return 0.0f; //fan out from vertex 0 to all other verts LTVector vFanPt = m_pBrush->m_Points[Index(0)]; for(uint32 nCurrPt = 1; nCurrPt < nNumPts - 1; nCurrPt++) { //get the two edges LTVector vEdge1 = m_pBrush->m_Points[Index(nCurrPt)] - vFanPt; LTVector vEdge2 = m_pBrush->m_Points[Index(nCurrPt + 1)] - vFanPt; //the cross product gives us the area of the rect, so we want to add //half of that fArea += vEdge1.Cross(vEdge2).Mag() / 2; } return fArea; }
bool CBasePoly::IsValid() { for( uint32 i=0; i < NumVerts(); i++ ) if( m_Indices[i] >= m_pBrush->m_Points ) return false; return true; }
bool CBasePoly::PointInPoly( const LTVector &point ) { CReal area; for(uint32 i=0; i < NumVerts(); i++ ) { area = g_TriArea2( Normal(), Pt(i), NextPt(i), point ); if( area > 0 ) return false; } return true; }
/** * Write the TIN to a Wavefront OBJ file. Note that we write X and Y as * geographic coordinates, but OBJ only supports single-precision floating * point values, so it may lose some precision. */ bool vtTin::WriteOBJ(const char *fname, bool progress_callback(int)) const { FILE *fp = vtFileOpen(fname, "wb"); if (!fp) return false; int i, count = 0; const int verts = NumVerts(); const int tris = NumTris(); const int total = verts + tris; fprintf(fp, "####\n"); fprintf(fp, "#\n"); fprintf(fp, "# OBJ File Generated by VTBuilder\n"); fprintf(fp, "#\n"); fprintf(fp, "####\n"); fprintf(fp, "# Object %s\n", fname); fprintf(fp, "#\n"); fprintf(fp, "# Vertices: %d\n", verts); fprintf(fp, "# Faces: %d\n", tris); fprintf(fp, "#\n"); fprintf(fp, "####\n"); // write verts for (i = 0; i < verts; i++) { fprintf(fp, "v %lf %lf %f\n", m_vert[i].x, m_vert[i].y, m_z[i]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, "# %d vertices, 0 vertices normals\n", verts); fprintf(fp, "\n"); // write tris for (i = 0; i < tris; i++) { // Here is triangle definition (zero based) A B C ... // the indices in the file are 1-based, so add 1 fprintf(fp, "f %d %d %d\n", m_tri[i*3+0]+1, m_tri[i*3+1]+1, m_tri[i*3+2]+1); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, "# %d faces, 0 coords texture\n", tris); fprintf(fp, "\n"); fprintf(fp, "# End of File\n"); fclose(fp); return true; }
void DumpVerts2IFrIT(const char *filename, tVertex verts) { int j, ntemp, ntot; float w; tVertex v; FILE *F; if(verts == NULL) return; ntot = NumVerts(verts); F = fopen(filename,"w"); if(F == NULL) { cart_error("Unable to open file %s for writing.\n",filename); } ntemp = sizeof(int); fwrite(&ntemp,sizeof(int),1,F); ntemp = ntot; fwrite(&ntemp,sizeof(int),1,F); ntemp = sizeof(int); fwrite(&ntemp,sizeof(int),1,F); ntemp = 6*sizeof(float); fwrite(&ntemp,sizeof(int),1,F); w = 0.0; fwrite(&w,sizeof(float),1,F); w = 0.0; fwrite(&w,sizeof(float),1,F); w = 0.0; fwrite(&w,sizeof(float),1,F); w = num_grid; fwrite(&w,sizeof(float),1,F); w = num_grid; fwrite(&w,sizeof(float),1,F); w = num_grid; fwrite(&w,sizeof(float),1,F); ntemp = 6*sizeof(float); fwrite(&ntemp,sizeof(int),1,F); for(j=0; j<3; j++) { ntemp = ntot*sizeof(float); fwrite(&ntemp,sizeof(int),1,F); v = verts; do { w = v->v[j] + 0.5; fwrite(&w,sizeof(float),1,F); v = v->next; } while(v != verts); fwrite(&ntemp,sizeof(int),1,F); } fclose(F); }
/** * Write the TIN to a Stanford Polygon File Format (PLY), * http://en.wikipedia.org/wiki/PLY_(file_format) */ bool vtTin::WritePLY(const char *fname, bool progress_callback(int)) const { FILE *fp = vtFileOpen(fname, "wb"); if (!fp) return false; int i, count = 0; int verts = NumVerts(); int tris = NumTris(); int total = verts + tris; fprintf(fp, "ply\n"); fprintf(fp, "format ascii 1.0\n"); fprintf(fp, "comment VTBuilder generated\n"); fprintf(fp, "element vertex %d\n", verts); fprintf(fp, "property float x\n"); fprintf(fp, "property float y\n"); fprintf(fp, "property float z\n"); fprintf(fp, "element face %d\n", tris); fprintf(fp, "property list uchar int vertex_indices\n"); fprintf(fp, "end_header\n"); // write verts for (i = 0; i < verts; i++) { fprintf(fp, "%lf %lf %f\n", m_vert[i].x, m_vert[i].y, m_z[i]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } // write tris for (i = 0; i < tris; i++) { // Here is triangle definition (zero based) A B C ... fprintf(fp, "3 %d %d %d\n", m_tri[i*3+0], m_tri[i*3+1], m_tri[i*3+2]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fclose(fp); return true; }
bool vtTin::ConvertProjection(const vtProjection &proj_new) { // Create conversion object ScopedOCTransform trans(CreateCoordTransform(&m_proj, &proj_new)); if (!trans) return false; // inconvertible projections int size = NumVerts(); for (int i = 0; i < size; i++) { DPoint2 &p = m_vert[i]; trans->Transform(1, &p.x, &p.y); } // adopt new projection m_proj = proj_new; return true; }
/** * Write the TIN to the GMS format. Historically GMS stood for 'Groundwater * Modeling System' from the EMS-I company, now called Aquaveo. */ bool vtTin::WriteGMS(const char *fname, bool progress_callback(int)) const { FILE *fp = vtFileOpen(fname, "wb"); if (!fp) return false; // first line is file identifier fprintf(fp, "TIN\n"); fprintf(fp, "BEGT\n"); fprintf(fp, "ID 1\n"); // Indices start at 1 //fprintf(fp, "TNAM tin\n"); // "name" of the TIN; optional //fprintf(fp, "MAT 1\n"); // "TIN material ID"; optional int count = 0; const int verts = NumVerts(); const int tris = NumTris(); const int total = verts + tris; // write verts fprintf(fp, "VERT %d\n", verts); for (int i = 0; i < verts; i++) { fprintf(fp, "%lf %lf %f\n", m_vert[i].x, m_vert[i].y, m_z[i]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } // write tris fprintf(fp, "TRI %d\n", tris); for (int i = 0; i < tris; i++) { // the indices in the file are 1-based, so add 1 fprintf(fp, "%d %d %d\n", m_tri[i*3+0]+1, m_tri[i*3+1]+1, m_tri[i*3+2]+1); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, "ENDT\n"); fclose(fp); return true; }
//determines if this polygon is concave or not bool CEditPoly::IsConcave() { uint32 nNumPts = NumVerts(); if(nNumPts <= 3) { return false; } //get the normal for this polygon LTVector vNormal = Normal(); //now go through every edge uint32 nPrevPt = nNumPts - 1; for(uint32 nCurrPt = 0; nCurrPt < nNumPts; nPrevPt = nCurrPt, nCurrPt++) { //build the edge normal LTVector vEdge = m_pBrush->m_Points[Index(nCurrPt)] - m_pBrush->m_Points[Index(nPrevPt)]; //find the normal LTVector vEdgeNorm = vNormal.Cross(vEdge); vEdgeNorm.Norm(); //now run through all the other points for(uint32 nTestPt = 0; nTestPt < nNumPts; nTestPt++) { //ignore the points on the edge if((nTestPt == nCurrPt) || (nTestPt == nPrevPt)) continue; //see if it is on the correct side if(vEdgeNorm.Dot(m_pBrush->m_Points[Index(nTestPt)] - m_pBrush->m_Points[Index(nCurrPt)]) > 0.001f) { return true; } } } return false; }
bool vtTin::ComputeExtents() { const int size = NumVerts(); if (size == 0) return false; m_EarthExtents.SetInsideOut(); m_fMinHeight = 1E9; m_fMaxHeight = -1E9; for (int j = 0; j < size; j++) { m_EarthExtents.GrowToContainPoint(m_vert[j]); float z = m_z[j]; if (z > m_fMaxHeight) m_fMaxHeight = z; if (z < m_fMinHeight) m_fMinHeight = z; } return true; }
bool CBasePoly::IsConvex() { CVector v1, v2, v3; CVector vec1, vec2; uint32 i; CDReal dot, sign=0.0f; for( i=0; i < NumVerts(); i++ ) { v1 = Pt(i); v2 = NextPt(i); v3 = NextPt(m_Indices.NextI(i) ); vec1 = v2 - v1; vec2 = v3 - v2; vec1.Norm(); vec2.Norm(); dot = Normal().Dot( vec1.Cross(vec2) ); if( (sign == 0.0f) && (dot != 0.0f) ) { sign = dot; } else { if( sign < 0.0f && dot > 0.0f ) return false; else if( sign > 0.0f && dot < 0.0f ) return false; } } return true; }
BOOL CEditPoly::IntersectRay( CEditRay &ray, CReal &t, BOOL bBackface ) { ASSERT(NumVerts() > 1); CReal dot1, dot2, div; LTVector testPt; // Trivial reject. if( (Normal().Dot(ray.m_Pos) - Dist()) >= 0.0f ) { // It's pointing away from (or is perpendicular to) the polygon. if( Normal().Dot(ray.m_Dir) >= -0.001f ) return FALSE; } else { // Backfacing. if( !bBackface ) { return FALSE; } else { // It's pointing away from (or is perpendicular to) the polygon. if( Normal().Dot(ray.m_Dir) <= 0.001f ) return FALSE; } } dot1 = Normal().Dot( ray.m_Pos ) - Dist(); dot2 = Normal().Dot( ray.m_Pos + ray.m_Dir ) - Dist(); div = dot2 - dot1; if(fabs(div) < 0.00001f) t = 0.0f; else t = -dot1 / div; ASSERT( t >= 0 ); testPt = ray.m_Pos + (ray.m_Dir * t); // See if the intersection point lies inside the poly. uint32 nFanPt = NumVerts() - 1; uint32 nPrevPt = 0; uint32 nCurrPt = 1; //the count of the number of triangles it is in uint32 nInCount = 0; for(; nCurrPt < NumVerts(); nPrevPt = nCurrPt, nCurrPt++) { //see if it the point is within the triangle defined by //the edges fanpt->prev, fanpt->curr if( (g_TriArea2( Normal(), Pt(nFanPt), Pt(nPrevPt), testPt ) > 0) || (g_TriArea2( Normal(), Pt(nPrevPt), Pt(nCurrPt), testPt ) > 0) || (g_TriArea2( Normal(), Pt(nCurrPt), Pt(nFanPt), testPt ) > 0)) continue; //we are in this tri nInCount++; } return (nInCount % 2) ? TRUE : FALSE; }
/** * Write the TIN to a AutoCAD DXF file using 3DFACE entities. */ bool vtTin::WriteDXF(const char *fname, bool progress_callback(int)) const { FILE *fp = vtFileOpen(fname, "wb"); if (!fp) return false; // Header fprintf(fp, " 0\nSECTION\n"); fprintf(fp, " 2\nHEADER\n 9\n$ACADVER\n 1\nAC1006\n"); fprintf(fp, " 9\n$EXTMIN\n"); fprintf(fp, " 10\n%lf\n", m_EarthExtents.left); fprintf(fp, " 20\n%lf\n", m_EarthExtents.bottom); fprintf(fp, " 9\n$EXTMAX\n"); fprintf(fp, " 10\n%lf\n", m_EarthExtents.right); fprintf(fp, " 20\n%lf\n", m_EarthExtents.top); fprintf(fp, " 0\nENDSEC\n"); // Tables section fprintf(fp, " 0\nSECTION\n"); fprintf(fp, " 2\nTABLES\n"); // ------------------------------------ // Table of Layers fprintf(fp, " 0\nTABLE\n"); fprintf(fp, " 2\nLAYER\n"); fprintf(fp, " 70\n1\n"); // max number of layers which follow // A layer fprintf(fp, " 0\nLAYER\n"); fprintf(fp, " 2\nPEN1\n"); // layer name fprintf(fp, " 70\n0\n"); // layer flags fprintf(fp, " 62\n3\n"); // color number 3 = green fprintf(fp, " 6\nCONTINUOUS\n"); // linetype name // end tables layer fprintf(fp, " 0\nENDTAB\n"); // ------------------------------------ // end tables section fprintf(fp, " 0\nENDSEC\n"); // Entities fprintf(fp, " 0\nSECTION\n"); fprintf(fp, " 2\nENTITIES\n"); // write tris int i, count = 0; int verts = NumVerts(); int tris = NumTris(); int total = verts + tris; const char *layer = "PEN1"; for (i = 0; i < tris; i++) { const int v0 = m_tri[i*3+0]; const int v1 = m_tri[i*3+1]; const int v2 = m_tri[i*3+2]; fprintf(fp, " 0\n3DFACE\n"); fprintf(fp, " 8\n%s\n", layer); fprintf(fp, " 62\n 3\n"); // color number fprintf(fp, " 10\n%lf\n", m_vert[v0].x); fprintf(fp, " 20\n%lf\n", m_vert[v0].y); fprintf(fp, " 30\n%f\n", m_z[v0]); fprintf(fp, " 11\n%lf\n", m_vert[v1].x); fprintf(fp, " 21\n%lf\n", m_vert[v1].y); fprintf(fp, " 31\n%f\n", m_z[v1]); fprintf(fp, " 12\n%lf\n", m_vert[v2].x); fprintf(fp, " 22\n%lf\n", m_vert[v2].y); fprintf(fp, " 32\n%f\n", m_z[v2]); // DXF wants the last point duplicated to make 4 points. fprintf(fp, " 13\n%lf\n", m_vert[v2].x); fprintf(fp, " 23\n%lf\n", m_vert[v2].y); fprintf(fp, " 33\n%f\n", m_z[v2]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, " 0\nENDSEC\n"); fprintf(fp, " 0\nEOF\n"); fclose(fp); return true; }
void chMakeHull(float tolnum, float tolvol, int numits, int loud) { int i, j, n, it; tVertex fverts, v, v0, vmin; tEdge fedges; tFace ffaces; int *pts, npts, nout; float w, w0, wmin; if(tolnum<0.0 || tolnum>=1.0) { cart_error("<tolnum> parameter in chMakeSubHull must be non-negative and strictly less than 1."); } if(tolvol<=0.0 || tolvol>=1.0) { cart_error("<tolvol> parameter in chMakeSubHull must be positive and strictly less than 1."); } if(numits < 1) { cart_error("<numits> parameter in chMakeSubHull must be positive."); } /* // Number of points we are allowed to miss. */ npts = NumVerts(vertices); nout = tolnum*npts; if(nout < 1) { /* // Tolerance is too small */ chMakeFullHull(); return; } if(loud > 1) DumpVerts2IFrIT("tmp1.bin",vertices); /* // Save the original points. */ pts = (int *)malloc(npts*sizeof(int)*3); if(pts == NULL) { cart_error("Unable to allocate %d bytes of memory in chMakeSubHull.",npts*sizeof(int)*3); } i = 0; v = vertices; do { for(j=0; j<3; j++) pts[3*i+j] = v->v[j]; i++; v = v->next; } while(v != vertices); /* // Make the full hull and save it. */ if(loud) cart_debug("Creating the full hull..."); chMakeFullHull(); fverts = vertices; fedges = edges; ffaces = faces; if(loud > 1) DumpVerts2IFrIT("tmp2.bin",vertices); /* // Loop while the stopping criterion is not met. */ for(it=0; it<numits; it++) { /* // For each vertex of the full hull remove it, redo the hull, and // check its volume; keep the hull that reduces the volume most. */ w0 = chHullVolume(); if(loud) cart_debug("Hull volume: %g %d",w0,NumVerts(vertices)); wmin = w0; vmin = NULL; v0 = fverts; do { MakeOneSubHull(v0,fverts,fedges,ffaces); w = chHullVolume(); if(w < wmin) { if(loud) cart_debug("Found sub-hull with volume: %g",w); wmin = w; vmin = v0; } /* // Remove that hull. */ chReset(); v0 = v0->next; } while(v0 != fverts); if(0) { /* // Redo the best hull */ MakeOneSubHull(vmin,fverts,fedges,ffaces); n = 0; } else { /* // Redo the full hull, but without one point */ for(i=0; i<npts; i++) { if(pts[3*i+0]==vmin->v[0] && pts[3*i+1]==vmin->v[1] && pts[3*i+2]==vmin->v[2]) break; } for(; i<npts-1; i++) { for(j=0; j<3; j++) pts[3*i+j] = pts[3*(i+1)+j]; } npts--; chAddPoints(npts,pts); chMakeFullHull(); wmin = chHullVolume(); n = 1; } if(loud) cart_debug("New hull volume: %g %d",wmin,NumVerts(vertices)); /* // Count the points outside. */ for(i=0; i<npts; i++) { if(chIsPointInside(pts+3*i) == 0) n++; } if(loud) cart_debug("Missing points: %d (allowed %d), volume reduction %f",n,nout,wmin/w0); /* // Is reduction worth the effort? // Do we miss too many points? */ if(wmin>(1-tolvol)*w0 || n>nout) break; if(loud) cart_debug("chMakeSubHull: squeezing the hull..."); while(fverts != NULL) DELETE(fverts,fverts); while(fedges != NULL) DELETE(fedges,fedges); while(ffaces != NULL) DELETE(ffaces,ffaces); fverts = vertices; fedges = edges; ffaces = faces; nout -= n; } /* // Restore data structures */ vertices = fverts; edges = fedges; faces = ffaces; free(pts); if(loud > 1) DumpVerts2IFrIT("tmp3.bin",vertices); }
/** * Combine all vertices which are at the same location. By removing these * redundant vertices, the mesh will consume less space in memory and on disk. */ void vtTin::MergeSharedVerts(bool progress_callback(int)) { uint verts = NumVerts(); uint i, j; int bin; DRECT rect = m_EarthExtents; double width = rect.Width(); // make it slightly larger avoid edge condition rect.left -= 0.000001; width += 0.000002; m_bReplace = new int[verts]; m_vertbin = new Bin[BINS]; m_tribin = new Bin[BINS]; // sort the vertices into bins for (i = 0; i < verts; i++) { // flag all vertices initially not to remove m_bReplace[i] = -1; // find the correct bin, and add the index of this vertex to it bin = (int) (BINS * (m_vert[i].x - rect.left) / width); m_vertbin[bin].push_back(i); } uint trisize = m_tri.size(); for (i = 0; i < trisize; i++) { // find the correct bin, and add the index of this index to it bin = (int) (BINS * (m_vert[m_tri[i]].x - rect.left) / width); m_tribin[bin].push_back(i); } // compare within each bin, and between each adjacent bin, // looking for matching vertices to flag for removal for (bin = 0; bin < BINS; bin++) { if (progress_callback != NULL) progress_callback(bin * 100 / BINS); _CompareBins(bin, bin); if (bin < BINS-1) _CompareBins(bin, bin+1); } // now update each triangle index to point to the merge result for (bin = 0; bin < BINS; bin++) { if (progress_callback != NULL) progress_callback(bin * 100 / BINS); _UpdateIndicesInInBin(bin); } // now compact the vertex bins into a single array // make a copy to copy from DLine2 *vertcopy = new DLine2(m_vert); float *zcopy = new float[m_z.size()]; for (i = 0; i < m_z.size(); i++) zcopy[i] = m_z[i]; int inew = 0; // index into brand new array (actually re-using old) for (bin = 0; bin < BINS; bin++) { if (progress_callback != NULL) progress_callback(bin * 100 / BINS); uint binverts = m_vertbin[bin].size(); for (i = 0; i < binverts; i++) { int v_old = m_vertbin[bin].at(i); if (m_bReplace[v_old] != -1) continue; int v_new = inew; // copy old to new m_vert[v_new] = vertcopy->GetAt(v_old); m_z[v_new] = zcopy[v_old]; uint bintris = m_tribin[bin].size(); for (j = 0; j < bintris; j++) { int trindx = m_tribin[bin].at(j); if (m_tri[trindx] == v_old) m_tri[trindx] = v_new; } inew++; } } // our original array containers now hold the compacted result int newsize = inew; m_vert.SetSize(newsize); m_z.resize(newsize); // free up all the stuff we allocated delete [] m_bReplace; delete [] m_vertbin; delete [] m_tribin; delete vertcopy; delete [] zcopy; }
/** * Write the TIN to a VRML (.wrl) file as an IndexedFaceSet. Note that we * write X and Y as geographic coordinates, but VRML only supports * single-precision floating point values, so it may lose some precision. */ bool vtTin::WriteWRL(const char *fname, bool progress_callback(int)) const { FILE *fp = vtFileOpen(fname, "wb"); if (!fp) return false; fprintf(fp, "#VRML V2.0 utf8\n"); fprintf(fp, "\n"); fprintf(fp, "WorldInfo\n"); fprintf(fp, " {\n"); fprintf(fp, " info\n"); fprintf(fp, " [\n"); fprintf(fp, " \"Generated by VTBuilder\"\n"); fprintf(fp, " ]\n"); fprintf(fp, " title \"TIN VRML Model\"\n"); fprintf(fp, " }\n"); fprintf(fp, "\n"); fprintf(fp, "# TIN---------\n"); fprintf(fp, "Transform\n"); fprintf(fp, " {\n"); fprintf(fp, " children\n"); fprintf(fp, " [\n"); fprintf(fp, " Shape\n"); fprintf(fp, " {\n"); fprintf(fp, " appearance Appearance\n"); fprintf(fp, " {\n"); fprintf(fp, " material Material\n"); fprintf(fp, " {\n"); fprintf(fp, " }\n"); fprintf(fp, " texture ImageTexture\n"); fprintf(fp, " {\n"); fprintf(fp, " url\n"); fprintf(fp, " [\n"); fprintf(fp, " \"OrtoImage.jpg\"\n"); fprintf(fp, " ]\n"); fprintf(fp, " }\n"); fprintf(fp, " }\n"); fprintf(fp, " geometry IndexedFaceSet {\n"); fprintf(fp, " ccw FALSE\n"); fprintf(fp, " solid FALSE\n"); fprintf(fp, " creaseAngle 1.396263\n"); fprintf(fp, "coord DEF Kxzy Coordinate {\n"); fprintf(fp, " point [\n"); int i, count = 0; const int verts = NumVerts(); const int tris = NumTris(); const int total = verts + tris; // write verts // fprintf(fp, "VERT %d\n", verts); for (i = 0; i < verts; i++) { fprintf(fp, "%lf %lf %f\n", m_vert[i].x, m_vert[i].y, m_z[i]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, " ]\n"); fprintf(fp, " }\n"); fprintf(fp, " coordIndex \n"); fprintf(fp, " [\n"); // write tris for (i = 0; i < tris; i++) { // Here is triangle definition (zero based) A B C -1... // the indices in the file are 1-based, so add 1 fprintf(fp, "%d %d %d -1\n", m_tri[i*3+0], m_tri[i*3+1], m_tri[i*3+2]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, " ]\n"); fprintf(fp, " }\n"); fprintf(fp, " }\n"); fprintf(fp, " ]\n"); fprintf(fp, " }\n"); fclose(fp); return true; }
/** * Write the TIN to a Collada (.dae) file. Note that we write X and Y as * geographic coordinates, but DAE only supports single-precision floating * point values, so it may lose some precision. */ bool vtTin::WriteDAE(const char *fname, bool progress_callback(int)) const { FILE *fp = vtFileOpen(fname, "wb"); if (!fp) return false; // first line is file identifier fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"); fprintf(fp, "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n"); fprintf(fp, " <asset>\n"); fprintf(fp, " <contributor>\n"); fprintf(fp, " <authoring_tool>VTBuilder</authoring_tool>\n"); fprintf(fp, " </contributor>\n"); // fprintf(fp, " <created>2012-01-09T14:26:45Z</created>\n"); // fprintf(fp, " <modified>2012-01-09T14:26:45Z</modified>\n"); // fprintf(fp, " <unit meter=\"0.02539999969303608\" name=\"inch\" />\n"); fprintf(fp, " <up_axis>Z_UP</up_axis>\n"); fprintf(fp, " </asset>\n"); fprintf(fp, " <library_visual_scenes>\n"); fprintf(fp, " <visual_scene id=\"ID1\">\n"); fprintf(fp, " <node name=\"VTBuilder\">\n"); fprintf(fp, " <node id=\"ID2\" name=\"Earth_Terrain\">\n"); fprintf(fp, " <matrix>1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>\n"); fprintf(fp, " <instance_geometry url=\"#ID3\">\n"); fprintf(fp, " <bind_material>\n"); fprintf(fp, " <technique_common>\n"); fprintf(fp, " <instance_material symbol=\"Material2\" target=\"#ID4\">\n"); fprintf(fp, " <bind_vertex_input semantic=\"UVSET0\" input_semantic=\"TEXCOORD\" input_set=\"0\" />\n"); fprintf(fp, " </instance_material>\n"); fprintf(fp, " </technique_common>\n"); fprintf(fp, " </bind_material>\n"); fprintf(fp, " </instance_geometry>\n"); fprintf(fp, " </node>\n"); fprintf(fp, " </node>\n"); fprintf(fp, " </visual_scene>\n"); fprintf(fp, " </library_visual_scenes>\n"); fprintf(fp, " <library_geometries>\n"); fprintf(fp, " <geometry id=\"ID3\">\n"); fprintf(fp, " <mesh>\n"); fprintf(fp, " <source id=\"ID6\">\n"); int count = 0; const int verts = NumVerts(); const int tris = NumTris(); const int total = verts + tris; // Here are: Count and Coordinates X Y Z... fprintf(fp, " <float_array id=\"ID10\" count=\"%d\">\n",verts); // write verts for (int i = 0; i < verts; i++) { fprintf(fp, "%lf %lf %f\n", m_vert[i].x, m_vert[i].y, m_z[i]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, " </float_array>\n"); fprintf(fp, " <technique_common>\n"); fprintf(fp, " <accessor count=\"222\" source=\"#ID10\" stride=\"3\">\n"); fprintf(fp, " <param name=\"X\" type=\"float\" />\n"); fprintf(fp, " <param name=\"Y\" type=\"float\" />\n"); fprintf(fp, " <param name=\"Z\" type=\"float\" />\n"); fprintf(fp, " </accessor>\n"); fprintf(fp, " </technique_common>\n"); fprintf(fp, " </source>\n"); fprintf(fp, "\n"); fprintf(fp, " <source id=\"ID8\">\n"); fprintf(fp, " <Name_array id=\"ID12\" count=\"0\" />\n"); fprintf(fp, " <technique_common>\n"); fprintf(fp, " <accessor count=\"0\" source=\"#ID12\" stride=\"1\">\n"); fprintf(fp, " <param name=\"skp_material\" type=\"Name\" />\n"); fprintf(fp, " </accessor>\n"); fprintf(fp, " </technique_common>\n"); fprintf(fp, " </source>\n"); fprintf(fp, " <vertices id=\"ID9\">\n"); fprintf(fp, " <input semantic=\"POSITION\" source=\"#ID6\" />\n"); fprintf(fp, " <input semantic=\"NORMAL\" source=\"#ID7\" />\n"); fprintf(fp, " </vertices>\n"); // Here is triangles Count fprintf(fp, " <triangles count=\"%d\" material=\"Material2\">\n", tris); fprintf(fp, " <input offset=\"0\" semantic=\"VERTEX\" source=\"#ID9\" />\n"); fprintf(fp, " <p>\n"); // write tris // fprintf(fp, "TRI %d\n", tris); for (int i = 0; i < tris; i++) { // Here is triangle definition (zero based) A B C ... // the indices in the file are 1-based, so add 1 fprintf(fp, "%d %d %d\n", m_tri[i*3+0], m_tri[i*3+1], m_tri[i*3+2]); if (progress_callback && (++count % 200) == 0) progress_callback(count * 99 / total); } fprintf(fp, "</p>\n"); fprintf(fp, " </triangles>\n"); fprintf(fp, " </mesh>\n"); fprintf(fp, " </geometry>\n"); fprintf(fp, " </library_geometries>\n"); fprintf(fp, " <library_materials>\n"); fprintf(fp, " <material id=\"ID4\" name=\"Google_Earth_Snapshot\">\n"); fprintf(fp, " <instance_effect url=\"#ID5\" />\n"); fprintf(fp, " </material>\n"); fprintf(fp, " </library_materials>\n"); fprintf(fp, " <library_effects>\n"); fprintf(fp, " <effect id=\"ID5\">\n"); fprintf(fp, " <profile_COMMON>\n"); fprintf(fp, " <technique sid=\"COMMON\">\n"); fprintf(fp, " <lambert>\n"); fprintf(fp, " <diffuse>\n"); // Here is the color definition of the surface fprintf(fp, " <color>0.3411764705882353 0.392156862745098 0.3411764705882353 1</color>\n"); fprintf(fp, " </diffuse>\n"); fprintf(fp, " </lambert>\n"); fprintf(fp, " </technique>\n"); fprintf(fp, " </profile_COMMON>\n"); fprintf(fp, " </effect>\n"); fprintf(fp, " </library_effects>\n"); fprintf(fp, " <scene>\n"); fprintf(fp, " <instance_visual_scene url=\"#ID1\" />\n"); fprintf(fp, " </scene>\n"); fprintf(fp, "</COLLADA>\n"); fclose(fp); return true; }