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