void Test2( void ) { int i, j, k; int v1, v2; int tri; for ( i = 0; i < vertexnum; i++ ) { tri = 0; for ( j = 0; j < verts[i].edgenum; j++ ) { v1 = verts[i].edges[j]; #if 0 fprintf( handle, "%f %f %f\n", vertices[i][0]/SCL, vertices[i][1]/SCL, vertices[i][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v1][0]/SCL, vertices[v1][1]/SCL, vertices[v1][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v1][0]/SCL, vertices[v1][1]/SCL, vertices[v1][2]/SCL ); fprintf( handle, "\n" ); #else for ( k = 0; k < verts[i].edgenum; k++ ) { if ( j == k ) continue; v2 = verts[i].edges[k]; if ( TestEdge( v1, v2 ) || TestEdge( v2, v1 ) ) { if ( TestTri( i, v1, v2 ) || TestTri( v1, i, v2 ) || TestTri( v2, i, v1 ) ) continue; AddTri( i, v1, v2 ); AddTri( v1, i, v2 ); AddTri( v2, i, v1 ); #if 0 fprintf( handle, "%f %f %f\n", vertices[i][0]/SCL, vertices[i][1]/SCL, vertices[i][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v1][0]/SCL, vertices[v1][1]/SCL, vertices[v1][2]/SCL ); fprintf( handle, "%f %f %f\n", vertices[v2][0]/SCL, vertices[v2][1]/SCL, vertices[v2][2]/SCL ); #else fprintf( handle, "%d %d %d\n", i, v1, v2 ); #endif fprintf( handle, "\n" ); tri++; } } #endif } printf( "v%d: %d tris\n", i, tri ); } }
bool vtTin::_ReadTinBody(FILE *fp, bool progress_callback(int)) { fseek(fp, m_file_data_start, SEEK_SET); // pre-allocate for efficiency m_vert.SetMaxSize(m_file_verts); m_tri.reserve(m_file_tris * 3); // read verts DPoint2 p; float z; for (int i = 0; i < m_file_verts; i++) { if (progress_callback != NULL && (i % 1024) == 0) progress_callback(i * 49 / m_file_verts); fread(&p.x, 8, 2, fp); // 2 doubles fread(&z, 4, 1, fp); // 1 float AddVert(p, z); } // read tris int tribuf[3]; for (int i = 0; i < m_file_tris; i++) { if (progress_callback != NULL && (i % 1024) == 0) progress_callback(50 + i * 49 / m_file_tris); fread(tribuf, 4, 3, fp); // 3 ints AddTri(tribuf[0], tribuf[1], tribuf[2]); } return true; }
/** 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(); }
//********************* // ASCII //****************** void ModelLoader::ReadASCIIObj(const tstring& assetName) { ifstream stream; stream.open(assetName.c_str()); if (stream.fail()) { wcout << "File open fail: '" << assetName << "'\n"; return; } string line; vector<vector<int>> faceData; for (int i = 0; i < 3; ++i) { faceData.push_back(vector<int>(3)); } while (stream.eof() == false) { getline(stream, line); if (line.find("vn", 0) == 0) { Vector3 v; sscanf_s(line.c_str(), "vn %f %f %f", &v.X, &v.Y, &v.Z); AddNormal(v); } else if (line.find("vt", 0) == 0) { Vector2 v; sscanf_s(line.c_str(), "vt %f %f ", &v.X, &v.Y); AddTexCoord(v); } else if (line.find("f", 0) == 0) { sscanf_s(line.c_str(), "f %d/%d/%d %d/%d/%d %d/%d/%d", &faceData[0][0], &faceData[0][1], &faceData[0][2], &faceData[1][0], &faceData[1][1], &faceData[1][2], &faceData[2][0], &faceData[2][1], &faceData[2][2]); AddTri(faceData); } else if (line.find("g", 0) == 0) { wchar_t s[40]; sscanf_s(line.c_str(), "g %s40", s, _countof(s)); AddMesh(s); } else if (line.find("v", 0) == 0) //v is 0'd char { Vector3 v; sscanf_s(line.c_str(), "v %f %f %f", &v.X, &v.Y, &v.Z); AddVertex(v); } } FlushMesh(); //apply last mesh stream.close(); }
/** * Attempt to read TIN data from a DXF file. */ bool vtTin::ReadDXF(const char *fname, bool progress_callback(int)) { VTLOG("vtTin::ReadDXF():\n"); std::vector<DxfEntity> entities; std::vector<DxfLayer> layers; DxfParser parser(fname, entities, layers); bool bSuccess = parser.RetrieveEntities(progress_callback); if (!bSuccess) { VTLOG(parser.GetLastError()); return false; } int vtx = 0; int found = 0; for (uint i = 0; i < entities.size(); i++) { const DxfEntity &ent = entities[i]; if (ent.m_iType == DET_3DFace || ent.m_iType == DET_Polygon) { int NumVerts = ent.m_points.size(); if (NumVerts == 3) { for (int j = 0; j < 3; j++) { DPoint2 p(ent.m_points[j].x, ent.m_points[j].y); float z = (float) ent.m_points[j].z; AddVert(p, z); } AddTri(vtx, vtx+1, vtx+2); vtx += 3; found ++; } } } VTLOG(" Found %d triangle entities, of type 3DFace or Polygon.\n", found); // If we didn't find any surfaces, we haven't got a TIN if (found == 0) return false; // Test each triangle for clockwisdom, fix if needed CleanupClockwisdom(); ComputeExtents(); return true; }
bool vtTin::_ReadTinOld(FILE *fp) { int i, num; FPoint3 f; DPoint2 p; fread(&num, 1, sizeof(int), fp); m_vert.SetMaxSize(num); for (i = 0; i < num; i++) { fread(&f.x, 3, sizeof(float), fp); p.Set(f.x, f.y); AddVert(p, f.z); } for (i = 0; i < num/3; i++) { AddTri(i*3, i*3+1, i*3+2); } return true; }
bool vtTin::ReadPLY(const char *fname, bool progress_callback(int)) { FILE *fp = vtFileOpen(fname, "rb"); if (!fp) return false; VTLOG("ReadPLY '%s'\n", fname); char buf[256]; int material_id; int num_points; int num_faces; // first line is file identifier if (fgets(buf, 256, fp) == NULL) return false; if (strncmp(buf, "ply", 3) != 0) return false; while (fgets(buf, 256, fp) != NULL) { // trim trailing EOL characters vtString vstr = buf; vstr.Remove('\r'); vstr.Remove('\n'); const char *str = (const char *)vstr; if (!strncmp(str, "format", 6)) // beginning of TIN block continue; if (!strncmp(str, "ID", 2)) // material ID { sscanf(str, "ID %d", &material_id); } else if (!strncmp(str, "MAT", 3)) // material ID { sscanf(str, "MAT %d", &material_id); } else if (!strncmp(str, "TCOL", 4)) // material ID { sscanf(str, "TCOL %d", &material_id); } else if (!strncmp(str, "element vertex", 14)) // Number of vertices { sscanf(buf, "element vertex %d\n", &num_points); } else if (!strncmp(str, "element face", 12)) // Number of triangles { sscanf(buf, "element face %d\n", &num_faces); } else if (!strncmp(str, "end_header", 10)) { DPoint2 p; float z; int optional; VTLOG("ReadPLY num_points %d\n", num_points); for (int i = 0; i < num_points; i++) { if (fgets(buf, 256, fp) == NULL) break; // First three are X, Y, Z. Optional fourth is "ID" or "locked". sscanf(buf, "%lf %lf %f %d", &p.x, &p.y, &z, &optional); #if 0 // Some files have Y/-Z flipped (but they are non-standard) double temp = p.y; p.y = -z; z = temp; #endif AddVert(p, z); if ((i%200) == 0 && progress_callback != NULL) { if (progress_callback(i * 49 / num_points)) { fclose(fp); return false; // user cancelled } } } // Then read the triangles VTLOG("ReadPLY num_faces %d\n", num_faces); int inu, a, b, c; for (int i = 0; i < num_faces; i++) { if (fgets(buf, 256, fp) == NULL) break; sscanf(buf, "%d %d %d %d\n", &inu, &a, &b, &c); AddTri(a, b, c); if ((i%200) == 0 && progress_callback != NULL) { if (progress_callback(49 + i * 50 / num_faces)) { fclose(fp); return false; // user cancelled } } } } } fclose(fp); ComputeExtents(); return true; }
/** * Write the TIN to the Aquaveo GMS format. */ bool vtTin::ReadGMS(const char *fname, bool progress_callback(int)) { FILE *fp = vtFileOpen(fname, "rb"); if (!fp) return false; char buf[256]; vtString tin_name; int material_id; int num_points; // first line is file identifier if (fgets(buf, 256, fp) == NULL) return false; if (strncmp(buf, "TIN", 3) != 0) return false; while (1) { if (fgets(buf, 256, fp) == NULL) break; // trim trailing EOL characters vtString vstr = buf; vstr.Remove('\r'); vstr.Remove('\n'); const char *str = (const char *)vstr; if (!strncmp(str, "BEGT", 4)) // beginning of TIN block continue; if (!strncmp(str, "ID", 2)) // material ID { sscanf(str, "ID %d", &material_id); } else if (!strncmp(str, "MAT", 3)) // material ID { sscanf(str, "MAT %d", &material_id); } else if (!strncmp(str, "TCOL", 4)) // material ID { sscanf(str, "TCOL %d", &material_id); } else if (!strncmp(str, "TNAM", 4)) // TIN name { tin_name = str + 5; } else if (!strncmp(str, "VERT", 4)) // Beginning of vertices { sscanf(buf, "VERT %d\n", &num_points); DPoint2 p; float z; int optional; for (int i = 0; i < num_points; i++) { if (fgets(buf, 256, fp) == NULL) break; // First three are X, Y, Z. Optional fourth is "ID" or "locked". sscanf(buf, "%lf %lf %f %d", &p.x, &p.y, &z, &optional); #if 0 // Some files have Y/-Z flipped (but they are non-standard) double temp = p.y; p.y = -z; z = temp; #endif AddVert(p, z); if ((i%200) == 0 && progress_callback != NULL) { if (progress_callback(i * 49 / num_points)) { fclose(fp); return false; // user cancelled } } } } else if (!strncmp(str, "TRI", 3)) // Beginning of triangles { int num_faces; sscanf(str, "TRI %d\n", &num_faces); int v[3]; for (int i = 0; i < num_faces; i++) { fscanf(fp, "%d %d %d\n", v, v+2, v+1); // the indices in the file are 1-based, so subtract 1 AddTri(v[0]-1, v[1]-1, v[2]-1); if ((i%200) == 0 && progress_callback != NULL) { if (progress_callback(49 + i * 50 / num_faces)) { fclose(fp); return false; // user cancelled } } } } } fclose(fp); ComputeExtents(); return true; }
bool vtTin::ReadADF(const char *fname, bool progress_callback(int)) { const vtString tnxy_name = fname; if (tnxy_name.Right(6) != "xy.adf") return false; vtString base = tnxy_name.Left(tnxy_name.GetLength()-6); vtString tnz_name = base + "z.adf"; vtString tnod_name = base + "od.adf"; FILE *fp1 = vtFileOpen(tnxy_name, "rb"); FILE *fp2 = vtFileOpen(tnz_name, "rb"); FILE *fp3 = vtFileOpen(tnod_name, "rb"); if (!fp1 || !fp2 || !fp3) return false; fseek(fp1, 0, SEEK_END); const int length_xy = ftell(fp1); rewind(fp1); // go back again uint num_points = length_xy / 16; // X and Y, each 8 byte doubles fseek(fp2, 0, SEEK_END); const int length_z = ftell(fp2); rewind(fp2); // go back again uint num_heights = length_z / 4; // Z is a 4 byte float DPoint2 p; float z; for (uint i = 0; i < num_points; i++) { if ((i%200) == 0 && progress_callback != NULL) progress_callback(i * 40 / num_points); FRead(&p.x, DT_DOUBLE, 2, fp1, BO_BIG_ENDIAN, BO_LITTLE_ENDIAN); FRead(&z, DT_FLOAT, 1, fp2, BO_BIG_ENDIAN, BO_LITTLE_ENDIAN); AddVert(p, z); } fseek(fp3, 0, SEEK_END); const int length_od = ftell(fp3); rewind(fp3); // go back again const uint num_faces = length_od / 12; // A B C as 4-byte ints int v[3]; for (uint i = 0; i < num_faces; i++) { if ((i%200) == 0 && progress_callback != NULL) progress_callback(40 + i * 40 / num_faces); FRead(v, DT_INT, 3, fp3, BO_BIG_ENDIAN, BO_LITTLE_ENDIAN); AddTri(v[0]-1, v[1]-1, v[2]-1); } fclose(fp1); fclose(fp2); fclose(fp3); // Cleanup: the ESRI TIN contains four "boundary" point far outside the // extents (directly North, South, East, and West). We should ignore // those four points and the triangles connected to them. // It seems we can assume the four 'extra' vertices are the first four. m_vert.RemoveAt(0, 4); m_z.erase(m_z.begin(), m_z.begin() + 4); m_vert_normal.RemoveAt(0, 4); // Re-index the triangles uint total = m_tri.size()/3; for (uint i = 0; i < total; i++) { if ((i%200) == 0 && progress_callback != NULL) progress_callback(80 + i * 20 / total); // Remove any triangles which referenced this vertex if (m_tri[i*3 + 0] < 4 || m_tri[i*3 + 1] < 4 || m_tri[i*3 + 2] < 4) { m_tri.erase(m_tri.begin() + i*3, m_tri.begin() + i*3 + 3); i--; total--; continue; } } // For all other triangles, adjust the indices to reflect the removal for (uint i = 0; i < m_tri.size(); i++) m_tri[i] = m_tri[i] - 4; // Test each triangle for clockwisdom, fix if needed CleanupClockwisdom(); ComputeExtents(); return true; }