contrib/oxl/vrml/vrml_out.cxx
Go to the documentation of this file.
00001 // This is oxl/vrml/vrml_out.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "vrml_out.h"
00009 
00010 #include <vcl_functional.h>
00011 #include <vcl_fstream.h>
00012 #include <vcl_map.h>
00013 #include <vcl_iostream.h>
00014 #include <vul/vul_printf.h>
00015 
00016 // Default ctor
00017 vrml_out::vrml_out()
00018 {
00019   s_ = 0;
00020   own_ostream_ = false;
00021 }
00022 
00023 //: Point vrml output to this stream
00024 vrml_out::vrml_out(vcl_ostream& s)
00025 {
00026   s_ = &s;
00027   own_ostream_ = false;
00028 }
00029 
00030 //: Open filename for writing, write prologue, and on closure write epilogue
00031 vrml_out::vrml_out(char const* filename)
00032 {
00033   s_ = new vcl_ofstream(filename);
00034   own_ostream_ = true;
00035   if (!s_ || !(*s_)) {
00036     vcl_cerr << "Cannot open " << filename << " for writing\n";
00037     delete s_; s_ = 0; own_ostream_ = false;
00038   }
00039   else prologue();
00040 }
00041 
00042 //: Destructor.  If we own the vcl_ostream, write the epilogue
00043 vrml_out::~vrml_out()
00044 {
00045   if (own_ostream_) {
00046     epilogue();
00047     delete s_;
00048   }
00049 }
00050 
00051 #define SETUP if (s_ == 0) { vcl_cerr << "vrml_out -- vcl_ostream not set!\n"; return; } vcl_ostream& f = *s_
00052 
00053 //: Write vrml_out header and an opening "Separator {"
00054 void vrml_out::prologue()
00055 {
00056   SETUP;
00057   f << "#VRML V1.0 ascii\n\n"
00058     << "#vxl vrml_out output\n"
00059     << "Separator {\n"
00060     << "ShapeHints {\n"
00061     << "\t vertexOrdering  CLOCKWISE\n"
00062     << "\t shapeType       UNKNOWN_SHAPE_TYPE\n"
00063 #if 0 // vrweb barfs on the following line if faces are triangles...
00064     << "\t faceType        UNKNOWN_FACE_TYPE\n"; // Not necessarily convex
00065 #endif
00066     << "}\n";
00067 }
00068 
00069 void vrml_out::comment(char const* msg)
00070 {
00071   SETUP;
00072   f << "# " << msg << vcl_endl;
00073 }
00074 
00075 void vrml_out::verbatim(char const* msg)
00076 {
00077   SETUP;
00078   f << msg << vcl_endl;
00079 }
00080 
00081 //: Write closing "}"
00082 void vrml_out::epilogue()
00083 {
00084   SETUP;
00085   f << "}\n"
00086     << "# End vxl vrml_out output\n";
00087 }
00088 
00089 #if 0
00090 void vrml_out::write_vertices(vcl_vector<vgl_point_3d<double> > const& points)
00091 {
00092   begin_pointset();
00093   for (vcl_vector<vgl_point_3d<double> >::const_iterator it = points.begin();
00094        it != points.end(); ++it)
00095     point3d(*it);
00096   end_pointset();
00097   display_pointset();
00098 }
00099 #endif
00100 
00101 void vrml_out::display_pointset ()
00102 {
00103   SETUP;
00104   f << "PointSet {}\n";
00105 }
00106 
00107 // -----------------------------------------------------------------------------
00108 
00109 #if 0 // commented out
00110 struct VRML_IO_VertexRememberer
00111 {
00112   vrml_out* vrml_;
00113   typedef vcl_map<void*, int, vcl_less<void*> > Map;
00114   Map vertex_ids;
00115   int current_vertex_id;
00116 
00117   VRML_IO_VertexRememberer(vrml_out* vrml, int /*approx_numverts*/)
00118     : vrml_(vrml), current_vertex_id(0) {}
00119   bool send_vertex(void*);
00120   int vertex_id(void*);
00121 };
00122 
00123 //: Return true if it was a new vertex.
00124 bool VRML_IO_VertexRememberer::send_vertex(void* v)
00125 {
00126   Map::iterator p = vertex_ids.find(v);
00127   if (p != vertex_ids.end()) {
00128     // Has already been sent, ignore.
00129     return false;
00130   }
00131 
00132   // Not there already, write the vertex and give it an index
00133   vertex_ids.insert(Map::value_type(v, current_vertex_id++));
00134   vrml_->point3d(v);
00135 
00136   return true;
00137 }
00138 
00139 int VRML_IO_VertexRememberer::vertex_id(vgl_point_3d<double> v)
00140 {
00141   Map::iterator p = vertex_ids.find(v);
00142   if (p != vertex_ids.end())
00143     return (*p).second;
00144 
00145   vcl_cerr << "VRML_IO_VertexRememberer::vertex_ids() WARNING! "
00146            << "This can't happen -- vertex " << v << " has no id.  Fnarrr.\n";
00147 
00148   return -1;
00149 }
00150 
00151 // -----------------------------------------------------------------------------
00152 
00153 void vrml_out::write_edges(vcl_list<vgl_line_segment_3d<double> >& edges)
00154 {
00155   // Start sending vertices
00156   begin_pointset();
00157   VRML_IO_VertexRememberer vertexer(this, edges.length() * 2);
00158   for (edges.reset(); edges.next(); ) {
00159     vertexer.send_vertex(edges.value()->GetV1());
00160     vertexer.send_vertex(edges.value()->GetV2());
00161   }
00162   end_pointset();
00163 
00164   begin_lineset();
00165   for (edges.reset(); edges.next(); ) {
00166     int i0 = vertexer.vertex_id(edges.value()->GetV1());
00167     int i1 = vertexer.vertex_id(edges.value()->GetV2());
00168     line(i0, i1);
00169   }
00170   end_lineset();
00171 }
00172 
00173 void vrml_out::write_faces(vcl_list<vgl_polygon<float> >& triangles)
00174 {
00175   VRML_IO_VertexRememberer vertexer(this, triangles.length() * 3/2);
00176 
00177   // Send vertices
00178   begin_pointset();
00179   for (triangles.reset(); triangles.next(); ) {
00180     vgl_polygon<float> face = triangles.value();
00181     vcl_list<vgl_point_3d<double> > vertices = face->Vertices();
00182     for (vertices->reset(); vertices->next();)
00183       vertexer.send_vertex(vertices->value());
00184   }
00185   end_pointset();
00186 
00187   // Now send triangles
00188   begin_faceset();
00189   for (triangles.reset(); triangles.next(); ) {
00190     vgl_polygon<float> face = triangles.value();
00191     vcl_list<vgl_point_3d<double> > vertices = face->Vertices();
00192     face_open();
00193     for (vertices->reset(); vertices->next();)
00194       face_index(vertexer.vertex_id(vertices->value()));
00195     face_close();
00196   }
00197   end_faceset();
00198 }
00199 
00200 void vrml_out::write_faces_textured(vcl_list<vgl_polygon<float> >& triangles,
00201                                     char const* texfile,
00202                                     vrml_out_vertex_to_texture const& v2t
00203                                    )
00204 {
00205   VRML_IO_VertexRememberer vertexer(this, triangles.length() * 3/2);
00206 
00207   vcl_ofstream phil3d("/tmp/pcptex.3d");
00208   vcl_ofstream phil2d("/tmp/pcptex.2d");
00209 
00210   begin_pointset();
00211   for (triangles.reset(); triangles.next(); ) {
00212     vgl_polygon<float> face = triangles.value();
00213     vcl_list<vgl_point_3d<double> > vertices = face->Vertices();
00214     for (vertices->reset(); vertices->next();) {
00215       Vertex *v = vertices->value();
00216       if (vertexer.send_vertex(v)) {
00217         // Save pcp3d
00218         phil3d << v->GetX() << ' ' << v->GetY() << ' ' << v->GetZ() << vcl_endl;
00219         // Save pcp texture coord
00220         int xsize = v2t.image_xsize;
00221         int ysize = v2t.image_ysize;
00222         double ix, iy;
00223         v2t.get_texture_coords(v, &ix, &iy);
00224         ix = ix / xsize;
00225         iy = 1.0 - iy / ysize;
00226         phil2d << ix << ' ' << iy << vcl_endl;
00227       }
00228     }
00229   }
00230   end_pointset();
00231 
00232   // Send texture coordinates
00233   int xsize = v2t.image_xsize;
00234   int ysize = v2t.image_ysize;
00235 
00236   begin_texture(texfile);
00237   int last_id = -1;
00238   for (triangles.reset(); triangles.next(); )
00239   {
00240     vgl_polygon<float> face = triangles.value();
00241     vcl_list<vgl_point_3d<double> > vertices = face->Vertices();
00242     for (vertices->reset(); vertices->next();)
00243     {
00244       Vertex *v = vertices->value();
00245       int id = vertexer.vertex_id(v);
00246       if (id > last_id) {
00247         if (last_id + 1 != id)
00248           vcl_cerr << "vrml_out::write_faces_textured() -- texture buggered\n";
00249         ++last_id;
00250 
00251         double ix, iy;
00252         v2t.get_texture_coords(v, &ix, &iy);
00253 
00254         texture2_image_coords(ix, iy, xsize, ysize);
00255       }
00256     }
00257   }
00258   end_texture();
00259 
00260   // Now send triangles
00261   begin_faceset();
00262   for (triangles.reset(); triangles.next(); ) {
00263     vgl_polygon<float> face = triangles.value();
00264     vcl_list<vgl_point_3d<double> > vertices = face->Vertices();
00265     face_open();
00266     for (vertices->reset(); vertices->next();)
00267       face_index(vertexer.vertex_id(vertices->value()));
00268     face_close();
00269   }
00270   end_faceset();
00271 }
00272 
00273 struct Hack_VertexToTexture : public vrml_out_vertex_to_texture
00274 {
00275   Hack_VertexToTexture(int xsize, int ysize)
00276     : vrml_out_vertex_to_texture(xsize, ysize) {}
00277 
00278   void get_texture_coords(const vgl_point_3d<double> vertex,
00279                           double* u, double* v) const
00280   {
00281     // Ugh - assume P matrix is [I 0];
00282     double tu = vertex->GetX() / vertex->GetZ();
00283     double tv = vertex->GetY() / vertex->GetZ();
00284 
00285     // Ugh ugh - assume C = [f 0 u; 0 f v; 0 0 1];
00286     double fhak = (image_xsize + image_ysize) * 0.5; // FIXME
00287     *u = tu * fhak + 0.5 * image_xsize; // 0..xsize
00288     *v = tv * fhak + 0.5 * image_ysize; // 0..ysize
00289   }
00290 };
00291 
00292 void vrml_out::write_faces_textured(vcl_list<vgl_polygon<float> >& triangles,
00293                                     char const* imagefilename,
00294                                     int xsize, int ysize
00295                                    )
00296 {
00297   vcl_cerr << "vrml_out::write_faces_textured() -- hacking image-world transform\n";
00298   Hack_VertexToTexture hack(xsize, ysize);
00299   write_faces_textured(triangles, imagefilename, hack);
00300 }
00301 
00302 class VTT : public vrml_out_vertex_to_texture
00303 {
00304  public:
00305   VTT(int xsize, int ysize, vnl_matrix<double> const& m)
00306         : vrml_out_vertex_to_texture(xsize, ysize), Pmatrix(m) {}
00307 
00308   void get_texture_coords(
00309         const vgl_point_3d<double> vertex,
00310         double* u,
00311         double* v) const
00312       {
00313         vnl_vector<double> p3d(4, vertex->GetX(), vertex->GetY(), vertex->GetZ(), 1.0);
00314         vnl_vector<double> p2d = Pmatrix*p3d;
00315         *u = p2d.x() / p2d.z(); // ==> texture coordinate *u / image_xsize;
00316         *v = p2d.y() / p2d.z(); // ==> texture coordinate 1 - *v / image_ysize;
00317       }
00318 
00319   vnl_matrix<double> Pmatrix;
00320 };
00321 
00322 void vrml_out::write_faces_textured(vcl_list<vgl_polygon<float> >& triangles,
00323                                     char const* imagefilename,
00324                                     int xsize, int ysize,
00325                                     vnl_matrix<double> const& Pmatrix
00326                                    )
00327 {
00328   VTT vtt(xsize, ysize, Pmatrix);
00329   write_faces_textured(triangles, imagefilename, vtt);
00330 }
00331 
00332 void vrml_out::write_block(Block* block)
00333 {
00334   write_faces(*block->Faces());
00335 }
00336 
00337 void vrml_out::write_topology(TopologyObject* topobj)
00338 {
00339   SETUP;
00340   Block* block = topobj->CastToBlock();
00341   if (block) {
00342     begin_separator();
00343     write_faces(*block->Faces());
00344     end_separator();
00345     return;
00346   }
00347 
00348   vgl_polygon<float> face = topobj->CastToFace();
00349   if (face) {
00350     begin_separator();
00351     vcl_list<vgl_polygon<float> > faces; faces.push(face);
00352     write_faces(faces);
00353     end_separator();
00354     return;
00355   }
00356 
00357   vgl_line_segment_3d<double> edge = topobj->CastToEdge();
00358   if (edge) {
00359     begin_separator();
00360     vcl_list<vgl_line_segment_3d<double> > edges(edge);
00361     write_edges(edges);
00362     end_separator();
00363     return;
00364   }
00365 
00366   vgl_point_3d<double> vertex = topobj->CastToVertex();
00367   if (vertex) {
00368     begin_separator();
00369     vcl_list<vgl_point_3d<double> > vertices(vertex);
00370     write_vertices(vertices);
00371     end_separator();
00372     return;
00373   }
00374 
00375   vcl_cerr << "VRML: not handling " << topobj << vcl_endl;
00376   f << "# vrml_out: Couldn't handle "
00377     << TopologyObject::TopoNames[topobj->GetTopologyType()] << vcl_endl;
00378 }
00379 
00380 void vrml_out::write_topology(vcl_list<TopologyObject*>& topobjs)
00381 {
00382   for (topobjs.reset(); topobjs.next(); )
00383     write_topology(topobjs.value());
00384 }
00385 
00386 #endif // 0
00387 
00388 // == IMPLEMENTORS ==
00389 void vrml_out::begin_separator()
00390 {
00391   SETUP;
00392   f << "Separator {\n";
00393 }
00394 
00395 void vrml_out::end_separator()
00396 {
00397   SETUP;
00398   f << "}\n\n";
00399 }
00400 
00401 void vrml_out::begin_pointset()
00402 {
00403   SETUP;
00404   f << "  Coordinate3 { point [\n";
00405 }
00406 
00407 void vrml_out::point3d(double x, double y, double z)
00408 {
00409   SETUP;
00410   vul_printf(f, "\t %10.4f %10.4f %10.4f,\n", x, y, z);
00411 }
00412 
00413 void vrml_out::point3d(double x, double y, double z, const char *format)
00414 {
00415   SETUP;
00416   vul_printf(f, "\t ");
00417   vul_printf(f, format, x);
00418   vul_printf(f, " ");
00419   vul_printf(f, format, y);
00420   vul_printf(f, " ");
00421   vul_printf(f, format, z);
00422   vul_printf(f, ",\n");
00423 }
00424 
00425 void vrml_out::end_pointset()
00426 {
00427   SETUP;
00428   f << "   ]}\n";
00429 }
00430 
00431 void vrml_out::begin_texture(char const* texture_filename)
00432 {
00433   SETUP;
00434   f << "  Texture2 { filename \"" << texture_filename << "\" }\n"
00435     << "  TextureCoordinate2 { point [\n";
00436 }
00437 
00438 void vrml_out::texture2(double u, double v)
00439 {
00440   SETUP;
00441   f << '\t' << u << ' ' << v << ",\n";
00442 }
00443 
00444 void vrml_out::texture2_image_coords(double u, double v, int w, int h)
00445 {
00446   texture2(u / w, 1.0 - v / h);
00447 }
00448 
00449 void vrml_out::end_texture()
00450 {
00451   SETUP;
00452   f << "   ]}\n";
00453 }
00454 
00455 void vrml_out::begin_lineset()
00456 {
00457   SETUP;
00458   f << "  IndexedLineSet { coordIndex [\n";
00459 }
00460 
00461 void vrml_out::line(int i0, int i1)
00462 {
00463   SETUP;
00464   f << '\t' << i0 << ", " << i1 << ",-1,\n";
00465 }
00466 
00467 void vrml_out::end_lineset()
00468 {
00469   SETUP;
00470   f << "  ]}\n";
00471 }
00472 
00473 void vrml_out::begin_faceset()
00474 {
00475   SETUP;
00476   f << "  IndexedFaceSet { coordIndex [\n";
00477 }
00478 
00479 void vrml_out::face_open()
00480 {
00481   SETUP;
00482   f << '\t';
00483 }
00484 
00485 void vrml_out::face_index(int i)
00486 {
00487   SETUP;
00488   f << i << ", ";
00489 }
00490 
00491 void vrml_out::face_close()
00492 {
00493   SETUP;
00494   f << "-1,\n";
00495 }
00496 
00497 void vrml_out::triangle(int i1, int i2, int i3)
00498 {
00499   SETUP;
00500   f << '\t' << i1 << ", " << i2 << ", " << i3 << ",-1,\n";
00501 }
00502 
00503 void vrml_out::quad(int i1, int i2, int i3, int i4)
00504 {
00505   SETUP;
00506   f << '\t' << i1 << ", " << i2 << ", " << i3 << ", " << i4 << ",-1,\n";
00507 }
00508 
00509 void vrml_out::face(const int* base, int n)
00510 {
00511   SETUP;
00512   f << '\t';
00513   for (int i = 0; i < n; ++i)
00514     f << base[i] << ", ";
00515   f << "-1,\n";
00516 }
00517 
00518 void vrml_out::end_faceset()
00519 {
00520   SETUP;
00521   f << "  ]}\n";
00522 }