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);
76 m_GUID = pWayPointMan->CreateGUID(NULL);
79 m_ArrivalRadius = g_n_arrival_circle_radius;
90 if (g_defaultBoatSpeed != ROUTE_DEFAULT_SPEED)
97 m_bsharedWPViz =
false;
109void Route::CloneRoute(
Route *psourceroute,
int start_nPoint,
int end_nPoint,
110 const wxString &suffix,
111 const bool duplicate_first_point) {
117 for (i = start_nPoint; i <= end_nPoint; i++) {
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 {
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) {
160 pNewPoint->SetShared(
true);
163 pNewPoint->m_bIsInRoute =
true;
168 if (!b_deferBoxCalc) FinalizeForRendering();
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);
204void Route::InsertPointAndSegment(
RoutePoint *pNewPoint,
int insert_after,
205 bool bRenamePoints,
bool b_deferBoxCalc) {
210 pNewPoint->SetShared(
true);
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);
224 if (bRenamePoints) RenameRoutePoints();
226 FinalizeForRendering();
227 UpdateSegmentDistances();
238 prp = node->GetData();
239 if (i == nWhichPoint) {
243 node = node->GetNext();
249RoutePoint *Route::GetPoint(
const wxString &guid) {
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() {
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) {
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);
314 if (bRenamePoints) RenameRoutePoints();
316 FinalizeForRendering();
317 UpdateSegmentDistances();
323 bool bRenamePoints) {
325 if (nRP >= GetnPoints() - 1)
return NULL;
329 GetNewMarkSequenced(), wxEmptyString);
330 newpoint->m_bIsInRoute =
true;
331 newpoint->SetNameShown(
false);
335 if (bRenamePoints) RenameRoutePoints();
337 FinalizeForRendering();
338 UpdateSegmentDistances();
343wxString Route::GetNewMarkSequenced(
void) {
345 ret.Printf(_T (
"NM%03d" ), m_nm_sequence);
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);
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);
401 Route *pcontainer_route = FindRouteContainingWaypoint(rp);
403 if (pcontainer_route == NULL) {
404 rp->m_bIsInRoute =
false;
408 if (bRenamePoints) RenameRoutePoints();
412 pSelect->AddAllSelectableRouteSegments(
this);
413 pSelect->AddAllSelectableRoutePoints(
this);
415 NavObjectChanges::getInstance()->UpdateRoute(
this);
417 FinalizeForRendering();
418 UpdateSegmentDistances();
422void Route::DeSelectRoute() {
427 rp = node->GetData();
428 rp->m_bPtIsSelected =
false;
430 node = node->GetNext();
434void Route::ReloadRoutePointIcons() {
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;
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);
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.) {
538 wxLongLong duration = wxLongLong(3600.0 * prp->m_seg_len / prp->
m_seg_vmg);
539 prp->SetETE(duration);
540 wxTimeSpan ts(0, 0, duration);
543 if (prp0->
GetETA().IsValid()) {
563void Route::UpdateSegmentDistances(
double planspeed) {
578 node = node->GetNext();
586 node = node->GetNext();
591void Route::Reverse(
bool bRenamePoints) {
593 wxArrayString RoutePointGUIDList;
596 for (
int i = 0; i < ncount; i++)
597 RoutePointGUIDList.Add(GetPoint(ncount - i)->
m_GUID);
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();
628void Route::SetVisible(
bool visible,
bool includeWpts) {
629 m_bVisible = visible;
631 if (!includeWpts)
return;
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) {
657 prp->SetNameShown(bshow);
659 node = node->GetNext();
663bool Route::AreWaypointNamesVisible() {
669 if (prp->GetNameShown()) bvis =
true;
671 node = node->GetNext();
677void Route::RenameRoutePoints(
void) {
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) {
711 wxRoutePointListNode *pthatnode = (ptargetroute->
pRoutePointList)->GetFirst();
713 if (NULL == pthisnode)
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();
Represents a waypoint or mark within the navigation system.
wxDateTime GetETD()
Retrieves the Estimated Time of Departure for this waypoint, in UTC.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
wxDateTime GetManualETD()
Retrieves the manually set Estimated Time of Departure for this waypoint, in UTC.
wxDateTime m_seg_etd
Estimated Time of Departure from this waypoint, in UTC.
bool m_manual_etd
Flag indicating whether the ETD has been manually set by the user.
double m_seg_vmg
Planned speed for traveling FROM this waypoint TO the next waypoint.
wxDateTime m_seg_eta
Estimated Time of Arrival at this waypoint, in UTC.
wxDateTime GetETA()
Retrieves the Estimated Time of Arrival for this waypoint, in UTC.
Represents a navigational route in the navigation system.
int m_hiliteWidth
Width in pixels for highlighting the route when selected.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
double m_PlannedSpeed
Default planned speed for the route in knots.
wxString m_RouteStartString
Name or description of the route's starting point.
bool m_bIsBeingCreated
Flag indicating that the route is currently being created by the user.
void UpdateSegmentDistance(RoutePoint *prp0, RoutePoint *prp, double planspeed=-1.0)
Updates the navigation data for a single route segment between two waypoints.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
wxString m_Colour
Color name for rendering the route on the chart.
bool m_bDeleteOnArrival
Flag indicating whether the route should be deleted once navigation reaches the end.
wxString m_RouteEndString
Name or description of the route's ending point.
RoutePoint * m_pRouteActivePoint
Pointer to the currently active waypoint within this route.
bool m_btemp
Flag indicating if this is a temporary route.
wxPenStyle m_style
Style of the route line when rendered on the chart.
wxString m_TimeDisplayFormat
Format for displaying times in the UI.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
wxDateTime m_PlannedDeparture
Planned departure time for the route, in UTC.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
double m_route_time
Total estimated time to complete the route in seconds.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
HyperlinkList * m_HyperlinkList
List of hyperlinks associated with this route.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
int m_LayerID
Identifier of the layer containing this route.