OpenCPN Partial API docs
Loading...
Searching...
No Matches
route_point.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Route Point Object
5 *
6 ***************************************************************************
7 * Copyright (C) 2013 by David S. Register *
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the *
21 * Free Software Foundation, Inc., *
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
23 **************************************************************************/
24
25#include <wx/colour.h>
26#include <wx/datetime.h>
27#include <wx/dynarray.h>
28#include <wx/string.h>
29#include <wx/tokenzr.h>
30
31#include "model/base_platform.h"
32#include "model/cutil.h"
33#include "model/georef.h"
34#include "model/navutil_base.h"
35#include "model/route.h"
36#include "model/routeman.h"
37#include "model/route_point.h"
38#include "model/select.h"
39
40#include <wx/listimpl.cpp>
41
42WX_DEFINE_LIST(RoutePointList);
43
44wxColour g_colourWaypointRangeRingsColour;
45
46int g_LayerIdx;
47
48wxRect g_blink_rect;
49
50std::function<void(unsigned, const unsigned *)> RoutePoint::delete_gl_textures =
51 [](unsigned, const unsigned *) { assert(true); };
52
53RoutePoint::RoutePoint() {
54 m_pbmIcon = NULL;
55
56 // Nice defaults
57 m_seg_len = 0.0;
58 m_seg_vmg = 0.0;
59
60 m_seg_etd = wxInvalidDateTime;
61 m_manual_etd = false;
62
63 m_seg_eta = wxInvalidDateTime;
64 m_bPtIsSelected = false;
65 m_bRPIsBeingEdited = false;
66 m_bIsActive = false;
67 m_bBlink = false;
68 m_bIsInRoute = false;
69 m_CreateTimeX = wxDateTime::Now();
70 m_bIsolatedMark = false;
71 m_bShowName = true;
72 SetShared(false);
73 m_bIsVisible = true;
74 m_bIsListed = true;
75 CurrentRect_in_DC = wxRect(0, 0, 0, 0);
76 m_NameLocationOffsetX = -10;
77 m_NameLocationOffsetY = 8;
78 m_pMarkFont = NULL;
79 m_btemp = false;
80 m_SelectNode = NULL;
81 m_ManagerNode = NULL;
82
83 m_iTextTexture = 0;
84
85 m_HyperlinkList = new HyperlinkList;
86
87 m_GUID = pWayPointMan->CreateGUID(this);
88
89 m_IconName = wxEmptyString;
90
91 m_MarkName = wxEmptyString;
92
93 m_bIsInLayer = false;
94 m_LayerID = 0;
95
96 m_WaypointArrivalRadius = g_n_arrival_circle_radius;
97
98 m_bShowWaypointRangeRings = (bool)g_iWaypointRangeRingsNumber;
99
100 m_iWaypointRangeRingsNumber = g_iWaypointRangeRingsNumber;
101 m_fWaypointRangeRingsStep = g_fWaypointRangeRingsStep;
102 m_iWaypointRangeRingsStepUnits = g_iWaypointRangeRingsStepUnits;
103 m_wxcWaypointRangeRingsColour = g_colourWaypointRangeRingsColour;
104 m_ScaMin = g_iWpt_ScaMin;
105 m_bShowName = g_bShowWptName;
106 m_ScaMax = 0;
107 b_UseScamin = g_bUseWptScaMin;
108
109 m_pos_on_screen = false;
110 m_bDrawDragHandle = false;
111 m_dragIconTexture = 0;
112 m_draggingOffsetx = m_draggingOffsety = 0;
113
114 m_PlannedSpeed = 0.;
115 m_IconIsDirty = true;
116}
117
118// Copy Constructor
119RoutePoint::RoutePoint(RoutePoint *orig) {
120 m_MarkName = orig->GetName();
121 m_lat = orig->m_lat;
122 m_lon = orig->m_lon;
123 m_seg_len = orig->m_seg_len;
124 m_seg_vmg = orig->m_seg_vmg;
125
126 m_seg_etd = orig->m_seg_etd;
127 m_manual_etd = false;
128
129 m_bPtIsSelected = orig->m_bPtIsSelected;
130 m_bRPIsBeingEdited = orig->m_bRPIsBeingEdited;
131 m_bIsActive = orig->m_bIsActive;
132 m_bBlink = orig->m_bBlink;
133 m_bIsInRoute = orig->m_bIsInRoute;
134 m_CreateTimeX = orig->m_CreateTimeX;
135 m_bIsolatedMark = orig->m_bIsolatedMark;
136 m_bShowName = orig->m_bShowName;
137 SetShared(orig->IsShared());
138 m_bIsVisible = orig->m_bIsVisible;
139 m_bIsListed = orig->m_bIsListed;
140 CurrentRect_in_DC = orig->CurrentRect_in_DC;
141 m_NameLocationOffsetX = orig->m_NameLocationOffsetX;
142 m_NameLocationOffsetY = orig->m_NameLocationOffsetY;
143 m_pMarkFont = orig->m_pMarkFont;
144 m_MarkDescription = orig->m_MarkDescription;
145 m_btemp = orig->m_btemp;
146 m_ScaMin = orig->m_ScaMin;
147 m_ScaMax = orig->m_ScaMax;
148 m_HyperlinkList = new HyperlinkList;
149 m_IconName = orig->m_IconName;
150 m_TideStation = orig->m_TideStation;
151 SetPlannedSpeed(orig->GetPlannedSpeed());
152
153 m_bIsInLayer = orig->m_bIsInLayer;
154 m_GUID = pWayPointMan->CreateGUID(this);
155
156 m_SelectNode = NULL;
157 m_ManagerNode = NULL;
158
159 m_WaypointArrivalRadius = orig->GetWaypointArrivalRadius();
160 m_bShowWaypointRangeRings = orig->m_bShowWaypointRangeRings;
161 m_iWaypointRangeRingsNumber = orig->m_iWaypointRangeRingsNumber;
162 m_fWaypointRangeRingsStep = orig->m_fWaypointRangeRingsStep;
163 m_iWaypointRangeRingsStepUnits = orig->m_iWaypointRangeRingsStepUnits;
164 m_wxcWaypointRangeRingsColour = orig->m_wxcWaypointRangeRingsColour;
165 m_ScaMin = orig->m_ScaMin;
166 m_ScaMax = orig->m_ScaMax;
167 b_UseScamin = orig->b_UseScamin;
168 m_IconIsDirty = orig->m_IconIsDirty;
169
170 m_bDrawDragHandle = false;
171 m_dragIconTexture = 0;
172 m_draggingOffsetx = m_draggingOffsety = 0;
173}
174
175RoutePoint::RoutePoint(double lat, double lon, const wxString &icon_ident,
176 const wxString &name, const wxString &pGUID,
177 bool bAddToList) {
178 // Establish points
179 m_lat = lat;
180 m_lon = lon;
181
182 // Normalize the longitude, to fix any old poorly formed points
183 if (m_lon < -180.)
184 m_lon += 360.;
185 else if (m_lon > 180.)
186 m_lon -= 360.;
187
188 // Nice defaults
189 m_seg_len = 0.0;
190 m_seg_vmg = 0.0;
191
192 m_seg_etd = wxInvalidDateTime;
193 m_manual_etd = false;
194
195 m_bPtIsSelected = false;
196 m_bRPIsBeingEdited = false;
197 m_bIsActive = false;
198 m_bBlink = false;
199 m_bIsInRoute = false;
200 m_CreateTimeX = wxDateTime::Now();
201 m_bIsolatedMark = false;
202 m_bShowName = true;
203 SetShared(false);
204 m_bIsVisible = true;
205 m_bIsListed = true;
206 CurrentRect_in_DC = wxRect(0, 0, 0, 0);
207 m_NameLocationOffsetX = -10;
208 m_NameLocationOffsetY = 8;
209 m_pMarkFont = NULL;
210 m_btemp = false;
211 m_bPreScaled = false;
212
213 m_SelectNode = NULL;
214 m_ManagerNode = NULL;
215 m_IconScaleFactor = 1.0;
216 m_ScaMin = MAX_INT_VAL;
217 m_ScaMax = 0;
218 m_HyperlinkList = new HyperlinkList;
219 m_IconIsDirty = true;
220
221 m_iTextTexture = 0;
222
223 if (!pGUID.IsEmpty())
224 m_GUID = pGUID;
225 else
226 m_GUID = pWayPointMan->CreateGUID(this);
227
228 // Get Icon bitmap
229 m_IconName = icon_ident;
230
231 SetName(name);
232
233 // Possibly add the waypoint to the global list maintained by the waypoint
234 // manager
235
236 if (bAddToList && NULL != pWayPointMan) pWayPointMan->AddRoutePoint(this);
237
238 m_bIsInLayer = false;
239 m_LayerID = 0;
240
241 SetWaypointArrivalRadius(g_n_arrival_circle_radius);
242
243 m_bShowWaypointRangeRings = (bool)g_iWaypointRangeRingsNumber;
244
245 m_iWaypointRangeRingsNumber = g_iWaypointRangeRingsNumber;
246 m_fWaypointRangeRingsStep = g_fWaypointRangeRingsStep;
247 m_iWaypointRangeRingsStepUnits = g_iWaypointRangeRingsStepUnits;
248 m_wxcWaypointRangeRingsColour = g_colourWaypointRangeRingsColour;
249 m_ScaMin = g_iWpt_ScaMin;
250 m_ScaMax = 0;
251 b_UseScamin = g_bUseWptScaMin;
252 m_bShowName = g_bShowWptName;
253
254 m_bDrawDragHandle = false;
255 m_dragIconTexture = 0;
256 m_draggingOffsetx = m_draggingOffsety = 0;
257
258 m_PlannedSpeed = 0.;
259}
260
261RoutePoint::~RoutePoint() {
262 // Remove this point from the global waypoint list
263 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(this);
264
265 if (m_HyperlinkList) {
266 m_HyperlinkList->DeleteContents(true);
267 delete m_HyperlinkList;
268 }
269 RoutePoint::delete_gl_textures(1, &m_dragIconTexture);
270}
271
272wxDateTime RoutePoint::GetCreateTime() {
273 if (!m_CreateTimeX.IsValid()) {
274 if (m_timestring.Len()) ParseGPXDateTime(m_CreateTimeX, m_timestring);
275 }
276 return m_CreateTimeX;
277}
278
279void RoutePoint::SetCreateTime(wxDateTime dt) { m_CreateTimeX = dt; }
280
281void RoutePoint::SetName(const wxString &name) {
282 if (m_iTextTexture) {
283 RoutePoint::delete_gl_textures(1, &m_iTextTexture);
284 m_iTextTexture = 0;
285 }
286 m_MarkName = name;
287 CalculateNameExtents();
288}
289
290void RoutePoint::CalculateNameExtents(void) {
291 if (m_pMarkFont) {
292 wxScreenDC dc;
293
294#ifdef __WXQT__ // avoiding "painter not active" warning
295 int w, h;
296 dc.GetTextExtent(m_MarkName, &w, &h, NULL, NULL, m_pMarkFont);
297 m_NameExtents = wxSize(w, h);
298#else
299 dc.SetFont(*m_pMarkFont);
300 m_NameExtents = dc.GetMultiLineTextExtent(m_MarkName);
301#endif
302 } else
303 m_NameExtents = wxSize(0, 0);
304}
305
306bool RoutePoint::IsVisibleSelectable(double scale_val, bool boverrideViz) {
307 if (m_bIsActive) // An active route point must always be visible
308 return true;
309
310 if (!boverrideViz) {
311 if (!m_bIsVisible) // if not visible nevermind the rest.
312 return false;
313 }
314
315 if (b_UseScamin) {
316 if (g_bOverruleScaMin)
317 return true;
318 else if (scale_val >= (double)(m_ScaMin + 1))
319 return false;
320 }
321 return true;
322}
323
324bool RoutePoint::IsSharedInVisibleRoute() {
325 if (IsShared()) {
326 // Get an array of all routes using this point
327 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(this);
328
329 // Use route array (if any) to determine actual visibility for this point
330 bool brp_viz = false;
331 if (proute_array) {
332 for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
333 Route *pr = (Route *)proute_array->Item(ir);
334 if (pr->IsVisible()) {
335 brp_viz = true;
336 break;
337 }
338 }
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);
391 return m_WaypointArrivalRadius;
392 } else
393 return m_WaypointArrivalRadius;
394}
395
396int RoutePoint::GetWaypointRangeRingsNumber() {
397 if (m_iWaypointRangeRingsNumber == -1)
398 return g_iWaypointRangeRingsNumber;
399 else
400 return m_iWaypointRangeRingsNumber;
401}
402
403float RoutePoint::GetWaypointRangeRingsStep() {
404 if (m_fWaypointRangeRingsStep == -1)
405 return g_fWaypointRangeRingsStep;
406 else
407 return m_fWaypointRangeRingsStep;
408}
409
410int RoutePoint::GetWaypointRangeRingsStepUnits() {
411 if (m_iWaypointRangeRingsStepUnits == -1)
412 return g_iWaypointRangeRingsStepUnits;
413 else
414 return m_iWaypointRangeRingsStepUnits;
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 (val < (long)m_ScaMax * 5) val = (long)m_ScaMax * 5;
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 if (val > (int)m_ScaMin / 5)
432 m_ScaMax = (int)m_ScaMin /
433 5; // prevent from waypoints hiding always with a nonlogic value
434}
435void RoutePoint::SetScaMax(wxString str) {
436 long val;
437 if (!str.ToLong(&val)) val = 0;
438 SetScaMax(val);
439}
440
441void RoutePoint::SetPlannedSpeed(double spd) {
442 if (spd >= 0.0 && spd <= 1000.0) m_PlannedSpeed = spd;
443}
444
445double RoutePoint::GetPlannedSpeed() {
446 if (m_PlannedSpeed < 0.0001 &&
447 m_MarkDescription.Find(_T("VMG=")) != wxNOT_FOUND) {
448 // In case there was speed encoded in the name of the waypoint, do the
449 // conversion here.
450 wxString s_vmg =
451 (m_MarkDescription.Mid(m_MarkDescription.Find(_T("VMG=")) + 4))
452 .BeforeFirst(';');
453 double vmg;
454 if (!s_vmg.ToDouble(&vmg)) {
455 m_MarkDescription.Replace(_T("VMG=") + s_vmg + ";", wxEmptyString);
456 SetPlannedSpeed(vmg);
457 }
458 }
459 return m_PlannedSpeed;
460}
461
462wxDateTime RoutePoint::GetETD() {
463 if (m_seg_etd.IsValid()) {
464 if (!GetETA().IsValid() || m_seg_etd > GetETA()) {
465 return m_seg_etd;
466 } else {
467 return GetETA();
468 }
469 } else {
470 if (m_MarkDescription.Find(_T("ETD=")) != wxNOT_FOUND) {
471 wxDateTime etd = wxInvalidDateTime;
472 wxString s_etd =
473 (m_MarkDescription.Mid(m_MarkDescription.Find(_T("ETD=")) + 4))
474 .BeforeFirst(';');
475 const wxChar *parse_return = etd.ParseDateTime(s_etd);
476 if (parse_return) {
477 wxString tz(parse_return);
478
479 if (tz.Find(_T("UT")) != wxNOT_FOUND) {
480 m_seg_etd = etd;
481 } else {
482 if (tz.Find(_T("LMT")) != wxNOT_FOUND) {
483 m_seg_etd = etd;
484 long lmt_offset = (long)((m_lon * 3600.) / 15.);
485 wxTimeSpan lmt(0, 0, (int)lmt_offset, 0);
486 m_seg_etd -= lmt;
487 } else {
488 m_seg_etd = etd.ToUTC();
489 }
490 }
491 if (etd.IsValid() && (!GetETA().IsValid() || etd > GetETA())) {
492 m_MarkDescription.Replace(s_etd, wxEmptyString);
493 m_seg_etd = etd;
494 return m_seg_etd;
495 } else {
496 return GetETA();
497 }
498 }
499 }
500 }
501 return wxInvalidDateTime;
502}
503
504wxDateTime RoutePoint::GetManualETD() {
505 if (m_manual_etd && m_seg_etd.IsValid()) {
506 return m_seg_etd;
507 }
508 return wxInvalidDateTime;
509}
510
511wxDateTime RoutePoint::GetETA() {
512 if (m_seg_eta.IsValid()) {
513 return m_seg_eta;
514 }
515 return wxInvalidDateTime;
516}
517
518wxString RoutePoint::GetETE() {
519 if (m_seg_ete != 0) {
520 return formatTimeDelta(m_seg_ete);
521 }
522 return wxEmptyString;
523}
524
525void RoutePoint::SetETE(wxLongLong secs) { m_seg_ete = secs; }
526
527void RoutePoint::SetETD(const wxDateTime &etd) {
528 m_seg_etd = etd;
529 m_manual_etd = TRUE;
530}
531
532bool RoutePoint::SetETD(const wxString &ts) {
533 if (ts.IsEmpty()) {
534 m_seg_etd = wxInvalidDateTime;
535 m_manual_etd = false;
536 return true;
537 }
538 wxDateTime tmp;
539 wxString::const_iterator end;
540 if (tmp.ParseISOCombined(ts)) {
541 SetETD(tmp);
542 return TRUE;
543 } else if (tmp.ParseDateTime(ts, &end)) {
544 SetETD(tmp);
545 return TRUE;
546 }
547 return FALSE;
548}
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Definition route_point.h:50
bool IsNameDynamic()
Definition route.h:75
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.