36#include <wx/datetime.h>
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"
53double g_defaultBoatSpeed;
55#include <wx/listimpl.cpp>
57WX_DEFINE_LIST(RouteList);
60 m_bRtIsSelected =
false;
61 m_bRtIsActive =
false;
62 m_pRouteActivePoint = NULL;
63 m_bIsBeingEdited =
false;
64 m_bIsBeingCreated =
false;
70 m_bDeleteOnArrival =
false;
71 m_width = WIDTH_UNDEFINED;
72 m_style = wxPENSTYLE_INVALID;
75 pRoutePointList =
new RoutePointList;
76 m_GUID = pWayPointMan->CreateGUID(NULL);
79 m_ArrivalRadius = g_n_arrival_circle_radius;
84 m_Colour = wxEmptyString;
86 m_lastMousePointIndex = 0;
87 m_NextLegGreatCircle =
false;
89 m_PlannedSpeed = ROUTE_DEFAULT_SPEED;
90 if (g_defaultBoatSpeed != ROUTE_DEFAULT_SPEED)
91 m_PlannedSpeed = g_defaultBoatSpeed;
93 m_PlannedDeparture = RTE_UNDEF_DEPARTURE;
94 m_TimeDisplayFormat = RTE_TIME_DISP_PC;
95 m_HyperlinkList =
new HyperlinkList;
97 m_bsharedWPViz =
false;
101 pRoutePointList->DeleteContents(
false);
102 delete pRoutePointList;
103 delete m_HyperlinkList;
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;
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);
122 RoutePoint *psourcepoint = psourceroute->GetPoint(i);
124 psourcepoint->m_lat, psourcepoint->m_lon, psourcepoint->GetIconName(),
125 psourcepoint->GetName(), wxEmptyString,
true);
126 ptargetpoint->m_bShowName =
127 psourcepoint->m_bShowName;
128 AddPoint(ptargetpoint,
false);
132 FinalizeForRendering();
135wxString Route::IsPointNameValid(
RoutePoint *pPoint,
136 const wxString &name)
const {
138 wxRoutePointListNode *node = pRoutePointList->GetFirst();
139 wxString substr = name.SubString(0, 6);
142 point = node->GetData();
143 wxString exist = point->GetName().SubString(0, 6);
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");
150 node = node->GetNext();
154 return wxEmptyString;
157void Route::AddPoint(
RoutePoint *pNewPoint,
bool b_rename_in_sequence,
158 bool b_deferBoxCalc) {
159 if (pNewPoint->m_bIsolatedMark) {
160 pNewPoint->SetShared(
true);
162 pNewPoint->m_bIsolatedMark =
false;
163 pNewPoint->m_bIsInRoute =
true;
166 pRoutePointList->Append(pNewPoint);
168 if (!b_deferBoxCalc) FinalizeForRendering();
170 if (prev) UpdateSegmentDistance(prev, pNewPoint);
172 if (b_rename_in_sequence && pNewPoint->GetName().IsEmpty() &&
173 !pNewPoint->IsShared()) {
175 name.Printf(_T(
"%03d"), GetnPoints());
176 pNewPoint->SetName(name);
181void Route::AddPointAndSegment(
RoutePoint *pNewPoint,
bool b_rename_in_sequence,
182 bool b_deferBoxCalc) {
183 int npoints = GetnPoints();
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;
192 AddPoint(newpoint,
false);
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);
201 m_lastMousePointIndex = GetnPoints();
204void Route::InsertPointAndSegment(
RoutePoint *pNewPoint,
int insert_after,
205 bool bRenamePoints,
bool b_deferBoxCalc) {
209 if (pNewPoint->m_bIsolatedMark) {
210 pNewPoint->SetShared(
true);
212 pNewPoint->m_bIsolatedMark =
false;
213 pNewPoint->m_bIsInRoute =
true;
215 if (insert_after >= GetnPoints() - 1) {
216 wxLogMessage(wxT(
"Error insert after last point"));
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();
234 wxRoutePointListNode *node = pRoutePointList->GetFirst();
238 prp = node->GetData();
239 if (i == nWhichPoint) {
243 node = node->GetNext();
249RoutePoint *Route::GetPoint(
const wxString &guid) {
251 wxRoutePointListNode *node = pRoutePointList->GetFirst();
254 prp = node->GetData();
255 if (guid == prp->m_GUID)
return prp;
257 node = node->GetNext();
263static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
265 double clon = (min + max) / 2;
266 if (min - lon > 180) lon += 360;
270 if (lon < clon - 180)
274 }
else if (lon > max) {
275 if (lon > clon + 180)
282bool Route::ContainsSharedWP() {
283 for (wxRoutePointListNode *node = pRoutePointList->GetFirst(); node;
284 node = node->GetNext()) {
286 if (prp->IsShared())
return true;
292int s_arrow_icon[] = {0, 0, 5, 2, 18, 6, 12, 0, 18, -6, 5, -2, 0, 0};
293void Route::ClearHighlights(
void) {
295 wxRoutePointListNode *node = pRoutePointList->GetFirst();
298 prp = node->GetData();
299 if (prp) prp->m_bPtIsSelected =
false;
300 node = node->GetNext();
305 bool bRenamePoints) {
307 GetNewMarkSequenced(), wxEmptyString);
308 newpoint->m_bIsInRoute =
true;
309 newpoint->SetNameShown(
false);
311 int nRP = pRoutePointList->IndexOf(pRP);
312 pRoutePointList->Insert(nRP, newpoint);
314 if (bRenamePoints) RenameRoutePoints();
316 FinalizeForRendering();
317 UpdateSegmentDistances();
323 bool bRenamePoints) {
324 int nRP = pRoutePointList->IndexOf(pRP);
325 if (nRP >= GetnPoints() - 1)
return NULL;
329 GetNewMarkSequenced(), wxEmptyString);
330 newpoint->m_bIsInRoute =
true;
331 newpoint->SetNameShown(
false);
333 pRoutePointList->Insert(nRP, newpoint);
335 if (bRenamePoints) RenameRoutePoints();
337 FinalizeForRendering();
338 UpdateSegmentDistances();
343wxString Route::GetNewMarkSequenced(
void) {
345 ret.Printf(_T (
"NM%03d" ), m_nm_sequence);
352 if (pRoutePointList->IsEmpty())
return NULL;
354 return pRoutePointList->GetLast()->GetData();
358 int ret = pRoutePointList->IndexOf(prp) + 1;
359 if (ret == wxNOT_FOUND)
365void Route::DeletePoint(
RoutePoint *rp,
bool bRenamePoints) {
368 if (rp->m_bIsInLayer)
return;
370 pSelect->DeleteAllSelectableRoutePoints(
this);
371 pSelect->DeleteAllSelectableRouteSegments(
this);
372 NavObjectChanges::getInstance()->DeleteWayPoint(rp);
374 pRoutePointList->DeleteObject(rp);
378 if (bRenamePoints) RenameRoutePoints();
380 if (GetnPoints() > 1) {
381 pSelect->AddAllSelectableRouteSegments(
this);
382 pSelect->AddAllSelectableRoutePoints(
this);
384 NavObjectChanges::getInstance()->UpdateRoute(
this);
386 FinalizeForRendering();
387 UpdateSegmentDistances();
391void Route::RemovePoint(
RoutePoint *rp,
bool bRenamePoints) {
392 if (rp->m_bIsActive && this->IsActive())
393 g_pRouteMan->DeactivateRoute();
395 pSelect->DeleteAllSelectableRoutePoints(
this);
396 pSelect->DeleteAllSelectableRouteSegments(
this);
398 pRoutePointList->DeleteObject(rp);
401 Route *pcontainer_route = FindRouteContainingWaypoint(rp);
403 if (pcontainer_route == NULL) {
404 rp->m_bIsInRoute =
false;
405 rp->m_bIsolatedMark =
true;
408 if (bRenamePoints) RenameRoutePoints();
412 pSelect->AddAllSelectableRouteSegments(
this);
413 pSelect->AddAllSelectableRoutePoints(
this);
415 NavObjectChanges::getInstance()->UpdateRoute(
this);
417 FinalizeForRendering();
418 UpdateSegmentDistances();
422void Route::DeSelectRoute() {
423 wxRoutePointListNode *node = pRoutePointList->GetFirst();
427 rp = node->GetData();
428 rp->m_bPtIsSelected =
false;
430 node = node->GetNext();
434void Route::ReloadRoutePointIcons() {
435 wxRoutePointListNode *node = pRoutePointList->GetFirst();
439 rp = node->GetData();
442 node = node->GetNext();
446void Route::FinalizeForRendering() { RBBox.Invalidate(); }
448LLBBox &Route::GetBBox(
void) {
449 if (RBBox.GetValid())
return RBBox;
451 double bbox_lonmin, bbox_lonmax, bbox_latmin, bbox_latmax;
453 wxRoutePointListNode *node = pRoutePointList->GetFirst();
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();
462 bbox_lonmax = bbox_lonmin = data->m_lon;
463 bbox_latmax = bbox_latmin = data->m_lat;
466 double lastlon = data->m_lon, wrap = 0;
468 node = node->GetNext();
470 data = node->GetData();
472 if (lastlon - data->m_lon > 180)
474 else if (data->m_lon - lastlon > 180)
477 double lon = data->m_lon + wrap;
479 if (lon > bbox_lonmax) bbox_lonmax = lon;
480 if (lon < bbox_lonmin) bbox_lonmin = lon;
482 if (data->m_lat > bbox_latmax) bbox_latmax = data->m_lat;
483 if (data->m_lat < bbox_latmin) bbox_latmin = data->m_lat;
485 lastlon = data->m_lon;
486 node = node->GetNext();
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;
494 if (bbox_lonmax - bbox_lonmin > 360) bbox_lonmin = -180, bbox_lonmax = 180;
496 RBBox.Set(bbox_latmin, bbox_lonmin, bbox_latmax, bbox_lonmax);
507 double slat1 = prp0->m_lat, slon1 = prp0->m_lon;
508 double slat2 = prp->m_lat, slon2 = prp->m_lon;
515 DistanceBearingMercator(slat2, slon2, slat1, slon1, &br, &dd);
518 prp->SetDistance(dd);
523 m_route_length += dd;
528 if (planspeed > 0.) {
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;
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();
547 m_PlannedDeparture + wxTimeSpan(0, 0, m_route_time - duration);
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;
563void Route::UpdateSegmentDistances(
double planspeed) {
566 m_route_length = 0.0;
569 wxRoutePointListNode *node = pRoutePointList->GetFirst();
574 if (!prp0->m_manual_etd) {
575 prp0->m_seg_eta = m_PlannedDeparture;
576 prp0->m_seg_etd = m_PlannedDeparture;
578 node = node->GetNext();
582 UpdateSegmentDistance(prp0, prp, planspeed);
586 node = node->GetNext();
591void Route::Reverse(
bool bRenamePoints) {
593 wxArrayString RoutePointGUIDList;
595 int ncount = pRoutePointList->GetCount();
596 for (
int i = 0; i < ncount; i++)
597 RoutePointGUIDList.Add(GetPoint(ncount - i)->m_GUID);
599 pRoutePointList->DeleteContents(
false);
600 pRoutePointList->Clear();
601 m_route_length = 0.0;
604 for (
unsigned int ip = 0; ip < RoutePointGUIDList.GetCount(); ip++) {
605 wxString GUID = RoutePointGUIDList[ip];
608 wxRoutePointListNode *prpnode = pWayPointMan->GetWaypointList()->GetFirst();
612 if (prp->m_GUID == GUID) {
616 prpnode = prpnode->GetNext();
620 if (bRenamePoints) RenameRoutePoints();
623 wxString tmp = m_RouteStartString;
624 m_RouteStartString = m_RouteEndString;
625 m_RouteEndString = tmp;
628void Route::SetVisible(
bool visible,
bool includeWpts) {
629 m_bVisible = visible;
631 if (!includeWpts)
return;
633 wxRoutePointListNode *node = pRoutePointList->GetFirst();
636 rp = node->GetData();
641 if (rp->IsShared()) {
642 if (visible) rp->SetVisible(visible);
644 node = node->GetNext();
648void Route::SetListed(
bool visible) { m_bListed = visible; }
650void Route::AssembleRoute(
void) {}
652void Route::ShowWaypointNames(
bool bshow) {
653 wxRoutePointListNode *node = pRoutePointList->GetFirst();
657 prp->SetNameShown(bshow);
659 node = node->GetNext();
663bool Route::AreWaypointNamesVisible() {
665 wxRoutePointListNode *node = pRoutePointList->GetFirst();
669 if (prp->GetNameShown()) bvis =
true;
671 node = node->GetNext();
677void Route::RenameRoutePoints(
void) {
681 wxRoutePointListNode *node = pRoutePointList->GetFirst();
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));
696 name.Printf(_T (
"%03d" ), i);
697 name.Append(prp->GetName().Mid(3));
702 node = node->GetNext();
709bool Route::IsEqualTo(
Route *ptargetroute) {
710 wxRoutePointListNode *pthisnode = (this->pRoutePointList)->GetFirst();
711 wxRoutePointListNode *pthatnode = (ptargetroute->pRoutePointList)->GetFirst();
713 if (NULL == pthisnode)
return false;
715 if (this->m_bIsInLayer || ptargetroute->m_bIsInLayer)
return false;
717 if (this->GetnPoints() != ptargetroute->GetnPoints())
return false;
720 if (NULL == pthatnode)
return false;
725 if ((fabs(pthisrp->m_lat - pthatrp->m_lat) > 1.0e-6) ||
726 (fabs(pthisrp->m_lon - pthatrp->m_lon) > 1.0e-6))
729 if (!pthisrp->GetName().IsSameAs(pthatrp->GetName()))
return false;
731 pthisnode = pthisnode->GetNext();
732 pthatnode = pthatnode->GetNext();