OpenCPN Partial API docs
Loading...
Searching...
No Matches
route.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 *
5 ***************************************************************************
6 * Copyright (C) 2013 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// For compilers that support precompilation, includes "wx.h".
25#include <wx/wxprec.h>
26
27#ifndef WX_PRECOMP
28#include <wx/wx.h>
29#endif // precompiled headers
30
31#ifndef WX_PRECOMP
32#include "wx/wx.h"
33#endif // precompiled headers
34
35#include <wx/arrstr.h>
36#include <wx/datetime.h>
37#include <wx/gdicmn.h>
38#include <wx/log.h>
39#include <wx/pen.h>
40#include <wx/string.h>
41
42#include "model/config_vars.h"
43#include "model/cutil.h"
44#include "model/georef.h"
45#include "model/georef.h"
46#include "model/config_vars.h"
47#include "model/nav_object_database.h"
48#include "model/route.h"
49#include "model/routeman.h"
50#include "model/select.h"
51
52WayPointman *pWayPointMan;
53double g_defaultBoatSpeed;
54
55#include <wx/listimpl.cpp>
56
57WX_DEFINE_LIST(RouteList);
58
59Route::Route() {
60 m_bRtIsSelected = false;
61 m_bRtIsActive = false;
62 m_pRouteActivePoint = NULL;
63 m_bIsBeingEdited = false;
64 m_bIsBeingCreated = false;
65 m_nm_sequence = 1;
66 m_route_length = 0.0;
67 m_route_time = 0.0;
68 m_bVisible = true;
69 m_bListed = true;
70 m_bDeleteOnArrival = false;
71 m_width = WIDTH_UNDEFINED;
72 m_style = wxPENSTYLE_INVALID;
73 m_hiliteWidth = 0;
74
75 pRoutePointList = new RoutePointList;
76 m_GUID = pWayPointMan->CreateGUID(NULL);
77 m_btemp = false;
78
79 m_ArrivalRadius = g_n_arrival_circle_radius; // Nautical Miles
80
81 m_LayerID = 0;
82 m_bIsInLayer = false;
83
84 m_Colour = wxEmptyString;
85
86 m_lastMousePointIndex = 0;
87 m_NextLegGreatCircle = false;
88
89 m_PlannedSpeed = ROUTE_DEFAULT_SPEED;
90 if (g_defaultBoatSpeed != ROUTE_DEFAULT_SPEED)
91 m_PlannedSpeed = g_defaultBoatSpeed;
92
93 m_PlannedDeparture = RTE_UNDEF_DEPARTURE;
94 m_TimeDisplayFormat = RTE_TIME_DISP_PC;
95 m_HyperlinkList = new HyperlinkList;
96
97 m_bsharedWPViz = false;
98}
99
100Route::~Route() {
101 pRoutePointList->DeleteContents(false); // do not delete Marks
102 delete pRoutePointList;
103 delete m_HyperlinkList;
104}
105
106// The following is used only for route splitting, assumes just created, empty
107// route
108//
109void Route::CloneRoute(Route *psourceroute, int start_nPoint, int end_nPoint,
110 const wxString &suffix,
111 const bool duplicate_first_point) {
112 m_RouteNameString = psourceroute->m_RouteNameString + suffix;
113 m_RouteStartString = psourceroute->m_RouteStartString;
114 m_RouteEndString = psourceroute->m_RouteEndString;
115
116 int i;
117 for (i = start_nPoint; i <= end_nPoint; i++) {
118 if (!psourceroute->m_bIsInLayer &&
119 !(i == start_nPoint && duplicate_first_point)) {
120 AddPoint(psourceroute->GetPoint(i), false);
121 } else {
122 RoutePoint *psourcepoint = psourceroute->GetPoint(i);
123 RoutePoint *ptargetpoint = new RoutePoint(
124 psourcepoint->m_lat, psourcepoint->m_lon, psourcepoint->GetIconName(),
125 psourcepoint->GetName(), wxEmptyString, true);
126 ptargetpoint->m_bShowName =
127 psourcepoint->m_bShowName; // do not change new wpt's name visibility
128 AddPoint(ptargetpoint, false);
129 }
130 }
131
132 FinalizeForRendering();
133}
134
135wxString Route::IsPointNameValid(RoutePoint *pPoint,
136 const wxString &name) const {
137 RoutePoint *point;
138 wxRoutePointListNode *node = pRoutePointList->GetFirst();
139 wxString substr = name.SubString(0, 6);
140
141 while (node) {
142 point = node->GetData();
143 wxString exist = point->GetName().SubString(0, 6);
144
145 if (pPoint->m_GUID == point->m_GUID) {
146 node = node->GetNext();
147 } else if (substr == exist) {
148 return wxString("Name is not unique in route");
149 } else {
150 node = node->GetNext();
151 }
152 }
153
154 return wxEmptyString;
155}
156
157void Route::AddPoint(RoutePoint *pNewPoint, bool b_rename_in_sequence,
158 bool b_deferBoxCalc) {
159 if (pNewPoint->m_bIsolatedMark) {
160 pNewPoint->SetShared(true);
161 }
162 pNewPoint->m_bIsolatedMark = false; // definitely no longer isolated
163 pNewPoint->m_bIsInRoute = true;
164
165 RoutePoint *prev = GetLastPoint();
166 pRoutePointList->Append(pNewPoint);
167
168 if (!b_deferBoxCalc) FinalizeForRendering();
169
170 if (prev) UpdateSegmentDistance(prev, pNewPoint);
171
172 if (b_rename_in_sequence && pNewPoint->GetName().IsEmpty() &&
173 !pNewPoint->IsShared()) {
174 wxString name;
175 name.Printf(_T("%03d"), GetnPoints());
176 pNewPoint->SetName(name);
177 }
178 return;
179}
180
181void Route::AddPointAndSegment(RoutePoint *pNewPoint, bool b_rename_in_sequence,
182 bool b_deferBoxCalc) {
183 int npoints = GetnPoints();
184 RoutePoint *newpoint = pNewPoint;
185 if (newpoint->m_bIsInLayer) {
186 newpoint = new RoutePoint(pNewPoint->m_lat, pNewPoint->m_lon,
187 pNewPoint->GetIconName(), pNewPoint->GetName(),
188 wxEmptyString, false);
189 newpoint->m_bShowName =
190 pNewPoint->m_bShowName; // do not change new wpt's name visibility
191 }
192 AddPoint(newpoint, false);
193 if (npoints != 0) {
194 double rlat = GetPoint(npoints)->m_lat;
195 double rlon = GetPoint(npoints)->m_lon;
196 npoints = GetnPoints();
197 pSelect->AddSelectableRouteSegment(
198 rlat, rlon, GetPoint(npoints)->m_lat, GetPoint(npoints)->m_lon,
199 GetPoint(npoints - 1), GetPoint(npoints), this);
200 }
201 m_lastMousePointIndex = GetnPoints();
202}
203
204void Route::InsertPointAndSegment(RoutePoint *pNewPoint, int insert_after,
205 bool bRenamePoints, bool b_deferBoxCalc) {
206 {
207 bool add = false;
208
209 if (pNewPoint->m_bIsolatedMark) {
210 pNewPoint->SetShared(true);
211 }
212 pNewPoint->m_bIsolatedMark = false; // definitely no longer isolated
213 pNewPoint->m_bIsInRoute = true;
214
215 if (insert_after >= GetnPoints() - 1) {
216 wxLogMessage(wxT("Error insert after last point"));
217 return;
218 }
219
220 int insert = insert_after++;
221 pNewPoint->m_bIsInRoute = true;
222 pNewPoint->SetNameShown(false);
223 pRoutePointList->Insert(insert, pNewPoint);
224 if (bRenamePoints) RenameRoutePoints();
225 m_lastMousePointIndex = GetnPoints();
226 FinalizeForRendering();
227 UpdateSegmentDistances();
228 return;
229 }
230}
231
232RoutePoint *Route::GetPoint(int nWhichPoint) {
233 RoutePoint *prp;
234 wxRoutePointListNode *node = pRoutePointList->GetFirst();
235
236 int i = 1;
237 while (node) {
238 prp = node->GetData();
239 if (i == nWhichPoint) {
240 return prp;
241 }
242 i++;
243 node = node->GetNext();
244 }
245
246 return (NULL);
247}
248
249RoutePoint *Route::GetPoint(const wxString &guid) {
250 RoutePoint *prp;
251 wxRoutePointListNode *node = pRoutePointList->GetFirst();
252
253 while (node) {
254 prp = node->GetData();
255 if (guid == prp->m_GUID) return prp;
256
257 node = node->GetNext();
258 }
259
260 return (NULL);
261}
262
263static void TestLongitude(double lon, double min, double max, bool &lonl,
264 bool &lonr) {
265 double clon = (min + max) / 2;
266 if (min - lon > 180) lon += 360;
267
268 lonl = lonr = false;
269 if (lon < min) {
270 if (lon < clon - 180)
271 lonr = true;
272 else
273 lonl = true;
274 } else if (lon > max) {
275 if (lon > clon + 180)
276 lonl = true;
277 else
278 lonr = true;
279 }
280}
281
282bool Route::ContainsSharedWP() {
283 for (wxRoutePointListNode *node = pRoutePointList->GetFirst(); node;
284 node = node->GetNext()) {
285 RoutePoint *prp = node->GetData();
286 if (prp->IsShared()) return true;
287 }
288 return false;
289}
290
291// FIXME (leamas): can this be moved to GUI?
292int s_arrow_icon[] = {0, 0, 5, 2, 18, 6, 12, 0, 18, -6, 5, -2, 0, 0};
293void Route::ClearHighlights(void) {
294 RoutePoint *prp = NULL;
295 wxRoutePointListNode *node = pRoutePointList->GetFirst();
296
297 while (node) {
298 prp = node->GetData();
299 if (prp) prp->m_bPtIsSelected = false;
300 node = node->GetNext();
301 }
302}
303
304RoutePoint *Route::InsertPointBefore(RoutePoint *pRP, double rlat, double rlon,
305 bool bRenamePoints) {
306 RoutePoint *newpoint = new RoutePoint(rlat, rlon, g_default_routepoint_icon,
307 GetNewMarkSequenced(), wxEmptyString);
308 newpoint->m_bIsInRoute = true;
309 newpoint->SetNameShown(false);
310
311 int nRP = pRoutePointList->IndexOf(pRP);
312 pRoutePointList->Insert(nRP, newpoint);
313
314 if (bRenamePoints) RenameRoutePoints();
315
316 FinalizeForRendering();
317 UpdateSegmentDistances();
318
319 return (newpoint);
320}
321
322RoutePoint *Route::InsertPointAfter(RoutePoint *pRP, double rlat, double rlon,
323 bool bRenamePoints) {
324 int nRP = pRoutePointList->IndexOf(pRP);
325 if (nRP >= GetnPoints() - 1) return NULL;
326 nRP++;
327
328 RoutePoint *newpoint = new RoutePoint(rlat, rlon, g_default_routepoint_icon,
329 GetNewMarkSequenced(), wxEmptyString);
330 newpoint->m_bIsInRoute = true;
331 newpoint->SetNameShown(false);
332
333 pRoutePointList->Insert(nRP, newpoint);
334
335 if (bRenamePoints) RenameRoutePoints();
336
337 FinalizeForRendering();
338 UpdateSegmentDistances();
339
340 return (newpoint);
341}
342
343wxString Route::GetNewMarkSequenced(void) {
344 wxString ret;
345 ret.Printf(_T ( "NM%03d" ), m_nm_sequence);
346 m_nm_sequence++;
347
348 return ret;
349}
350
351RoutePoint *Route::GetLastPoint() {
352 if (pRoutePointList->IsEmpty()) return NULL;
353
354 return pRoutePointList->GetLast()->GetData();
355}
356
357int Route::GetIndexOf(RoutePoint *prp) {
358 int ret = pRoutePointList->IndexOf(prp) + 1;
359 if (ret == wxNOT_FOUND)
360 return 0;
361 else
362 return ret;
363}
364
365void Route::DeletePoint(RoutePoint *rp, bool bRenamePoints) {
366 // n.b. must delete Selectables and update config before deleting the
367 // point
368 if (rp->m_bIsInLayer) return;
369
370 pSelect->DeleteAllSelectableRoutePoints(this);
371 pSelect->DeleteAllSelectableRouteSegments(this);
372 NavObjectChanges::getInstance()->DeleteWayPoint(rp);
373
374 pRoutePointList->DeleteObject(rp);
375
376 delete rp;
377
378 if (bRenamePoints) RenameRoutePoints();
379
380 if (GetnPoints() > 1) {
381 pSelect->AddAllSelectableRouteSegments(this);
382 pSelect->AddAllSelectableRoutePoints(this);
383
384 NavObjectChanges::getInstance()->UpdateRoute(this);
385
386 FinalizeForRendering();
387 UpdateSegmentDistances();
388 }
389}
390
391void Route::RemovePoint(RoutePoint *rp, bool bRenamePoints) {
392 if (rp->m_bIsActive && this->IsActive()) // FS#348
393 g_pRouteMan->DeactivateRoute();
394
395 pSelect->DeleteAllSelectableRoutePoints(this);
396 pSelect->DeleteAllSelectableRouteSegments(this);
397
398 pRoutePointList->DeleteObject(rp);
399
400 // check all other routes to see if this point appears in any other route
401 Route *pcontainer_route = FindRouteContainingWaypoint(rp);
402
403 if (pcontainer_route == NULL) {
404 rp->m_bIsInRoute = false; // Take this point out of this (and only) route
405 rp->m_bIsolatedMark = true; // This has become an isolated mark
406 }
407
408 if (bRenamePoints) RenameRoutePoints();
409
410 // if ( m_nPoints > 1 )
411 {
412 pSelect->AddAllSelectableRouteSegments(this);
413 pSelect->AddAllSelectableRoutePoints(this);
414
415 NavObjectChanges::getInstance()->UpdateRoute(this);
416
417 FinalizeForRendering();
418 UpdateSegmentDistances();
419 }
420}
421
422void Route::DeSelectRoute() {
423 wxRoutePointListNode *node = pRoutePointList->GetFirst();
424
425 RoutePoint *rp;
426 while (node) {
427 rp = node->GetData();
428 rp->m_bPtIsSelected = false;
429
430 node = node->GetNext();
431 }
432}
433
434void Route::ReloadRoutePointIcons() {
435 wxRoutePointListNode *node = pRoutePointList->GetFirst();
436
437 RoutePoint *rp;
438 while (node) {
439 rp = node->GetData();
440 rp->ReLoadIcon();
441
442 node = node->GetNext();
443 }
444}
445
446void Route::FinalizeForRendering() { RBBox.Invalidate(); }
447
448LLBBox &Route::GetBBox(void) {
449 if (RBBox.GetValid()) return RBBox;
450
451 double bbox_lonmin, bbox_lonmax, bbox_latmin, bbox_latmax;
452
453 wxRoutePointListNode *node = pRoutePointList->GetFirst();
454 RoutePoint *data = node->GetData();
455
456 if (data->m_wpBBox.GetValid()) {
457 bbox_lonmax = data->m_wpBBox.GetMaxLon();
458 bbox_lonmin = data->m_wpBBox.GetMinLon();
459 bbox_latmax = data->m_wpBBox.GetMaxLat();
460 bbox_latmin = data->m_wpBBox.GetMinLat();
461 } else {
462 bbox_lonmax = bbox_lonmin = data->m_lon;
463 bbox_latmax = bbox_latmin = data->m_lat;
464 }
465
466 double lastlon = data->m_lon, wrap = 0;
467
468 node = node->GetNext();
469 while (node) {
470 data = node->GetData();
471
472 if (lastlon - data->m_lon > 180)
473 wrap += 360;
474 else if (data->m_lon - lastlon > 180)
475 wrap -= 360;
476
477 double lon = data->m_lon + wrap;
478
479 if (lon > bbox_lonmax) bbox_lonmax = lon;
480 if (lon < bbox_lonmin) bbox_lonmin = lon;
481
482 if (data->m_lat > bbox_latmax) bbox_latmax = data->m_lat;
483 if (data->m_lat < bbox_latmin) bbox_latmin = data->m_lat;
484
485 lastlon = data->m_lon;
486 node = node->GetNext();
487 }
488
489 if (bbox_lonmin < -360)
490 bbox_lonmin += 360, bbox_lonmax += 360;
491 else if (bbox_lonmax > 360)
492 bbox_lonmin -= 360, bbox_lonmax -= 360;
493
494 if (bbox_lonmax - bbox_lonmin > 360) bbox_lonmin = -180, bbox_lonmax = 180;
495
496 RBBox.Set(bbox_latmin, bbox_lonmin, bbox_latmax, bbox_lonmax);
497
498 return RBBox;
499}
500
501/*
502 Update a single route segment lengths
503 Also, compute total route length by summing segment distances.
504 */
505void Route::UpdateSegmentDistance(RoutePoint *prp0, RoutePoint *prp,
506 double planspeed) {
507 double slat1 = prp0->m_lat, slon1 = prp0->m_lon;
508 double slat2 = prp->m_lat, slon2 = prp->m_lon;
509
510 // Calculate the absolute distance from 1->2
511
512 double dd;
513 double br;
514 // why are we using mercator rather than great circle here?? [sean 8-11-2015]
515 DistanceBearingMercator(slat2, slon2, slat1, slon1, &br, &dd);
516
517 prp->SetCourse(br);
518 prp->SetDistance(dd);
519
520 // And store in Point 2
521 prp->m_seg_len = dd;
522
523 m_route_length += dd;
524
525 // If Point1 Description contains VMG, store it for Properties Dialog in
526 // Point2 If Point1 Description contains ETD, store it in Point1
527
528 if (planspeed > 0.) {
529 wxDateTime etd;
530
531 double legspeed = planspeed;
532 if (prp->GetPlannedSpeed() > 0.1 && prp->GetPlannedSpeed() < 1000.)
533 legspeed = prp->GetPlannedSpeed();
534 if (legspeed > 0.1 && legspeed < 1000.) {
535 m_route_time += 3600. * dd / legspeed;
536 prp->m_seg_vmg = legspeed;
537 }
538 wxLongLong duration = wxLongLong(3600.0 * prp->m_seg_len / prp->m_seg_vmg);
539 prp->SetETE(duration);
540 wxTimeSpan ts(0, 0, duration);
541 if (!prp0->GetManualETD().IsValid()) {
542 prp0->m_manual_etd = false;
543 if (prp0->GetETA().IsValid()) {
544 prp0->m_seg_etd = prp0->GetETA();
545 } else {
546 prp0->m_seg_etd =
547 m_PlannedDeparture + wxTimeSpan(0, 0, m_route_time - duration);
548 }
549 }
550
551 prp->m_seg_eta = prp0->GetETD() + ts;
552 if (!prp->m_manual_etd || !prp->GetETD().IsValid()) {
553 prp->m_seg_etd = prp->m_seg_eta;
554 prp->m_manual_etd = false;
555 }
556 }
557}
558
559/*
560 Update the route segment lengths, storing each segment length in <destination>
561 point. Also, compute total route length by summing segment distances.
562 */
563void Route::UpdateSegmentDistances(double planspeed) {
564 wxPoint rpt, rptn;
565
566 m_route_length = 0.0;
567 m_route_time = 0.0;
568
569 wxRoutePointListNode *node = pRoutePointList->GetFirst();
570
571 if (node) {
572 // Route start point
573 RoutePoint *prp0 = node->GetData();
574 if (!prp0->m_manual_etd) {
575 prp0->m_seg_eta = m_PlannedDeparture;
576 prp0->m_seg_etd = m_PlannedDeparture;
577 }
578 node = node->GetNext();
579
580 while (node) {
581 RoutePoint *prp = node->GetData();
582 UpdateSegmentDistance(prp0, prp, planspeed);
583
584 prp0 = prp;
585
586 node = node->GetNext();
587 }
588 }
589}
590
591void Route::Reverse(bool bRenamePoints) {
592 // Reverse the GUID list
593 wxArrayString RoutePointGUIDList;
594
595 int ncount = pRoutePointList->GetCount();
596 for (int i = 0; i < ncount; i++)
597 RoutePointGUIDList.Add(GetPoint(ncount - i)->m_GUID);
598
599 pRoutePointList->DeleteContents(false);
600 pRoutePointList->Clear();
601 m_route_length = 0.0;
602
603 // iterate over the RoutePointGUIDs
604 for (unsigned int ip = 0; ip < RoutePointGUIDList.GetCount(); ip++) {
605 wxString GUID = RoutePointGUIDList[ip];
606
607 // And on the RoutePoints themselves
608 wxRoutePointListNode *prpnode = pWayPointMan->GetWaypointList()->GetFirst();
609 while (prpnode) {
610 RoutePoint *prp = prpnode->GetData();
611
612 if (prp->m_GUID == GUID) {
613 AddPoint(prp);
614 break;
615 }
616 prpnode = prpnode->GetNext(); // RoutePoint
617 }
618 }
619
620 if (bRenamePoints) RenameRoutePoints();
621
622 // Switch start/end strings. anders, 2010-01-29
623 wxString tmp = m_RouteStartString;
624 m_RouteStartString = m_RouteEndString;
625 m_RouteEndString = tmp;
626}
627
628void Route::SetVisible(bool visible, bool includeWpts) {
629 m_bVisible = visible;
630
631 if (!includeWpts) return;
632
633 wxRoutePointListNode *node = pRoutePointList->GetFirst();
634 RoutePoint *rp;
635 while (node) {
636 rp = node->GetData();
637
638 // if this is a "shared" point, then do not turn off visibility.
639 // This step keeps the point available for selection to other routes,
640 // or may be manaully hidden in route-manager dialog.
641 if (rp->IsShared()) {
642 if (visible) rp->SetVisible(visible);
643 }
644 node = node->GetNext();
645 }
646}
647
648void Route::SetListed(bool visible) { m_bListed = visible; }
649
650void Route::AssembleRoute(void) {}
651
652void Route::ShowWaypointNames(bool bshow) {
653 wxRoutePointListNode *node = pRoutePointList->GetFirst();
654
655 while (node) {
656 RoutePoint *prp = node->GetData();
657 prp->SetNameShown(bshow);
658
659 node = node->GetNext();
660 }
661}
662
663bool Route::AreWaypointNamesVisible() {
664 bool bvis = false;
665 wxRoutePointListNode *node = pRoutePointList->GetFirst();
666
667 while (node) {
668 RoutePoint *prp = node->GetData();
669 if (prp->GetNameShown()) bvis = true;
670
671 node = node->GetNext();
672 }
673
674 return bvis;
675}
676
677void Route::RenameRoutePoints(void) {
678 // iterate on the route points.
679 // If dynamically named, rename according to current list position
680
681 wxRoutePointListNode *node = pRoutePointList->GetFirst();
682
683 int i = 1;
684 while (node) {
685 RoutePoint *prp = node->GetData();
686 if (prp->IsNameDynamic()) {
687 wxString name = prp->GetName();
688 if (name.Len() == 3) {
689 name.Printf(_T ( "%03d" ), i);
690 } else if (name.Left(2) == "NM") {
691 name.Printf(_T ( "%03d" ), i);
692 if (prp->GetName().Len() >= 5) {
693 name.Append(prp->GetName().Mid(5));
694 }
695 } else {
696 name.Printf(_T ( "%03d" ), i);
697 name.Append(prp->GetName().Mid(3));
698 }
699 prp->SetName(name);
700 }
701
702 node = node->GetNext();
703 i++;
704 }
705}
706
707// Is this route equal to another, meaning,
708// Do all routepoint positions and names match?
709bool Route::IsEqualTo(Route *ptargetroute) {
710 wxRoutePointListNode *pthisnode = (this->pRoutePointList)->GetFirst();
711 wxRoutePointListNode *pthatnode = (ptargetroute->pRoutePointList)->GetFirst();
712
713 if (NULL == pthisnode) return false;
714
715 if (this->m_bIsInLayer || ptargetroute->m_bIsInLayer) return false;
716
717 if (this->GetnPoints() != ptargetroute->GetnPoints()) return false;
718
719 while (pthisnode) {
720 if (NULL == pthatnode) return false;
721
722 RoutePoint *pthisrp = pthisnode->GetData();
723 RoutePoint *pthatrp = pthatnode->GetData();
724
725 if ((fabs(pthisrp->m_lat - pthatrp->m_lat) > 1.0e-6) ||
726 (fabs(pthisrp->m_lon - pthatrp->m_lon) > 1.0e-6))
727 return false;
728
729 if (!pthisrp->GetName().IsSameAs(pthatrp->GetName())) return false;
730
731 pthisnode = pthisnode->GetNext();
732 pthatnode = pthatnode->GetNext();
733 }
734
735 return true; // success, they are the same
736}
bool IsNameDynamic()
Definition route.h:75