/** * Remove all the triangles of this TIN which intersect a given line segment. * * \param ep1, ep2 The endpoints of the line segment. * \return The number of triangles removed. */ int vtTin::RemoveTrianglesBySegment(const DPoint2 &ep1, const DPoint2 &ep2) { int count = 0; uint tris = NumTris(); for (uint i = 0; i < tris; i++) { // get 2D points const int v0 = m_tri[i*3]; const int v1 = m_tri[i*3+1]; const int v2 = m_tri[i*3+2]; const DPoint2 &p1 = m_vert[v0]; const DPoint2 &p2 = m_vert[v1]; const DPoint2 &p3 = m_vert[v2]; if (LineSegmentsIntersect(ep1, ep2, p1, p2) || LineSegmentsIntersect(ep1, ep2, p2, p3) || LineSegmentsIntersect(ep1, ep2, p3, p1)) { m_tri.erase(m_tri.begin() + i*3, m_tri.begin() + i*3 + 3); i--; tris--; count++; } } if (count > 0) { RemoveUnusedVertices(); ComputeExtents(); } return count; }
/** * 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; }
double vtTin::GetArea2D() { double area = 0.0; uint tris = NumTris(); for (uint i = 0; i < tris; i++) { const DPoint2 &p1 = m_vert[m_tri[i*3]]; const DPoint2 &p2 = m_vert[m_tri[i*3+1]]; const DPoint2 &p3 = m_vert[m_tri[i*3+2]]; area += AreaOfTriangle(p1, p2, p3); } return area; }
/** * 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; }
bool BEZIER::Collide(VERTEX origin, VERTEX direction, VERTEX &outtri) { int i; VERTEX curtri[3]; int retval = 0; float t, u, v; int x, y; for (i = 0; i < NumTris(COLLISION_DIVS) && !retval; i++) { GetTri(COLLISION_DIVS, i, curtri); retval = INTERSECT_FUNCTION(origin.v3(), direction.v3(), curtri[0].v3(), curtri[1].v3(), curtri[2].v3(), &t, &u, &v); if (retval) { if (i % 2 == 0) { u = 1.0 - u; v = 1.0 - v; } u = 1.0 - u; v = 1.0 - v; x = (i/2) % COLLISION_DIVS; y = (i/2) / COLLISION_DIVS; u += (float) x; v += (float) y; u = u / (float) COLLISION_DIVS; v = v / (float) COLLISION_DIVS; //u = 1.0 - u; //v = 1.0 - v; //cout << u << "," << v << endl; outtri = SurfCoord(u, v); return true; } } outtri = origin; return false; }
Triangle OgreMeshAsset::Tri(int submeshIndex, int triangleIndex) { if (subMeshTriangleCounts.size() == 0) CreateKdTree(); if (triangleIndex < 0 || NumTris(submeshIndex) < triangleIndex) { LogError("Invalid triangle index to call to OgreMeshAsset::Tri(submeshIndex=" + QString::number(submeshIndex) + ", triangleIndex=" + QString::number(triangleIndex) + "), the specified submesh has only " + NumTris(submeshIndex) + " triangles!"); return Triangle(); } // Shift to index in proper location of the submesh triangles array. for(int i = 0; i < submeshIndex; ++i) triangleIndex += subMeshTriangleCounts[i]; return meshData.Object(triangleIndex); }
/** * If you are going to do a large number of height-testing of this TIN * (with FindAltitudeOnEarth), call this method once first to set up a * series of indexing bins which greatly speed up testing. * * \param bins Number of bins per dimension, e.g. a value of 50 produces * 50*50=2500 bins. More bins produces faster height-testing with * the only tradeoff being a small amount of RAM per bin. * \param progress_callback If supplied, this function will be called back * with a value of 0 to 100 as the operation progresses. */ void vtTin::SetupTriangleBins(int bins, bool progress_callback(int)) { DRECT rect = m_EarthExtents; m_BinSize.x = rect.Width() / bins; m_BinSize.y = rect.Height() / bins; delete m_trianglebins; m_trianglebins = new BinArray(bins, bins); uint tris = NumTris(); for (uint i = 0; i < tris; i++) { if ((i%100)==0 && progress_callback) progress_callback(i * 100 / tris); // get 2D points const DPoint2 &p1 = m_vert[m_tri[i*3]]; const DPoint2 &p2 = m_vert[m_tri[i*3+1]]; const DPoint2 &p3 = m_vert[m_tri[i*3+2]]; // find the correct range of bins, and add the index of this index to it DPoint2 fminrange, fmaxrange; fminrange.x = std::min(std::min(p1.x, p2.x), p3.x); fmaxrange.x = std::max(std::max(p1.x, p2.x), p3.x); fminrange.y = std::min(std::min(p1.y, p2.y), p3.y); fmaxrange.y = std::max(std::max(p1.y, p2.y), p3.y); IPoint2 bin_start, bin_end; bin_start.x = (uint) ((fminrange.x-rect.left) / m_BinSize.x); bin_end.x = (uint) ((fmaxrange.x-rect.left) / m_BinSize.x); bin_start.y = (uint) ((fminrange.y-rect.bottom) / m_BinSize.y); bin_end.y = (uint) ((fmaxrange.y-rect.bottom) / m_BinSize.y); for (int j = bin_start.x; j <= bin_end.x; j++) { for (int k = bin_start.y; k <= bin_end.y; k++) { Bin *bin = m_trianglebins->GetBin(j, k); if (bin) bin->push_back(i); } } } }
/** * 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; }
/** * 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; }
double vtTin::GetArea3D() { double area = 0.0; uint tris = NumTris(); for (uint i = 0; i < tris; i++) { const int v0 = m_tri[i*3]; const int v1 = m_tri[i*3+1]; const int v2 = m_tri[i*3+2]; const DPoint2 &p1 = m_vert[v0]; const DPoint2 &p2 = m_vert[v1]; const DPoint2 &p3 = m_vert[v2]; DPoint3 dp1(p1.x, p1.y, m_z[v0]); DPoint3 dp2(p2.x, p2.y, m_z[v1]); DPoint3 dp3(p3.x, p3.y, m_z[v2]); area += AreaOfTriangle(dp1, dp2, dp3); } return area; }
/** * Return the length of the longest edge of a specific triangle. */ double vtTin::GetTriMaxEdgeLength(int iTri) const { const int tris = NumTris(); if (iTri < 0 || iTri >= tris) return 0.0; // get points const int v0 = m_tri[iTri*3]; const int v1 = m_tri[iTri*3+1]; const int v2 = m_tri[iTri*3+2]; const DPoint2 &p1 = m_vert[v0]; const DPoint2 &p2 = m_vert[v1]; const DPoint2 &p3 = m_vert[v2]; // check lengths double len1 = (p2 - p1).Length(); double len2 = (p3 - p2).Length(); double len3 = (p1 - p3).Length(); return len1 > len2 ? (len1 > len3 ? len1 : len3) : (len2 > len3 ? len2 : len3); }
/** * Test each triangle for clockwisdom, fix if needed. The result should * be a TIN with consistent vertex ordering, such that all face normals * point up rather than down, that is, counter-clockwise. */ void vtTin::CleanupClockwisdom() { int v0, v1, v2; uint tris = NumTris(); for (uint i = 0; i < tris; i++) { v0 = m_tri[i*3]; v1 = m_tri[i*3+1]; v2 = m_tri[i*3+2]; // get 2D points const DPoint2 &p1 = m_vert[v0]; const DPoint2 &p2 = m_vert[v1]; const DPoint2 &p3 = m_vert[v2]; // The so-called 2D cross product double cross2d = (p2-p1).Cross(p3-p1); if (cross2d < 0) { // flip m_tri[i*3+1] = v2; m_tri[i*3+2] = v1; } } }
bool vtTin::FindTriangleOnEarth(const DPoint2 &p, float &fAltitude, int &iTriangle, bool bTrue) const { uint tris = NumTris(); // If we have some triangle bins, they can be used for a much faster test if (m_trianglebins != NULL) { int col = (int) ((p.x - m_EarthExtents.left) / m_BinSize.x); int row = (int) ((p.y - m_EarthExtents.bottom) / m_BinSize.y); Bin *bin = m_trianglebins->GetBin(col, row); if (!bin) return false; for (uint i = 0; i < bin->size(); i++) { if (TestTriangle(bin->at(i), p, fAltitude)) { iTriangle = bin->at(i); return true; } } // If it was not in any of these bins, then it did not hit anything return false; } // If no bins, we do a naive slow search. for (uint i = 0; i < tris; i++) { if (TestTriangle(i, p, fAltitude)) { iTriangle = i; return true; } } return false; }
/** * 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; }
/** * 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; }