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