contrib/brl/bbas/imesh/imesh_fileio.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/imesh_fileio.cxx
00002 #include "imesh_fileio.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_fstream.h>
00007 #include <vcl_sstream.h>
00008 #include <vcl_limits.h>
00009 #include <vul/vul_file.h>
00010 #include <vgl/vgl_point_2d.h>
00011 
00012 
00013 //: Read a mesh from a file, determine type from extension
00014 bool imesh_read(const vcl_string& filename, imesh_mesh& mesh)
00015 {
00016   vcl_string ext = vul_file::extension(filename);
00017   if (ext == ".ply2")
00018     return imesh_read_ply2(filename,mesh);
00019   if (ext == ".ply")
00020     return imesh_read_ply(filename,mesh);
00021   else if (ext == ".obj")
00022     return imesh_read_obj(filename,mesh);
00023 
00024   return false;
00025 }
00026 
00027 
00028 //: Read a mesh from a PLY2 file
00029 bool imesh_read_ply2(const vcl_string& filename, imesh_mesh& mesh)
00030 {
00031   vcl_ifstream fh(filename.c_str());
00032   bool retval = imesh_read_ply2(fh,mesh);
00033   fh.close();
00034   return retval;
00035 }
00036 
00037 
00038 //: Read a mesh from a PLY2 stream
00039 bool imesh_read_ply2(vcl_istream& is, imesh_mesh& mesh)
00040 {
00041   unsigned int num_verts, num_faces;
00042   is >> num_verts >> num_faces;
00043   vcl_auto_ptr<imesh_vertex_array<3> > verts(new imesh_vertex_array<3>(num_verts));
00044   vcl_auto_ptr<imesh_face_array > faces(new imesh_face_array(num_faces));
00045   for (unsigned int v=0; v<num_verts; ++v) {
00046     imesh_vertex<3>& vert = (*verts)[v];
00047     is >> vert[0] >> vert[1] >> vert[2];
00048   }
00049   for (unsigned int f=0; f<num_faces; ++f) {
00050     vcl_vector<unsigned int>& face = (*faces)[f];
00051     unsigned int cnt;
00052     is >> cnt;
00053     face.resize(cnt,0);
00054     for (unsigned int v=0; v<cnt; ++v)
00055       is >> face[v];
00056   }
00057 
00058   mesh.set_vertices(vcl_auto_ptr<imesh_vertex_array_base>(verts));
00059   mesh.set_faces(vcl_auto_ptr<imesh_face_array_base>(faces));
00060   return true;
00061 }
00062 
00063 //: Read a mesh from a PLY2 file
00064 bool imesh_read_ply(const vcl_string& filename, imesh_mesh& mesh)
00065 {
00066   vcl_ifstream fh(filename.c_str());
00067   bool retval = imesh_read_ply(fh,mesh);
00068   fh.close();
00069   return retval;
00070 }
00071 
00072 
00073 //: Read a mesh from a PLY2 stream
00074 bool imesh_read_ply(vcl_istream& is, imesh_mesh& mesh)
00075 {
00076   unsigned int num_verts, num_faces;
00077   vcl_string str;
00078   is >> str;
00079   bool done=false;
00080   while (!done) {
00081     is >> str;
00082     if (str.compare("element")==0)  {
00083       is >> str;
00084       if (str.compare("vertex")==0) {
00085         is >> num_verts;
00086       }
00087       else if (str.compare("face")==0) {
00088         is >> num_faces;
00089       }
00090     }
00091     else if (str.compare("end_header")==0)  {
00092       done = true;
00093     }
00094   }
00095   vcl_auto_ptr<imesh_vertex_array<3> > verts(new imesh_vertex_array<3>(num_verts));
00096   vcl_auto_ptr<imesh_face_array > faces(new imesh_face_array(num_faces));
00097   for (unsigned int v=0; v<num_verts; ++v) {
00098     imesh_vertex<3>& vert = (*verts)[v];
00099     is >> vert[0] >> vert[1] >> vert[2];
00100   }
00101   for (unsigned int f=0; f<num_faces; ++f) {
00102     vcl_vector<unsigned int>& face = (*faces)[f];
00103     unsigned int cnt;
00104     is >> cnt;
00105     face.resize(cnt,0);
00106     for (unsigned int v=0; v<cnt; ++v)
00107       is >> face[v];
00108   }
00109 
00110   mesh.set_vertices(vcl_auto_ptr<imesh_vertex_array_base>(verts));
00111   mesh.set_faces(vcl_auto_ptr<imesh_face_array_base>(faces));
00112   return true;
00113 }
00114 
00115 //: Write a mesh to a PLY2 file
00116 void imesh_write_ply2(const vcl_string& filename, const imesh_mesh& mesh)
00117 {
00118   vcl_ofstream fh(filename.c_str());
00119   imesh_write_ply2(fh,mesh);
00120   fh.close();
00121 }
00122 
00123 
00124 //: Write a mesh to a PLY2 stream
00125 void imesh_write_ply2(vcl_ostream& os, const imesh_mesh& mesh)
00126 {
00127   os << mesh.num_verts() <<'\n'<< mesh.num_faces() <<'\n';
00128   const imesh_vertex_array_base& verts = mesh.vertices();
00129   for (unsigned int v=0; v<verts.size(); ++v) {
00130     os << verts(v,0) << ' '
00131        << verts(v,1) << ' '
00132        << verts(v,2) << '\n';
00133   }
00134 
00135   const imesh_face_array_base& faces = mesh.faces();
00136   for (unsigned int f=0; f<faces.size(); ++f) {
00137     os << faces.num_verts(f);
00138     for (unsigned int v=0; v<faces.num_verts(f); ++v)
00139       os << ' ' << faces(f,v);
00140     os << '\n';
00141   }
00142 }
00143 
00144 
00145 //: Read texture coordinates from a UV2 file
00146 bool imesh_read_uv2(const vcl_string& filename, imesh_mesh& mesh)
00147 {
00148    vcl_ifstream fh(filename.c_str());
00149    bool retval = imesh_read_uv2(fh,mesh);
00150    fh.close();
00151    return retval;
00152 }
00153 
00154 
00155 //: Read texture coordinates from a UV2 stream
00156 bool imesh_read_uv2(vcl_istream& is, imesh_mesh& mesh)
00157 {
00158    vcl_vector<vgl_point_2d<double> > uv;
00159    unsigned int num_verts, num_faces;
00160    is >> num_verts >> num_faces;
00161    if (num_verts != mesh.num_verts() && num_verts != mesh.num_edges()*2)
00162      return false;
00163 
00164    for (unsigned int i=0; i<num_verts; ++i) {
00165       double u,v;
00166       is >> u >> v;
00167       uv.push_back(vgl_point_2d<double>(u,v));
00168    }
00169    mesh.set_tex_coords(uv);
00170    return true;
00171 }
00172 
00173 
00174 //: Read a mesh from a wavefront OBJ file
00175 bool imesh_read_obj(const vcl_string& filename, imesh_mesh& mesh)
00176 {
00177   vcl_ifstream fh(filename.c_str());
00178   bool retval = imesh_read_obj(fh,mesh);
00179   fh.close();
00180   return retval;
00181 }
00182 
00183 
00184 //: Read a mesh from a wavefront OBJ stream
00185 bool imesh_read_obj(vcl_istream& is, imesh_mesh& mesh)
00186 {
00187   vcl_auto_ptr<imesh_vertex_array<3> > verts(new imesh_vertex_array<3>);
00188   vcl_auto_ptr<imesh_face_array> faces(new imesh_face_array);
00189   vcl_vector<vgl_vector_3d<double> > normals;
00190   vcl_vector<vgl_point_2d<double> > tex;
00191   vcl_string last_group = "ungrouped";
00192   char c;
00193   while (is >> c)
00194   {
00195     switch (c)
00196     {
00197       case 'v': // read a vertex
00198       {
00199         char c2 = (char)is.peek();
00200         switch (c2)
00201         {
00202           case 'n': // read a normal
00203           {
00204             is.ignore();
00205             double x,y,z;
00206             is >> x >> y >> z;
00207             normals.push_back(vgl_vector_3d<double>(x,y,z));
00208             break;
00209           }
00210           case 't': // read a texture coord
00211           {
00212             is.ignore();
00213             double x,y;
00214             is >> x >> y;
00215             is.ignore(256,'\n');
00216             tex.push_back(vgl_point_2d<double>(x,y));
00217             break;
00218           }
00219           default: // read a position
00220           {
00221             double x,y,z;
00222             is >> x >> y >> z;
00223             verts->push_back(imesh_vertex<3>(x,y,z));
00224             break;
00225           }
00226         }
00227         break;
00228       }
00229       case 'f':
00230       {
00231         vcl_string line;
00232         vcl_getline(is,line);
00233         vcl_vector<unsigned int> vi, ti, ni;
00234         unsigned int v;
00235         vcl_stringstream ss(line);
00236         while (ss >> v) {
00237           vi.push_back(v-1);
00238           if (ss.peek() == '/') {
00239             ss.ignore();
00240             if (ss.peek() != '/') {
00241               ss >> v;
00242               ti.push_back(v-1);
00243               if (ss.peek() == '/') {
00244                 ss.ignore();
00245                 if (ss.peek() >= '0' && ss.peek() <= '9') {
00246                   ss >> v;
00247                   ni.push_back(v-1);
00248                 }
00249                 else {
00250                   vcl_cerr << "improperly formed face line in OBJ: "<<line<<'\n';
00251                   return false;
00252                 }
00253               }
00254             }
00255             else {
00256               ss.ignore();
00257               if (ss.peek() >= '0' && ss.peek() <= '9') {
00258                 ss >> v;
00259                 ni.push_back(v-1);
00260               }
00261               else {
00262                 vcl_cerr << "improperly formed face line in OBJ: "<<line<<'\n';
00263                 return false;
00264               }
00265             }
00266           }
00267         }
00268         faces->push_back(vi);
00269         break;
00270       }
00271       case 'g':
00272       {
00273         faces->make_group(last_group);
00274         is.ignore();
00275         vcl_getline(is,last_group);
00276         break;
00277       }
00278       default:
00279         is.ignore(vcl_numeric_limits<vcl_streamsize>::max(),'\n');
00280         break;
00281     }
00282   }
00283 
00284   // make the last group
00285   if (faces->has_groups())
00286     faces->make_group(last_group);
00287 
00288   if (normals.size() == verts->size())
00289     verts->set_normals(normals);
00290 
00291   mesh.set_vertices(vcl_auto_ptr<imesh_vertex_array_base>(verts));
00292   mesh.set_faces(vcl_auto_ptr<imesh_face_array_base>(faces));
00293   mesh.set_tex_coords(tex);
00294 
00295   return true;
00296 }
00297 
00298 
00299 //: Write a mesh to a wavefront OBJ file
00300 void imesh_write_obj(const vcl_string& filename, const imesh_mesh& mesh)
00301 {
00302   vcl_ofstream fh(filename.c_str());
00303   imesh_write_obj(fh,mesh);
00304   fh.close();
00305 }
00306 
00307 
00308 //: Write a mesh to a wavefront OBJ stream
00309 // Rotated about X because Y is up in wavefront (not Z)
00310 void imesh_write_obj(vcl_ostream& os, const imesh_mesh& mesh)
00311 {
00312   const imesh_vertex_array_base& verts = mesh.vertices();
00313   for (unsigned int v=0; v<verts.size(); ++v) {
00314     os << "v "
00315        << verts(v,0) << ' '
00316        << verts(v,1) << ' '
00317        << verts(v,2) << '\n';
00318   }
00319 
00320   if (verts.has_normals()) {
00321     for (unsigned int n=0; n<verts.size(); ++n) {
00322       const vgl_vector_3d<double>& v = verts.normal(n);
00323       os << "vn "
00324          << v.x() << ' '
00325          << v.y() << ' '
00326          << v.z() << '\n';
00327     }
00328   }
00329 
00330   if (mesh.has_tex_coords()) {
00331     const vcl_vector<vgl_point_2d<double> >& tex = mesh.tex_coords();
00332     for (unsigned int t=0; t<tex.size(); ++t) {
00333       os << "vt " << tex[t].x() << ' ' << tex[t].y() << '\n';
00334     }
00335   }
00336 
00337   const imesh_face_array_base& faces = mesh.faces();
00338   const vcl_vector<vcl_pair<vcl_string,unsigned int> >& groups = faces.groups();
00339 
00340   bool write_extra = mesh.has_tex_coords() || verts.has_normals();
00341 
00342   if (!groups.empty())
00343     os << "g " << groups[0].first << '\n';
00344   unsigned int g=0;
00345   unsigned int e=0;
00346   for (unsigned int f=0; f<faces.size(); ++f)
00347   {
00348     while (g < groups.size() && groups[g].second <= f) {
00349       ++g;
00350       if (g < groups.size())
00351         os << "g " << groups[g].first << '\n';
00352       else {
00353         os << "g ungrouped\n";
00354       }
00355     }
00356     os << 'f';
00357     for (unsigned int v=0; v<faces.num_verts(f); ++v) {
00358       os << ' ' << faces(f,v)+1;
00359       if (write_extra) {
00360         os << '/';
00361         if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_CORNER) {
00362           os << ++e;
00363         }
00364         if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT)
00365           os << faces(f,v)+1;
00366         if (verts.has_normals())
00367           os << '/' << faces(f,v)+1;
00368       }
00369     }
00370     os << '\n';
00371   }
00372 }
00373 
00374 void imesh_write_kml(vcl_ostream& os, const imesh_mesh& mesh)
00375 {
00376   const imesh_face_array_base& faces = mesh.faces();
00377   const imesh_vertex_array_base& verts = mesh.vertices();
00378 
00379   if (faces.size() <= 1) {
00380       // single mesh face is probably ground plane, which we do not want to render
00381       return;
00382   }
00383 
00384   os.precision(12);
00385   for (unsigned int f=0; f<faces.size(); ++f)
00386   {
00387     // originally it was id=buildingX_faceY, but we have to pass a mesh number
00388     os << "      <Polygon id=\"building_face" << f << "\">\n"
00389        << "        <extrude>0</extrude>\n"
00390        << "        <tessellate>0</tessellate>\n"
00391        << "        <altitudeMode>absolute</altitudeMode>\n"
00392        << "        <outerBoundaryIs>\n"
00393        << "          <LinearRing>\n"
00394        << "            <coordinates>" << vcl_endl;
00395 
00396     for (unsigned int v=0; v<faces.num_verts(f); ++v) {
00397       unsigned int idx = faces(f,v);
00398       double x = verts(idx, 0);
00399       double y = verts(idx, 1);
00400       double z = verts(idx, 2);
00401       os << "             " << x  << ", " << y << ", " << z << vcl_endl;
00402     }
00403 
00404     //Now print the first vertex again to close the polygon
00405     unsigned int idx = faces(f,0);
00406     double x = verts(idx, 0);
00407     double y = verts(idx, 1);
00408     double z = verts(idx, 2);
00409     os << "             " << x  << ", " << y << ", " << z << vcl_endl
00410        << "            </coordinates>\n"
00411        << "          </LinearRing>\n"
00412        << "        </outerBoundaryIs>\n"
00413        << "      </Polygon>" << vcl_endl;
00414   }
00415 }
00416 
00417 void imesh_write_kml_collada(vcl_ostream& os, const imesh_mesh& mesh)
00418 {
00419   // get mesh faces as triangles
00420   if (mesh.faces().regularity() != 3)
00421   {
00422     vcl_cerr << "ERROR! only triangle meshes are supported.\n";
00423     return;
00424   }
00425   const imesh_regular_face_array<3>& tris =
00426       static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00427   const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00428   const unsigned int nverts = verts.size();
00429   const unsigned int nfaces = tris.size();
00430 
00431   vcl_string geometry_id = "geometry";
00432   vcl_string geometry_position_id = "geometry_position";
00433   vcl_string geometry_position_array_id = "geometry_position_array";
00434   vcl_string geometry_uv_id = "geometry_uv";
00435   vcl_string geometry_uv_array_id = "geometry_uv_array";
00436   vcl_string geometry_vertex_id = "geometry_vertex";
00437   vcl_string geometry_normal_id = "geometry_normal";
00438 
00439   // Write the COLLADA XML
00440   os <<"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
00441      << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n"
00442 
00443      << "  <asset>\n"
00444      << "    <contributor>\n"
00445      << "      <authoring_tool>VXL imesh library</authoring_tool>\n"
00446      << "    </contributor>\n"
00447 #if 0 // When we figure out how to get a date string we can write this
00448      << "    <created>2008-04-08T13:07:52-08:00</created>\n"
00449      << "    <modified>2008-04-08T13:07:52-08:00</modified>\n"
00450 #endif
00451      << "    <unit name=\"meters\" meter=\"1\"/>\n"
00452      << "    <up_axis>Z_UP</up_axis>\n"
00453      << "  </asset>\n";
00454 
00455   // Write materials.  Use a single grey material
00456   os << "  <library_materials>" << vcl_endl
00457      << "    <material id=\"GreyID\" name=\"Grey\">"<< vcl_endl
00458      << "       <instance_effect url=\"#Grey-effect\"/>"<< vcl_endl
00459      << "    </material>"<< vcl_endl
00460      << "  </library_materials>"<< vcl_endl
00461 
00462      << "  <library_effects>"<< vcl_endl
00463      << "    <effect id=\"Grey-effect\" name=\"Grey-effect\">\n"
00464      << "      <profile_COMMON>\n"
00465      << "         <technique sid=\"COMMON\">\n"
00466      << "            <phong>\n"
00467      << "              <diffuse>\n"
00468      << "                 <color>1.000000 1.000000 1.000000 1</color>\n"
00469      << "              </diffuse>\n"
00470      << "            </phong>\n"
00471      << "         </technique>\n"
00472      << "         <extra>\n"
00473      << "         <technique profile=\"GOOGLEEARTH\">\n"
00474      << "           <double_sided>1</double_sided>\n"
00475      << "         </technique>\n"
00476      << "         </extra>\n"
00477      << "      </profile_COMMON>\n"
00478      << "    </effect>\n"
00479      << "  </library_effects>\n";
00480 
00481   // write geometry
00482   os << "  <library_geometries>\n"
00483      <<"    <geometry id=\"" << geometry_id << "\" name=\"" << geometry_id << "\">\n"
00484      <<"      <mesh>\n"
00485      <<"        <source id=\"" << geometry_position_id << "\">\n"
00486      <<"        <float_array id=\"" << geometry_position_array_id << "\" count=\"" << nverts*3 << "\">\n";
00487 
00488   for (unsigned int v=0; v<nverts; ++v)
00489     os << "          "<< verts[v][0] << ' ' << verts[v][1] << ' ' << verts[v][2] << '\n';
00490 
00491   os <<"\n        </float_array>\n"
00492      <<"        <technique_common>\n"
00493      <<"          <accessor source=\"#" << geometry_position_array_id << "\" count=\"" << nverts << "\" stride=\"3\">\n"
00494      <<"            <param name=\"X\" type=\"float\"/>\n"
00495      <<"            <param name=\"Y\" type=\"float\"/>\n"
00496      <<"            <param name=\"Z\" type=\"float\"/>\n"
00497      <<"          </accessor>\n"
00498      <<"        </technique_common>\n"
00499      <<"      </source>\n"
00500      <<"      <source id=\"" << "geometry_normal" << "\">\n"
00501 
00502      <<"        <float_array id=\"" << "geometry_normal_array" << "\" count=\"" << nfaces*3 << "\">\n";
00503   for (unsigned int f=0; f<nfaces; ++f) {
00504     const vgl_vector_3d<double>& n = tris.normal(f);
00505     os << "          " << n.x() << ' ' << n.y() << ' ' << n.z() << '\n';
00506   }
00507 
00508   os <<"\n        </float_array>\n"
00509      <<"        <technique_common>\n"
00510      <<"          <accessor source=\"#" << "geometry_normal_array" << "\" count=\"" << nfaces << "\" stride=\"3\">\n"
00511      <<"            <param name=\"X\" type=\"float\"/>\n"
00512      <<"            <param name=\"Y\" type=\"float\"/>\n"
00513      <<"            <param name=\"Z\" type=\"float\"/>\n"
00514      <<"          </accessor>\n"
00515      <<"        </technique_common>\n"
00516      <<"      </source>\n"
00517 
00518      <<"      <vertices id=\"" <<geometry_vertex_id << "\">\n"
00519      <<"        <input semantic=\"POSITION\" source=\"#" << geometry_position_id << "\"/>\n"
00520      <<"      </vertices>\n"
00521      <<"      <triangles material=\"Grey\" count=\"" << nfaces << "\">\n"
00522      <<"        <input semantic=\"VERTEX\" source=\"#" << geometry_vertex_id <<  "\" offset=\"0\"/>\n"
00523      <<"        <input semantic=\"NORMAL\" source=\"#" << "geometry_normal" <<  "\" offset=\"1\"/>\n"
00524 
00525      <<"        <p>\n";
00526 
00527   for (unsigned int f=0; f<nfaces; ++f) {
00528     os << "          "
00529        << tris[f][0] << ' ' << f <<"  "
00530        << tris[f][1] << ' ' << f <<"  "
00531        << tris[f][2] << ' ' << f <<'\n';
00532   }
00533   os << "        </p>\n"
00534      << "      </triangles>\n"
00535      << "    </mesh>\n"
00536      << "  </geometry>\n"
00537      << "  </library_geometries>\n";
00538 
00539   // write the scene
00540   os << "  <library_visual_scenes>\n"
00541      << "    <visual_scene id=\"vis_scene\">\n"
00542      << "      <node id=\"Model\" name=\"Model\">\n"
00543      << "        <node id=\"mesh\" name=\"mesh\">\n"
00544      << "          <instance_geometry url=\"#geometry\">\n"
00545      << "            <bind_material>\n"
00546      << "              <technique_common>\n"
00547      << "                <instance_material symbol=\"Grey\" target=\"#GreyID\"/>\n"
00548      << "              </technique_common>\n"
00549      << "            </bind_material>\n"
00550      << "          </instance_geometry>\n"
00551      << "        </node>"
00552      << "      </node>"
00553      << "    </visual_scene>\n"
00554      << "  </library_visual_scenes>\n"
00555      << "  <scene>\n"
00556      << "    <instance_visual_scene url=\"#vis_scene\"/>\n"
00557      << "  </scene>\n"
00558      << "</COLLADA>\n";
00559 }
00560 
00561 void imesh_write_vrml(vcl_ostream& os, const imesh_mesh& mesh)
00562 {
00563   // get mesh faces as triangles
00564   if (mesh.faces().regularity() != 3)
00565   {
00566     vcl_cerr << "ERROR! only triangle meshes are supported.\n";
00567     return;
00568   }
00569   const imesh_regular_face_array<3>& tris =
00570     static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00571   const imesh_vertex_array_base& vertsb = mesh.vertices();
00572   unsigned d = vertsb.dim();
00573   if (d!=2&&d!=3)
00574   {
00575     vcl_cerr << "vertex dimension must be 2 or 3.\n";
00576     return;
00577   }
00578   const unsigned int nfaces = tris.size();
00579   os << "#VRML V2.0 utf8\n\n"
00580      << "Transform {\n"
00581      << "  translation 0 0 0\n"
00582      << "  children\n"
00583      << " Shape {\n";
00584 
00585   //write appearance
00586   os << "  appearance Appearance {\n"
00587      << "    material Material{}\n"
00588      << "    texture ImageTexture {\n"
00589      << "      url \""<< mesh.tex_source() <<"\"\n"
00590      << "    }\n"
00591      << "  }\n";
00592 
00593   //write coordinates in 2 or 3d
00594   os << " geometry IndexedFaceSet\n"
00595      << "  {\n"
00596      << "   coord Coordinate{\n"
00597      << "    point [\n";
00598   if (d == 2) {
00599     const imesh_vertex_array<2>& verts2= mesh.vertices<2>();
00600     for (unsigned i=0;i<verts2.size();++i)
00601       os << "    " << verts2[i][0] << ' ' << verts2[i][1] << ' ' << 0.0 << '\n';
00602   }
00603   else {
00604     const imesh_vertex_array<3>& verts3= mesh.vertices<3>();
00605     for (unsigned i=0;i<verts3.size();++i)
00606       os << "    " << verts3[i][0] << ' ' << verts3[i][1] << ' ' << verts3[i][2] << '\n';
00607   }
00608   os << "    ]}\n";
00609 
00610   //write faces (all triangles)
00611   os << "  coordIndex [\n";
00612   for (unsigned i=0;i<nfaces;++i) {
00613     os << "    "
00614        << tris[i][0] << ' '
00615        << tris[i][1] << ' '
00616        << tris[i][2] << ' '
00617        << -1 << '\n';
00618   }
00619   os << "  ]\n";
00620 
00621   //write texture coordinates
00622   if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT) {
00623     os << " texCoord TextureCoordinate {\n"
00624        << "   point [\n";
00625 
00626     //write tex coordinates (should be same number as vertices above)
00627     const vcl_vector<vgl_point_2d<double> >& tc = mesh.tex_coords();
00628     for (unsigned int i=0; i<tc.size(); ++i)
00629       os << "    " << tc[i].x() << ' ' << tc[i].y() << ",\n";
00630 
00631     //close texture coordinates
00632     os << "    ]}\n";
00633 
00634     //write face mapping again
00635     os << "   texCoordIndex [\n";
00636     for (unsigned i=0;i<nfaces;++i) {
00637       os << "    "
00638          << tris[i][0] << ' '
00639          << tris[i][1] << ' '
00640          << tris[i][2] << ' '
00641          << -1 << '\n';
00642     }
00643     os << "  ]\n";
00644   }
00645 
00646   //
00647   os << "solid TRUE\n"
00648      << "convex FALSE\n"
00649      << "creaseAngle 0\n";
00650 
00651 #if 0
00652   os << "  colorPerVertex FALSE\n"
00653      << "  color Color {\n"
00654      << "   color [ ]\n"
00655      << "  }\n"
00656      << "  colorIndex [ ]\n";
00657 #endif
00658 
00659   //close geometry indexed face set
00660   os << " }\n";
00661 
00662   //close shape
00663   os << "}\n";
00664   
00665   //close transform
00666   os << "}\n";
00667 }