00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
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
00017 vrml_out::vrml_out()
00018 {
00019 s_ = 0;
00020 own_ostream_ = false;
00021 }
00022
00023
00024 vrml_out::vrml_out(vcl_ostream& s)
00025 {
00026 s_ = &s;
00027 own_ostream_ = false;
00028 }
00029
00030
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
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
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";
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
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 )
00118 : vrml_(vrml), current_vertex_id(0) {}
00119 bool send_vertex(void*);
00120 int vertex_id(void*);
00121 };
00122
00123
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
00129 return false;
00130 }
00131
00132
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
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
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
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
00218 phil3d << v->GetX() << ' ' << v->GetY() << ' ' << v->GetZ() << vcl_endl;
00219
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
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
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
00282 double tu = vertex->GetX() / vertex->GetZ();
00283 double tv = vertex->GetY() / vertex->GetZ();
00284
00285
00286 double fhak = (image_xsize + image_ysize) * 0.5;
00287 *u = tu * fhak + 0.5 * image_xsize;
00288 *v = tv * fhak + 0.5 * image_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();
00316 *v = p2d.y() / p2d.z();
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
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 }