OpenCPN Partial API docs
Loading...
Searching...
No Matches
route_point.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2013 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 **************************************************************************/
17
24#include <wx/colour.h>
25#include <wx/datetime.h>
26#include <wx/dynarray.h>
27#include <wx/string.h>
28#include <wx/tokenzr.h>
29
30#include "model/base_platform.h"
31#include "model/cutil.h"
32#include "model/georef.h"
33#include "model/navutil_base.h"
34#include "model/route.h"
35#include "model/routeman.h"
36#include "model/route_point.h"
37#include "model/select.h"
38
39#include <wx/listimpl.cpp>
40
42
44
46
47std::function<void(unsigned, const unsigned *)> RoutePoint::delete_gl_textures =
48 [](unsigned, const unsigned *) { assert(true); };
49
50RoutePoint::RoutePoint() {
51 m_pbmIcon = NULL;
52
53 // Nice defaults
54 m_seg_len = 0.0;
55 m_seg_vmg = 0.0;
56
57 m_seg_etd = wxInvalidDateTime;
58 m_manual_etd = false;
59
60 m_seg_eta = wxInvalidDateTime;
61 m_bPtIsSelected = false;
62 m_bRPIsBeingEdited = false;
63 m_bIsActive = false;
64 m_bBlink = false;
65 m_bIsInRoute = false;
66 m_CreateTimeX = wxDateTime::Now();
67 m_bIsolatedMark = false;
68 m_bShowName = true;
69 SetShared(false);
70 m_bIsVisible = true;
71 m_bIsListed = true;
72 CurrentRect_in_DC = wxRect(0, 0, 0, 0);
75 m_pMarkFont = NULL;
76 m_btemp = false;
77 m_SelectNode = NULL;
78 m_ManagerNode = NULL;
79
81
82 m_HyperlinkList = new HyperlinkList;
83
84 m_GUID = pWayPointMan->CreateGUID(this);
85
86 m_IconName = "";
87
88 m_MarkName = "";
89
90 m_bIsInLayer = false;
91 m_LayerID = 0;
92
93 m_WaypointArrivalRadius = g_n_arrival_circle_radius;
94
95 m_bShowWaypointRangeRings = (bool)g_iWaypointRangeRingsNumber;
96
97 m_iWaypointRangeRingsNumber = g_iWaypointRangeRingsNumber;
98 m_fWaypointRangeRingsStep = g_fWaypointRangeRingsStep;
99 m_iWaypointRangeRingsStepUnits = g_iWaypointRangeRingsStepUnits;
101 m_ScaMin = g_iWpt_ScaMin;
102 m_bShowName = g_bShowWptName;
103 m_ScaMax = 0;
104 b_UseScamin = g_bUseWptScaMin;
105
106 m_pos_on_screen = false;
107 m_bDrawDragHandle = false;
108 m_dragIconTexture = 0;
109 m_draggingOffsetx = m_draggingOffsety = 0;
110
111 m_PlannedSpeed = 0.;
112 m_IconIsDirty = true;
113}
114
115// Copy Constructor
116RoutePoint::RoutePoint(RoutePoint *orig) {
117 m_MarkName = orig->GetName();
118 m_lat = orig->m_lat;
119 m_lon = orig->m_lon;
120 m_seg_len = orig->m_seg_len;
121 m_seg_vmg = orig->m_seg_vmg;
122
123 m_seg_etd = orig->m_seg_etd;
124 m_manual_etd = false;
125
128 m_bIsActive = orig->m_bIsActive;
129 m_bBlink = orig->m_bBlink;
133 m_bShowName = orig->m_bShowName;
134 SetShared(orig->IsShared());
136 m_bIsListed = orig->m_bIsListed;
140 m_pMarkFont = orig->m_pMarkFont;
142 m_btemp = orig->m_btemp;
143 m_ScaMin = orig->m_ScaMin;
144 m_ScaMax = orig->m_ScaMax;
145 m_HyperlinkList = new HyperlinkList;
146 m_IconName = orig->m_IconName;
148 SetPlannedSpeed(orig->GetPlannedSpeed());
149
151 m_GUID = pWayPointMan->CreateGUID(this);
152
153 m_SelectNode = NULL;
154 m_ManagerNode = NULL;
155
156 m_WaypointArrivalRadius = orig->GetWaypointArrivalRadius();
162 m_ScaMin = orig->m_ScaMin;
163 m_ScaMax = orig->m_ScaMax;
164 b_UseScamin = orig->b_UseScamin;
166
167 m_bDrawDragHandle = false;
168 m_dragIconTexture = 0;
169 m_draggingOffsetx = m_draggingOffsety = 0;
170}
171
172RoutePoint::RoutePoint(double lat, double lon, const wxString &icon_ident,
173 const wxString &name, const wxString &pGUID,
174 bool bAddToList) {
175 // Establish points
176 m_lat = lat;
177 m_lon = lon;
178
179 // Normalize the longitude, to fix any old poorly formed points
180 if (m_lon < -180.)
181 m_lon += 360.;
182 else if (m_lon > 180.)
183 m_lon -= 360.;
184
185 // Nice defaults
186 m_seg_len = 0.0;
187 m_seg_vmg = 0.0;
188
189 m_seg_etd = wxInvalidDateTime;
190 m_manual_etd = false;
191
192 m_bPtIsSelected = false;
193 m_bRPIsBeingEdited = false;
194 m_bIsActive = false;
195 m_bBlink = false;
196 m_bIsInRoute = false;
197 m_CreateTimeX = wxDateTime::Now();
198 m_bIsolatedMark = false;
199 m_bShowName = true;
200 SetShared(false);
201 m_bIsVisible = true;
202 m_bIsListed = true;
203 CurrentRect_in_DC = wxRect(0, 0, 0, 0);
206 m_pMarkFont = NULL;
207 m_btemp = false;
208 m_bPreScaled = false;
209
210 m_SelectNode = NULL;
211 m_ManagerNode = NULL;
212 m_IconScaleFactor = 1.0;
213 m_ScaMin = MAX_INT_VAL;
214 m_ScaMax = 0;
215 m_HyperlinkList = new HyperlinkList;
216 m_IconIsDirty = true;
217
218 m_iTextTexture = 0;
219
220 if (!pGUID.IsEmpty())
221 m_GUID = pGUID;
222 else
223 m_GUID = pWayPointMan->CreateGUID(this);
224
225 // Get Icon bitmap
226 m_IconName = icon_ident;
227
228 SetName(name);
229
230 // Possibly add the waypoint to the global list maintained by the waypoint
231 // manager
232
233 if (bAddToList && NULL != pWayPointMan) pWayPointMan->AddRoutePoint(this);
234
235 m_bIsInLayer = false;
236 m_LayerID = 0;
237
238 SetWaypointArrivalRadius(g_n_arrival_circle_radius);
239
240 m_bShowWaypointRangeRings = (bool)g_iWaypointRangeRingsNumber;
241
242 m_iWaypointRangeRingsNumber = g_iWaypointRangeRingsNumber;
243 m_fWaypointRangeRingsStep = g_fWaypointRangeRingsStep;
244 m_iWaypointRangeRingsStepUnits = g_iWaypointRangeRingsStepUnits;
246 m_ScaMin = g_iWpt_ScaMin;
247 m_ScaMax = 0;
248 b_UseScamin = g_bUseWptScaMin;
249 m_bShowName = g_bShowWptName;
250
251 m_bDrawDragHandle = false;
252 m_dragIconTexture = 0;
253 m_draggingOffsetx = m_draggingOffsety = 0;
254
255 m_PlannedSpeed = 0.;
256}
257
258RoutePoint::~RoutePoint() {
259 // Remove this point from the global waypoint list
260 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(this);
261
262 if (m_HyperlinkList) {
263 auto &list = m_HyperlinkList;
264 for (auto it = list->begin(); it != list->end(); ++it) delete *it;
265 delete m_HyperlinkList;
266 }
267 RoutePoint::delete_gl_textures(1, &m_dragIconTexture);
268}
269
271 if (!m_CreateTimeX.IsValid()) {
273 }
274 return m_CreateTimeX;
275}
276
277void RoutePoint::SetCreateTime(wxDateTime dt) { m_CreateTimeX = dt; }
278
279void RoutePoint::SetName(const wxString &name) {
280 if (m_iTextTexture) {
282 m_iTextTexture = 0;
283 }
284 m_MarkName = name;
285 CalculateNameExtents();
286}
287
288void RoutePoint::CalculateNameExtents() {
289 if (m_pMarkFont) {
290 wxScreenDC dc;
291
292#ifdef __WXQT__ // avoiding "painter not active" warning
293 int w, h;
294 dc.GetTextExtent(m_MarkName, &w, &h, NULL, NULL, m_pMarkFont);
295 m_NameExtents = wxSize(w, h);
296#else
297 dc.SetFont(*m_pMarkFont);
298 m_NameExtents = dc.GetMultiLineTextExtent(m_MarkName);
299#endif
300 } else
301 m_NameExtents = wxSize(0, 0);
302}
303
304bool RoutePoint::IsVisibleSelectable(double scale_val, bool boverrideViz) {
305 if (m_bIsActive) // An active route point must always be visible
306 return true;
307
308 if (!boverrideViz) {
309 if (!m_bIsVisible) // if not visible nevermind the rest.
310 return false;
311 }
312
313 if (b_UseScamin) {
314 if (g_bOverruleScaMin)
315 return true;
316 else if (scale_val >= (double)(m_ScaMin + 1))
317 return false;
318 }
319 return true;
320}
321
322bool RoutePoint::IsSharedInVisibleRoute() {
323 if (IsShared()) {
324 // Get an array of all routes using this point
325 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(this);
326
327 // Use route array (if any) to determine actual visibility for this point
328 bool brp_viz = false;
329 if (proute_array) {
330 for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
331 Route *pr = (Route *)proute_array->Item(ir);
332 if (pr->IsVisible()) {
333 brp_viz = true;
334 break;
335 }
336 }
337 delete proute_array;
338 }
339
340 return brp_viz;
341 } else // point is not shared
342 return false;
343}
344
345void RoutePoint::SetPosition(double lat, double lon) {
346 m_lat = lat;
347 m_lon = lon;
348}
349
350bool RoutePoint::IsSame(RoutePoint *pOtherRP) {
351 bool IsSame = false;
352
353 if (this->m_MarkName == pOtherRP->m_MarkName) {
354 if (fabs(this->m_lat - pOtherRP->m_lat) < 1.e-6 &&
355 fabs(this->m_lon - pOtherRP->m_lon) < 1.e-6)
356 IsSame = true;
357 }
358 return IsSame;
359}
360
367 bool b_numeric = false;
368 if (m_bIsInRoute) {
369 if (GetName().Len() >= 2) {
370 wxString substring = GetName().Left(2);
371 if (substring == "NM") {
372 substring = GetName().substr(2, 3);
373 } else {
374 substring = GetName().Left(3);
375 }
376 b_numeric = true; // assume it is numeric
377 for (unsigned int i = 0; i < substring.Len(); i++) {
378 if (b_numeric == true) {
379 b_numeric = wxIsdigit(substring[i]);
380 } // don't change the value if it is already false
381 }
382 }
383 }
384 return b_numeric;
385}
386
387double RoutePoint::GetWaypointArrivalRadius() {
388 if ((m_WaypointArrivalRadius >= 0) && (m_WaypointArrivalRadius < 0.001)) {
389 SetWaypointArrivalRadius(g_n_arrival_circle_radius);
391 } else
393}
394
395int RoutePoint::GetWaypointRangeRingsNumber() {
397 return g_iWaypointRangeRingsNumber;
398 else
400}
401
402float RoutePoint::GetWaypointRangeRingsStep() {
404 return g_fWaypointRangeRingsStep;
405 else
407}
408
409int RoutePoint::GetWaypointRangeRingsStepUnits() {
411 return g_iWaypointRangeRingsStepUnits;
412 else
414}
415
416void RoutePoint::SetScaMin(long val) {
417 if (val < SCAMIN_MIN)
418 val = SCAMIN_MIN; // prevent from waypoints hiding always with a nonlogic
419 // value
420 if (val < (long)m_ScaMax * 5) val = (long)m_ScaMax * 5;
421 m_ScaMin = val;
422}
423void RoutePoint::SetScaMin(wxString str) {
424 long val;
425 if (!str.ToLong(&val)) val = MAX_INT_VAL;
426 SetScaMin(val);
427}
428
429void RoutePoint::SetScaMax(long val) {
430 if (val > (int)m_ScaMin / 5)
431 m_ScaMax = (int)m_ScaMin /
432 5; // prevent from waypoints hiding always with a nonlogic value
433}
434void RoutePoint::SetScaMax(wxString str) {
435 long val;
436 if (!str.ToLong(&val)) val = 0;
437 SetScaMax(val);
438}
439
440void RoutePoint::SetPlannedSpeed(double spd) {
441 if (spd >= 0.0 && spd <= 1000.0) m_PlannedSpeed = spd;
442}
443
445 if (m_PlannedSpeed < 0.0001 &&
446 m_MarkDescription.Find("VMG=") != wxNOT_FOUND) {
447 // In case there was speed encoded in the name of the waypoint, do the
448 // conversion here.
449 wxString s_vmg = (m_MarkDescription.Mid(m_MarkDescription.Find("VMG=") + 4))
450 .BeforeFirst(';');
451 double vmg;
452 if (!s_vmg.ToDouble(&vmg)) {
453 m_MarkDescription.Replace("VMG=" + s_vmg + ";", "");
454 SetPlannedSpeed(vmg);
455 }
456 }
457 return m_PlannedSpeed;
458}
459
460wxDateTime RoutePoint::GetETD() {
461 if (m_seg_etd.IsValid()) {
462 if (!GetETA().IsValid() || m_seg_etd > GetETA()) {
463 return m_seg_etd;
464 } else {
465 return GetETA();
466 }
467 } else {
468 if (m_MarkDescription.Find("ETD=") != wxNOT_FOUND) {
469 wxDateTime etd = wxInvalidDateTime;
470 wxString s_etd =
471 (m_MarkDescription.Mid(m_MarkDescription.Find("ETD=") + 4))
472 .BeforeFirst(';');
473 const wxChar *parse_return = etd.ParseDateTime(s_etd);
474 if (parse_return) {
475 wxString tz(parse_return);
476
477 if (tz.Find("UT") != wxNOT_FOUND) {
478 // TODO: This is error-prone. It would match any string containing
479 // these characters, not just time zone codes For example, "UT" would
480 // match "UTC+2".
481 m_seg_etd = etd;
482 } else {
483 if (tz.Find("LMT") != wxNOT_FOUND) {
484 m_seg_etd = etd;
485 long lmt_offset = (long)((m_lon * 3600.) / 15.);
486 wxTimeSpan lmt(0, 0, (int)lmt_offset, 0);
487 m_seg_etd -= lmt;
488 } else {
489 m_seg_etd = etd.ToUTC();
490 }
491 }
492 if (etd.IsValid() && (!GetETA().IsValid() || etd > GetETA())) {
493 m_MarkDescription.Replace(s_etd, "");
494 m_seg_etd = etd;
495 return m_seg_etd;
496 } else {
497 return GetETA();
498 }
499 }
500 }
501 }
502 return wxInvalidDateTime;
503}
504
506 if (m_manual_etd && m_seg_etd.IsValid()) {
507 return m_seg_etd;
508 }
509 return wxInvalidDateTime;
510}
511
512wxDateTime RoutePoint::GetETA() {
513 if (m_seg_eta.IsValid()) {
514 return m_seg_eta;
515 }
516 return wxInvalidDateTime;
517}
518
520 if (m_seg_ete != 0) {
521 return formatTimeDelta(m_seg_ete);
522 }
523 return "";
524}
525
526void RoutePoint::SetETE(wxLongLong secs) { m_seg_ete = secs; }
527
528void RoutePoint::SetETD(const wxDateTime &etd) {
529 m_seg_etd = etd;
530 m_manual_etd = TRUE;
531}
532
533bool RoutePoint::SetETD(const wxString &ts) {
534 if (ts.IsEmpty()) {
535 m_seg_etd = wxInvalidDateTime;
536 m_manual_etd = false;
537 return true;
538 }
539 wxDateTime tmp;
540 wxString::const_iterator end;
541 // No timezone conversion is done because the serialized string
542 // does not include timezone information, e.g., "2025-03-26T18:57:01"
543 // The input string is assumed to be in UTC format.
544 if (tmp.ParseISOCombined(ts)) {
545 SetETD(tmp);
546 return TRUE;
547 } else if (tmp.ParseDateTime(ts, &end)) {
548 SetETD(tmp);
549 return TRUE;
550 }
551 return FALSE;
552}
Basic platform specific support utilities without GUI deps.
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
HyperlinkList * m_HyperlinkList
List of hyperlinks associated with this waypoint.
wxColour m_wxcWaypointRangeRingsColour
Color for the range rings display.
wxString m_MarkDescription
Description text for the waypoint.
int m_iWaypointRangeRingsNumber
Number of range rings to display around the waypoint.
int m_NameLocationOffsetX
Horizontal offset for waypoint name placement relative to the icon.
void SetCreateTime(wxDateTime dt)
Sets the create time of this RoutePoint in UTC.
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Definition route_point.h:47
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
unsigned int m_iTextTexture
Texture identifier for rendered text.
wxString m_GUID
Globally Unique Identifier for the waypoint.
wxDateTime GetETD()
Retrieves the Estimated Time of Departure for this waypoint, in UTC.
wxDateTime m_CreateTimeX
Creation timestamp for the waypoint, in UTC.
int m_NameLocationOffsetY
Vertical offset for waypoint name placement relative to the icon.
bool IsNameDynamic()
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_pos_on_screen
Flag indicating if the waypoint is currently visible on screen.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
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_bIsInRoute
Flag indicating if this waypoint is part of a route.
bool m_IconIsDirty
Flag indicating if the waypoint icon needs to be reloaded or redrawn.
wxFont * m_pMarkFont
Font used for rendering the waypoint name.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
wxString GetETE()
Retrieves the Estimated Time En route as a formatted string.
wxString m_timestring
String representation of the waypoint creation time.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
double GetPlannedSpeed()
Return the planned speed associated with this waypoint.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
double m_WaypointArrivalRadius
Arrival radius in nautical miles.
bool m_btemp
Flag indicating if this is a temporary waypoint.
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.
wxSize m_NameExtents
Size of the waypoint name text when rendered.
wxDateTime m_seg_eta
Estimated Time of Arrival at this waypoint, in UTC.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
int m_iWaypointRangeRingsStepUnits
Units for the range rings step (0=nm, 1=km).
wxDateTime GetCreateTime(void)
Returns the Create Time of this RoutePoint in UTC.
float m_fWaypointRangeRingsStep
Distance between consecutive range rings.
wxLongLong m_seg_ete
Estimated Time Enroute for the leg leading to this waypoint.
wxString m_TideStation
Associated tide station identifier.
bool m_bShowWaypointRangeRings
Flag indicating if range rings should be shown around the waypoint.
void SetETD(const wxDateTime &etd)
Sets the Estimated Time of Departure for this waypoint, in UTC.
wxDateTime GetETA()
Retrieves the Estimated Time of Arrival for this waypoint, in UTC.
bool m_bIsListed
Flag indicating if the waypoint should appear in the Route Manager dialog's waypoint list.
Represents a navigational route in the navigation system.
Definition route.h:99
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
Definition routeman.cpp:150
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
Definition routeman.cpp:998
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Extern C linked utilities.
OpenCPN Georef utility.
const wxChar * ParseGPXDateTime(wxDateTime &dt, const wxChar *datetime)
This function parses a string containing a GPX time representation and returns a wxDateTime containin...
Navigation Utility Functions without GUI dependencies.
Route abstraction.
wxColour g_colourWaypointRangeRingsColour
Global instance.
int g_LayerIdx
Global instance.
wxRect g_blink_rect
Global instance.
Waypoint or mark abstraction.
wxColour g_colourWaypointRangeRingsColour
Global instance.
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
Route Manager.
Selected route, segment, waypoint, etc.