36#include <wx/datetime.h>
45#include "nav_object_database.h"
52extern int g_route_line_width;
54extern double g_n_arrival_circle_radius;
55extern float g_GLMinSymbolLineWidth;
56extern double g_PlanSpeed;
57extern wxString g_default_routepoint_icon;
58extern bool g_bAllowShipToActive;
61#include <wx/listimpl.cpp>
62WX_DEFINE_LIST(RouteList);
65 m_bRtIsSelected =
false;
66 m_bRtIsActive =
false;
67 m_pRouteActivePoint = NULL;
68 m_bIsBeingEdited =
false;
69 m_bIsBeingCreated =
false;
75 m_bDeleteOnArrival =
false;
76 m_width = WIDTH_UNDEFINED;
77 m_style = wxPENSTYLE_INVALID;
80 pRoutePointList =
new RoutePointList;
81 m_GUID = pWayPointMan->CreateGUID(NULL);
84 m_ArrivalRadius = g_n_arrival_circle_radius;
89 m_Colour = wxEmptyString;
91 m_lastMousePointIndex = 0;
92 m_NextLegGreatCircle =
false;
94 m_PlannedSpeed = ROUTE_DEFAULT_SPEED;
95 if (g_PlanSpeed != ROUTE_DEFAULT_SPEED) m_PlannedSpeed = g_PlanSpeed;
97 m_PlannedDeparture = RTE_UNDEF_DEPARTURE;
98 m_TimeDisplayFormat = RTE_TIME_DISP_PC;
99 m_HyperlinkList =
new HyperlinkList;
101 m_bsharedWPViz =
false;
105 pRoutePointList->DeleteContents(
false);
106 delete pRoutePointList;
107 delete m_HyperlinkList;
113void Route::CloneRoute(
Route *psourceroute,
int start_nPoint,
int end_nPoint,
114 const wxString &suffix,
115 const bool duplicate_first_point) {
116 m_RouteNameString = psourceroute->m_RouteNameString + suffix;
117 m_RouteStartString = psourceroute->m_RouteStartString;
118 m_RouteEndString = psourceroute->m_RouteEndString;
121 for (i = start_nPoint; i <= end_nPoint; i++) {
122 if (!psourceroute->m_bIsInLayer &&
123 !(i == start_nPoint && duplicate_first_point)) {
124 AddPoint(psourceroute->GetPoint(i),
false);
127 RoutePoint *psourcepoint = psourceroute->GetPoint(i);
129 psourcepoint->m_lat, psourcepoint->m_lon, psourcepoint->GetIconName(),
130 psourcepoint->GetName(), wxEmptyString,
false);
131 ptargetpoint->m_bShowName =
132 psourcepoint->m_bShowName;
133 AddPoint(ptargetpoint,
false);
137 FinalizeForRendering();
140void Route::AddPoint(
RoutePoint *pNewPoint,
bool b_rename_in_sequence,
141 bool b_deferBoxCalc) {
142 if (pNewPoint->m_bIsolatedMark) {
143 pNewPoint->SetShared(
true);
145 pNewPoint->m_bIsolatedMark =
false;
146 pNewPoint->m_bIsInRoute =
true;
149 pRoutePointList->Append(pNewPoint);
151 if (!b_deferBoxCalc) FinalizeForRendering();
153 if (prev) UpdateSegmentDistance(prev, pNewPoint);
155 if (b_rename_in_sequence && pNewPoint->GetName().IsEmpty() &&
156 !pNewPoint->IsShared()) {
158 name.Printf(_T(
"%03d"), GetnPoints());
159 pNewPoint->SetName(name);
160 pNewPoint->m_bDynamicName =
true;
165void Route::AddPointAndSegment(
RoutePoint *pNewPoint,
bool b_rename_in_sequence,
166 bool b_deferBoxCalc) {
167 int npoints = GetnPoints();
169 if (newpoint->m_bIsInLayer) {
170 newpoint =
new RoutePoint(pNewPoint->m_lat, pNewPoint->m_lon,
171 pNewPoint->GetIconName(), pNewPoint->GetName(), wxEmptyString,
false);
172 newpoint->m_bShowName = pNewPoint->m_bShowName;
174 AddPoint(newpoint,
false);
176 double rlat = GetPoint(npoints)->m_lat;
177 double rlon = GetPoint(npoints)->m_lon;
178 npoints = GetnPoints();
179 pSelect->AddSelectableRouteSegment(rlat, rlon,
180 GetPoint(npoints)->m_lat, GetPoint(npoints)->m_lon, GetPoint(npoints - 1), GetPoint(npoints),
this);
182 m_lastMousePointIndex = GetnPoints();
185void Route::InsertPointAndSegment(
RoutePoint *pNewPoint,
int insert_after,
bool bRenamePoints,
bool b_deferBoxCalc)
190 if (pNewPoint->m_bIsolatedMark) {
191 pNewPoint->SetShared(
true);
193 pNewPoint->m_bIsolatedMark =
false;
194 pNewPoint->m_bIsInRoute =
true;
196 if (insert_after >= GetnPoints() - 1) {
197 wxLogMessage(wxT(
"Error insert after last point"));
201 int insert = insert_after++;
202 pNewPoint->m_bIsInRoute =
true;
203 pNewPoint->m_bDynamicName =
true;
204 pNewPoint->SetNameShown(
false);
205 pRoutePointList->Insert(insert, pNewPoint);
206 if (bRenamePoints) RenameRoutePoints();
207 m_lastMousePointIndex = GetnPoints();
208 FinalizeForRendering();
209 UpdateSegmentDistances();
216 wxRoutePointListNode *node = pRoutePointList->GetFirst();
220 prp = node->GetData();
221 if (i == nWhichPoint) {
225 node = node->GetNext();
231RoutePoint *Route::GetPoint(
const wxString &guid) {
233 wxRoutePointListNode *node = pRoutePointList->GetFirst();
236 prp = node->GetData();
237 if (guid == prp->m_GUID)
return prp;
239 node = node->GetNext();
245static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
247 double clon = (min + max) / 2;
248 if (min - lon > 180) lon += 360;
252 if (lon < clon - 180)
256 }
else if (lon > max) {
257 if (lon > clon + 180)
264bool Route::ContainsSharedWP() {
265 for (wxRoutePointListNode *node = pRoutePointList->GetFirst(); node;
266 node = node->GetNext()) {
268 if (prp->IsShared())
return true;
274int s_arrow_icon[] = {0, 0, 5, 2, 18, 6, 12, 0, 18, -6, 5, -2, 0, 0};
275void Route::ClearHighlights(
void) {
277 wxRoutePointListNode *node = pRoutePointList->GetFirst();
280 prp = node->GetData();
281 if (prp) prp->m_bPtIsSelected =
false;
282 node = node->GetNext();
287 bool bRenamePoints) {
289 GetNewMarkSequenced(), wxEmptyString);
290 newpoint->m_bIsInRoute =
true;
291 newpoint->m_bDynamicName =
true;
292 newpoint->SetNameShown(
false);
294 int nRP = pRoutePointList->IndexOf(pRP);
295 pRoutePointList->Insert(nRP, newpoint);
297 if (bRenamePoints) RenameRoutePoints();
299 FinalizeForRendering();
300 UpdateSegmentDistances();
306 bool bRenamePoints) {
307 int nRP = pRoutePointList->IndexOf(pRP);
308 if (nRP >= GetnPoints() - 1)
return NULL;
312 GetNewMarkSequenced(), wxEmptyString);
313 newpoint->m_bIsInRoute =
true;
314 newpoint->m_bDynamicName =
true;
315 newpoint->SetNameShown(
false);
317 pRoutePointList->Insert(nRP, newpoint);
319 if (bRenamePoints) RenameRoutePoints();
321 FinalizeForRendering();
322 UpdateSegmentDistances();
327wxString Route::GetNewMarkSequenced(
void) {
329 ret.Printf(_T (
"NM%03d" ), m_nm_sequence);
336 if (pRoutePointList->IsEmpty())
return NULL;
338 return pRoutePointList->GetLast()->GetData();
342 int ret = pRoutePointList->IndexOf(prp) + 1;
343 if (ret == wxNOT_FOUND)
349void Route::DeletePoint(
RoutePoint *rp,
bool bRenamePoints) {
352 if (rp->m_bIsInLayer)
return;
354 pSelect->DeleteAllSelectableRoutePoints(
this);
355 pSelect->DeleteAllSelectableRouteSegments(
this);
356 NavObjectChanges::getInstance()->DeleteWayPoint(rp);
358 pRoutePointList->DeleteObject(rp);
362 if (bRenamePoints) RenameRoutePoints();
364 if (GetnPoints() > 1) {
365 pSelect->AddAllSelectableRouteSegments(
this);
366 pSelect->AddAllSelectableRoutePoints(
this);
368 NavObjectChanges::getInstance()->UpdateRoute(
this);
370 FinalizeForRendering();
371 UpdateSegmentDistances();
375void Route::RemovePoint(
RoutePoint *rp,
bool bRenamePoints) {
376 if (rp->m_bIsActive && this->IsActive())
377 g_pRouteMan->DeactivateRoute();
379 pSelect->DeleteAllSelectableRoutePoints(
this);
380 pSelect->DeleteAllSelectableRouteSegments(
this);
382 pRoutePointList->DeleteObject(rp);
385 Route *pcontainer_route = FindRouteContainingWaypoint(rp);
387 if (pcontainer_route == NULL) {
388 rp->m_bIsInRoute =
false;
389 rp->m_bDynamicName =
false;
390 rp->m_bIsolatedMark =
true;
393 if (bRenamePoints) RenameRoutePoints();
397 pSelect->AddAllSelectableRouteSegments(
this);
398 pSelect->AddAllSelectableRoutePoints(
this);
400 NavObjectChanges::getInstance()->UpdateRoute(
this);
402 FinalizeForRendering();
403 UpdateSegmentDistances();
407void Route::DeSelectRoute() {
408 wxRoutePointListNode *node = pRoutePointList->GetFirst();
412 rp = node->GetData();
413 rp->m_bPtIsSelected =
false;
415 node = node->GetNext();
419void Route::ReloadRoutePointIcons() {
420 wxRoutePointListNode *node = pRoutePointList->GetFirst();
424 rp = node->GetData();
427 node = node->GetNext();
431void Route::FinalizeForRendering() { RBBox.Invalidate(); }
433LLBBox &Route::GetBBox(
void) {
434 if (RBBox.GetValid())
return RBBox;
436 double bbox_lonmin, bbox_lonmax, bbox_latmin, bbox_latmax;
438 wxRoutePointListNode *node = pRoutePointList->GetFirst();
441 if (data->m_wpBBox.GetValid()) {
442 bbox_lonmax = data->m_wpBBox.GetMaxLon();
443 bbox_lonmin = data->m_wpBBox.GetMinLon();
444 bbox_latmax = data->m_wpBBox.GetMaxLat();
445 bbox_latmin = data->m_wpBBox.GetMinLat();
447 bbox_lonmax = bbox_lonmin = data->m_lon;
448 bbox_latmax = bbox_latmin = data->m_lat;
451 double lastlon = data->m_lon, wrap = 0;
453 node = node->GetNext();
455 data = node->GetData();
457 if (lastlon - data->m_lon > 180)
459 else if (data->m_lon - lastlon > 180)
462 double lon = data->m_lon + wrap;
464 if (lon > bbox_lonmax) bbox_lonmax = lon;
465 if (lon < bbox_lonmin) bbox_lonmin = lon;
467 if (data->m_lat > bbox_latmax) bbox_latmax = data->m_lat;
468 if (data->m_lat < bbox_latmin) bbox_latmin = data->m_lat;
470 lastlon = data->m_lon;
471 node = node->GetNext();
474 if (bbox_lonmin < -360)
475 bbox_lonmin += 360, bbox_lonmax += 360;
476 else if (bbox_lonmax > 360)
477 bbox_lonmin -= 360, bbox_lonmax -= 360;
479 if (bbox_lonmax - bbox_lonmin > 360) bbox_lonmin = -180, bbox_lonmax = 180;
481 RBBox.Set(bbox_latmin, bbox_lonmin, bbox_latmax, bbox_lonmax);
492 double slat1 = prp0->m_lat, slon1 = prp0->m_lon;
493 double slat2 = prp->m_lat, slon2 = prp->m_lon;
500 DistanceBearingMercator(slat2, slon2, slat1, slon1, &br, &dd);
503 prp->SetDistance(dd);
508 m_route_length += dd;
513 if (planspeed > 0.) {
516 double legspeed = planspeed;
517 if (prp->GetPlannedSpeed() > 0.1 && prp->GetPlannedSpeed() < 1000.)
518 legspeed = prp->GetPlannedSpeed();
519 if (legspeed > 0.1 && legspeed < 1000.) {
520 m_route_time += 3600. * dd / legspeed;
521 prp->m_seg_vmg = legspeed;
523 wxLongLong duration = wxLongLong(3600.0 * prp->m_seg_len / prp->m_seg_vmg);
524 prp->SetETE(duration);
525 wxTimeSpan ts(0, 0, duration);
526 if (!prp0->GetManualETD().IsValid()) {
527 prp0->m_manual_etd =
false;
528 if (prp0->GetETA().IsValid()) {
529 prp0->m_seg_etd = prp0->GetETA();
532 m_PlannedDeparture + wxTimeSpan(0, 0, m_route_time - duration);
536 prp->m_seg_eta = prp0->GetETD() + ts;
537 if (!prp->m_manual_etd || !prp->GetETD().IsValid()) {
538 prp->m_seg_etd = prp->m_seg_eta;
539 prp->m_manual_etd =
false;
548void Route::UpdateSegmentDistances(
double planspeed) {
551 m_route_length = 0.0;
554 wxRoutePointListNode *node = pRoutePointList->GetFirst();
559 if (!prp0->m_manual_etd) {
560 prp0->m_seg_eta = m_PlannedDeparture;
561 prp0->m_seg_etd = m_PlannedDeparture;
563 node = node->GetNext();
567 UpdateSegmentDistance(prp0, prp, planspeed);
571 node = node->GetNext();
576void Route::Reverse(
bool bRenamePoints) {
578 wxArrayString RoutePointGUIDList;
580 int ncount = pRoutePointList->GetCount();
581 for (
int i = 0; i < ncount; i++)
582 RoutePointGUIDList.Add(GetPoint(ncount - i)->m_GUID);
584 pRoutePointList->DeleteContents(
false);
585 pRoutePointList->Clear();
586 m_route_length = 0.0;
589 for (
unsigned int ip = 0; ip < RoutePointGUIDList.GetCount(); ip++) {
590 wxString GUID = RoutePointGUIDList[ip];
593 wxRoutePointListNode *prpnode = pWayPointMan->GetWaypointList()->GetFirst();
597 if (prp->m_GUID == GUID) {
601 prpnode = prpnode->GetNext();
605 if (bRenamePoints) RenameRoutePoints();
608 wxString tmp = m_RouteStartString;
609 m_RouteStartString = m_RouteEndString;
610 m_RouteEndString = tmp;
613void Route::SetVisible(
bool visible,
bool includeWpts) {
614 m_bVisible = visible;
616 if (!includeWpts)
return;
618 wxRoutePointListNode *node = pRoutePointList->GetFirst();
621 rp = node->GetData();
626 if (rp->IsShared()) {
627 if (visible) rp->SetVisible(visible);
629 node = node->GetNext();
633void Route::SetListed(
bool visible) { m_bListed = visible; }
635void Route::AssembleRoute(
void) {}
637void Route::ShowWaypointNames(
bool bshow) {
638 wxRoutePointListNode *node = pRoutePointList->GetFirst();
642 prp->SetNameShown(bshow);
644 node = node->GetNext();
648bool Route::AreWaypointNamesVisible() {
650 wxRoutePointListNode *node = pRoutePointList->GetFirst();
654 if (prp->GetNameShown()) bvis =
true;
656 node = node->GetNext();
662void Route::RenameRoutePoints(
void) {
666 wxRoutePointListNode *node = pRoutePointList->GetFirst();
671 if (prp->m_bDynamicName) {
673 name.Printf(_T (
"%03d" ), i);
677 node = node->GetNext();
684bool Route::IsEqualTo(
Route *ptargetroute) {
685 wxRoutePointListNode *pthisnode = (this->pRoutePointList)->GetFirst();
686 wxRoutePointListNode *pthatnode = (ptargetroute->pRoutePointList)->GetFirst();
688 if (NULL == pthisnode)
return false;
690 if (this->m_bIsInLayer || ptargetroute->m_bIsInLayer)
return false;
692 if (this->GetnPoints() != ptargetroute->GetnPoints())
return false;
695 if (NULL == pthatnode)
return false;
700 if ((fabs(pthisrp->m_lat - pthatrp->m_lat) > 1.0e-6) ||
701 (fabs(pthisrp->m_lon - pthatrp->m_lon) > 1.0e-6))
704 if (!pthisrp->GetName().IsSameAs(pthatrp->GetName()))
return false;
706 pthisnode = pthisnode->GetNext();
707 pthatnode = pthatnode->GetNext();