1 /******************************************************************************
2 * $Id: chartcatalog.cpp,v 1.0 2011/02/26 01:54:37 nohal Exp $
3 *
4 * Project: OpenCPN
5 * Purpose: Chart downloader Plugin
6 * Author: Pavel Kalian
7 *
8 ***************************************************************************
9 * Copyright (C) 2011 by Pavel Kalian *
10 * $EMAIL$ *
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program; if not, write to the *
24 * Free Software Foundation, Inc., *
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
26 ***************************************************************************
27 */
28
29 #include "chartcatalog.h"
30 #include <wx/tokenzr.h>
31
32 #include <wx/arrimpl.cpp>
33 //WX_DEFINE_OBJARRAY(wxArrayOfNoticeToMariners);
34 WX_DEFINE_OBJARRAY(wxArrayOfVertexes);
35 WX_DEFINE_OBJARRAY(wxArrayOfPanels);
36 WX_DEFINE_OBJARRAY(wxArrayOfCharts);
37
38
39 // Chart Catalog implementation
LoadFromFile(wxString path,bool headerOnly)40 bool ChartCatalog::LoadFromFile( wxString path, bool headerOnly )
41 {
42 dt_valid = wxInvalidDateTime; // Invalidate all dates
43 date_created = dt_valid; // so dates of one catalog
44 time_created = dt_valid; // don't propagate into another
45 date_valid = dt_valid;
46 title = _("Catalog is not valid."); // Invalidate the title in case we read a bad file
47 if( !wxFileExists(path) )
48 return false;
49
50 pugi::xml_document *doc = new pugi::xml_document;
51 bool ret = doc->load_file( path.mb_str() );
52 if (ret)
53 ret = LoadFromXml( doc, headerOnly );
54 else
55 charts.Clear();
56
57 wxDELETE(doc);
58
59 return ret;
60 }
61
ChartCatalog()62 ChartCatalog::ChartCatalog()
63 {
64 }
65
~ChartCatalog()66 ChartCatalog::~ChartCatalog()
67 {
68 }
69
GetReleaseDate()70 wxDateTime ChartCatalog::GetReleaseDate()
71 {
72 if( !dt_valid.IsValid() )
73 {
74 // date-time was invalid so we will create it from time_created and date_created
75 // If they are not valid then we return an invalid date for debugging purposes
76 if ( date_created.IsValid() && time_created.IsValid() )
77 {
78 dt_valid.ParseDate(date_created.FormatDate());
79 dt_valid.ParseTime(time_created.FormatTime());
80 dt_valid.MakeFromTimezone(wxDateTime::UTC);
81 }
82 }
83 wxASSERT(dt_valid.IsValid());
84 return dt_valid;
85 }
86
LoadFromXml(pugi::xml_document * doc,bool headerOnly)87 bool ChartCatalog::LoadFromXml( pugi::xml_document * doc, bool headerOnly )
88 {
89 pugi::xml_node root = doc->first_child();
90
91 wxString rootName = wxString::FromUTF8( root.name() );
92 charts.Clear();
93 if( rootName.StartsWith( _T("RncProductCatalog") ) )
94 {
95 if( !ParseNoaaHeader(root.first_child()) )
96 {
97 return false;
98 }
99 if (headerOnly)
100 return true;
101
102 for (pugi::xml_node element = root.first_child(); element; element = element.next_sibling()){
103 if( !strcmp(element.name(), "chart") ){
104 charts.Add(new RasterChart(element));
105 }
106 }
107 }
108 else if( rootName.StartsWith( _T("EncProductCatalog") ) )
109 {
110 if( !ParseNoaaHeader(root.first_child()) )
111 {
112 return false;
113 }
114 if (headerOnly)
115 return true;
116
117 for (pugi::xml_node element = root.first_child(); element; element = element.next_sibling()){
118 if( !strcmp(element.name(), "cell") ){
119 charts.Add(new EncCell(element));
120 }
121 }
122 }
123 // "IENCBuoyProductCatalog" and "IENCSouthwestPassProductCatalog" added by .Paul.
124 else if( rootName.StartsWith(_T("IENCU37ProductCatalog")) ||
125 rootName.StartsWith(_T("IENCBuoyProductCatalog")) ||
126 rootName.StartsWith(_T("IENCSouthwestPassProductCatalog")) )
127 {
128 if( !ParseNoaaHeader(root.first_child()) )
129 {
130 return false;
131 }
132 if( headerOnly )
133 return true;
134
135 for (pugi::xml_node element = root.first_child(); element; element = element.next_sibling()){
136 if( !strcmp(element.name(), "Cell") ){
137 charts.Add(new IEncCell(element));
138 }
139 }
140 }
141 else
142 {
143 return false;
144 }
145
146 return true;
147 }
148
ParseNoaaHeader(const pugi::xml_node & xmldata)149 bool ChartCatalog::ParseNoaaHeader( const pugi::xml_node &xmldata )
150 {
151 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
152 if( !strcmp(element.name(), "title") ){
153 title = wxString::FromUTF8(element.first_child().value());
154 }
155 else if( !strcmp(element.name(), "date_created")) {
156 date_created.ParseDate( wxString::FromUTF8(element.first_child().value()) );
157 wxASSERT(date_created.IsValid());
158 }
159 else if( !strcmp(element.name(), "time_created")) {
160 time_created.ParseTime( wxString::FromUTF8(element.first_child().value()) );
161 wxASSERT(time_created.IsValid());
162 }
163 else if( !strcmp(element.name(), "date_valid")) {
164 date_valid.ParseDate( wxString::FromUTF8(element.first_child().value()) );
165 wxASSERT(time_created.IsValid());
166 }
167 else if( !strcmp(element.name(), "time_valid")) {
168 time_valid.ParseTime( wxString::FromUTF8(element.first_child().value()) );
169 wxASSERT(time_created.IsValid());
170 }
171 else if( !strcmp(element.name(), "dt_valid")) {
172 wxStringTokenizer tk( wxString::FromUTF8(element.first_child().value()), _T("TZ") );
173 dt_valid.ParseDate(tk.GetNextToken());
174 dt_valid.ParseTime(tk.GetNextToken());
175 dt_valid.MakeFromTimezone(wxDateTime::UTC);
176 wxASSERT(dt_valid.IsValid());
177 }
178 else if( !strcmp(element.name(), "ref_spec")) {
179 ref_spec = wxString::FromUTF8(element.first_child().value());
180 }
181 else if( !strcmp(element.name(), "ref_spec_vers")) {
182 ref_spec_vers = wxString::FromUTF8(element.first_child().value());
183 }
184 else if( !strcmp(element.name(), "s62AgencyCode")) {
185 s62AgencyCode = wxString::FromUTF8(element.first_child().value());
186 }
187
188 }
189
190 return true;
191 }
192
~Chart()193 Chart::~Chart()
194 {
195 coast_guard_districts->Clear();
196 wxDELETE(coast_guard_districts);
197 states->Clear();
198 wxDELETE(states);
199 regions->Clear();
200 wxDELETE(regions);
201 wxDELETE(nm);
202 wxDELETE(lnm);
203 }
204
Chart(pugi::xml_node & xmldata)205 Chart::Chart( pugi::xml_node &xmldata )
206 {
207 coast_guard_districts = new wxArrayString();
208 states = new wxArrayString();
209 regions = new wxArrayString();
210 target_filename = wxEmptyString;
211 reference_file = wxEmptyString;
212 manual_download_url = wxEmptyString;
213 title = wxEmptyString;
214 zipfile_location = wxEmptyString;
215 zipfile_size = -1;
216 zipfile_datetime = wxInvalidDateTime;
217 zipfile_datetime_iso8601 = wxInvalidDateTime;
218 nm = NULL;
219 lnm = NULL;
220
221 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
222 if( !strcmp(element.name(), "title")) {
223 title = wxString::FromUTF8(element.first_child().value());
224 }
225 else if( !strcmp(element.name(), "lname")) {
226 title = wxString::FromUTF8(element.first_child().value());
227 }
228 else if( !strcmp(element.name(), "coast_guard_districts")) {
229 for (pugi::xml_node subElement = element.first_child(); subElement; subElement = subElement.next_sibling()){
230 coast_guard_districts->Add( wxString::FromUTF8(subElement.first_child().value()) );
231 }
232 }
233 else if( !strcmp(element.name(), "states")) {
234 for (pugi::xml_node subElement = element.first_child(); subElement; subElement = subElement.next_sibling()){
235 states->Add( wxString::FromUTF8(subElement.first_child().value()) );
236 }
237 }
238 else if( !strcmp(element.name(), "regions")) {
239 for (pugi::xml_node subElement = element.first_child(); subElement; subElement = subElement.next_sibling()){
240 regions->Add( wxString::FromUTF8(subElement.first_child().value()) );
241 }
242 }
243 else if( !strcmp(element.name(), "zipfile_location")) {
244 zipfile_location = wxString::FromUTF8(element.first_child().value());
245 }
246 else if( !strcmp(element.name(), "zipfile_datetime")) {
247 if( zipfile_datetime.ParseFormat(wxString::FromUTF8(element.first_child().value()), _T("%Y%m%d_%H%M%S")) )
248 zipfile_datetime.MakeFromTimezone(wxDateTime::UTC);
249 }
250 else if( !strcmp(element.name(), "zipfile_datetime_iso8601")) {
251 wxStringTokenizer tk(wxString::FromUTF8(element.first_child().value()), _T("TZ"));
252 zipfile_datetime_iso8601.ParseDate(tk.GetNextToken());
253 zipfile_datetime_iso8601.ParseTime(tk.GetNextToken());
254 zipfile_datetime_iso8601.MakeFromTimezone(wxDateTime::UTC);
255 }
256 else if( !strcmp(element.name(), "zipfile_size")) {
257 zipfile_size = wxAtoi(wxString::FromUTF8(element.first_child().value()));
258 }
259 else if( !strcmp(element.name(), "cov")) {
260 for (pugi::xml_node subElement = element.first_child(); subElement; subElement = subElement.next_sibling()){
261 coverage.Add(new Panel(subElement));
262 }
263 }
264 else if( !strcmp(element.name(), "target_filename")) {
265 target_filename = wxString::FromUTF8(element.first_child().value());
266 }
267 else if( !strcmp(element.name(), "reference_file")) {
268 reference_file = wxString::FromUTF8(element.first_child().value());
269 }
270 else if( !strcmp(element.name(), "manual_download_url")) {
271 manual_download_url = wxString::FromUTF8(element.first_child().value());
272 }
273 else if( !strcmp(element.name(), "nm")) {
274 // NOT USED
275 // nm = new NoticeToMariners(element);
276 }
277 else if( !strcmp(element.name(), "lnm")) {
278 // NOT USED
279 // lnm = new NoticeToMariners(element);
280 }
281 }
282 }
283
GetChartFilename(bool to_check)284 wxString Chart::GetChartFilename( bool to_check )
285 {
286 if( to_check && reference_file != wxEmptyString )
287 return reference_file;
288 if( target_filename != wxEmptyString )
289 return target_filename;
290 wxString file;
291 wxStringTokenizer tk(zipfile_location, _T("/"));
292 do
293 {
294 file = tk.GetNextToken();
295 } while(tk.HasMoreTokens());
296 return file;
297 }
298
RasterChart(pugi::xml_node & xmldata)299 RasterChart::RasterChart( pugi::xml_node &xmldata ) : Chart( xmldata )
300 {
301 number = wxEmptyString;
302 source_edition = -1;
303 raster_edition = -1;
304 ntm_edition = -1;
305 source_date = wxEmptyString;
306 ntm_date = wxEmptyString;
307 source_edition_last_correction = wxEmptyString;
308 raster_edition_last_correction = wxEmptyString;
309 ntm_edition_last_correction = wxEmptyString;
310
311 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
312 if( !strcmp(element.name(), "number")) {
313 number = wxString::FromUTF8(element.first_child().value());
314 }
315 else if( !strcmp(element.name(), "source_edition")) {
316 source_edition = wxAtoi(wxString::FromUTF8(element.first_child().value()));
317 }
318 else if( !strcmp(element.name(), "raster_edition")) {
319 raster_edition = wxAtoi(wxString::FromUTF8(element.first_child().value()));
320 }
321 else if( !strcmp(element.name(), "ntm_edition")) {
322 ntm_edition = wxAtoi(wxString::FromUTF8(element.first_child().value()));
323 }
324 else if( !strcmp(element.name(), "source_date")) {
325 source_date = wxString::FromUTF8(element.first_child().value());
326 }
327 else if( !strcmp(element.name(), "ntm_date")) {
328 ntm_date = wxString::FromUTF8(element.first_child().value());
329 }
330 else if( !strcmp(element.name(), "source_edition_last_correction")) {
331 source_edition_last_correction = wxString::FromUTF8(element.first_child().value());
332 }
333 else if( !strcmp(element.name(), "raster_edition_last_correction")) {
334 raster_edition_last_correction = wxString::FromUTF8(element.first_child().value());
335 }
336 else if( !strcmp(element.name(), "ntm_edition_last_correction")) {
337 ntm_edition_last_correction = wxString::FromUTF8(element.first_child().value());
338 }
339 }
340 }
341
EncCell(pugi::xml_node & xmldata)342 EncCell::EncCell( pugi::xml_node &xmldata ) : Chart( xmldata )
343 {
344 number = wxEmptyString; // Use number (not name) for zip file name and cell name .Paul.
345 src_chart = wxEmptyString;
346 cscale = -1;
347 status = wxEmptyString;
348 edtn = -1;
349 updn = -1;
350 uadt = wxInvalidDateTime;
351 isdt = wxInvalidDateTime;
352
353 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
354 if( !strcmp(element.name(), "name")) {
355 number = wxString::FromUTF8(element.first_child().value());
356 }
357 else if( !strcmp(element.name(), "src_chart")) {
358 src_chart = wxString::FromUTF8(element.first_child().value());
359 }
360 else if( !strcmp(element.name(), "cscale")) {
361 cscale = wxAtoi(wxString::FromUTF8(element.first_child().value()));
362 }
363 else if( !strcmp(element.name(), "status")) {
364 status = wxString::FromUTF8(element.first_child().value());
365 }
366 else if( !strcmp(element.name(), "edtn")) {
367 edtn = wxAtoi(wxString::FromUTF8(element.first_child().value()));
368 }
369 else if( !strcmp(element.name(), "updn")) {
370 updn = wxAtoi(wxString::FromUTF8(element.first_child().value()));
371 }
372 else if( !strcmp(element.name(), "uadt")) {
373 uadt.ParseDateTime(wxString::FromUTF8(element.first_child().value()));
374 }
375 else if( !strcmp(element.name(), "isdt")) {
376 isdt.ParseDateTime(wxString::FromUTF8(element.first_child().value()));
377 }
378 }
379 }
380
IEncCell(pugi::xml_node & xmldata)381 IEncCell::IEncCell( pugi::xml_node &xmldata ) : Chart( xmldata )
382 {
383 // Use number (not name) for zip file name and cell name .Paul.
384 number = wxEmptyString;
385 location = NULL;
386 river_name = wxEmptyString;
387 river_miles = NULL;
388 area = NULL;
389 edition = wxEmptyString;
390 shp_file = NULL;
391 s57_file = NULL;
392 kml_file = NULL;
393
394 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
395 if( !strcmp(element.name(), "name")) {
396 // Use number (not name) for zip file name and cell name .Paul.
397 number = wxString::FromUTF8(element.first_child().value());
398 zipfile_location = wxString::Format(_T("%s.zip"), number.c_str());
399 }
400 else if( !strcmp(element.name(), "location")) {
401 location = new Location(element);
402 }
403 else if( !strcmp(element.name(), "river_name")) {
404 river_name = wxString::FromUTF8(element.first_child().value());
405 }
406 else if( !strcmp(element.name(), "river_miles")) {
407 river_miles = new RiverMiles(element);
408 }
409 else if( !strcmp(element.name(), "river_miles")) {
410 river_miles = new RiverMiles(element);
411 }
412 else if( !strcmp(element.name(), "area")) {
413 area = new Area(element);
414 }
415 else if( !strcmp(element.name(), "shp_file")) {
416 shp_file = new ChartFile(element);
417 }
418 else if( !strcmp(element.name(), "s57_file")) {
419 s57_file = new ChartFile(element);
420 }
421 else if( !strcmp(element.name(), "kml_file")) {
422 kml_file = new ChartFile(element);
423 }
424 else if( !strcmp(element.name(), "edition")) {
425 edition = wxString::FromUTF8(element.first_child().value());
426 }
427 }
428 }
429
~IEncCell()430 IEncCell::~IEncCell()
431 {
432 wxDELETE(location);
433 wxDELETE(river_miles);
434 wxDELETE(area);
435 wxDELETE(shp_file);
436 wxDELETE(s57_file);
437 wxDELETE(kml_file);
438 }
439
GetChartTitle()440 wxString IEncCell::GetChartTitle()
441 // Revised by .Paul. to support IENC catalogs that do not identify rivers or river miles.
442 {
443 if( river_name != wxEmptyString )
444 {
445 // This formatting of river_name.c_str() ... river_miles->end works for "IENCU37ProductCatalog"
446 // where river_name is specified.
447 return wxString::Format(_("%s (%s to %s), river miles %3.1f - %3.1f"), river_name.c_str(), location->from.c_str(), location->to.c_str(), river_miles->begin, river_miles->end);
448 }
449 else
450 {
451 // Simply use the Cell_name for "IENCBuoyProductCatalog" or "IENCSouthwestPassProductCatalog"
452 // where river_name is not specified.
453 // Cell_name is in number.c_str() Cell_name was in name.c_str()
454 return wxString::Format(_("%s"), number.c_str());// .Paul.
455 }
456 }
457
GetDownloadLocation()458 wxString IEncCell::GetDownloadLocation()
459 {
460 return s57_file->location;
461 }
462
GetUpdateDatetime()463 wxDateTime IEncCell::GetUpdateDatetime()
464 {
465 return s57_file->date_posted;
466 }
467
ChartFile(pugi::xml_node & xmldata)468 ChartFile::ChartFile( pugi::xml_node &xmldata )
469 {
470 file_size = -1;
471 location = wxEmptyString;
472 date_posted = wxInvalidDateTime;
473 time_posted = wxInvalidDateTime;
474
475 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
476 if( !strcmp(element.name(), "location")) {
477 location = wxString::FromUTF8(element.first_child().value());
478 }
479 else if( !strcmp(element.name(), "date_posted")) {
480 date_posted.ParseDate(wxString::FromUTF8(element.first_child().value()));
481 }
482 else if( !strcmp(element.name(), "time_posted")) {
483 if(strlen(element.first_child().value()))
484 time_posted.ParseTime(wxString::FromUTF8(element.first_child().value()));
485 else
486 time_posted.ParseTime(_T("00:00:00"));
487 }
488 else if( !strcmp(element.name(), "file_size")) {
489 if(strlen(element.first_child().value()))
490 file_size = wxAtoi(wxString::FromUTF8(element.first_child().value()));
491 else
492 file_size = -1;
493 }
494 }
495 }
496
Area(pugi::xml_node & xmldata)497 Area::Area( pugi::xml_node &xmldata )
498 {
499 north = 0.0;
500 south = 0.0;
501 east = 0.0;
502 west = 0.0;
503
504 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
505 if( !strcmp(element.name(), "north")) {
506 north = wxAtof(wxString::FromUTF8(element.first_child().value()));
507 }
508 else if( !strcmp(element.name(), "south")) {
509 south = wxAtof(wxString::FromUTF8(element.first_child().value()));
510 }
511 else if( !strcmp(element.name(), "east")) {
512 east = wxAtof(wxString::FromUTF8(element.first_child().value()));
513 }
514 else if( !strcmp(element.name(), "west")) {
515 west = wxAtof(wxString::FromUTF8(element.first_child().value()));
516 }
517 }
518 }
519
RiverMiles(pugi::xml_node & xmldata)520 RiverMiles::RiverMiles( pugi::xml_node &xmldata )
521 {
522 begin = -1;
523 end = -1;
524 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
525 if( !strcmp(element.name(), "begin")) {
526 begin = wxAtof(wxString::FromUTF8(element.first_child().value()));
527 }
528 else if( !strcmp(element.name(), "end")) {
529 end = wxAtof(wxString::FromUTF8(element.first_child().value()));
530 }
531 }
532 }
533
Location(pugi::xml_node & xmldata)534 Location::Location( pugi::xml_node &xmldata )
535 {
536 from = wxEmptyString;
537 to = wxEmptyString;
538 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
539 if( !strcmp(element.name(), "from")) {
540 from = wxString::FromUTF8(element.first_child().value());
541 }
542 else if( !strcmp(element.name(), "to")) {
543 to = wxString::FromUTF8(element.first_child().value());
544 }
545 }
546 }
547
548
NoticeToMariners(pugi::xml_node & xmldata)549 NoticeToMariners::NoticeToMariners( pugi::xml_node &xmldata )
550 {
551 agency = wxEmptyString;
552 doc = wxEmptyString;
553 date = wxInvalidDateTime;
554
555 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
556 if( !strcmp(element.name(), "nm_agency")) {
557 agency = wxString::FromUTF8(element.first_child().value());
558 }
559 else if( !strcmp(element.name(), "lnm_agency")) {
560 agency = wxString::FromUTF8(element.first_child().value());
561 }
562 else if( !strcmp(element.name(), "doc")) {
563 doc = wxString::FromUTF8(element.first_child().value());
564 }
565 else if( !strcmp(element.name(), "date")) {
566 date.ParseDate(wxString::FromUTF8(element.first_child().value()));
567 }
568 }
569 }
570
Panel(pugi::xml_node & xmldata)571 Panel::Panel( pugi::xml_node &xmldata )
572 {
573 panel_no = -1;
574
575 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
576 if( !strcmp(element.name(), "panel_no")) {
577 panel_no = wxAtoi(wxString::FromUTF8(element.first_child().value()));
578 }
579 else if( !strcmp(element.name(), "vertex")) {
580 // NOT USED
581 //vertexes.Add(new Vertex(element));
582 }
583 }
584 }
585
~Panel()586 Panel::~Panel()
587 {
588 }
589
RncPanel(pugi::xml_node & xmldata)590 RncPanel::RncPanel( pugi::xml_node &xmldata ) : Panel( xmldata )
591 {
592 panel_title = wxEmptyString;
593 file_name = wxEmptyString;
594 scale = 0;
595
596 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
597 if( !strcmp(element.name(), "panel_title")) {
598 panel_title = wxString::FromUTF8(element.first_child().value());
599 }
600 else if( !strcmp(element.name(), "file_name")) {
601 file_name = wxString::FromUTF8(element.first_child().value());
602 }
603 else if( !strcmp(element.name(), "scale")) {
604 scale = wxAtoi(wxString::FromUTF8(element.first_child().value()));
605 }
606 }
607 }
608
EncPanel(pugi::xml_node & xmldata)609 EncPanel::EncPanel( pugi::xml_node &xmldata ) : Panel( xmldata )
610 {
611 type = wxEmptyString;
612 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
613 if( !strcmp(element.name(), "type")) {
614 type = wxString::FromUTF8(element.first_child().value());
615 }
616 }
617 }
618
Vertex(pugi::xml_node & xmldata)619 Vertex::Vertex( pugi::xml_node &xmldata )
620 {
621 //Init properties
622 lat = 999.0;
623 lon = 999.0;
624 for (pugi::xml_node element = xmldata.first_child(); element; element = element.next_sibling()){
625 if( !strcmp(element.name(), "lat")) {
626 wxString::FromUTF8(element.first_child().value()).ToDouble(&lat);
627 }
628 else if( !strcmp(element.name(), "lon")) {
629 wxString::FromUTF8(element.first_child().value()).ToDouble(&lon);
630 }
631 }
632 }
633