1 //:
2 // \file
3 // \brief  executable to take a polygonal ROI and cover it with bvxm scenes with different lvcs's
4 //
5 // \author Ozge C. Ozcanli
6 // \date August 22, 2013
7 // \verbatim
8 //  Modifications
9 //   Yi Dong         Feb-2014   modify it to use geo coordinated geo_index leaf size to define the scene size
10 // \endverbatim
11 //
12 #include <iostream>
13 #include <volm/volm_tile.h>
14 #ifdef _MSC_VER
15 #  include "vcl_msvc_warnings.h"
16 #endif
17 #include <volm/volm_osm_objects.h>
18 #include <volm/volm_geo_index2.h>
19 #include <volm/volm_io.h>
20 #include <volm/volm_io_tools.h>
21 #include "vul/vul_file.h"
22 #include "vul/vul_arg.h"
23 #include <vcl_where_root_dir.h>
24 #include "vpgl/vpgl_lvcs.h"
25 #include <bkml/bkml_parser.h>
26 #include <volm/volm_loc_hyp_sptr.h>
27 #include <bvxm/bvxm_world_params.h>
28 #include <bkml/bkml_write.h>
29 #include "vpgl/vpgl_utm.h"
30 
31 
main(int argc,char ** argv)32 int main(int argc, char** argv)
33 {
34   // input
35   vul_arg<std::string> in_folder("-in", "input folder to read DEM files as .tif", "");
36   vul_arg<std::string> in_poly("-poly", "region polygon as kml, the scenes that cover this polygon will be created", "");
37   vul_arg<std::string> out_folder("-out", "folder to write xml files","");
38   vul_arg<std::string> lvcs_root("-lvcs", "folder to write lvcs files","");
39   vul_arg<std::string> world_root("-world_dir", "the world folder where bvxm vox binary will be stored","");
40   vul_arg<float> voxel_size("-vox", "size of voxel in meters", 1.0f);
41   vul_arg<float> world_size_input("-size", "the size of the world in meters", 500.0f);
42   vul_arg<float> height("-height", "the amount to be added on top of the terrain height to create the scene in meters", 0.0f);
43 
44   vul_arg_parse(argc, argv);
45 
46   // check input
47   if (in_folder().compare("") == 0 || in_poly().compare("") == 0 || out_folder().compare("") == 0 || world_root().compare("") == 0) {
48     std::cerr << " ERROR: input is missing!\n";
49     vul_arg_display_usage_and_exit();
50     return volm_io::EXE_ARGUMENT_ERROR;
51   }
52 
53   std::string lvcs_folder;
54   if (lvcs_root() == "")
55     lvcs_folder = out_folder();
56   else
57     lvcs_folder = lvcs_root();
58 
59   vgl_polygon<double> poly = bkml_parser::parse_polygon(in_poly());
60   std::cout << "outer poly  has: " << poly[0].size() << std::endl;
61 
62   // find the bbox of ROI from its polygon
63   vgl_box_2d<double> bbox_rect;
64   for (auto i : poly[0]) {
65     bbox_rect.add(i);
66   }
67   double square_size = (bbox_rect.width() >= bbox_rect.height()) ? bbox_rect.width() : bbox_rect.height();
68   vgl_box_2d<double> bbox(bbox_rect.min_point(), square_size, square_size, vgl_box_2d<double>::min_pos);
69 
70   // truncate the world size from voxel size
71   double world_size = (unsigned)std::ceil(world_size_input()/voxel_size())*(double)voxel_size();
72 
73   // from defined world size, calculate the min_size of the geoindex
74   vgl_point_2d<double> ll(bbox_rect.min_x(), bbox_rect.min_y());
75   vgl_point_2d<double> ur(bbox_rect.max_x(), bbox_rect.max_y());
76   vpgl_lvcs_sptr lvcs_ll = new vpgl_lvcs(ll.y(), ll.x(), 0.0, vpgl_lvcs::wgs84, vpgl_lvcs::DEG, vpgl_lvcs::METERS);
77   vpgl_lvcs_sptr lvcs_ur = new vpgl_lvcs(ur.y(), ur.x(), 0.0, vpgl_lvcs::wgs84, vpgl_lvcs::DEG, vpgl_lvcs::METERS);
78 
79   double scale_ll_x, scale_ll_y, gz;
80   lvcs_ll->local_to_global(world_size, world_size, 0.0, vpgl_lvcs::wgs84, scale_ll_x, scale_ll_y, gz);
81   scale_ll_x -= ll.x();  scale_ll_y -= ll.y();
82   double scale_ur_x, scale_ur_y;
83   lvcs_ur->local_to_global(world_size, world_size, 0.0, vpgl_lvcs::wgs84, scale_ur_x, scale_ur_y, gz);
84   scale_ur_x -= ur.x();
85   scale_ur_y -= ur.y();
86   std::cout << " pre-defined world_size is " << world_size_input() << " and voxel size is " << voxel_size() << " actual world size is " << world_size << std::endl;
87   std::cout << " bounding box for input polygon: " << bbox_rect << " expending to square: " << bbox << std::endl;
88   std::cout << " ll: " << ll << " ---> " << " scale_x = " << scale_ll_x << " scale_y = " << scale_ll_y << std::endl;
89   std::cout << " ur: " << ur << " ---> " << " scale_x = " << scale_ur_x << " scale_y = " << scale_ur_y << std::endl;
90   std::set<double> scale_set;
91   scale_set.insert(scale_ur_x);  scale_set.insert(scale_ur_y);  scale_set.insert(scale_ll_x);  scale_set.insert(scale_ll_y);
92   double min_size = *scale_set.begin();
93   std::cout << " given maximum allowed world size " << world_size_input() << " the min_size for geo index is: " << min_size << std::endl;
94 
95   // create a geo index and use the leaves as scenes, use template param as volm_loc_hyp_sptr but it won't actually be used
96   volm_geo_index2_node_sptr root = volm_geo_index2::construct_tree<volm_loc_hyp_sptr>(bbox, min_size, poly);
97   std::string txt_filename = out_folder() + "/geo_index.txt";
98   volm_geo_index2::write(root, txt_filename, min_size);
99   std::string kml_filename = out_folder() + "/scene_geo_index.kml";
100   unsigned tree_depth = volm_geo_index2::depth(root);
101   //volm_geo_index2::write_to_kml(root, tree_depth, kml_filename);
102   std::vector<volm_geo_index2_node_sptr> leaves;
103   volm_geo_index2::get_leaves(root, leaves);
104   std::cout << "the geo-index quad tree for scene has " << leaves.size() << " leaves and depth is " << tree_depth << std::endl;
105 
106   // write to kml files with leaf ids (which will be used as scene ids)
107   std::ofstream ofs(kml_filename.c_str());
108   bkml_write::open_document(ofs);
109   for (unsigned i = 0; i < leaves.size(); i++) {
110     std::stringstream explanation; explanation << "scene_" << i;
111     volm_geo_index2::write_to_kml_node(ofs, leaves[i], 0, 0, explanation.str());
112   }
113   bkml_write::close_document(ofs);
114 
115   // load DEM images
116   std::vector<volm_img_info> infos;
117   volm_io_tools::load_aster_dem_imgs(in_folder(), infos);
118   std::cout << " loaded " << infos.size() << " DEM tiles!\n";
119 
120   // create scenes for each leaf, note the scene size is different
121   double largest_dif = 0;
122   for (unsigned i = 0; i < leaves.size(); i++) {
123     std::stringstream name;  name << out_folder() << "scene_" << i;
124     vgl_point_2d<double> lower_left = leaves[i]->extent_.min_point();
125     vgl_point_2d<double> upper_right = leaves[i]->extent_.max_point();
126     // find the maximum elevation difference
127     double min = 10000.0, max = -10000.0;
128     if (!volm_io_tools::find_min_max_height(lower_left, upper_right, infos, min, max)) {
129       std::cerr << " problems in the leaf: " << lower_left << " " << upper_right << " - cannot find height!\n";
130       return volm_io::EXE_ARGUMENT_ERROR;
131     }
132     double dif = max-min;
133     if (dif > largest_dif) largest_dif = dif;
134     //construct lvcs
135     vpgl_lvcs_sptr lvcs = new vpgl_lvcs(lower_left.y(), lower_left.x(), min, vpgl_lvcs::wgs84, vpgl_lvcs::DEG, vpgl_lvcs::METERS);
136     std::stringstream name_lvcs;  name_lvcs << lvcs_folder << "/scene_" << i;
137     std::string lvcs_name = name_lvcs.str() + ".lvcs";
138     std::ofstream ofs(lvcs_name.c_str());
139     if (!ofs) {
140       std::cerr << "Cannot open file: " << lvcs_name << "!\n";
141       return volm_io::EXE_ARGUMENT_ERROR;
142     }
143     lvcs->write(ofs);
144     ofs.close();
145 
146     // create scene based on leaf size in lat/lon
147     vgl_point_3d<float> corner(0.0f, 0.0f, 0.0f);
148     double lx, ly, lz;
149     lvcs->global_to_local(upper_right.x(), upper_right.y(), height()+max, vpgl_lvcs::wgs84, lx, ly, lz);
150     auto dim_x = (unsigned)std::ceil(lx/voxel_size());
151     auto dim_y = (unsigned)std::ceil(ly/voxel_size());
152     auto dim_z = (unsigned)std::ceil(height()+dif);
153     vgl_vector_3d<unsigned> num_voxels(dim_x, dim_y, dim_z);
154     bvxm_world_params params;
155     std::stringstream world_dir;
156     world_dir << world_root() << "/scene_" << i;
157     if (!vul_file::is_directory(world_dir.str()))
158       vul_file::make_directory(world_dir.str());
159     params.set_params(world_dir.str(), corner, num_voxels, voxel_size(), lvcs);
160     std::string xml_name = name.str() + ".xml";
161     params.write_xml(xml_name, lvcs_name);
162   }
163 
164   std::cout << "largest height difference in the whole ROI is: " << largest_dif << std::endl;
165 
166 
167 #if 0
168 
169 
170   std::vector<volm_img_info> infos;
171   volm_io_tools::load_aster_dem_imgs(in_folder(), infos);
172   std::cout << " loaded " << infos.size() << " DEM tiles!\n";
173 
174   double largest_dif = 0;
175   for (unsigned i = 0; i < leaves.size(); i++) {
176     std::stringstream name; name << out_folder() << "scene_" << i ;
177     //std::cout << name.str() << std::endl;
178     //vul_file::make_directory(dir);
179     vgl_point_2d<double> lower_left = leaves[i]->extent_.min_point();
180     vgl_point_2d<double> upper_right = leaves[i]->extent_.max_point();
181 
182     double min = 10000.0, max = -10000.0;
183     if (!volm_io_tools::find_min_max_height(lower_left, upper_right, infos, min, max)) {
184       std::cerr << " problems in the leaf: " << lower_left << " " << upper_right << " - cannot find height!\n";
185       return volm_io::EXE_ARGUMENT_ERROR;
186     }
187     double dif = max-min;
188     if (dif > largest_dif) largest_dif = dif;
189     //std::cout << "min: " << min << " " << max << "\n";
190 
191     //construct lvcs
192     vpgl_lvcs_sptr lvcs = new vpgl_lvcs(lower_left.y(), lower_left.x(), min, vpgl_lvcs::wgs84, vpgl_lvcs::DEG, vpgl_lvcs::METERS);
193     std::string lvcs_name = name.str() + ".lvcs";
194     std::ofstream ofs(lvcs_name.c_str());
195     if (!ofs) {
196       std::cerr << "Cannot open file: " << lvcs_name << "!\n";
197       return volm_io::EXE_ARGUMENT_ERROR;
198     }
199     lvcs->write(ofs);
200     ofs.close();
201 
202     vgl_point_3d<float> corner(0,0,0);
203     unsigned dim_xy = (unsigned)std::ceil(world_size()/voxel_size());
204     unsigned dim_z = (unsigned)std::ceil(dif+height());
205     vgl_vector_3d<unsigned int> num_voxels(dim_xy, dim_xy, dim_z);
206     bvxm_world_params params;
207     //params.set_params(name.str(), corner, num_voxels, voxel_size(), lvcs);
208     //params.set_params(out_folder().substr(0, out_folder().size()-1), corner, num_voxels, voxel_size(), lvcs);  // for now set model dir as out_folder
209     // set bvxm_scene world parameters
210     std::stringstream world_dir;
211     world_dir << world_root() << "/scene_" << i;
212     if (!vul_file::is_directory(world_dir.str())) {
213       vul_file::make_directory(world_dir.str());
214     }
215     params.set_params(world_dir.str(), corner, num_voxels, voxel_size(), lvcs);   // the world dir is now different from the out_folder where scene.xml and scene.lvcs stores
216     std::string xml_name = name.str() + ".xml";
217     params.write_xml(xml_name, lvcs_name);
218   }
219 
220   std::cout << "largest height difference in the whole ROI is: " << largest_dif << '\n';
221 
222 #endif
223   return volm_io::SUCCESS;
224 }
225