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 SetScaMax(g_iWpt_ScaMax);
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 SetScaMax(g_iWpt_ScaMax);
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 if (m_ScaMax > 0 && scale_val <= (double)m_ScaMax - 1.0) return false;
319 }
320 return true;
321}
322
323bool RoutePoint::IsSharedInVisibleRoute() {
324 if (IsShared()) {
325 // Get an array of all routes using this point
326 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(this);
327
328 // Use route array (if any) to determine actual visibility for this point
329 bool brp_viz = false;
330 if (proute_array) {
331 for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
332 Route *pr = (Route *)proute_array->Item(ir);
333 if (pr->IsVisible()) {
334 brp_viz = true;
335 break;
336 }
337 }
338 delete proute_array;
339 }
340
341 return brp_viz;
342 } else // point is not shared
343 return false;
344}
345
346void RoutePoint::SetPosition(double lat, double lon) {
347 m_lat = lat;
348 m_lon = lon;
349}
350
351bool RoutePoint::IsSame(RoutePoint *pOtherRP) {
352 bool IsSame = false;
353
354 if (this->m_MarkName == pOtherRP->m_MarkName) {
355 if (fabs(this->m_lat - pOtherRP->m_lat) < 1.e-6 &&
356 fabs(this->m_lon - pOtherRP->m_lon) < 1.e-6)
357 IsSame = true;
358 }
359 return IsSame;
360}
361
368 bool b_numeric = false;
369 if (m_bIsInRoute) {
370 if (GetName().Len() >= 2) {
371 wxString substring = GetName().Left(2);
372 if (substring == "NM") {
373 substring = GetName().substr(2, 3);
374 } else {
375 substring = GetName().Left(3);
376 }
377 b_numeric = true; // assume it is numeric
378 for (unsigned int i = 0; i < substring.Len(); i++) {
379 if (b_numeric == true) {
380 b_numeric = wxIsdigit(substring[i]);
381 } // don't change the value if it is already false
382 }
383 }
384 }
385 return b_numeric;
386}
387
388double RoutePoint::GetWaypointArrivalRadius() {
389 if ((m_WaypointArrivalRadius >= 0) && (m_WaypointArrivalRadius < 0.001)) {
390 SetWaypointArrivalRadius(g_n_arrival_circle_radius);
392 } else
394}
395
396int RoutePoint::GetWaypointRangeRingsNumber() {
398 return g_iWaypointRangeRingsNumber;
399 else
401}
402
403float RoutePoint::GetWaypointRangeRingsStep() {
405 return g_fWaypointRangeRingsStep;
406 else
408}
409
410int RoutePoint::GetWaypointRangeRingsStepUnits() {
412 return g_iWaypointRangeRingsStepUnits;
413 else
415}
416
417void RoutePoint::SetScaMin(long val) {
418 if (val < SCAMIN_MIN)
419 val = SCAMIN_MIN; // prevent from waypoints hiding always with a nonlogic
420 // value
421 if (m_ScaMax > 0 && val < (long)m_ScaMax) val = (long)m_ScaMax;
422 m_ScaMin = val;
423}
424void RoutePoint::SetScaMin(wxString str) {
425 long val;
426 if (!str.ToLong(&val)) val = MAX_INT_VAL;
427 SetScaMin(val);
428}
429
430void RoutePoint::SetScaMax(long val) {
431 long max_allowed = m_ScaMin > 0 ? (long)m_ScaMin : 0;
432 m_ScaMax = val;
433 if (max_allowed > 0 && m_ScaMax > max_allowed) {
434 m_ScaMax = max_allowed; // prevent from waypoints hiding always with a
435 // nonlogic value
436 }
437}
438void RoutePoint::SetScaMax(wxString str) {
439 long val;
440 if (!str.ToLong(&val)) val = 0;
441 SetScaMax(val);
442}
443
444void RoutePoint::SetPlannedSpeed(double spd) {
445 if (spd >= 0.0 && spd <= 1000.0) m_PlannedSpeed = spd;
446}
447
449 if (m_PlannedSpeed < 0.0001 &&
450 m_MarkDescription.Find("VMG=") != wxNOT_FOUND) {
451 // In case there was speed encoded in the name of the waypoint, do the
452 // conversion here.
453 wxString s_vmg = (m_MarkDescription.Mid(m_MarkDescription.Find("VMG=") + 4))
454 .BeforeFirst(';');
455 double vmg;
456 if (!s_vmg.ToDouble(&vmg)) {
457 m_MarkDescription.Replace("VMG=" + s_vmg + ";", "");
458 SetPlannedSpeed(vmg);
459 }
460 }
461 return m_PlannedSpeed;
462}
463
464wxDateTime RoutePoint::GetETD() {
465 if (m_seg_etd.IsValid()) {
466 if (!GetETA().IsValid() || m_seg_etd > GetETA()) {
467 return m_seg_etd;
468 } else {
469 return GetETA();
470 }
471 } else {
472 if (m_MarkDescription.Find("ETD=") != wxNOT_FOUND) {
473 wxDateTime etd = wxInvalidDateTime;
474 wxString s_etd =
475 (m_MarkDescription.Mid(m_MarkDescription.Find("ETD=") + 4))
476 .BeforeFirst(';');
477 const wxChar *parse_return = etd.ParseDateTime(s_etd);
478 if (parse_return) {
479 wxString tz(parse_return);
480
481 if (tz.Find("UT") != wxNOT_FOUND) {
482 // TODO: This is error-prone. It would match any string containing
483 // these characters, not just time zone codes For example, "UT" would
484 // match "UTC+2".
485 m_seg_etd = etd;
486 } else {
487 if (tz.Find("LMT") != wxNOT_FOUND) {
488 m_seg_etd = etd;
489 long lmt_offset = (long)((m_lon * 3600.) / 15.);
490 wxTimeSpan lmt(0, 0, (int)lmt_offset, 0);
491 m_seg_etd -= lmt;
492 } else {
493 m_seg_etd = etd.ToUTC();
494 }
495 }
496 if (etd.IsValid() && (!GetETA().IsValid() || etd > GetETA())) {
497 m_MarkDescription.Replace(s_etd, "");
498 m_seg_etd = etd;
499 return m_seg_etd;
500 } else {
501 return GetETA();
502 }
503 }
504 }
505 }
506 return wxInvalidDateTime;
507}
508
510 if (m_manual_etd && m_seg_etd.IsValid()) {
511 return m_seg_etd;
512 }
513 return wxInvalidDateTime;
514}
515
516wxDateTime RoutePoint::GetETA() {
517 if (m_seg_eta.IsValid()) {
518 return m_seg_eta;
519 }
520 return wxInvalidDateTime;
521}
522
524 if (m_seg_ete != 0) {
525 return formatTimeDelta(m_seg_ete);
526 }
527 return "";
528}
529
530void RoutePoint::SetETE(wxLongLong secs) { m_seg_ete = secs; }
531
532void RoutePoint::SetETD(const wxDateTime &etd) {
533 m_seg_etd = etd;
534 m_manual_etd = TRUE;
535}
536
537bool RoutePoint::SetETD(const wxString &ts) {
538 if (ts.IsEmpty()) {
539 m_seg_etd = wxInvalidDateTime;
540 m_manual_etd = false;
541 return true;
542 }
543 wxDateTime tmp;
544 wxString::const_iterator end;
545 // No timezone conversion is done because the serialized string
546 // does not include timezone information, e.g., "2025-03-26T18:57:01"
547 // The input string is assumed to be in UTC format.
548 if (tmp.ParseISOCombined(ts)) {
549 SetETD(tmp);
550 return TRUE;
551 } else if (tmp.ParseDateTime(ts, &end)) {
552 SetETD(tmp);
553 return TRUE;
554 }
555 return FALSE;
556}
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.