1 //:
2 // \file
3 #include <sstream>
4 #include <iostream>
5 #include <cstdio>
6 #include <cstring>
7 #include <algorithm>
8 #include <cstddef>
9 #include "bkml_parser.h"
10 //
11 // \brief Parses the kml configuration file for bwm tool.
12 // \verbatim
13 //  Modifications
14 //   2012-09-10 Yi Dong - Modified to parser the polygon and path(LineString) coordinates stored in kml
15 // \endverbatim
16 //
17 #ifdef _MSC_VER
18 #  include "vcl_msvc_warnings.h"
19 #endif
20 
21 // --------------
22 // --- PARSER ---
23 // --------------
24 template <typename T>
convert(const char * t,T & d)25 void convert(const char* t, T& d)
26 {
27   std::stringstream strm(t);
28   strm >> d;
29 }
30 
bkml_parser()31 bkml_parser::bkml_parser()
32 {
33   init_params();
34 }
35 
init_params()36 void bkml_parser::init_params()
37 {
38   heading_ = 0.0;
39   tilt_ = 0.0;
40   roll_ = 0.0;
41   right_fov_ = 0.0;
42   top_fov_ = 0.0;
43   near_ = 0.0;
44   heading_dev_ = 0.0;
45   tilt_dev_ = 0.0;
46   roll_dev_ = 0.0;
47   right_fov_dev_ = 0.0;
48   top_fov_dev_ = 0.0;
49 }
50 
51 void
cdataHandler(const std::string &,const std::string &)52 bkml_parser ::cdataHandler(const std::string&  /*name*/, const std::string&  /*data*/)
53 {
54 }
55 
56 void
handleAtts(const XML_Char **)57 bkml_parser::handleAtts(const XML_Char** /*atts*/)
58 {
59 }
60 
61 
62 void
startElement(const char * name,const char **)63 bkml_parser::startElement(const char* name, const char**  /*atts*/)
64 {
65   if (std::strcmp(name, KML_LON_TAG) == 0) {
66     last_tag = KML_LON_TAG;
67   }
68   else if (std::strcmp(name, KML_LAT_TAG) == 0) {
69     last_tag = KML_LAT_TAG;
70   }
71   else if (std::strcmp(name, KML_ALT_TAG) == 0) {
72     last_tag = KML_ALT_TAG;
73   }
74   else if (std::strcmp(name, KML_HEAD_TAG) == 0 ) {
75     last_tag = KML_HEAD_TAG;
76   }
77   else if (std::strcmp(name, KML_HEAD_DEV_TAG) == 0 ) {
78     last_tag = KML_HEAD_DEV_TAG;
79   }
80   else if (std::strcmp(name, KML_TILT_TAG) == 0 ) {
81     last_tag = KML_TILT_TAG;
82   }
83   else if (std::strcmp(name, KML_TILT_DEV_TAG) == 0 ) {
84     last_tag = KML_TILT_DEV_TAG;
85   }
86   else if (std::strcmp(name, KML_ROLL_TAG) == 0 ) {
87     last_tag = KML_ROLL_TAG;
88   }
89   else if (std::strcmp(name, KML_ROLL_DEV_TAG) == 0 ) {
90     last_tag = KML_ROLL_DEV_TAG;
91   }
92   else if (std::strcmp(name, KML_RFOV_TAG) == 0) {
93     last_tag = KML_RFOV_TAG;
94   }
95   else if (std::strcmp(name, KML_RFOV_DEV_TAG) == 0 ) {
96     last_tag = KML_RFOV_DEV_TAG;
97   }
98   else if (std::strcmp(name, KML_TFOV_TAG) == 0) {
99     last_tag = KML_TFOV_TAG;
100   }
101   else if (std::strcmp(name, KML_TFOV_DEV_TAG) == 0) {
102     last_tag = KML_TFOV_DEV_TAG;
103   }
104   else if (std::strcmp(name, KML_NEAR_TAG) == 0) {
105     last_tag = KML_NEAR_TAG;
106   }
107   else if (std::strcmp(name, KML_CORD_TAG) == 0 && (cord_tag_ != "") ) {
108     last_tag = KML_CORD_TAG;
109   }
110   else if (std::strcmp(name, KML_PLACEMARK_NAME_TAG) == 0) {
111     last_tag = KML_PLACEMARK_NAME_TAG;
112   }
113   else if (std::strcmp(name, KML_POLYOB_TAG) == 0) {
114     cord_tag_ = KML_POLYOB_TAG;
115   }
116   else if (std::strcmp(name, KML_POLYIB_TAG) == 0) {
117     cord_tag_ = KML_POLYIB_TAG;
118   }
119   else if (std::strcmp(name, KML_LINE_TAG) == 0) {
120     cord_tag_ = KML_LINE_TAG;
121   }
122   else if (std::strcmp(name, KML_POINT_TAG) == 0) {
123     cord_tag_ = KML_POINT_TAG;
124   }
125   /*else if (std::strcmp(name, KML_COORDS_TAG) == 0) {
126   last_tag = KML_COORDS_TAG;
127   }
128   else if (std::strcmp(name, KML_PLACEMARK_NAME_TAG) == 0) {
129   last_tag = KML_PLACEMARK_NAME_TAG;
130   }*/
131 }
132 
133 
134 void
endElement(const char *)135 bkml_parser::endElement(const char*  /*name*/)
136 {
137 }
138 
charData(const XML_Char * s,int len)139 void bkml_parser::charData(const XML_Char* s, int len)
140 {
141   const int leadingSpace = skipWhiteSpace(s);
142   if (len==0 || len<=leadingSpace)
143     return;  // called with whitespace between elements
144   if (last_tag == KML_LON_TAG) {
145     std::stringstream str;
146     for (int i =0; i<len; ++i)
147       str << s[i];
148     str >> longitude_;
149     last_tag = "";
150   }
151   else if (last_tag == KML_LAT_TAG) {
152     std::stringstream str;
153     for (int i =0; i<len; ++i)
154       str << s[i];
155     str >> latitude_;
156     last_tag = "";
157   }
158   else if (last_tag == KML_PLACEMARK_NAME_TAG) {
159     std::stringstream str;
160     for (int i =0; i<len; ++i)
161       str << s[i];
162     current_name_ = str.str();
163     last_tag = "";
164   }
165   /*else if (last_tag == KML_COORDS_TAG) {
166     if (current_name_.compare("Camera Ground Truth") == 0) {
167       std::stringstream str;
168       for (int i =0; i<len; ++i) {
169         if (s[i] == ',')
170           str << ' ';
171         else
172           str << s[i];
173       }
174       str >> longitude_ >> latitude_;
175     }
176     last_tag = "";
177   }
178   else if (last_tag == KML_PLACEMARK_NAME_TAG) {
179     std::stringstream str;
180     for (int i =0; i<len; ++i)
181       str << s[i];
182     current_name_ = str.str();
183     last_tag = "";
184   }*/
185   else if (last_tag == KML_ALT_TAG) {
186     std::stringstream str;
187     for (int i =0; i<len; ++i)
188       str << s[i];
189     str >> altitude_;
190     last_tag = "";
191   }
192   else if (last_tag == KML_HEAD_TAG) {
193     std::stringstream str;
194     for (int i =0; i<len; ++i)
195       str << s[i];
196     str >> heading_;
197     last_tag = "";
198   }
199   else if (last_tag == KML_HEAD_DEV_TAG) {
200     std::stringstream str;
201     for (int i = 0; i < len; i++)
202       str << s[i];
203     str >> heading_dev_;
204     last_tag = "";
205   }
206   else if (last_tag == KML_TILT_TAG) {
207     std::stringstream str;
208     for (int i =0; i<len; ++i)
209       str << s[i];
210     str >> tilt_;
211     last_tag = "";
212   }
213   else if (last_tag == KML_TILT_DEV_TAG) {
214     std::stringstream str;
215     for (int i = 0; i < len; i++)
216       str << s[i];
217     str >> tilt_dev_;
218     last_tag = "";
219   }
220   else if (last_tag == KML_ROLL_TAG) {
221     std::stringstream str;
222     for (int i =0; i<len; ++i)
223       str << s[i];
224     str >> roll_;
225     last_tag = "";
226   }
227   else if (last_tag == KML_ROLL_DEV_TAG) {
228     std::stringstream str;
229     for (int i = 0; i < len; i++)
230       str << s[i];
231     str >> roll_dev_;
232     last_tag = "";
233   }
234   else if (last_tag == KML_RFOV_TAG) {
235     std::stringstream str;
236     for (int i =0; i<len; ++i)
237       str << s[i];
238     str >> right_fov_;
239     last_tag = "";
240   }
241   else if (last_tag == KML_RFOV_DEV_TAG) {
242     std::stringstream str;
243     for (int i = 0; i < len; i++)
244       str << s[i];
245     str >> right_fov_dev_;
246     last_tag = "";
247   }
248   else if (last_tag == KML_TFOV_TAG) {
249     std::stringstream str;
250     for (int i =0; i<len; ++i)
251       str << s[i];
252     str >> top_fov_;
253     last_tag = "";
254   }
255   else if (last_tag == KML_TFOV_DEV_TAG) {
256     std::stringstream str;
257     for (int i = 0; i < len; ++i)
258       str << s[i];
259     str >> top_fov_dev_;
260     last_tag = "";
261   }
262   else if (last_tag == KML_NEAR_TAG) {
263     std::stringstream str;
264     for (int i =0; i<len; ++i)
265       str << s[i];
266     str >> near_;
267     last_tag = "";
268   }
269   else if (last_tag == KML_CORD_TAG) {
270     std::stringstream str;
271     double x,y,z;
272     std::string str_s;
273     str_s = s;
274     std::size_t cord_end = str_s.find(KML_POLYCORE_END_TAG);
275     if (str_s[len] == '<')
276       cord_end = len;
277     else {
278       while (str_s[cord_end] != '\n')
279         cord_end--;
280       while (str_s[cord_end-1] == ' ')
281         cord_end--;
282     }
283 
284     for (unsigned int i=0; i<cord_end; ++i)
285       str << s[i];
286     std::vector<vgl_point_3d<double> > poly_verts;
287     while (!str.eof()) {
288       str >> x;
289       str.ignore();
290       str >> y;
291       str.ignore();
292       str >> z;
293       str.ignore(128, ' ');
294       vgl_point_3d<double> vpt(x,y,z);
295       // check whether same point exists inside the poly_verts already
296       if (std::find(poly_verts.begin(), poly_verts.end(), vpt) == poly_verts.end())
297         poly_verts.push_back(vpt);
298       //else
299       //  std::cout << "WARNING: duplicated point: "
300       //           << x << ", " << y << ", " << z << " exists in polygon coordinates and is ignored" << std::endl;
301       //if (cord_tag_ == KML_POLYOB_TAG)
302       //  poly_verts.push_back(vpt);
303       //else if (cord_tag_ == KML_POLYIB_TAG)
304       //  poly_verts.push_back(vpt);
305       //else if (cord_tag_ == KML_LINE_TAG)
306       //  poly_verts.push_back(vpt);
307       //else {
308       //  std::cout << "WARNING: shape tag can not be recognized (not LineString or Polygon)" << std::endl;
309       //}
310     }
311     if (cord_tag_ == KML_POLYOB_TAG)
312       polyouter_.push_back(poly_verts);
313     else if (cord_tag_ == KML_POLYIB_TAG)
314       polyinner_.push_back(poly_verts);
315     else if (cord_tag_ == KML_LINE_TAG)
316       linecord_.push_back(poly_verts);
317     else if (cord_tag_ == KML_POINT_TAG )
318       points_.push_back(poly_verts[0]);
319     else
320       std::cout << "WARNING: shape tag: " << cord_tag_ << " will not be parsed" << std::endl;
321     last_tag = "";
322     cord_tag_ = "";
323   }
324 }
325 
trim_string(std::string & s)326 void bkml_parser::trim_string(std::string& s)
327 {
328   int i = (int)s.find_first_not_of(' ');
329   int j = (int)s.find_last_not_of(' ');
330   std::string t = s.substr(i,j-i+1);
331   s = t;
332 }
333 
parse_points(const std::string & kml_file)334 std::vector<vgl_point_3d<double> > bkml_parser::parse_points(const std::string& kml_file)
335 {
336   auto* parser = new bkml_parser();
337   std::vector<vgl_point_3d<double> > out;
338   std::FILE* xmlFile = std::fopen(kml_file.c_str(), "r");
339   if (!xmlFile) {
340     std::cerr << kml_file.c_str() << " error on opening the input kml file\n";
341     delete parser;
342     return out;
343   }
344   if (!parser->parseFile(xmlFile)) {
345     std::cerr << XML_ErrorString(parser->XML_GetErrorCode()) << " at line "
346              << parser->XML_GetCurrentLineNumber() << '\n';
347     delete parser;
348     return out;
349   }
350   // return the points retrieved from kml
351   return parser->points_;
352 }
353 
354 //: the returned polygon only contains outer boundary
parse_polygon(const std::string & poly_kml_file)355 vgl_polygon<double> bkml_parser::parse_polygon(const std::string& poly_kml_file)
356 {
357   auto* parser = new bkml_parser();
358   vgl_polygon<double> out;
359   std::FILE* xmlFile = std::fopen(poly_kml_file.c_str(), "r");
360   if (!xmlFile) {
361     std::cerr << poly_kml_file.c_str() << " error on opening the input kml file\n";
362     delete parser;
363     return out;
364   }
365   if (!parser->parseFile(xmlFile)) {
366     std::cerr << XML_ErrorString(parser->XML_GetErrorCode()) << " at line "
367              << parser->XML_GetCurrentLineNumber() << '\n';
368     delete parser;
369     return out;
370   }
371   // create polygon from parser
372   if (parser->polyouter_.empty()) {
373     std::cerr << "input kml has no polygon outerboundary, return an empty polygon" << '\n';
374     delete parser;
375     return out;
376   }
377   for (auto & sh_idx : parser->polyouter_) {
378     out.new_sheet();
379     auto n_points = (unsigned)sh_idx.size();
380     for (unsigned pt_idx = 0; pt_idx < n_points; pt_idx++) {
381       out.push_back(sh_idx[pt_idx].x(), sh_idx[pt_idx].y());
382     }
383   }
384   return out;
385 }
386 
parse_polygon_with_inner(const std::string & poly_kml_file,vgl_polygon<double> & outer,vgl_polygon<double> & inner,unsigned & n_out,unsigned & n_in)387 vgl_polygon<double> bkml_parser::parse_polygon_with_inner(const std::string& poly_kml_file, vgl_polygon<double>& outer, vgl_polygon<double>& inner,
388                                                           unsigned& n_out, unsigned& n_in)
389 {
390   auto* parser = new bkml_parser();
391   vgl_polygon<double> out;
392   out.clear();
393   outer.clear();
394   inner.clear();
395   std::FILE* xmlFile = std::fopen(poly_kml_file.c_str(), "r");
396   if (!xmlFile) {
397     std::cerr << poly_kml_file.c_str() << " error on opening the input kml file\n";
398     delete parser;
399     return out;
400   }
401   if (!parser->parseFile(xmlFile)) {
402     std::cerr << XML_ErrorString(parser->XML_GetErrorCode()) << " at line "
403              << parser->XML_GetCurrentLineNumber() << '\n';
404     delete parser;
405     return out;
406   }
407   // create polygon from parser
408   n_out = (unsigned)parser->polyouter_.size();
409   n_in = (unsigned)parser->polyinner_.size();
410   // load the outer boundary
411   for (unsigned sh_idx = 0; sh_idx < n_out; sh_idx++) {
412     out.new_sheet();
413     outer.new_sheet();
414     auto n_points = (unsigned)parser->polyouter_[sh_idx].size();
415     for (unsigned pt_idx = 0; pt_idx < n_points; pt_idx++) {
416       out.push_back(parser->polyouter_[sh_idx][pt_idx].x(), parser->polyouter_[sh_idx][pt_idx].y());
417       outer.push_back(parser->polyouter_[sh_idx][pt_idx].x(), parser->polyouter_[sh_idx][pt_idx].y());
418     }
419   }
420   // load the inner boundary
421   for (unsigned sh_idx = 0; sh_idx < n_in; sh_idx++) {
422     out.new_sheet();
423     inner.new_sheet();
424     auto n_points = (unsigned)parser->polyinner_[sh_idx].size();
425     for (unsigned pt_idx = 0; pt_idx < n_points; pt_idx++) {
426       out.push_back(parser->polyinner_[sh_idx][pt_idx].x(), parser->polyinner_[sh_idx][pt_idx].y());
427       inner.push_back(parser->polyinner_[sh_idx][pt_idx].x(), parser->polyinner_[sh_idx][pt_idx].y());
428     }
429   }
430   return out;
431 }
432 
parse_location_from_kml(const std::string & kml_file,double & lat,double & lon)433 bool bkml_parser::parse_location_from_kml(const std::string& kml_file, double& lat, double& lon)
434 {
435   auto* parser = new bkml_parser();
436   std::FILE* xmlFile = std::fopen(kml_file.c_str(), "r");
437   if(!xmlFile) {
438     std::cerr << kml_file.c_str() << " error on opening the input kml file\n";
439     delete parser;
440     return false;
441   }
442   if(!parser->parseFile(xmlFile)){
443     std::cerr << XML_ErrorString(parser->XML_GetErrorCode()) << " at line "
444              << parser->XML_GetCurrentLineNumber() << '\n';
445     delete parser;
446     return false;
447   }
448   lat = parser->latitude_;
449   lon = parser->longitude_;
450   return true;
451 }
452