1 #include <iostream>
2 #include <sstream>
3 #include "bwm_world.h"
4 #include "bwm_observer_mgr.h"
5 #include "algo/bwm_shape_file.h"
6 #include "algo/bwm_algo.h"
7 #include "algo/bwm_utils.h"
8
9 #ifdef _MSC_VER
10 # include "vcl_msvc_warnings.h"
11 #endif
12
13 #include "vul/vul_file.h"
14 #include "vgl/vgl_vector_3d.h"
15 #include "vgui/vgui_dialog.h"
16
17 #include "bwm_observable.h"
18 #include "bwm_observable_textured_mesh.h"
19
20 bwm_world* bwm_world::instance_ = nullptr;
21
instance()22 bwm_world* bwm_world::instance()
23 {
24 if (!instance_)
25 instance_ = new bwm_world();
26 return bwm_world::instance_;
27 }
28
29
set_world_pt(vgl_point_3d<double> const & pt)30 void bwm_world::set_world_pt(vgl_point_3d<double> const& pt)
31 {
32 world_pt_ = pt;
33 vgl_vector_3d<double> normal(0, 0, 1);//z axis
34 world_plane_ = vgl_plane_3d<double>(normal, pt);
35 world_pt_valid_ = true;
36 }
37 // adds an observable to the world
add(bwm_observable_sptr obj)38 bool bwm_world::add(bwm_observable_sptr obj)
39 {
40 // find the object
41 std::vector<bwm_observable_sptr>::iterator it = objects_.begin();
42 while (it != objects_.end()) {
43 if (*it == obj)
44 return false;
45 ++it;
46 }
47 objects_.push_back(obj);
48 return true;
49 }
50 // removes an observable from the world
remove(bwm_observable_sptr obj)51 bool bwm_world::remove(bwm_observable_sptr obj)
52 {
53 // find the object
54 std::vector<bwm_observable_sptr>::iterator it = objects_.begin();
55 while (it != objects_.end()) {
56 if (*it == obj) {
57 objects_.erase(it, it+1);
58 return true;
59 }
60 it++;
61 }
62 return false; // object was not in the world
63 }
64
set_lvcs(double lat,double lon,double elev)65 void bwm_world::set_lvcs(double lat, double lon, double elev)
66 {
67 // clean up the olde one, if any
68 lvcs_ = vpgl_lvcs(lat, lon, elev);
69 lvcs_valid_ = true;
70 }
71
get_lvcs(vpgl_lvcs & lvcs)72 bool bwm_world::get_lvcs(vpgl_lvcs &lvcs)
73 {
74 // if lvcs is set get that
75 if (lvcs_valid_) {
76 lvcs = lvcs_;
77 return true;
78 }
79 #if 0 // commented out
80 // else, create from the world point
81 else if (world_pt_valid_) {
82 lvcs = vpgl_lvcs(world_pt_.x(), world_pt_.y(), world_pt_.z());
83 return true;
84 }
85
86 // get from the tableau mgr, as the avg of the camera centers
87 else if (bwm_observer_mgr::instance()->comp_avg_camera_center(center)) {
88 lvcs = vpgl_lvcs(center.x(), center.y(), center.z());
89 return true;
90 }
91 #endif // 0
92
93 // else, request from user
94 double lat, lon, elev;
95 vgui_dialog lvcs_dialog("Set LVCS");
96 lvcs_dialog.message("Please Enter and LVCS origin:");
97 lvcs_dialog.field("Latitude:", lat);
98 lvcs_dialog.field("Longitude:", lon);
99 lvcs_dialog.field("Elevation:", elev);
100 if (!lvcs_dialog.ask())
101 return false;
102 lvcs_ = vpgl_lvcs(lat, lon, elev);
103 lvcs_valid_ = true;
104 return true;
105 }
106
load_shape_file()107 void bwm_world::load_shape_file()
108 {
109 std::string file = bwm_utils::select_file();
110 bwm_shape_file sfile;
111 if (sfile.load(file)) {
112 // "#define SHPT_POLYGONZ 15" in shapefil.h
113 if (sfile.shape_type() == 15) {
114 std::vector<std::vector<vsol_point_3d_sptr> > polys = sfile.vertices();
115 for (unsigned i=0; i<polys.size(); i++) {
116 bwm_observable_mesh_sptr mesh = new bwm_observable_mesh();
117 bwm_observer_mgr::instance()->attach(mesh);
118 vsol_polygon_3d_sptr poly3d = bwm_algo::move_points_to_plane(polys[i]);
119 mesh->set_object(poly3d);
120 }
121 }
122 }
123 }
124
125 #if 0
126 void bwm_world::save_all()
127 {
128 if (objects_.size() == 0) {
129 vgui_dialog error ("Error");
130 error.message ("There is no object to save..." );
131 error.ask();
132 return;
133 }
134
135 vgui_dialog_extensions save("Save 3D objects");
136 std::vector<std::string> file_types;
137 file_types.push_back("ply");
138 file_types.push_back("gml");
139 file_types.push_back("kml");
140 file_types.push_back("kml collada");
141 file_types.push_back("x3d");
142
143 std::string ext, file_path;
144 unsigned t = 0;
145 save.dir("Path:", ext, file_path);
146 save.choice("File Type", file_types, t);
147 //save.line_break();
148
149 if (!save.ask())
150 return;
151
152 // what if they choose a dir instead of a file name
153 if (vul_file::is_directory(file_path)) {
154 // for (unsigned i=0; i<objects_.size(); i++) {
155 // std::string path = file_path + "\\objects";
156
157 if (file_types[t].compare("ply") == 0)
158 save_ply(path); // HOW ABOUT LVCS, do we use world point to create one
159
160 else if (file_types[t].compare("gml") == 0)
161 save_gml(path);
162
163 else if (file_types[t].compare("kml") == 0)
164 bwm_file_io::save_kml(objects_[i], path+".kml");
165
166 else if (file_types[t].compare("kml collada") == 0)
167 bwm_file_io::save_kml_collada(objects_[i], path+".kml"); // ??what is the extension of kml collada??
168
169 else if (file_types[t].compare("x3d") == 0)
170 bwm_file_io::save_x3d(objects_[i], path+".x3d");
171 }
172 }
173 }
174 #endif // 0
175
save_ply()176 void bwm_world::save_ply() // how about use lvcs??
177 {
178 vgui_dialog params("File Save");
179 std::string ext, list_name, empty="";
180 bool use_lvcs = false;
181
182 params.file ("Filename...", ext, list_name);
183 params.checkbox("Use LVCS", use_lvcs);
184
185 if (!params.ask())
186 return;
187
188 if (list_name == "") {
189 vgui_dialog error ("Error");
190 error.message ("Please specify a filename." );
191 error.ask();
192 return;
193 }
194
195 std::string directory_name = vul_file::dirname(list_name);
196
197 std::ofstream list_out(list_name.data());
198 if (!list_out.good()) {
199 std::cerr << "error opening file "<< list_name <<std::endl;
200 return;
201 }
202
203 for (unsigned idx=0; idx<objects_.size(); idx++) {
204 std::ostringstream objname;
205 std::ostringstream fullpath;
206 objname << "obj" << idx <<".ply";
207 fullpath << directory_name << '/' << objname.str();
208
209 list_out << objname.str() << std::endl;
210 bwm_observable_sptr o = objects_[idx];
211 // figure out the lvcs here
212
213 o->save(fullpath.str().data(),&lvcs_);
214 }
215 }
216
save_gml()217 void bwm_world::save_gml()
218 {
219 #if 0
220 if (!lvcs_) {
221 std::cerr << "Error: lvcs not defined.\n";
222 return;
223 }
224 #endif // 0
225
226 vgui_dialog params("File Save (.gml) ");
227 std::string ext, gml_filename, empty="";
228 std::string model_name;
229
230 params.field("model name", model_name);
231
232 params.file("Save...", ext, gml_filename);
233 if (!params.ask())
234 return;
235
236 if (gml_filename == "") {
237 std::cerr << "Error: no filename selected.\n";
238 return;
239 }
240
241 std::ofstream os(gml_filename.c_str());
242
243 os << "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n"
244 << "<CityModel xmlns=\"http://www.citygml.org/citygml/1/0/0\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.citygml.org/citygml/1/0/0 http://www.citygml.org/citygml/1/0/0/CityGML.xsd\">\n"
245 << "<gml:description>" << model_name.c_str() << "</gml:description>\n"
246 << "<gml:name>" << model_name.c_str() << "</gml:name>\n";
247
248 int obj_count = 0;
249 for (unsigned idx=0; idx<objects_.size(); idx++) {
250 bwm_observable_sptr obj = objects_[idx];
251 if (obj->type_name().compare("bwm_observable_textured_mesh") == 0) {
252 bwm_observable_textured_mesh* tm_obj = static_cast<bwm_observable_textured_mesh*>(obj.as_pointer());
253 tm_obj->save_gml(os, obj_count, &lvcs_);
254 os << " </Building>"
255 << " </cityObjectMember>";
256 }
257 }
258 os << " </CityModel>";
259 os.close();
260 }
261
save_kml()262 void bwm_world::save_kml()
263 {
264 vpgl_lvcs lvcs;
265 if (!get_lvcs(lvcs)) {
266 std::cerr << "Error: lvcs not defined.\n";
267 return;
268 }
269
270 vgui_dialog params("File Save");
271 std::string ext, kml_filename, empty="";
272 std::string model_name;
273 double ground_height = 0.0;
274 double x_offset = 0.0;
275 double y_offset = 0.0;
276
277 params.field("model name",model_name);
278 params.field("ground height",ground_height);
279 params.field("x offset",x_offset);
280 params.field("y offset",y_offset);
281
282 params.file("Save...",ext,kml_filename);
283 if (!params.ask())
284 return;
285
286 if (kml_filename == "") {
287 std::cerr << "Error: no filename selected.\n";
288 return;
289 }
290
291 std::ofstream os(kml_filename.c_str());
292
293 os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
294 << "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n"
295 << "<Document>\n"
296 << " <name>" << vul_file::strip_directory(kml_filename.c_str()) << "</name>\n"
297 << " <open>1</open>\n"
298 << " <Placemark>\n"
299 << " <name>" << model_name.c_str() << "</name>\n"
300 << " <visibility>1</visibility>\n"
301 << " <MultiGeometry>\n";
302
303 for (unsigned idx=0; idx<objects_.size(); idx++) {
304 bwm_observable_sptr obj = objects_[idx];
305 if (obj->type_name().compare("bwm_observable_textured_mesh") == 0) {
306 bwm_observable_textured_mesh* tm_obj = static_cast<bwm_observable_textured_mesh*>(obj.as_pointer());
307 tm_obj->save_kml(os, idx, &lvcs, ground_height, x_offset, y_offset);
308 }
309 }
310
311 os << " </MultiGeometry>\n"
312 << " </Placemark>\n"
313 << "</Document>\n"
314 << "</kml>\n";
315
316 os.close();
317 }
318
save_x3d()319 void bwm_world::save_x3d()
320 {
321 vpgl_lvcs lvcs;
322 if (!get_lvcs(lvcs)) {
323 std::cerr << "Error: lvcs not defined.\n";
324 return;
325 }
326
327 vgui_dialog params("File Save");
328 std::string ext, x3d_filename, empty="";
329
330 params.file("Save...",ext,x3d_filename);
331 if (!params.ask())
332 return;
333
334 if (x3d_filename == "") {
335 std::cerr << "Error: no filename selected.\n";
336 return;
337 }
338
339 std::ofstream os(x3d_filename.c_str());
340
341 os << "#VRML V2.0 utf8\n"
342 << "PROFILE Immersive\n\n";
343
344 for (unsigned idx=0; idx<objects_.size(); idx++) {
345 bwm_observable_sptr obj = objects_[idx];
346 if (obj->type_name().compare("bwm_observable_textured_mesh") == 0) {
347 bwm_observable_textured_mesh* tm_obj = static_cast<bwm_observable_textured_mesh*> (obj.as_pointer());
348 tm_obj->save_x3d(os, &lvcs);
349 os << " ]\n\n"
350 << " solid TRUE\n"
351 << " convex FALSE\n"
352 << " creaseAngle 0\n"
353 << " }\n"
354 << " }\n"
355 << "}\n\n\n";
356 }
357 }
358
359 os.close();
360 return;
361 }
362
save_kml_collada()363 void bwm_world::save_kml_collada()
364 {
365 vpgl_lvcs lvcs;
366 if (!get_lvcs(lvcs)) {
367 std::cerr << "Error: lvcs not defined.\n";
368 return;
369 }
370
371 double origin_lat = 0,origin_lon = 0, origin_elev = 0;
372 lvcs_.get_origin(origin_lat,origin_lon,origin_elev);
373
374 vgui_dialog params("File Save");
375 std::string ext, kmz_dir, empty="";
376
377 // guess at ground height = lowest vertex
378 double minz = 1e6;
379 for (unsigned idx=0; idx<objects_.size(); idx++) {
380 bwm_observable_sptr obj = objects_[idx];
381 obj->global_to_local(&lvcs, minz);
382 }
383
384 double ground_height = minz;
385 double lat_offset = 0.0;
386 double lon_offset = 0.0;
387 std::string model_name;
388
389 params.field("model name",model_name);
390 params.field("ground height",ground_height);
391 params.field("latitude offset",lat_offset);
392 params.field("longitude offset",lon_offset);
393
394 params.file("Save...",ext,kmz_dir);
395 if (!params.ask())
396 return;
397
398 if (kmz_dir == "") {
399 std::cerr << "Error: no filename selected.\n";
400 return;
401 }
402
403 if (!vul_file::is_directory(kmz_dir)) {
404 std::cerr << "Error: Select a directory name.\n";
405 return;
406 }
407
408 std::ostringstream dae_fname;
409 dae_fname << kmz_dir << "/models/mesh.dae";
410
411 std::ofstream os (dae_fname.str().data());
412
413 std::vector<std::string> image_names;
414 std::vector<std::string> image_fnames;
415 std::vector<std::string> material_ids;
416 std::vector<std::string> material_names;
417 std::vector<std::string> effect_ids;
418 std::vector<std::string> surface_ids;
419 std::vector<std::string> image_sampler_ids;
420 std::vector<std::string> geometry_ids;
421 std::vector<std::string> geometry_position_ids;
422 std::vector<std::string> geometry_position_array_ids;
423 std::vector<std::string> geometry_uv_ids;
424 std::vector<std::string> geometry_uv_array_ids;
425 std::vector<std::string> geometry_vertex_ids;
426 std::vector<std::string> mesh_ids;
427
428 int nobjects = 0;
429 unsigned min_faces = 3;
430
431 for (unsigned idx=0; idx<objects_.size(); idx++) {
432 bwm_observable_sptr obj = objects_[idx];
433 if ( obj->num_faces() < min_faces)
434 // single mesh face is probably ground plane, which we do not want to render
435 continue;
436
437 // check if object is texture mapped
438 if (obj->type_name().compare("bwm_observable_textured_mesh") == 0)
439 {
440 bwm_observable_textured_mesh* mesh = static_cast<bwm_observable_textured_mesh*>(obj.as_pointer());
441 std::string image_fname = vul_file::strip_directory(mesh->tex_map_uri()); // assume all faces have same texmap img
442 std::string image_name = vul_file::strip_extension(image_fname);
443
444 std::ostringstream image_path;
445 image_path << "../images/" << image_fname;
446
447 std::ostringstream objname;
448 objname << "object_"<<nobjects;
449
450 std::ostringstream material_id;
451 material_id << objname.str() <<"_materialID";
452
453 std::ostringstream material_name;
454 material_name << objname.str() <<"_material";
455
456 std::ostringstream effect_id;
457 effect_id << objname.str() << "_effect";
458
459 std::ostringstream surface_id;
460 surface_id << objname.str() << "_surface";
461
462 std::ostringstream image_sampler_id;
463 image_sampler_id << objname.str() << "_sampler";
464
465 std::ostringstream geometry_id;
466 geometry_id << objname.str() << "_geometry";
467
468 std::ostringstream geometry_position_id;
469 geometry_position_id << objname.str() << "_geometry_position";
470
471 std::ostringstream geometry_position_array_id;
472 geometry_position_array_id << objname.str() <<"_geometry_position_array";
473
474 std::ostringstream geometry_uv_id;
475 geometry_uv_id << objname.str() << "_geometry_uv";
476
477 std::ostringstream geometry_uv_array_id;
478 geometry_uv_array_id << objname.str() << "_geometry_uv_array";
479
480 std::stringstream geometry_vertex_id;
481 geometry_vertex_id << objname.str() << "_geometry_vertex";
482
483 mesh_ids.push_back(objname.str());
484 image_names.push_back(image_name);
485 image_fnames.push_back(image_path.str());
486 material_names.push_back(material_name.str());
487 material_ids.push_back(material_id.str());
488 effect_ids.push_back(effect_id.str());
489 surface_ids.push_back(surface_id.str());
490 image_sampler_ids.push_back(image_sampler_id.str());
491 geometry_ids.push_back(geometry_id.str());
492 geometry_position_ids.push_back(geometry_position_id.str());
493 geometry_position_array_ids.push_back(geometry_position_array_id.str());
494 geometry_uv_ids.push_back(geometry_uv_id.str());
495 geometry_uv_array_ids.push_back(geometry_uv_array_id.str());
496 geometry_vertex_ids.push_back(geometry_vertex_id.str());
497
498 nobjects++;
499 }
500 }
501
502 os <<"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
503 << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">\n"
504
505 << " <asset>\n"
506 << " <contributor>\n"
507 << " <authoring_tool> Brown University World Modeler </authoring_tool>\n"
508 << " </contributor>\n"
509 << " <unit name=\"meters\" meter=\"1\"/>\n"
510 << " <up_axis>Z_UP</up_axis>\n"
511 << " </asset>\n"
512 << " <library_images>\n";
513
514 for (int i=0; i<nobjects; i++) {
515 os << " <image id=\"" << image_names[i].c_str() << "\" name=\"" << image_names[i].c_str() << "\">\n"
516 << " <init_from>" << image_fnames[i].c_str() << "</init_from>\n"
517 << " </image>\n";
518 }
519 os << " </library_images>\n";
520
521 os << " <library_materials>\n";
522 for (int i=0; i<nobjects; i++) {
523 os << " <material id=\"" << material_ids[i].c_str() << "\" name=\"" << material_names[i].c_str() << "\">\n"
524 << " <instance_effect url=\"#" << effect_ids[i].c_str() << "\"/>\n"
525 << " </material>\n";
526 }
527 os << " </library_materials>\n";
528
529 os << " <library_effects>\n";
530 for (int i=0; i<nobjects; i++)
531 {
532 os << " <effect id=\"" << effect_ids[i].c_str() << "\" name=\"" << effect_ids[i].c_str() << "\">\n"
533 << " <profile_COMMON>\n"
534 << " <newparam sid=\"" << surface_ids[i].c_str() << "\">\n"
535 << " <surface type=\"2D\">\n"
536 << " <init_from>" << image_names[i].c_str() << "</init_from>\n"
537 << " </surface>\n"
538 << " </newparam>\n"
539 << " <newparam sid=\"" << image_sampler_ids[i].c_str() << "\">\n"
540 << " <sampler2D>\n"
541 << " <source>" << surface_ids[i].c_str() << "</source>\n"
542 << " </sampler2D>\n"
543 << " </newparam>\n"
544 << " <technique sid=\"COMMON\">\n"
545 << " <phong>\n"
546 << " <emission>\n"
547 << " <color>0.0 0.0 0.0 1</color>\n"
548 << " </emission>\n"
549 << " <ambient>\n"
550 << " <color>0.0 0.0 0.0 1</color>\n"
551 << " </ambient>\n"
552 << " <diffuse>\n"
553 << " <texture texture=\"" << image_sampler_ids[i].c_str() << "\" texcoord=\"UVSET0\"/>\n"
554 << " </diffuse>\n"
555 << " <specular>\n"
556 << " <color>0.33 0.33 0.33 1</color>\n"
557 << " </specular>\n"
558 << " <shininess>\n"
559 << " <float>20.0</float>\n"
560 << " </shininess>\n"
561 << " <reflectivity>\n"
562 << " <float>0.1</float>\n"
563 << " </reflectivity>\n"
564 << " <transparent>\n"
565 << " <color>1 1 1 1</color>\n"
566 << " </transparent>\n"
567 << " <transparency>\n"
568 << " <float>0.0</float>\n"
569 << " </transparency>\n"
570 << " </phong>\n"
571 << " </technique>\n"
572 << " </profile_COMMON>\n"
573 << " </effect>\n";
574 }
575 os << " </library_effects>\n";
576
577 os << " <library_geometries>\n";
578
579 for (unsigned idx=0; idx<objects_.size(); idx++) {
580 bwm_observable_sptr obj = objects_[idx];
581 // assume object is texture mapped
582 //dbmsh3d_textured_mesh_mc* mesh = (dbmsh3d_textured_mesh_mc*)obj->get_object();
583 if (obj->num_faces() < min_faces) {
584 // single mesh face is probably ground plane, which we do not want to render
585 continue;
586 }
587
588 if (obj->type_name().compare("bwm_observable_textured_mesh") == 0) {
589 bwm_observable_textured_mesh* tm_obj = static_cast<bwm_observable_textured_mesh*>(obj.as_pointer());
590 tm_obj->save_kml_collada(os, &lvcs, geometry_ids[idx],
591 geometry_position_ids[idx],
592 geometry_position_array_ids[idx],
593 geometry_uv_ids[idx],
594 geometry_uv_array_ids[idx],
595 geometry_vertex_ids[idx],
596 material_names[idx]);
597 }
598
599 os << "</p>\n"
600 << " </triangles>\n"
601 << " </mesh>\n"
602 << " </geometry>\n";
603 idx++;
604 }
605 os << "</library_geometries>\n";
606
607 os << "<library_nodes>\n";
608 for (int i=0; i<nobjects; i++) {
609 os << " <node id=\"Component_" << i << "\" name=\"Component_" << i << "\">\n"
610 << " <node id=\"" << mesh_ids[i].c_str() << "\" name=\"" << mesh_ids[i].c_str() << "\">\n"
611 << " <instance_geometry url=\"#" << geometry_ids[i].c_str() << "\">\n"
612 << " <bind_material>\n"
613 << " <technique_common>\n"
614 << " <instance_material symbol=\"" <<material_names[i].c_str() << "\" target=\"#" << material_ids[i].c_str()<< "\">\n"
615 << " <bind_vertex_input semantic=\"UVSET0\" input_semantic=\"TEXCOORD\" input_set=\"0\"/>\n"
616 << " </instance_material>\n"
617 << " </technique_common>\n"
618 << " </bind_material>\n"
619 << " </instance_geometry>\n"
620 << " </node>\n"
621 << " </node>\n";
622 }
623 os << "</library_nodes>\n";
624
625 os << "<library_visual_scenes>\n"
626 << " <visual_scene id=\"WorldModelerScene\" name=\"WorldModelerScene\">\n"
627 << " <node id=\"Model\" name=\"Model\">\n";
628 for (int i=0; i<nobjects; i++) {
629 os << " <node id=\"Component_" << i << "_1\" name=\"Component_" << i << "_1\">\n"
630 << " <instance_node url=\"#Component_" << i << "\"/>\n"
631 << " </node>\n";
632 }
633 os << " </node>\n"
634 << " </visual_scene>\n"
635 << "</library_visual_scenes>\n";
636
637 os << "<scene>\n"
638 << " <instance_visual_scene url=\"#WorldModelerScene\"/>\n"
639 << "</scene>\n"
640 << "</COLLADA>\n";
641
642 os.close();
643
644 std::ostringstream textures_fname;
645 textures_fname << kmz_dir << "/textures.txt";
646
647 std::ofstream ost(textures_fname.str().data());
648
649 for (int i=0; i<nobjects; i++) {
650 ost << '<' << image_fnames[i].c_str() << "> <" << image_fnames[i].c_str() << ">\n";
651 }
652
653 std::ostringstream kml_fname;
654 kml_fname << kmz_dir << "/doc.kml";
655
656 std::ofstream oskml(kml_fname.str().data());
657
658 oskml << "<?xml version='1.0' encoding='UTF-8'?>\n"
659 << "<kml xmlns='http://earth.google.com/kml/2.1'>\n"
660 << "<Folder>\n"
661 << " <name>" << model_name.c_str() << "</name>\n"
662 << " <description><![CDATA[Created with <a href=\"http://www.lems.brown.edu\">CrossCut</a>]]></description>\n"
663 << " <DocumentSource>CrossCut 1.0</DocumentSource>\n"
664 << " <visibility>1</visibility>\n"
665 << " <LookAt>\n"
666 << " <heading>0</heading>\n"
667 << " <tilt>45</tilt>\n"
668 << " <longitude>" << origin_lon << "</longitude>\n"
669 << " <latitude>" << origin_lat << "</latitude>\n"
670 << " <range>200</range>\n"
671 << " <altitude>" << 0.0f << "</altitude>\n"
672 << " </LookAt>\n"
673 << " <Folder>\n"
674 << " <name>Tour</name>\n"
675 << " <Placemark>\n"
676 << " <name>Camera</name>\n"
677 << " <visibility>1</visibility>\n"
678 << " </Placemark>\n"
679 << " </Folder>\n"
680 << " <Placemark>\n"
681 << " <name>Model</name>\n"
682 << " <description><![CDATA[]]></description>\n"
683 << " <Style id='default'>\n"
684 << " </Style>\n"
685 << " <Model>\n"
686 << " <altitudeMode>relativeToGround</altitudeMode>\n"
687 << " <Location>\n"
688 << " <longitude>" << origin_lon + lon_offset << "</longitude>\n"
689 << " <latitude>" << origin_lat + lat_offset << "</latitude>\n"
690 << " <altitude>" << origin_elev - ground_height << "</altitude>\n"
691 << " </Location>\n"
692 << " <Orientation>\n"
693 << " <heading>0</heading>\n"
694 << " <tilt>0</tilt>\n"
695 << " <roll>0</roll>\n"
696 << " </Orientation>\n"
697 << " <Scale>\n"
698 << " <x>1.0</x>\n"
699 << " <y>1.0</y>\n"
700 << " <z>1.0</z>\n"
701 << " </Scale>\n"
702 << " <Link>\n"
703 << " <href>models/mesh.dae</href>\n"
704 << " </Link>\n"
705 << " </Model>\n"
706 << " </Placemark>\n"
707 << "</Folder>\n"
708 << "</kml>\n";
709 }
710
clear()711 void bwm_world::clear()
712 {
713 world_pt_valid_ = false;
714 lvcs_valid_ = false;
715 objects_.clear();
716 }
717