OpenCPN Partial API docs
nav_object_database.cpp
1 /******************************************************************************
2  *
3  * Project: OpenCPN
4  *
5  ***************************************************************************
6  * Copyright (C) 2010 by David S. Register *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the *
20  * Free Software Foundation, Inc., *
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22  ***************************************************************************
23  */
24 #include <wx/string.h>
25 
26 #include "model/nav_object_database.h"
27 #include "model/routeman.h"
28 #include "model/navutil_base.h"
29 #include "model/select.h"
30 #include "model/track.h"
31 #include "model/route.h"
32 
33 #ifdef __ANDROID__
34 #include <QDebug>
35 #endif
36 
37 NavObjectCollection1::NavObjectCollection1()
38  : pugi::xml_document(), m_bSkipChangeSetUpdate(false) {}
39 
40 NavObjectCollection1::~NavObjectCollection1() {}
41 
42 RoutePoint *GPXLoadWaypoint1(pugi::xml_node &wpt_node,
43  wxString def_symbol_name, wxString GUID,
44  bool b_fullviz, bool b_layer,
45  bool b_layerviz, int layer_id) {
46  bool bviz = false;
47  bool bviz_name = false;
48  bool bauto_name = false;
49  bool bshared = false;
50  bool b_propvizname = false;
51  bool b_propviz = false;
52 
53  wxString SymString = def_symbol_name; // default icon
54  wxString NameString;
55  wxString DescString;
56  wxString TideStation;
57  double plan_speed = 0.0;
58  wxString etd;
59  wxString TypeString;
60  wxString GuidString = GUID; // default
61  wxString TimeString;
62  wxDateTime dt;
63  RoutePoint *pWP;
64 
65  HyperlinkList *linklist = NULL;
66 
67  double rlat = wpt_node.attribute("lat").as_double();
68  double rlon = wpt_node.attribute("lon").as_double();
69  double ArrivalRadius = 0;
70  int l_iWaypointRangeRingsNumber = -1;
71  float l_fWaypointRangeRingsStep = -1;
72  int l_pWaypointRangeRingsStepUnits = -1;
73  bool l_bWaypointRangeRingsVisible = false;
74  long l_iWaypointScaleMin = 2147483646;
75  long l_iWaypoinScaleMax = 0;
76  bool l_bWaypointUseScale = false;
77  wxColour l_wxcWaypointRangeRingsColour;
78  l_wxcWaypointRangeRingsColour.Set(_T( "#FFFFFF" ));
79 
80  for (pugi::xml_node child = wpt_node.first_child(); child != 0;
81  child = child.next_sibling()) {
82  const char *pcn = child.name();
83 
84  if (!strcmp(pcn, "sym")) {
85  SymString = wxString::FromUTF8(child.first_child().value());
86  } else if (!strcmp(pcn, "time"))
87  TimeString = wxString::FromUTF8(child.first_child().value());
88 
89  else if (!strcmp(pcn, "name")) {
90  NameString = wxString::FromUTF8(child.first_child().value());
91  if (NameString.StartsWith("@~~")) {
92  // Convert the legacy tidal event definition and change the name so
93  // that it does not kick in next time and cause overiding subsequent
94  // changes
95  TideStation = NameString.Right(NameString.length() - 3);
96  NameString.Replace("@~~", "@-~");
97  }
98  }
99 
100  else if (!strcmp(pcn, "desc")) {
101  DescString = wxString::FromUTF8(child.first_child().value());
102  }
103 
104  else if (!strcmp(pcn, "type")) {
105  TypeString = wxString::FromUTF8(child.first_child().value());
106  }
107 
108  else // Read hyperlink
109  if (!strcmp(pcn, "link")) {
110  wxString HrefString;
111  wxString HrefTextString;
112  wxString HrefTypeString;
113  if (linklist == NULL) linklist = new HyperlinkList;
114  HrefString = wxString::FromUTF8(child.first_attribute().value());
115 
116  for (pugi::xml_node child1 = child.first_child(); child1;
117  child1 = child1.next_sibling()) {
118  wxString LinkString = wxString::FromUTF8(child1.name());
119 
120  if (LinkString == _T ( "text" ))
121  HrefTextString = wxString::FromUTF8(child1.first_child().value());
122  if (LinkString == _T ( "type" ))
123  HrefTypeString = wxString::FromUTF8(child1.first_child().value());
124  }
125 
126  Hyperlink *link = new Hyperlink;
127  link->Link = HrefString;
128  link->DescrText = HrefTextString;
129  link->LType = HrefTypeString;
130  linklist->Append(link);
131  }
132 
133  // OpenCPN Extensions....
134  else if (!strcmp(pcn, "extensions")) {
135  for (pugi::xml_node ext_child = child.first_child(); ext_child;
136  ext_child = ext_child.next_sibling()) {
137  wxString ext_name = wxString::FromUTF8(ext_child.name());
138  if (ext_name == _T ( "opencpn:guid" )) {
139  GuidString = wxString::FromUTF8(ext_child.first_child().value());
140  } else if (ext_name == _T ( "opencpn:viz" )) {
141  b_propviz = true;
142  wxString s = wxString::FromUTF8(ext_child.first_child().value());
143  long v = 0;
144  if (s.ToLong(&v)) bviz = (v != 0);
145  } else if (ext_name == _T ( "opencpn:viz_name" )) {
146  b_propvizname = true;
147  wxString s = wxString::FromUTF8(ext_child.first_child().value());
148  long v = 0;
149  if (s.ToLong(&v)) bviz_name = (v != 0);
150  } else if (ext_name == _T ( "opencpn:auto_name" )) {
151  wxString s = wxString::FromUTF8(ext_child.first_child().value());
152  long v = 0;
153  if (s.ToLong(&v)) bauto_name = (v != 0);
154  } else if (ext_name == _T ( "opencpn:shared" )) {
155  wxString s = wxString::FromUTF8(ext_child.first_child().value());
156  long v = 0;
157  if (s.ToLong(&v)) bshared = (v != 0);
158  }
159  if (ext_name == _T ( "opencpn:arrival_radius" )) {
160  wxString::FromUTF8(ext_child.first_child().value())
161  .ToDouble(&ArrivalRadius);
162  }
163  if (ext_name == _T("opencpn:waypoint_range_rings")) {
164  for (pugi::xml_attribute attr = ext_child.first_attribute(); attr;
165  attr = attr.next_attribute()) {
166  if (wxString::FromUTF8(attr.name()) == _T("number"))
167  l_iWaypointRangeRingsNumber = attr.as_int();
168  else if (wxString::FromUTF8(attr.name()) == _T("step"))
169  l_fWaypointRangeRingsStep = attr.as_float();
170  else if (wxString::FromUTF8(attr.name()) == _T("units"))
171  l_pWaypointRangeRingsStepUnits = attr.as_int();
172  else if (wxString::FromUTF8(attr.name()) == _T("visible"))
173  l_bWaypointRangeRingsVisible = attr.as_bool();
174  else if (wxString::FromUTF8(attr.name()) == _T("colour"))
175  l_wxcWaypointRangeRingsColour.Set(
176  wxString::FromUTF8(attr.as_string()));
177  }
178  }
179  if (ext_name == _T("opencpn:scale_min_max")) {
180  for (pugi::xml_attribute attr = ext_child.first_attribute(); attr;
181  attr = attr.next_attribute()) {
182  if (wxString::FromUTF8(attr.name()) == _T("UseScale"))
183  l_bWaypointUseScale = attr.as_bool();
184  else if (wxString::FromUTF8(attr.name()) == _T("ScaleMin"))
185  l_iWaypointScaleMin = attr.as_int();
186  else if (wxString::FromUTF8(attr.name()) == _T("ScaleMax"))
187  l_iWaypoinScaleMax = attr.as_float();
188  }
189  }
190  if (ext_name == _T ( "opencpn:tidestation" )) {
191  TideStation = wxString::FromUTF8(ext_child.first_child().value());
192  }
193  if (ext_name == _T ( "opencpn:rte_properties" )) {
194  for (pugi::xml_attribute attr = ext_child.first_attribute(); attr;
195  attr = attr.next_attribute()) {
196  if (!strcmp(attr.name(), "planned_speed"))
197  plan_speed = attr.as_double();
198  else if (!strcmp(attr.name(), "etd"))
199  etd = attr.as_string();
200  }
201  }
202  } // for
203  } // extensions
204  } // for
205 
206  // Create waypoint
207 
208  if (b_layer) {
209  if (GuidString.IsEmpty()) GuidString = pWayPointMan->CreateGUID(NULL);
210  }
211 
212  pWP = new RoutePoint(rlat, rlon, SymString, NameString, GuidString,
213  false); // do not add to global WP list yet...
214  pWP->m_MarkDescription = DescString;
215  pWP->m_TideStation = TideStation;
216  pWP->m_bIsolatedMark = bshared; // This is an isolated mark
217  pWP->SetWaypointArrivalRadius(ArrivalRadius);
218  pWP->SetWaypointRangeRingsNumber(l_iWaypointRangeRingsNumber);
219  pWP->SetWaypointRangeRingsStep(l_fWaypointRangeRingsStep);
220  pWP->SetWaypointRangeRingsStepUnits(l_pWaypointRangeRingsStepUnits);
221  pWP->SetShowWaypointRangeRings(l_bWaypointRangeRingsVisible);
222 
223  // Migrate from O4.x XML format.
224  // In O5, the attribute "range rings visible" is synonymous with ( "range
225  // rings number" != 0 ) So, if we see an attribute "visible"=false in
226  // importing from XML, we must set "number" = 0 to be consistent
227  if (!l_bWaypointRangeRingsVisible) pWP->SetWaypointRangeRingsNumber(0);
228 
229  pWP->SetWaypointRangeRingsColour(l_wxcWaypointRangeRingsColour);
230  pWP->SetScaMin(l_iWaypointScaleMin);
231  pWP->SetScaMax(l_iWaypoinScaleMax);
232  pWP->SetUseSca(l_bWaypointUseScale);
233  pWP->SetPlannedSpeed(plan_speed);
234  pWP->SetETD(etd);
235 
236  pWP->m_bShowNameData = bviz_name;
237  if (b_propvizname)
238  pWP->m_bShowName = bviz_name;
239  else if (b_fullviz)
240  pWP->m_bShowName = true;
241  else
242  pWP->m_bShowName = false;
243 
244  if (b_propviz)
245  pWP->m_bIsVisible = bviz;
246  else if (b_fullviz)
247  pWP->m_bIsVisible = true;
248 
249  if (b_layer) {
250  pWP->m_bIsInLayer = true;
251  pWP->m_LayerID = layer_id;
252  pWP->m_bIsVisible = b_layerviz;
253  pWP->SetListed(false);
254  }
255 
256  pWP->SetShared(bshared);
257  pWP->m_bDynamicName = bauto_name;
258 
259  if (TimeString.Len()) {
260  pWP->m_timestring = TimeString;
261  pWP->SetCreateTime(wxInvalidDateTime); // cause deferred timestamp parsing
262  }
263 
264  if (linklist) {
265  delete pWP->m_HyperlinkList; // created in RoutePoint ctor
266  pWP->m_HyperlinkList = linklist;
267  }
268 
269  return pWP;
270 }
271 
272 static TrackPoint *GPXLoadTrackPoint1(pugi::xml_node &wpt_node) {
273  wxString TimeString;
274 
275  double rlat = wpt_node.attribute("lat").as_double();
276  double rlon = wpt_node.attribute("lon").as_double();
277 
278  for (pugi::xml_node child = wpt_node.first_child(); child != 0;
279  child = child.next_sibling()) {
280  const char *pcn = child.name();
281  if (!strcmp(pcn, "time"))
282  TimeString = wxString::FromUTF8(child.first_child().value());
283 
284  // OpenCPN Extensions....
285  else if (!strcmp(pcn, "extensions")) {
286  for (pugi::xml_node ext_child = child.first_child(); ext_child;
287  ext_child = ext_child.next_sibling()) {
288  wxString ext_name = wxString::FromUTF8(ext_child.name());
289  if (ext_name == _T ( "opencpn:action" )) {
290  }
291  } // for
292  } // extensions
293  } // for
294 
295  // Create trackpoint
296  return new TrackPoint(rlat, rlon, TimeString);
297 }
298 
299 Track *GPXLoadTrack1(pugi::xml_node &trk_node, bool b_fullviz,
300  bool b_layer, bool b_layerviz, int layer_id) {
301  wxString TrackName;
302  wxString DescString;
303  unsigned short int GPXSeg;
304  bool b_propviz = false;
305  bool b_viz = true;
306  Track *pTentTrack = NULL;
307  HyperlinkList *linklist = NULL;
308 
309  wxString Name = wxString::FromUTF8(trk_node.name());
310  if (Name == _T ( "trk" )) {
311  pTentTrack = new Track();
312  GPXSeg = 0;
313 
314  TrackPoint *pWp = NULL;
315 
316  for (pugi::xml_node tschild = trk_node.first_child(); tschild;
317  tschild = tschild.next_sibling()) {
318  wxString ChildName = wxString::FromUTF8(tschild.name());
319  if (ChildName == _T ( "trkseg" )) {
320  GPXSeg += 1;
321 
322  // Official GPX spec calls for trkseg to have children trkpt
323  for (pugi::xml_node tpchild = tschild.first_child(); tpchild;
324  tpchild = tpchild.next_sibling()) {
325  wxString tpChildName = wxString::FromUTF8(tpchild.name());
326  if (tpChildName == _T("trkpt")) {
327  pWp = ::GPXLoadTrackPoint1(tpchild);
328  if (pWp){
329  pTentTrack->AddPoint(pWp); // defer BBox calculation
330  pWp->m_GPXTrkSegNo = GPXSeg;
331  }
332  }
333  }
334  } else if (ChildName == _T ( "name" ))
335  TrackName = wxString::FromUTF8(tschild.first_child().value());
336  else if (ChildName == _T ( "desc" ))
337  DescString = wxString::FromUTF8(tschild.first_child().value());
338  else
339 
340  if (ChildName == _T ( "link")) {
341  wxString HrefString;
342  wxString HrefTextString;
343  wxString HrefTypeString;
344  if (linklist == NULL) linklist = new HyperlinkList;
345  HrefString = wxString::FromUTF8(tschild.first_attribute().value());
346 
347  for (pugi::xml_node child1 = tschild.first_child(); child1;
348  child1 = child1.next_sibling()) {
349  wxString LinkString = wxString::FromUTF8(child1.name());
350 
351  if (LinkString == _T ( "text" ))
352  HrefTextString = wxString::FromUTF8(child1.first_child().value());
353  if (LinkString == _T ( "type" ))
354  HrefTypeString = wxString::FromUTF8(child1.first_child().value());
355  }
356 
357  Hyperlink *link = new Hyperlink;
358  link->Link = HrefString;
359  link->DescrText = HrefTextString;
360  link->LType = HrefTypeString;
361  linklist->Append(link);
362  }
363 
364  else if (ChildName == _T ( "extensions" )) {
365  for (pugi::xml_node ext_child = tschild.first_child(); ext_child;
366  ext_child = ext_child.next_sibling()) {
367  wxString ext_name = wxString::FromUTF8(ext_child.name());
368  if (ext_name == _T ( "opencpn:start" )) {
369  pTentTrack->m_TrackStartString =
370  wxString::FromUTF8(ext_child.first_child().value());
371  } else if (ext_name == _T ( "opencpn:end" )) {
372  pTentTrack->m_TrackEndString =
373  wxString::FromUTF8(ext_child.first_child().value());
374  }
375 
376  else if (ext_name == _T ( "opencpn:viz" )) {
377  wxString viz = wxString::FromUTF8(ext_child.first_child().value());
378  b_propviz = true;
379  b_viz = (viz == _T("1"));
380  } else if (ext_name == _T ( "opencpn:style" )) {
381  for (pugi::xml_attribute attr = ext_child.first_attribute(); attr;
382  attr = attr.next_attribute()) {
383  if (!strcmp(attr.name(), "style"))
384  pTentTrack->m_style = (wxPenStyle)attr.as_int();
385  else if (!strcmp(attr.name(), "width"))
386  pTentTrack->m_width = attr.as_int();
387  }
388  }
389 
390  else if (ext_name == _T ( "opencpn:guid" )) {
391  pTentTrack->m_GUID =
392  wxString::FromUTF8(ext_child.first_child().value());
393  }
394 
395  else if (ext_name.EndsWith(
396  _T ( "TrackExtension" ))) // Parse GPXX color
397  {
398  for (pugi::xml_node gpxx_child = ext_child.first_child();
399  gpxx_child; gpxx_child = gpxx_child.next_sibling()) {
400  wxString gpxx_name = wxString::FromUTF8(gpxx_child.name());
401  if (gpxx_name.EndsWith(_T ( "DisplayColor" )))
402  pTentTrack->m_Colour =
403  wxString::FromUTF8(gpxx_child.first_child().value());
404  }
405  }
406  } // extensions
407  }
408  }
409 
410  pTentTrack->SetName(TrackName);
411  pTentTrack->m_TrackDescription = DescString;
412 
413  if (b_propviz)
414  pTentTrack->SetVisible(b_viz);
415  else {
416  if (b_fullviz) pTentTrack->SetVisible();
417  }
418 
419  if (b_layer) {
420  pTentTrack->SetVisible(b_layerviz);
421  pTentTrack->m_bIsInLayer = true;
422  pTentTrack->m_LayerID = layer_id;
423  pTentTrack->SetListed(false);
424  }
425 
426  pTentTrack->SetCurrentTrackSeg(GPXSeg);
427  }
428 
429  if (linklist) {
430  delete pTentTrack->m_HyperlinkList; // created in TrackPoint ctor
431  pTentTrack->m_HyperlinkList = linklist;
432  }
433 
434  return pTentTrack;
435 }
436 
437 Route *GPXLoadRoute1(pugi::xml_node &wpt_node, bool b_fullviz,
438  bool b_layer, bool b_layerviz, int layer_id,
439  bool b_change, bool load_points) {
440  wxString RouteName;
441  wxString DescString;
442  bool b_propviz = false;
443  bool b_propSWPviz = false;
444  bool b_viz = true;
445  bool swpViz = false;
446  Route *pTentRoute = NULL;
447 
448  wxString Name = wxString::FromUTF8(wpt_node.name());
449  if (Name == _T ( "rte" )) {
450  pTentRoute = new Route();
451  HyperlinkList *linklist = NULL;
452 
453  RoutePoint *pWp = NULL;
454  bool route_existing = false;
455  pTentRoute->m_TimeDisplayFormat = RTE_TIME_DISP_UTC;
456 
457  for (pugi::xml_node tschild = wpt_node.first_child(); tschild;
458  tschild = tschild.next_sibling()) {
459  wxString ChildName = wxString::FromUTF8(tschild.name());
460 
461  // load extentions first to determine if the route still exists
462  if (ChildName == _T ( "extensions" )) {
463  for (pugi::xml_node ext_child = tschild.first_child(); ext_child;
464  ext_child = ext_child.next_sibling()) {
465  wxString ext_name = wxString::FromUTF8(ext_child.name());
466 
467  if (ext_name == _T ( "opencpn:start" )) {
468  pTentRoute->m_RouteStartString =
469  wxString::FromUTF8(ext_child.first_child().value());
470  } else if (ext_name == _T ( "opencpn:end" )) {
471  pTentRoute->m_RouteEndString =
472  wxString::FromUTF8(ext_child.first_child().value());
473  }
474 
475  else if (ext_name == _T ( "opencpn:viz" )) {
476  wxString viz = wxString::FromUTF8(ext_child.first_child().value());
477  b_propviz = true;
478  b_viz = (viz == _T("1"));
479  }
480 
481  else if (ext_name == _T ( "opencpn:sharedWPviz" )) {
482  wxString viz = wxString::FromUTF8(ext_child.first_child().value());
483  b_propSWPviz = true;
484  swpViz = (viz == _T("1"));
485  } else if (ext_name == _T ( "opencpn:style" )) {
486  for (pugi::xml_attribute attr = ext_child.first_attribute(); attr;
487  attr = attr.next_attribute()) {
488  if (!strcmp(attr.name(), "style"))
489  pTentRoute->m_style = (wxPenStyle)attr.as_int();
490  else if (!strcmp(attr.name(), "width"))
491  pTentRoute->m_width = attr.as_int();
492  }
493  }
494 
495  else if (ext_name == _T ( "opencpn:guid" )) {
496  pTentRoute->m_GUID =
497  wxString::FromUTF8(ext_child.first_child().value());
498  }
499 
500  else if (ext_name == _T ( "opencpn:planned_speed" )) {
501  pTentRoute->m_PlannedSpeed = atof(ext_child.first_child().value());
502  }
503 
504  else if (ext_name == _T ( "opencpn:planned_departure" )) {
505  ParseGPXDateTime(
506  pTentRoute->m_PlannedDeparture,
507  wxString::FromUTF8(ext_child.first_child().value()));
508  }
509 
510  else if (ext_name == _T ( "opencpn:time_display" )) {
511  pTentRoute->m_TimeDisplayFormat =
512  wxString::FromUTF8(ext_child.first_child().value());
513  } else if (ext_name.EndsWith(
514  _T ( "RouteExtension" ))) // Parse GPXX color
515  {
516  for (pugi::xml_node gpxx_child = ext_child.first_child();
517  gpxx_child; gpxx_child = gpxx_child.next_sibling()) {
518  wxString gpxx_name = wxString::FromUTF8(gpxx_child.name());
519  if (gpxx_name.EndsWith(_T ( "DisplayColor" )))
520  pTentRoute->m_Colour =
521  wxString::FromUTF8(gpxx_child.first_child().value());
522  }
523  }
524  }
525  if (!b_change) {
526  if (RouteExists(pTentRoute->m_GUID)) { // we are loading a different
527  // route with the same guid so
528  // let's generate a new guid
529  pTentRoute->m_GUID = pWayPointMan->CreateGUID(NULL);
530  route_existing = true;
531  }
532  }
533  } // extension
534  else if (load_points && ChildName == _T ( "rtept" )) {
535  RoutePoint *tpWp =
536  ::GPXLoadWaypoint1(tschild, _T("square"), _T(""), b_fullviz,
537  b_layer, b_layerviz, layer_id);
538  RoutePoint *erp = NULL;
539  if (!b_layer) erp = ::WaypointExists(tpWp->m_GUID);
540  // 1) if b_change is true, that means we are after crash - load the
541  // route and points as found in source file 2) if route_existing, we are
542  // loading a different route with the same guid. In this case load
543  // points as found in
544  // source file, changing the guid, but keep existing "isolated point" as
545  // found in the DB
546  // 3) in all other cases keep existing points if found and load new
547  // points if not found
548  bool new_wpt = true;
549  if (b_change) {
550  pWp = tpWp;
551  } else {
552  if (erp != NULL &&
553  (!route_existing || (route_existing && tpWp->IsShared()))) {
554  pWp = erp;
555  new_wpt = false;
556  } else {
557  if (route_existing) tpWp->m_GUID = pWayPointMan->CreateGUID(NULL);
558  pWp = tpWp;
559  }
560  }
561 
562  pTentRoute->AddPoint(pWp, false, true); // defer BBox calculation
563  pWp->m_bIsInRoute = true; // Hack
564 
565  if (new_wpt){
566  if (erp == NULL) {
567  pWayPointMan->AddRoutePoint(pWp);
568  }
569  }
570  else {
571  delete tpWp;
572  }
573  } else if (ChildName == _T ( "name" )) {
574  RouteName = wxString::FromUTF8(tschild.first_child().value());
575  } else if (ChildName == _T ( "desc" )) {
576  DescString = wxString::FromUTF8(tschild.first_child().value());
577  }
578 
579  if (ChildName == _T ( "link")) {
580  wxString HrefString;
581  wxString HrefTextString;
582  wxString HrefTypeString;
583  if (linklist == NULL) linklist = new HyperlinkList;
584  HrefString = wxString::FromUTF8(tschild.first_attribute().value());
585 
586  for (pugi::xml_node child1 = tschild.first_child(); child1;
587  child1 = child1.next_sibling()) {
588  wxString LinkString = wxString::FromUTF8(child1.name());
589 
590  if (LinkString == _T ( "text" ))
591  HrefTextString = wxString::FromUTF8(child1.first_child().value());
592  if (LinkString == _T ( "type" ))
593  HrefTypeString = wxString::FromUTF8(child1.first_child().value());
594  }
595 
596  Hyperlink *link = new Hyperlink;
597  link->Link = HrefString;
598  link->DescrText = HrefTextString;
599  link->LType = HrefTypeString;
600  linklist->Append(link);
601  }
602 
603  else
604  // TODO: This is wrong, left here just to save data of the 3.3 beta
605  // series users.
606  if (ChildName.EndsWith(_T ( "RouteExtension" ))) // Parse GPXX color
607  {
608  for (pugi::xml_node gpxx_child = tschild.first_child(); gpxx_child;
609  gpxx_child = gpxx_child.next_sibling()) {
610  wxString gpxx_name = wxString::FromUTF8(gpxx_child.name());
611  if (gpxx_name.EndsWith(_T ( "DisplayColor" )))
612  pTentRoute->m_Colour =
613  wxString::FromUTF8(gpxx_child.first_child().value());
614  }
615  }
616  }
617 
618  pTentRoute->m_RouteNameString = RouteName;
619  pTentRoute->m_RouteDescription = DescString;
620  if (linklist) {
621  pTentRoute->m_HyperlinkList = linklist;
622  }
623 
624  if (b_propviz) {
625  pTentRoute->SetVisible(b_viz);
626  } else if (b_fullviz) {
627  pTentRoute->SetVisible();
628  }
629 
630  if (b_propSWPviz) pTentRoute->SetSharedWPViz(swpViz);
631 
632  if (b_layer) {
633  pTentRoute->SetVisible(b_layerviz);
634  pTentRoute->m_bIsInLayer = true;
635  pTentRoute->m_LayerID = layer_id;
636  pTentRoute->SetListed(false);
637  }
638  }
639 
640  return pTentRoute;
641 }
642 
643 static bool GPXCreateWpt(pugi::xml_node node, RoutePoint *pr,
644  unsigned int flags) {
645  wxString s;
646  pugi::xml_node child;
647  pugi::xml_attribute attr;
648 
649  s.Printf(_T("%.9f"), pr->m_lat);
650  node.append_attribute("lat") = s.mb_str();
651  s.Printf(_T("%.9f"), pr->m_lon);
652  node.append_attribute("lon") = s.mb_str();
653 
654  if (flags & OUT_TIME) {
655  child = node.append_child("time");
656  if (pr->m_timestring.Len())
657  child.append_child(pugi::node_pcdata)
658  .set_value(pr->m_timestring.mb_str());
659  else {
660  wxDateTime dt = pr->GetCreateTime();
661  if ( !dt.IsValid() )
662  dt = wxDateTime::Now();
663 
664  wxString t = dt.ToUTC().FormatISODate()
665  .Append(_T("T"))
666  .Append(dt.ToUTC().FormatISOTime())
667  .Append(_T("Z"));
668  child.append_child(pugi::node_pcdata).set_value(t.mb_str());
669  }
670  }
671 
672  if ((!pr->GetName().IsEmpty() && (flags & OUT_NAME)) ||
673  (flags & OUT_NAME_FORCE)) {
674  wxCharBuffer buffer = pr->GetName().ToUTF8();
675  if (buffer.data()) {
676  child = node.append_child("name");
677  child.append_child(pugi::node_pcdata).set_value(buffer.data());
678  }
679  }
680 
681  if ((!pr->GetDescription().IsEmpty() && (flags & OUT_DESC)) ||
682  (flags & OUT_DESC_FORCE)) {
683  wxCharBuffer buffer = pr->GetDescription().ToUTF8();
684  if (buffer.data()) {
685  child = node.append_child("desc");
686  child.append_child(pugi::node_pcdata).set_value(buffer.data());
687  }
688  }
689 
690  // Hyperlinks
691  if (flags & OUT_HYPERLINKS) {
692  HyperlinkList *linklist = pr->m_HyperlinkList;
693  if (linklist && linklist->GetCount()) {
694  wxHyperlinkListNode *linknode = linklist->GetFirst();
695  while (linknode) {
696  Hyperlink *link = linknode->GetData();
697 
698  pugi::xml_node child_link = node.append_child("link");
699  ;
700  wxCharBuffer buffer = link->Link.ToUTF8();
701  if (buffer.data()) child_link.append_attribute("href") = buffer.data();
702 
703  buffer = link->DescrText.ToUTF8();
704  if (buffer.data()) {
705  child = child_link.append_child("text");
706  child.append_child(pugi::node_pcdata).set_value(buffer.data());
707  }
708 
709  buffer = link->LType.ToUTF8();
710  if (buffer.data() && strlen(buffer.data()) > 0) {
711  child = child_link.append_child("type");
712  child.append_child(pugi::node_pcdata).set_value(buffer.data());
713  }
714 
715  linknode = linknode->GetNext();
716  }
717  }
718  }
719 
720  if (flags & OUT_SYM_FORCE) {
721  child = node.append_child("sym");
722  if (!pr->GetIconName().IsEmpty()) {
723  child.append_child(pugi::node_pcdata)
724  .set_value(pr->GetIconName().mb_str());
725  } else {
726  child.append_child("empty");
727  }
728  }
729 
730  if (flags & OUT_TYPE) {
731  child = node.append_child("type");
732  child.append_child(pugi::node_pcdata).set_value("WPT");
733  }
734 
735  if ((flags & OUT_GUID) || (flags & OUT_VIZ) || (flags & OUT_VIZ_NAME) ||
736  (flags & OUT_SHARED) || (flags & OUT_AUTO_NAME) ||
737  (flags & OUT_EXTENSION) || (flags & OUT_TIDE_STATION) ||
738  (flags & OUT_RTE_PROPERTIES)) {
739  pugi::xml_node child_ext = node.append_child("extensions");
740 
741  if (!pr->m_GUID.IsEmpty() && (flags & OUT_GUID)) {
742  child = child_ext.append_child("opencpn:guid");
743  child.append_child(pugi::node_pcdata).set_value(pr->m_GUID.mb_str());
744  }
745 
746  if ((flags & OUT_VIZ) && !pr->m_bIsVisible) {
747  child = child_ext.append_child("opencpn:viz");
748  child.append_child(pugi::node_pcdata).set_value("0");
749  }
750 
751  if ((flags & OUT_VIZ_NAME) && pr->m_bShowName) {
752  child = child_ext.append_child("opencpn:viz_name");
753  child.append_child(pugi::node_pcdata).set_value("1");
754  }
755 
756  if ((flags & OUT_AUTO_NAME) && pr->m_bDynamicName) {
757  child = child_ext.append_child("opencpn:auto_name");
758  child.append_child(pugi::node_pcdata).set_value("1");
759  }
760  if ((flags & OUT_SHARED) && pr->IsShared()) {
761  child = child_ext.append_child("opencpn:shared");
762  child.append_child(pugi::node_pcdata).set_value("1");
763  }
764  if (flags & OUT_ARRIVAL_RADIUS) {
765  child = child_ext.append_child("opencpn:arrival_radius");
766  s.Printf(_T("%.3f"), pr->GetWaypointArrivalRadius());
767  child.append_child(pugi::node_pcdata).set_value(s.mbc_str());
768  }
769  if (flags & OUT_WAYPOINT_RANGE_RINGS) {
770  child = child_ext.append_child("opencpn:waypoint_range_rings");
771  pugi::xml_attribute viz = child.append_attribute("visible");
772  viz.set_value(pr->m_bShowWaypointRangeRings);
773  pugi::xml_attribute number = child.append_attribute("number");
774  number.set_value(pr->m_iWaypointRangeRingsNumber);
775  pugi::xml_attribute step = child.append_attribute("step");
776  step.set_value(pr->m_fWaypointRangeRingsStep);
777  pugi::xml_attribute units = child.append_attribute("units");
778  units.set_value(pr->m_iWaypointRangeRingsStepUnits);
779 
780  // Color specification in GPX file must be fully opaque
781  if (pr->m_wxcWaypointRangeRingsColour.IsOk()) {
782  pr->m_wxcWaypointRangeRingsColour.Set(
783  pr->m_wxcWaypointRangeRingsColour.Red(),
784  pr->m_wxcWaypointRangeRingsColour.Green(),
785  pr->m_wxcWaypointRangeRingsColour.Blue(),
786  wxALPHA_OPAQUE);
787  }
788  else {
789  pr->m_wxcWaypointRangeRingsColour.Set(0,0,0,wxALPHA_OPAQUE);
790  }
791 
792  pugi::xml_attribute colour = child.append_attribute("colour");
793  colour.set_value(
794  pr->m_wxcWaypointRangeRingsColour.GetAsString(wxC2S_HTML_SYNTAX)
795  .utf8_str());
796  }
797  if (flags & OUT_WAYPOINT_SCALE) {
798  child = child_ext.append_child("opencpn:scale_min_max");
799  pugi::xml_attribute use = child.append_attribute("UseScale");
800  use.set_value(pr->GetUseSca());
801  pugi::xml_attribute sca = child.append_attribute("ScaleMin");
802  sca.set_value(pr->GetScaMin());
803  pugi::xml_attribute max = child.append_attribute("ScaleMax");
804  max.set_value(pr->GetScaMax());
805  }
806  if ((flags & OUT_TIDE_STATION) && !pr->m_TideStation.IsEmpty()) {
807  child = child_ext.append_child("opencpn:tidestation");
808  child.append_child(pugi::node_pcdata)
809  .set_value(pr->m_TideStation.mb_str());
810  }
811  if ((flags & OUT_RTE_PROPERTIES) &&
812  (pr->GetPlannedSpeed() > 0.0001 || pr->m_manual_etd)) {
813  child = child_ext.append_child("opencpn:rte_properties");
814  if (pr->GetPlannedSpeed() > 0.0001) {
815  pugi::xml_attribute use = child.append_attribute("planned_speed");
816  use.set_value(
817  wxString::Format(_T("%.1lf"), pr->GetPlannedSpeed()).mb_str());
818  }
819  if (pr->m_manual_etd) {
820  pugi::xml_attribute use = child.append_attribute("etd");
821  use.set_value(pr->GetManualETD().FormatISOCombined().mb_str());
822  }
823  }
824  }
825 
826  return true;
827 }
828 
829 static bool GPXCreateTrkpt(pugi::xml_node node, TrackPoint *pt,
830  unsigned int flags) {
831  wxString s;
832  pugi::xml_node child;
833  pugi::xml_attribute attr;
834 
835  s.Printf(_T("%.9f"), pt->m_lat);
836  node.append_attribute("lat") = s.mb_str();
837  s.Printf(_T("%.9f"), pt->m_lon);
838  node.append_attribute("lon") = s.mb_str();
839 
840  if (flags & OUT_TIME && pt->HasValidTimestamp()) {
841  child = node.append_child("time");
842  child.append_child(pugi::node_pcdata).set_value(pt->GetTimeString());
843  }
844 
845  return true;
846 }
847 
848 static bool GPXCreateTrk(pugi::xml_node node, Track *pTrack,
849  unsigned int flags) {
850  pugi::xml_node child;
851 
852  if (pTrack->GetName().Len()) {
853  wxCharBuffer buffer = pTrack->GetName().ToUTF8();
854  if (buffer.data()) {
855  child = node.append_child("name");
856  child.append_child(pugi::node_pcdata).set_value(buffer.data());
857  }
858  }
859 
860  if (pTrack->m_TrackDescription.Len()) {
861  wxCharBuffer buffer = pTrack->m_TrackDescription.ToUTF8();
862  if (buffer.data()) {
863  child = node.append_child("desc");
864  child.append_child(pugi::node_pcdata).set_value(buffer.data());
865  }
866  }
867 
868  // Hyperlinks
869  HyperlinkList *linklist = pTrack->m_HyperlinkList;
870  if (linklist && linklist->GetCount()) {
871  wxHyperlinkListNode *linknode = linklist->GetFirst();
872  while (linknode) {
873  Hyperlink *link = linknode->GetData();
874 
875  pugi::xml_node child_link = node.append_child("link");
876  wxCharBuffer buffer = link->Link.ToUTF8();
877  if (buffer.data()) child_link.append_attribute("href") = buffer.data();
878 
879  buffer = link->DescrText.ToUTF8();
880  if (buffer.data()) {
881  child = child_link.append_child("text");
882  child.append_child(pugi::node_pcdata).set_value(buffer.data());
883  }
884 
885  buffer = link->LType.ToUTF8();
886  if (buffer.data() && strlen(buffer.data()) > 0) {
887  child = child_link.append_child("type");
888  child.append_child(pugi::node_pcdata).set_value(buffer.data());
889  }
890 
891  linknode = linknode->GetNext();
892  }
893  }
894 
895  pugi::xml_node child_ext = node.append_child("extensions");
896 
897  child = child_ext.append_child("opencpn:guid");
898  child.append_child(pugi::node_pcdata).set_value(pTrack->m_GUID.mb_str());
899 
900  child = child_ext.append_child("opencpn:viz");
901  child.append_child(pugi::node_pcdata)
902  .set_value(pTrack->IsVisible() == true ? "1" : "0");
903 
904  if (pTrack->m_TrackStartString.Len()) {
905  wxCharBuffer buffer = pTrack->m_TrackStartString.ToUTF8();
906  if (buffer.data()) {
907  child = child_ext.append_child("opencpn:start");
908  child.append_child(pugi::node_pcdata).set_value(buffer.data());
909  }
910  }
911 
912  if (pTrack->m_TrackEndString.Len()) {
913  wxCharBuffer buffer = pTrack->m_TrackEndString.ToUTF8();
914  if (buffer.data()) {
915  child = child_ext.append_child("opencpn:end");
916  child.append_child(pugi::node_pcdata).set_value(buffer.data());
917  }
918  }
919 
920  if (pTrack->m_width != WIDTH_UNDEFINED ||
921  pTrack->m_style != wxPENSTYLE_INVALID) {
922  child = child_ext.append_child("opencpn:style");
923 
924  if (pTrack->m_width != WIDTH_UNDEFINED)
925  child.append_attribute("width") = pTrack->m_width;
926  if (pTrack->m_style != wxPENSTYLE_INVALID)
927  child.append_attribute("style") = pTrack->m_style;
928  }
929 
930  if (pTrack->m_Colour != wxEmptyString) {
931  pugi::xml_node gpxx_ext = child_ext.append_child("gpxx:TrackExtension");
932  child = gpxx_ext.append_child("gpxx:DisplayColor");
933  child.append_child(pugi::node_pcdata).set_value(pTrack->m_Colour.mb_str());
934  }
935 
936  if (flags & RT_OUT_NO_RTPTS) return true;
937 
938  int node2 = 0;
939  TrackPoint *prp;
940 
941  unsigned short int GPXTrkSegNo1 = 1;
942 
943  do {
944  unsigned short int GPXTrkSegNo2 = GPXTrkSegNo1;
945 
946  pugi::xml_node seg = node.append_child("trkseg");
947 
948  while (node2 < pTrack->GetnPoints()) {
949  prp = pTrack->GetPoint(node2);
950  GPXTrkSegNo1 = prp->m_GPXTrkSegNo;
951  if (GPXTrkSegNo1 != GPXTrkSegNo2) break;
952 
953  GPXCreateTrkpt(seg.append_child("trkpt"), prp, OPT_TRACKPT);
954 
955  node2++;
956  }
957  } while (node2 < pTrack->GetnPoints());
958 
959  return true;
960 }
961 
962 static bool GPXCreateRoute(pugi::xml_node node, Route *pRoute) {
963  pugi::xml_node child;
964 
965  if (pRoute->m_RouteNameString.Len()) {
966  wxCharBuffer buffer = pRoute->m_RouteNameString.ToUTF8();
967  if (buffer.data()) {
968  child = node.append_child("name");
969  child.append_child(pugi::node_pcdata).set_value(buffer.data());
970  }
971  }
972 
973  if (pRoute->m_RouteDescription.Len()) {
974  wxCharBuffer buffer = pRoute->m_RouteDescription.ToUTF8();
975  if (buffer.data()) {
976  child = node.append_child("desc");
977  child.append_child(pugi::node_pcdata).set_value(buffer.data());
978  }
979  }
980 
981  // Hyperlinks
982  HyperlinkList *linklist = pRoute->m_HyperlinkList;
983  if (linklist && linklist->GetCount()) {
984  wxHyperlinkListNode *linknode = linklist->GetFirst();
985  while (linknode) {
986  Hyperlink *link = linknode->GetData();
987 
988  pugi::xml_node child_link = node.append_child("link");
989  wxCharBuffer buffer = link->Link.ToUTF8();
990  if (buffer.data()) child_link.append_attribute("href") = buffer.data();
991 
992  buffer = link->DescrText.ToUTF8();
993  if (buffer.data()) {
994  child = child_link.append_child("text");
995  child.append_child(pugi::node_pcdata).set_value(buffer.data());
996  }
997 
998  buffer = link->LType.ToUTF8();
999  if (buffer.data() && strlen(buffer.data()) > 0) {
1000  child = child_link.append_child("type");
1001  child.append_child(pugi::node_pcdata).set_value(buffer.data());
1002  }
1003 
1004  linknode = linknode->GetNext();
1005  }
1006  }
1007 
1008  pugi::xml_node child_ext = node.append_child("extensions");
1009 
1010  child = child_ext.append_child("opencpn:guid");
1011  child.append_child(pugi::node_pcdata).set_value(pRoute->m_GUID.mb_str());
1012 
1013  child = child_ext.append_child("opencpn:viz");
1014  child.append_child(pugi::node_pcdata)
1015  .set_value(pRoute->IsVisible() == true ? "1" : "0");
1016 
1017  if (pRoute->ContainsSharedWP()) {
1018  child = child_ext.append_child("opencpn:sharedWPviz");
1019  child.append_child(pugi::node_pcdata)
1020  .set_value(pRoute->GetSharedWPViz() == true ? "1" : "0");
1021  }
1022 
1023  if (pRoute->m_RouteStartString.Len()) {
1024  wxCharBuffer buffer = pRoute->m_RouteStartString.ToUTF8();
1025  if (buffer.data()) {
1026  child = child_ext.append_child("opencpn:start");
1027  child.append_child(pugi::node_pcdata).set_value(buffer.data());
1028  }
1029  }
1030 
1031  if (pRoute->m_RouteEndString.Len()) {
1032  wxCharBuffer buffer = pRoute->m_RouteEndString.ToUTF8();
1033  if (buffer.data()) {
1034  child = child_ext.append_child("opencpn:end");
1035  child.append_child(pugi::node_pcdata).set_value(buffer.data());
1036  }
1037  }
1038 
1039  if (pRoute->m_PlannedSpeed != ROUTE_DEFAULT_SPEED) {
1040  child = child_ext.append_child("opencpn:planned_speed");
1041  wxString s;
1042  s.Printf(_T("%.2f"), pRoute->m_PlannedSpeed);
1043  child.append_child(pugi::node_pcdata).set_value(s.mb_str());
1044  }
1045 
1046  if (pRoute->m_PlannedDeparture.IsValid()) {
1047  child = child_ext.append_child("opencpn:planned_departure");
1048  wxString t = pRoute->m_PlannedDeparture.FormatISODate()
1049  .Append(_T("T"))
1050  .Append(pRoute->m_PlannedDeparture.FormatISOTime())
1051  .Append(_T("Z"));
1052  child.append_child(pugi::node_pcdata).set_value(t.mb_str());
1053  }
1054 
1055  child = child_ext.append_child("opencpn:time_display");
1056  child.append_child(pugi::node_pcdata)
1057  .set_value(pRoute->m_TimeDisplayFormat.mb_str());
1058 
1059  if (pRoute->m_width != WIDTH_UNDEFINED ||
1060  pRoute->m_style != wxPENSTYLE_INVALID) {
1061  child = child_ext.append_child("opencpn:style");
1062 
1063  if (pRoute->m_width != WIDTH_UNDEFINED)
1064  child.append_attribute("width") = pRoute->m_width;
1065  if (pRoute->m_style != wxPENSTYLE_INVALID)
1066  child.append_attribute("style") = pRoute->m_style;
1067  }
1068 
1069  pugi::xml_node gpxx_ext = child_ext.append_child("gpxx:RouteExtension");
1070  child = gpxx_ext.append_child("gpxx:IsAutoNamed");
1071  child.append_child(pugi::node_pcdata).set_value("false");
1072 
1073  if (pRoute->m_Colour != wxEmptyString) {
1074  child = gpxx_ext.append_child("gpxx:DisplayColor");
1075  child.append_child(pugi::node_pcdata).set_value(pRoute->m_Colour.mb_str());
1076  }
1077 
1078  RoutePointList *pRoutePointList = pRoute->pRoutePointList;
1079  wxRoutePointListNode *node2 = pRoutePointList->GetFirst();
1080  RoutePoint *prp;
1081 
1082  while (node2) {
1083  prp = node2->GetData();
1084 
1085  GPXCreateWpt(node.append_child("rtept"), prp, OPT_ROUTEPT);
1086 
1087  node2 = node2->GetNext();
1088  }
1089 
1090  return true;
1091 }
1092 
1093 bool InsertRouteA(Route *pTentRoute, NavObjectCollection1* navobj) {
1094  if (!pTentRoute) return false;
1095 
1096  bool bAddroute = true;
1097  // If the route has only 1 point, don't load it.
1098  if (pTentRoute->GetnPoints() < 2) bAddroute = false;
1099 
1100  // TODO All this trouble for a tentative route.......Should make some
1101  // Route methods????
1102  if (bAddroute) {
1103  pRouteList->Append(pTentRoute);
1104 
1105  // Do the (deferred) calculation of BBox
1106  pTentRoute->FinalizeForRendering();
1107 
1108  // Add the selectable points and segments
1109 
1110  int ip = 0;
1111  float prev_rlat = 0., prev_rlon = 0.;
1112  RoutePoint *prev_pConfPoint = NULL;
1113 
1114  wxRoutePointListNode *node = pTentRoute->pRoutePointList->GetFirst();
1115  while (node) {
1116  RoutePoint *prp = node->GetData();
1117 
1118  if (ip)
1119  pSelect->AddSelectableRouteSegment(prev_rlat, prev_rlon, prp->m_lat,
1120  prp->m_lon, prev_pConfPoint, prp,
1121  pTentRoute);
1122  pSelect->AddSelectableRoutePoint(prp->m_lat, prp->m_lon, prp);
1123  prev_rlat = prp->m_lat;
1124  prev_rlon = prp->m_lon;
1125  prev_pConfPoint = prp;
1126 
1127  ip++;
1128 
1129  node = node->GetNext();
1130  }
1131  } else {
1132  // walk the route, deleting points used only by this route
1133  wxRoutePointListNode *pnode = (pTentRoute->pRoutePointList)->GetFirst();
1134  while (pnode) {
1135  RoutePoint *prp = pnode->GetData();
1136 
1137  // check all other routes to see if this point appears in any other route
1138  Route *pcontainer_route = g_pRouteMan->FindRouteContainingWaypoint(prp);
1139 
1140  if (pcontainer_route == NULL) {
1141  prp->m_bIsInRoute =
1142  false; // Take this point out of this (and only) track/route
1143  if (!prp->IsShared()) {
1144  navobj->m_bSkipChangeSetUpdate = true;
1145  NavObjectChanges::getInstance()->DeleteWayPoint(prp);
1146  navobj->m_bSkipChangeSetUpdate = false;
1147  delete prp;
1148  }
1149  }
1150 
1151  pnode = pnode->GetNext();
1152  }
1153 
1154  delete pTentRoute;
1155  }
1156  return bAddroute;
1157 }
1158 
1159 bool InsertTrack(Track *pTentTrack, bool bApplyChanges) {
1160  if (!pTentTrack) return false;
1161 
1162  bool bAddtrack = true;
1163  // If the track has only 1 point, don't load it.
1164  // This usually occurs if some points were discarded as being co-incident.
1165  if (!bApplyChanges && pTentTrack->GetnPoints() < 2) bAddtrack = false;
1166 
1167  // TODO All this trouble for a tentative track.......Should make some
1168  // Track methods????
1169  if (bAddtrack) {
1170  g_TrackList.push_back(pTentTrack);
1171 
1172  // Do the (deferred) calculation of Track BBox
1173  // pTentTrack->FinalizeForRendering();
1174 
1175  // Add the selectable points and segments
1176 
1177  float prev_rlat = 0., prev_rlon = 0.;
1178  TrackPoint *prev_pConfPoint = NULL;
1179 
1180  for (int i = 0; i < pTentTrack->GetnPoints(); i++) {
1181  TrackPoint *prp = pTentTrack->GetPoint(i);
1182 
1183  if (i)
1184  pSelect->AddSelectableTrackSegment(prev_rlat, prev_rlon, prp->m_lat,
1185  prp->m_lon, prev_pConfPoint, prp,
1186  pTentTrack);
1187 
1188  prev_rlat = prp->m_lat;
1189  prev_rlon = prp->m_lon;
1190  prev_pConfPoint = prp;
1191  }
1192  } else
1193  delete pTentTrack;
1194 
1195  return bAddtrack;
1196 }
1197 
1198 bool InsertWpt(RoutePoint *pWp, bool overwrite) {
1199  bool res = false;
1200  RoutePoint *pExisting =
1201  WaypointExists(pWp->GetName(), pWp->m_lat, pWp->m_lon);
1202  if (!pExisting || overwrite) {
1203  if (NULL != pWayPointMan) {
1204  if (pExisting) {
1205  pWayPointMan->DestroyWaypoint(pExisting);
1206  }
1207  pWayPointMan->AddRoutePoint(pWp);
1208  res = true;
1209  }
1210  pSelect->AddSelectableRoutePoint(pWp->m_lat, pWp->m_lon, pWp);
1211  }
1212  return res;
1213 }
1214 
1215 static void UpdateRouteA(Route* pTentRoute,
1216  NavObjectCollection1* navobj,
1217  NavObjectChanges* nav_obj_changes) {
1218  if (!pTentRoute) return;
1219  if (pTentRoute->GetnPoints() < 2) return;
1220 
1221  // first delete the route to be modified if exists
1222  Route *pExisting = ::RouteExists(pTentRoute->m_GUID);
1223  if (pExisting) {
1224  navobj->m_bSkipChangeSetUpdate = true;
1225  g_pRouteMan->DeleteRoute(pExisting, nav_obj_changes);
1226  navobj->m_bSkipChangeSetUpdate = false;
1227  }
1228 
1229  // create a new route
1230  Route *pChangeRoute = new Route();
1231  pRouteList->Append(pChangeRoute);
1232 
1233  // update new route keeping the same gui
1234  pChangeRoute->m_GUID = pTentRoute->m_GUID;
1235  pChangeRoute->m_RouteNameString = pTentRoute->m_RouteNameString;
1236  pChangeRoute->m_RouteStartString = pTentRoute->m_RouteStartString;
1237  pChangeRoute->m_RouteEndString = pTentRoute->m_RouteEndString;
1238  pChangeRoute->SetVisible(pTentRoute->IsVisible());
1239 
1240  // Add points and segments to new route
1241  int ip = 0;
1242  float prev_rlat = 0., prev_rlon = 0.;
1243  RoutePoint *prev_pConfPoint = NULL;
1244 
1245  wxRoutePointListNode *node = pTentRoute->pRoutePointList->GetFirst();
1246  while (node) {
1247  RoutePoint *prp = node->GetData();
1248 
1249  // if some wpts have been not deleted, that meens they should be used in
1250  // other routes or are isolated way points so need to be updated
1251  RoutePoint *ex_rp = ::WaypointExists(prp->m_GUID);
1252  if (ex_rp) {
1253  pSelect->DeleteSelectableRoutePoint(ex_rp);
1254  ex_rp->m_lat = prp->m_lat;
1255  ex_rp->m_lon = prp->m_lon;
1256  ex_rp->SetIconName(prp->GetIconName());
1257  ex_rp->m_MarkDescription = prp->m_MarkDescription;
1258  ex_rp->SetName(prp->GetName());
1259  ex_rp->m_TideStation = prp->m_TideStation;
1260  ex_rp->SetPlannedSpeed(prp->GetPlannedSpeed());
1261  pChangeRoute->AddPoint(ex_rp);
1262  pSelect->AddSelectableRoutePoint(prp->m_lat, prp->m_lon, ex_rp);
1263 
1264  } else {
1265  pChangeRoute->AddPoint(prp);
1266  pSelect->AddSelectableRoutePoint(prp->m_lat, prp->m_lon, prp);
1267  pWayPointMan->AddRoutePoint(prp);
1268  }
1269 
1270  if (ip)
1271  pSelect->AddSelectableRouteSegment(prev_rlat, prev_rlon, prp->m_lat,
1272  prp->m_lon, prev_pConfPoint, prp,
1273  pChangeRoute);
1274  prev_rlat = prp->m_lat;
1275  prev_rlon = prp->m_lon;
1276  prev_pConfPoint = prp;
1277 
1278  ip++;
1279 
1280  node = node->GetNext();
1281  }
1282  // Do the (deferred) calculation of BBox
1283  pChangeRoute->FinalizeForRendering();
1284 }
1285 
1286 Route* FindRouteContainingWaypoint(RoutePoint *pWP) {
1287  wxRouteListNode *node = pRouteList->GetFirst();
1288  while (node) {
1289  Route *proute = node->GetData();
1290 
1291  wxRoutePointListNode *pnode = (proute->pRoutePointList)->GetFirst();
1292  while (pnode) {
1293  RoutePoint *prp = pnode->GetData();
1294  if (prp == pWP) return proute;
1295  pnode = pnode->GetNext();
1296  }
1297 
1298  node = node->GetNext();
1299  }
1300 
1301  return NULL; // not found
1302 }
1303 
1304 
1305 bool NavObjectCollection1::CreateNavObjGPXPoints(void) {
1306  // Iterate over the Routepoint list, creating Nodes for
1307  // Routepoints that are not in any Route
1308  // as indicated by m_bIsolatedMark == false
1309 
1310  if (!pWayPointMan) return false;
1311 
1312  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
1313 
1314  RoutePoint *pr;
1315 
1316  while (node) {
1317  pr = node->GetData();
1318 
1319  if ((pr->m_bIsolatedMark) && !(pr->m_bIsInLayer) && !(pr->m_btemp)) {
1320  pugi::xml_node doc = root();
1321  pugi::xml_node gpx = doc.first_child();
1322  pugi::xml_node new_node = gpx.append_child("wpt");
1323 
1324  GPXCreateWpt(new_node, pr, OPT_WPT);
1325  }
1326  node = node->GetNext();
1327  }
1328 
1329  return true;
1330 }
1331 
1332 bool NavObjectCollection1::CreateNavObjGPXRoutes(void) {
1333  // Routes
1334  if (!pRouteList) return false;
1335 
1336  wxRouteListNode *node1 = pRouteList->GetFirst();
1337  while (node1) {
1338  Route *pRoute = node1->GetData();
1339 
1340  if (!pRoute->m_bIsInLayer && !pRoute->m_btemp){
1341  pugi::xml_node doc = root();
1342  pugi::xml_node gpx = doc.first_child();
1343  pugi::xml_node new_node = gpx.append_child("rte");
1344 
1345  GPXCreateRoute(new_node, pRoute);
1346  }
1347 
1348  node1 = node1->GetNext();
1349  }
1350 
1351  return true;
1352 }
1353 
1354 bool NavObjectCollection1::CreateNavObjGPXTracks(void) {
1355  // Tracks
1356  for (Track *pTrack : g_TrackList) {
1357  if (pTrack->GetnPoints()) {
1358  if (!pTrack->m_bIsInLayer && !pTrack->m_btemp){
1359  pugi::xml_node doc = root();
1360  pugi::xml_node gpx = doc.first_child();
1361  pugi::xml_node new_node = gpx.append_child("trk");
1362 
1363  GPXCreateTrk(new_node, pTrack, 0);
1364  }
1365  }
1366  }
1367 
1368  return true;
1369 }
1370 
1371 bool NavObjectCollection1::CreateAllGPXObjects() {
1372  SetRootGPXNode();
1373 
1374  CreateNavObjGPXPoints();
1375  CreateNavObjGPXRoutes();
1376  CreateNavObjGPXTracks();
1377 
1378  return true;
1379 }
1380 
1381 bool NavObjectCollection1::AddGPXRoute(Route *pRoute) {
1382  SetRootGPXNode();
1383  pugi::xml_node doc = root();
1384  pugi::xml_node gpx = doc.first_child();
1385  pugi::xml_node new_node = gpx.append_child("rte");
1386 
1387  GPXCreateRoute(new_node, pRoute);
1388  return true;
1389 }
1390 
1391 bool NavObjectCollection1::AddGPXTrack(Track *pTrk) {
1392  SetRootGPXNode();
1393  pugi::xml_node doc = root();
1394  pugi::xml_node gpx = doc.first_child();
1395  pugi::xml_node new_node = gpx.append_child("trk");
1396 
1397  GPXCreateTrk(new_node, pTrk, 0);
1398  return true;
1399 }
1400 
1401 bool NavObjectCollection1::AddGPXWaypoint(RoutePoint *pWP) {
1402  SetRootGPXNode();
1403  pugi::xml_node doc = root();
1404  pugi::xml_node gpx = doc.first_child();
1405  pugi::xml_node new_node = gpx.append_child("wpt");
1406 
1407  GPXCreateWpt(new_node, pWP, OPT_WPT);
1408  return true;
1409 }
1410 
1411 void NavObjectCollection1::AddGPXRoutesList(RouteList *pRoutes) {
1412  SetRootGPXNode();
1413 
1414  wxRouteListNode *pRoute = pRoutes->GetFirst();
1415  while (pRoute) {
1416  Route *pRData = pRoute->GetData();
1417  AddGPXRoute(pRData);
1418  pRoute = pRoute->GetNext();
1419  }
1420 }
1421 
1422 void NavObjectCollection1::AddGPXTracksList(std::vector<Track*> *pTracks) {
1423  SetRootGPXNode();
1424 
1425  for (Track *pRData : *pTracks) {
1426  AddGPXTrack(pRData);
1427  }
1428 }
1429 
1430 bool NavObjectCollection1::AddGPXPointsList(RoutePointList *pRoutePoints) {
1431  SetRootGPXNode();
1432 
1433  wxRoutePointListNode *pRoutePointNode = pRoutePoints->GetFirst();
1434  while (pRoutePointNode) {
1435  RoutePoint *pRP = pRoutePointNode->GetData();
1436  AddGPXWaypoint(pRP);
1437  pRoutePointNode = pRoutePointNode->GetNext();
1438  }
1439 
1440  return true;
1441 }
1442 
1443 void NavObjectCollection1::SetRootGPXNode(void) {
1444  if (!strlen(first_child().name())) {
1445  pugi::xml_node gpx_root = append_child("gpx");
1446  gpx_root.append_attribute("version") = "1.1";
1447  gpx_root.append_attribute("creator") = "OpenCPN";
1448  gpx_root.append_attribute("xmlns:xsi") =
1449  "http://www.w3.org/2001/XMLSchema-instance";
1450  gpx_root.append_attribute("xmlns") = "http://www.topografix.com/GPX/1/1";
1451  gpx_root.append_attribute("xmlns:gpxx") =
1452  "http://www.garmin.com/xmlschemas/GpxExtensions/v3";
1453  gpx_root.append_attribute("xsi:schemaLocation") =
1454  "http://www.topografix.com/GPX/1/1 "
1455  "http://www.topografix.com/GPX/1/1/gpx.xsd "
1456  "http://www.garmin.com/xmlschemas/GpxExtensions/v3 "
1457  "http://www8.garmin.com/xmlschemas/GpxExtensionsv3.xsd";
1458  gpx_root.append_attribute("xmlns:opencpn") = "http://www.opencpn.org";
1459  }
1460 }
1461 
1462 bool NavObjectCollection1::IsOpenCPN() {
1463  for (pugi::xml_attribute attr = root().first_child().first_attribute(); attr;
1464  attr = attr.next_attribute())
1465  if (!strcmp(attr.name(), "creator") && !strcmp(attr.value(), "OpenCPN"))
1466  return true;
1467  return false;
1468 }
1469 
1470 bool NavObjectCollection1::SaveFile(const wxString filename) {
1471  wxString tmp_filename = filename + ".tmp";
1472  if (wxFileExists(tmp_filename)) {
1473  wxRemoveFile(tmp_filename);
1474  }
1475  save_file(tmp_filename.fn_str(), " ");
1476  wxRenameFile(tmp_filename.fn_str(), filename.fn_str(), true);
1477  return true;
1478 }
1479 
1480 bool NavObjectCollection1::LoadAllGPXObjects(bool b_full_viz,
1481  int &wpt_duplicates,
1482  bool b_compute_bbox) {
1483  wpt_duplicates = 0;
1484  pugi::xml_node objects = this->child("gpx");
1485 
1486  for (pugi::xml_node object = objects.first_child(); object;
1487  object = object.next_sibling()) {
1488  if (!strcmp(object.name(), "wpt")) {
1489  RoutePoint *pWp = ::GPXLoadWaypoint1(object, _T("circle"), _T(""),
1490  b_full_viz, false, false, 0);
1491 
1492  pWp->m_bIsolatedMark = true; // This is an isolated mark
1493  RoutePoint *pExisting =
1494  WaypointExists(pWp->GetName(), pWp->m_lat, pWp->m_lon);
1495  if (!pExisting) {
1496  if (NULL != pWayPointMan) pWayPointMan->AddRoutePoint(pWp);
1497  pSelect->AddSelectableRoutePoint(pWp->m_lat, pWp->m_lon, pWp);
1498  LLBBox wptbox;
1499  wptbox.Set(pWp->m_lat, pWp->m_lon, pWp->m_lat, pWp->m_lon);
1500  BBox.Expand(wptbox);
1501  } else {
1502  delete pWp;
1503  wpt_duplicates++;
1504  }
1505  } else if (!strcmp(object.name(), "trk")) {
1506  Track *pTrack = GPXLoadTrack1(object, b_full_viz, false, false, 0);
1507  if (InsertTrack(pTrack) && b_compute_bbox && pTrack->IsVisible()) {
1508  // BBox.Expand(pTrack->GetBBox());
1509  }
1510  } else if (!strcmp(object.name(), "rte")) {
1511  Route *pRoute = GPXLoadRoute1(object, b_full_viz, false, false, 0, false);
1512  if (InsertRouteA(pRoute, this) && b_compute_bbox && pRoute->IsVisible()) {
1513  BBox.Expand(pRoute->GetBBox());
1514  }
1515  }
1516  }
1517 
1518  return true;
1519 }
1520 
1521 
1522 int NavObjectCollection1::LoadAllGPXObjectsAsLayer(int layer_id,
1523  bool b_layerviz,
1524  wxCheckBoxState b_namesviz) {
1525  if (!pWayPointMan) return 0;
1526 
1527  int n_obj = 0;
1528  pugi::xml_node objects = this->child("gpx");
1529 
1530  for (pugi::xml_node object = objects.first_child(); object;
1531  object = object.next_sibling()) {
1532  if (!strcmp(object.name(), "wpt")) {
1533  RoutePoint *pWp = ::GPXLoadWaypoint1(object, _T("circle"), _T(""),
1534  b_namesviz != wxCHK_UNDETERMINED,
1535  true, b_layerviz, layer_id);
1536  if (b_namesviz != wxCHK_UNDETERMINED) {
1537  pWp->SetNameShown(b_namesviz == wxCHK_CHECKED);
1538  }
1539  pWp->m_bIsolatedMark = true; // This is an isolated mark
1540  pWayPointMan->AddRoutePoint(pWp);
1541  pSelect->AddSelectableRoutePoint(pWp->m_lat, pWp->m_lon, pWp);
1542  n_obj++;
1543  } else {
1544  if (!strcmp(object.name(), "trk")) {
1545  Track *pTrack =
1546  GPXLoadTrack1(object, false, true, b_layerviz, layer_id);
1547  n_obj++;
1548  InsertTrack(pTrack);
1549  } else if (!strcmp(object.name(), "rte")) {
1550  Route *pRoute =
1551  GPXLoadRoute1(object, true, true, b_layerviz, layer_id, false);
1552  n_obj++;
1553  InsertRouteA(pRoute, this);
1554  }
1555  }
1556  }
1557 
1558  return n_obj;
1559 }
1560 
1561 NavObjectChanges::NavObjectChanges(wxString file_name)
1562  : NavObjectCollection1() {
1563  m_filename = file_name;
1564  m_changes_file = fopen(m_filename.mb_str(), "a");
1565  m_bdirty = false;
1566 }
1567 
1568 NavObjectChanges::~NavObjectChanges() {
1569  if (m_changes_file) fclose(m_changes_file);
1570  if (::wxFileExists(m_filename)) ::wxRemoveFile(m_filename);
1571 }
1572 
1573 void NavObjectChanges::AddRoute(Route *pr, const char *action) {
1574  SetRootGPXNode();
1575 
1576  pugi::xml_node object = root().append_child("rte");
1577  GPXCreateRoute(object, pr);
1578 
1579  pugi::xml_node xchild = object.child("extensions");
1580  // FIXME What if extensions do not exist?
1581  pugi::xml_node child = xchild.append_child("opencpn:action");
1582  child.append_child(pugi::node_pcdata).set_value(action);
1583 
1584  if (m_changes_file){
1585  pugi::xml_writer_file writer(m_changes_file);
1586  object.print(writer, " ");
1587  fflush(m_changes_file);
1588  m_bdirty = true;
1589  }
1590 }
1591 
1592 void NavObjectChanges::AddTrack(Track *pr, const char *action) {
1593  SetRootGPXNode();
1594 
1595  pugi::xml_node object = root().append_child("trk");
1596  GPXCreateTrk(object, pr, RT_OUT_NO_RTPTS); // emit a void track, no waypoints
1597 
1598  pugi::xml_node xchild = object.child("extensions");
1599  pugi::xml_node child = xchild.append_child("opencpn:action");
1600  child.append_child(pugi::node_pcdata).set_value(action);
1601 
1602  if (m_changes_file){
1603  pugi::xml_writer_file writer(m_changes_file);
1604  object.print(writer, " ");
1605  fflush(m_changes_file);
1606  m_bdirty = true;
1607  }
1608 }
1609 
1610 void NavObjectChanges::AddWP(RoutePoint *pWP, const char *action) {
1611  SetRootGPXNode();
1612 
1613  pugi::xml_node object = root().append_child("wpt");
1614 
1615  int flags = OPT_WPT;
1616  // If the action is a simple deletion, simplify the output flags
1617  if(!strncmp(action, "delete", 6))
1618  flags = OUT_GUID | OUT_NAME;
1619 
1620  GPXCreateWpt(object, pWP, flags);
1621 
1622  pugi::xml_node xchild = object.child("extensions");
1623  pugi::xml_node child = xchild.append_child("opencpn:action");
1624  child.append_child(pugi::node_pcdata).set_value(action);
1625 
1626  if (m_changes_file){
1627  pugi::xml_writer_file writer(m_changes_file);
1628  object.print(writer, " ");
1629  fflush(m_changes_file);
1630  m_bdirty = true;
1631  }
1632 }
1633 
1634 void NavObjectChanges::AddTrackPoint(TrackPoint *pWP, const char *action,
1635  const wxString &parent_GUID) {
1636  SetRootGPXNode();
1637 
1638  pugi::xml_node object = root().append_child("tkpt");
1639  GPXCreateTrkpt(object, pWP, OPT_TRACKPT);
1640 
1641  pugi::xml_node xchild = object.append_child("extensions");
1642 
1643  pugi::xml_node child = xchild.append_child("opencpn:action");
1644  child.append_child(pugi::node_pcdata).set_value(action);
1645 
1646  pugi::xml_node gchild = xchild.append_child("opencpn:track_GUID");
1647  gchild.append_child(pugi::node_pcdata).set_value(parent_GUID.mb_str());
1648 
1649  if (m_changes_file){
1650  pugi::xml_writer_file writer(m_changes_file);
1651  object.print(writer, " ");
1652  fflush(m_changes_file);
1653  m_bdirty = true;
1654  }
1655 }
1656 
1657 bool NavObjectChanges::ApplyChanges(void) {
1658  // Let's reconstruct the unsaved changes
1659 
1660  pugi::xml_node object = this->first_child();
1661 
1662  while (strlen(object.name())) {
1663  if (!strcmp(object.name(), "wpt") && pWayPointMan) {
1664  RoutePoint *pWp = ::GPXLoadWaypoint1(object, _T("circle"), _T(""), false,
1665  false, false, 0);
1666 
1667  pWp->m_bIsolatedMark = true;
1668  RoutePoint *pExisting = WaypointExists(pWp->m_GUID);
1669 
1670  pugi::xml_node xchild = object.child("extensions");
1671  pugi::xml_node child = xchild.child("opencpn:action");
1672 
1673  if (!strcmp(child.first_child().value(), "add")) {
1674  if (!pExisting) pWayPointMan->AddRoutePoint(pWp);
1675  pSelect->AddSelectableRoutePoint(pWp->m_lat, pWp->m_lon, pWp);
1676  }
1677 
1678  else if (!strcmp(child.first_child().value(), "update")) {
1679  if (pExisting) {
1680  pWayPointMan->RemoveRoutePoint(pExisting);
1681  pWayPointMan->DestroyWaypoint(pExisting, false);
1682  delete pExisting;
1683  pWayPointMan->AddRoutePoint(pWp);
1684  pSelect->AddSelectableRoutePoint(pWp->m_lat, pWp->m_lon, pWp);
1685  } else {
1686  delete pWp;
1687  }
1688  }
1689 
1690  else if (!strcmp(child.first_child().value(), "delete")) {
1691  if (pExisting) pWayPointMan->DestroyWaypoint(pExisting, false);
1692  delete pExisting;
1693  delete pWp;
1694  } else
1695  delete pWp;
1696  } else if (!strcmp(object.name(), "trk") && g_pRouteMan) {
1697  Track *pTrack = GPXLoadTrack1(object, false, false, false, 0);
1698 
1699  if (pTrack) {
1700  pugi::xml_node xchild = object.child("extensions");
1701  pugi::xml_node child = xchild.child("opencpn:action");
1702 
1703  Track *pExisting = TrackExists(pTrack->m_GUID);
1704  if (!strcmp(child.first_child().value(), "update")) {
1705  if (pExisting) {
1706  pExisting->SetName(pTrack->GetName());
1707  pExisting->m_TrackStartString = pTrack->m_TrackStartString;
1708  pExisting->m_TrackEndString = pTrack->m_TrackEndString;
1709  }
1710  delete pTrack;
1711  }
1712 
1713  else if (!strcmp(child.first_child().value(), "delete")) {
1714  if (pExisting) {
1715  m_bSkipChangeSetUpdate = true;
1716  //evt_delete_track.Notify(std::make_shared<Track>(*pExisting), ""); // Why were we doing this? pExisting got destroyed immediately...
1717  g_pRouteMan->DeleteTrack(pExisting);
1718  m_bSkipChangeSetUpdate = false;
1719  }
1720  delete pTrack;
1721  }
1722 
1723  else if (!strcmp(child.first_child().value(), "add")) {
1724  if (!pExisting) ::InsertTrack(pTrack, true);
1725  }
1726 
1727  else
1728  delete pTrack;
1729  }
1730  }
1731 
1732  else if (!strcmp(object.name(), "rte") && g_pRouteMan) {
1733  Route *pRoute = GPXLoadRoute1(object, false, false, false, 0, true, false);
1734 
1735  if (pRoute) {
1736  Route *pExisting = RouteExists(pRoute->m_GUID);
1737  pugi::xml_node xchild = object.child("extensions");
1738  pugi::xml_node child = xchild.child("opencpn:action");
1739 
1740  if (!strcmp(child.first_child().value(), "add")) {
1741  delete pRoute;
1742  pRoute = GPXLoadRoute1(object, false, false, false, 0, true, true);
1743  ::UpdateRouteA(pRoute, this, this);
1744  delete pRoute;
1745  }
1746 
1747  else if (!strcmp(child.first_child().value(), "update")) {
1748  if (pExisting) {
1749  delete pRoute;
1750  pRoute = GPXLoadRoute1(object, false, false, false, 0, true, true);
1751  ::UpdateRouteA(pRoute, this, this);
1752  }
1753  delete pRoute;
1754  }
1755 
1756  else if (!strcmp(child.first_child().value(), "delete")) {
1757  if (pExisting) {
1758  m_bSkipChangeSetUpdate = true;
1759  //evt_delete_route.Notify(std::make_shared<Route>(*pExisting), ""); // Why were we doing this? pExisting got destroyed immediately...
1760  g_pRouteMan->DeleteRoute(pExisting, this);
1761  m_bSkipChangeSetUpdate = false;
1762  }
1763  delete pRoute;
1764  }
1765 
1766  else {
1767  delete pRoute;
1768  }
1769  }
1770  } else if (!strcmp(object.name(), "tkpt") && pWayPointMan) {
1771  TrackPoint *pWp = ::GPXLoadTrackPoint1(object);
1772 
1773  // RoutePoint *pExisting = WaypointExists(
1774  // pWp->GetName(), pWp->m_lat, pWp->m_lon );
1775 
1776  pugi::xml_node xchild = object.child("extensions");
1777  pugi::xml_node child = xchild.child("opencpn:action");
1778 
1779  pugi::xml_node guid_child = xchild.child("opencpn:track_GUID");
1780  wxString track_GUID(guid_child.first_child().value(), wxConvUTF8);
1781 
1782  Track *pExistingTrack = TrackExists(track_GUID);
1783 
1784  if (!strcmp(child.first_child().value(), "add") && pExistingTrack && pWp) {
1785  pExistingTrack->AddPoint(pWp);
1786  pWp->m_GPXTrkSegNo = pExistingTrack->GetCurrentTrackSeg() + 1;
1787  } else
1788  delete pWp;
1789  }
1790 
1791  object = object.next_sibling();
1792  }
1793  // Check to make sure we haven't loaded tracks with less than 2 points
1794  auto it = g_TrackList.begin();
1795  while (it != g_TrackList.end()) {
1796  Track *pTrack = *it;
1797  if (pTrack->GetnPoints() < 2) {
1798  auto to_erase = it;
1799  --it;
1800  g_TrackList.erase(to_erase);
1801  delete pTrack;
1802  }
1803  ++it;
1804  }
1805 
1806  return true;
1807 }
1808 
1809 
1810 void NavObjectChanges::AddNewRoute(Route *pr) {
1811  // if( pr->m_bIsInLayer )
1812  // return true;
1813  if (!m_bSkipChangeSetUpdate) AddRoute(pr, "add");
1814 }
1815 
1816 void NavObjectChanges::UpdateRoute(Route *pr) {
1817  // if( pr->m_bIsInLayer ) return true;
1818  if (!m_bSkipChangeSetUpdate) AddRoute(pr, "update");
1819 }
1820 
1821 void NavObjectChanges::DeleteConfigRoute(Route *pr) {
1822  // if( pr->m_bIsInLayer )
1823  // return true;
1824  if (!m_bSkipChangeSetUpdate) AddRoute(pr, "delete");
1825 }
1826 
1827 void NavObjectChanges::AddNewTrack(Track *pt) {
1828  if (!pt->m_bIsInLayer && !m_bSkipChangeSetUpdate) AddTrack(pt, "add");
1829 }
1830 
1831 void NavObjectChanges::UpdateTrack(Track *pt) {
1832  if (pt->m_bIsInLayer && !m_bSkipChangeSetUpdate) AddTrack(pt, "update");
1833 }
1834 
1835 void NavObjectChanges::DeleteConfigTrack(Track *pt) {
1836  if (!pt->m_bIsInLayer && !m_bSkipChangeSetUpdate) AddTrack(pt, "delete");
1837 }
1838 
1839 void NavObjectChanges::AddNewWayPoint(RoutePoint *pWP, int crm) {
1840  if (!pWP->m_bIsInLayer && pWP->m_bIsolatedMark && !m_bSkipChangeSetUpdate)
1841  AddWP(pWP, "add");
1842 }
1843 
1844 void NavObjectChanges::UpdateWayPoint(RoutePoint *pWP) {
1845  if (!pWP->m_bIsInLayer && !m_bSkipChangeSetUpdate) AddWP(pWP, "update");
1846 }
1847 
1848 void NavObjectChanges::DeleteWayPoint(RoutePoint *pWP) {
1849  if (!pWP->m_bIsInLayer && !m_bSkipChangeSetUpdate) AddWP(pWP, "delete");
1850 }
1851 
1852 void NavObjectChanges::AddNewTrackPoint(TrackPoint *pWP,
1853  const wxString &parent_GUID) {
1854  if (!m_bSkipChangeSetUpdate) AddTrackPoint(pWP, "add", parent_GUID);
1855 }
1856 
1857 RoutePoint *WaypointExists(const wxString &name, double lat, double lon) {
1858  RoutePoint *pret = NULL;
1859  // if( g_bIsNewLayer ) return NULL;
1860  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
1861  while (node) {
1862  RoutePoint *pr = node->GetData();
1863 
1864  // if( pr->m_bIsInLayer ) return NULL;
1865 
1866  if (name == pr->GetName()) {
1867  if (fabs(lat - pr->m_lat) < 1.e-6 && fabs(lon - pr->m_lon) < 1.e-6) {
1868  pret = pr;
1869  break;
1870  }
1871  }
1872  node = node->GetNext();
1873  }
1874 
1875  return pret;
1876 }
1877 
1878 RoutePoint *WaypointExists(const wxString &guid) {
1879  wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
1880  while (node) {
1881  RoutePoint *pr = node->GetData();
1882 
1883  // if( pr->m_bIsInLayer ) return NULL;
1884 
1885  if (guid == pr->m_GUID) {
1886  return pr;
1887  }
1888  node = node->GetNext();
1889  }
1890 
1891  return NULL;
1892 }
1893 
1894 bool WptIsInRouteList(RoutePoint *pr) {
1895  bool IsInList = false;
1896 
1897  wxRouteListNode *node1 = pRouteList->GetFirst();
1898  while (node1) {
1899  Route *pRoute = node1->GetData();
1900  RoutePointList *pRoutePointList = pRoute->pRoutePointList;
1901 
1902  wxRoutePointListNode *node2 = pRoutePointList->GetFirst();
1903  RoutePoint *prp;
1904 
1905  while (node2) {
1906  prp = node2->GetData();
1907 
1908  if (pr->IsSame(prp)) {
1909  IsInList = true;
1910  break;
1911  }
1912 
1913  node2 = node2->GetNext();
1914  }
1915  node1 = node1->GetNext();
1916  }
1917  return IsInList;
1918 }
1919 
1920 Route *RouteExists(const wxString &guid) {
1921  wxRouteListNode *route_node = pRouteList->GetFirst();
1922 
1923  while (route_node) {
1924  Route *proute = route_node->GetData();
1925 
1926  if (guid == proute->m_GUID) return proute;
1927 
1928  route_node = route_node->GetNext();
1929  }
1930  return NULL;
1931 }
1932 
1933 Route *RouteExists(Route *pTentRoute) {
1934  wxRouteListNode *route_node = pRouteList->GetFirst();
1935  while (route_node) {
1936  Route *proute = route_node->GetData();
1937 
1938  if (proute->IsEqualTo(pTentRoute)) return proute;
1939 
1940  route_node = route_node->GetNext(); // next route
1941  }
1942  return NULL;
1943 }
1944 
1945 Track *TrackExists(const wxString &guid) {
1946  for (Track* ptrack : g_TrackList) {
1947  if (guid == ptrack->m_GUID) return ptrack;
1948  }
1949  return NULL;
1950 }
Definition: route.h:75
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
Definition: routeman.cpp:751
Definition: track.h:78