OpenCPN Partial API docs
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/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 
41 WX_DEFINE_LIST(RoutePointList);
42 
43 wxColour g_colourWaypointRangeRingsColour;
44 
45 int g_LayerIdx;
46 
47 wxRect g_blink_rect;
48 
49 std::function<void(unsigned, const unsigned*)> RoutePoint::delete_gl_textures
50  = [](unsigned, const unsigned*) { assert(true); };
51 
52 RoutePoint::RoutePoint() {
53  m_pbmIcon = NULL;
54 
55  // Nice defaults
56  m_seg_len = 0.0;
57  m_seg_vmg = 0.0;
58 
59  m_seg_etd = wxInvalidDateTime;
60  m_manual_etd = false;
61 
62  m_seg_eta = wxInvalidDateTime;
63  m_bDynamicName = false;
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
119 RoutePoint::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_bDynamicName = orig->m_bDynamicName;
130  m_bPtIsSelected = orig->m_bPtIsSelected;
131  m_bRPIsBeingEdited = orig->m_bRPIsBeingEdited;
132  m_bIsActive = orig->m_bIsActive;
133  m_bBlink = orig->m_bBlink;
134  m_bIsInRoute = orig->m_bIsInRoute;
135  m_CreateTimeX = orig->m_CreateTimeX;
136  m_bIsolatedMark = orig->m_bIsolatedMark;
137  m_bShowName = orig->m_bShowName;
138  SetShared(orig->IsShared());
139  m_bIsVisible = orig->m_bIsVisible;
140  m_bIsListed = orig->m_bIsListed;
141  CurrentRect_in_DC = orig->CurrentRect_in_DC;
142  m_NameLocationOffsetX = orig->m_NameLocationOffsetX;
143  m_NameLocationOffsetY = orig->m_NameLocationOffsetY;
144  m_pMarkFont = orig->m_pMarkFont;
145  m_MarkDescription = orig->m_MarkDescription;
146  m_btemp = orig->m_btemp;
147  m_ScaMin = orig->m_ScaMin;
148  m_ScaMax = orig->m_ScaMax;
149  m_HyperlinkList = new HyperlinkList;
150  m_IconName = orig->m_IconName;
151  m_TideStation = orig->m_TideStation;
152  SetPlannedSpeed(orig->GetPlannedSpeed());
153 
154  m_bIsInLayer = orig->m_bIsInLayer;
155  m_GUID = pWayPointMan->CreateGUID(this);
156 
157  m_SelectNode = NULL;
158  m_ManagerNode = NULL;
159 
160  m_WaypointArrivalRadius = orig->GetWaypointArrivalRadius();
161  m_bShowWaypointRangeRings = orig->m_bShowWaypointRangeRings;
162  m_iWaypointRangeRingsNumber = orig->m_iWaypointRangeRingsNumber;
163  m_fWaypointRangeRingsStep = orig->m_fWaypointRangeRingsStep;
164  m_iWaypointRangeRingsStepUnits = orig->m_iWaypointRangeRingsStepUnits;
165  m_wxcWaypointRangeRingsColour = orig->m_wxcWaypointRangeRingsColour;
166  m_ScaMin = orig->m_ScaMin;
167  m_ScaMax = orig->m_ScaMax;
168  b_UseScamin = orig->b_UseScamin;
169  m_IconIsDirty = orig->m_IconIsDirty;
170 
171  m_bDrawDragHandle = false;
172  m_dragIconTexture = 0;
173  m_draggingOffsetx = m_draggingOffsety = 0;
174 }
175 
176 RoutePoint::RoutePoint(double lat, double lon, const wxString &icon_ident,
177  const wxString &name, const wxString &pGUID,
178  bool bAddToList) {
179  // Establish points
180  m_lat = lat;
181  m_lon = lon;
182 
183  // Normalize the longitude, to fix any old poorly formed points
184  if (m_lon < -180.)
185  m_lon += 360.;
186  else if (m_lon > 180.)
187  m_lon -= 360.;
188 
189  // Nice defaults
190  m_seg_len = 0.0;
191  m_seg_vmg = 0.0;
192 
193  m_seg_etd = wxInvalidDateTime;
194  m_manual_etd = false;
195 
196  m_bDynamicName = false;
197  m_bPtIsSelected = false;
198  m_bRPIsBeingEdited = false;
199  m_bIsActive = false;
200  m_bBlink = false;
201  m_bIsInRoute = false;
202  m_CreateTimeX = wxDateTime::Now();
203  m_bIsolatedMark = false;
204  m_bShowName = true;
205  SetShared(false);
206  m_bIsVisible = true;
207  m_bIsListed = true;
208  CurrentRect_in_DC = wxRect(0, 0, 0, 0);
209  m_NameLocationOffsetX = -10;
210  m_NameLocationOffsetY = 8;
211  m_pMarkFont = NULL;
212  m_btemp = false;
213  m_bPreScaled = false;
214 
215  m_SelectNode = NULL;
216  m_ManagerNode = NULL;
217  m_IconScaleFactor = 1.0;
218  m_ScaMin = MAX_INT_VAL;
219  m_ScaMax = 0;
220  m_HyperlinkList = new HyperlinkList;
221  m_IconIsDirty = true;
222 
223  m_iTextTexture = 0;
224 
225  if (!pGUID.IsEmpty())
226  m_GUID = pGUID;
227  else
228  m_GUID = pWayPointMan->CreateGUID(this);
229 
230  // Get Icon bitmap
231  m_IconName = icon_ident;
232 
233  SetName(name);
234 
235  // Possibly add the waypoint to the global list maintained by the waypoint
236  // manager
237 
238  if (bAddToList && NULL != pWayPointMan) pWayPointMan->AddRoutePoint(this);
239 
240  m_bIsInLayer = false;
241  m_LayerID = 0;
242 
243  SetWaypointArrivalRadius(g_n_arrival_circle_radius);
244 
245  m_bShowWaypointRangeRings = (bool)g_iWaypointRangeRingsNumber;
246 
247  m_iWaypointRangeRingsNumber = g_iWaypointRangeRingsNumber;
248  m_fWaypointRangeRingsStep = g_fWaypointRangeRingsStep;
249  m_iWaypointRangeRingsStepUnits = g_iWaypointRangeRingsStepUnits;
250  m_wxcWaypointRangeRingsColour = g_colourWaypointRangeRingsColour;
251  m_ScaMin = g_iWpt_ScaMin;
252  m_ScaMax = 0;
253  b_UseScamin = g_bUseWptScaMin;
254  m_bShowName = g_bShowWptName;
255 
256  m_bDrawDragHandle = false;
257  m_dragIconTexture = 0;
258  m_draggingOffsetx = m_draggingOffsety = 0;
259 
260  m_PlannedSpeed = 0.;
261 }
262 
263 RoutePoint::~RoutePoint() {
264  // Remove this point from the global waypoint list
265  if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(this);
266 
267  if (m_HyperlinkList) {
268  m_HyperlinkList->DeleteContents(true);
269  delete m_HyperlinkList;
270  }
271  RoutePoint::delete_gl_textures(1, &m_dragIconTexture);
272 }
273 
274 wxDateTime RoutePoint::GetCreateTime() {
275  if (!m_CreateTimeX.IsValid()) {
276  if (m_timestring.Len()) ParseGPXDateTime(m_CreateTimeX, m_timestring);
277  }
278  return m_CreateTimeX;
279 }
280 
281 void RoutePoint::SetCreateTime(wxDateTime dt) { m_CreateTimeX = dt; }
282 
283 void RoutePoint::SetName(const wxString &name) {
284  if (m_iTextTexture) {
285  RoutePoint::delete_gl_textures(1, &m_iTextTexture);
286  m_iTextTexture = 0;
287  }
288  m_MarkName = name;
289  CalculateNameExtents();
290 }
291 
292 void RoutePoint::CalculateNameExtents(void) {
293  if (m_pMarkFont) {
294  wxScreenDC dc;
295 
296 #ifdef __WXQT__ // avoiding "painter not active" warning
297  int w, h;
298  dc.GetTextExtent(m_MarkName, &w, &h, NULL, NULL, m_pMarkFont);
299  m_NameExtents = wxSize(w, h);
300 #else
301  dc.SetFont(*m_pMarkFont);
302  m_NameExtents = dc.GetMultiLineTextExtent(m_MarkName);
303 #endif
304  } else
305  m_NameExtents = wxSize(0, 0);
306 }
307 
308 
309 bool RoutePoint::IsVisibleSelectable(double scale_val, bool boverrideViz) {
310  if (m_bIsActive) // An active route point must always be visible
311  return true;
312 
313  if (!boverrideViz) {
314  if (!m_bIsVisible) // if not visible nevermind the rest.
315  return false;
316  }
317 
318  if (b_UseScamin) {
319  if (g_bOverruleScaMin)
320  return true;
321  else if (scale_val >= (double)(m_ScaMin + 1))
322  return false;
323  }
324  return true;
325 }
326 
327 bool RoutePoint::IsSharedInVisibleRoute() {
328  if (IsShared()) {
329  // Get an array of all routes using this point
330  wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(this);
331 
332  // Use route array (if any) to determine actual visibility for this point
333  bool brp_viz = false;
334  if (proute_array) {
335  for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
336  Route *pr = (Route *)proute_array->Item(ir);
337  if (pr->IsVisible()) {
338  brp_viz = true;
339  break;
340  }
341  }
342  }
343 
344  return brp_viz;
345  } else // point is not shared
346  return false;
347 }
348 
349 void RoutePoint::SetPosition(double lat, double lon) {
350  m_lat = lat;
351  m_lon = lon;
352 }
353 
354 bool RoutePoint::IsSame(RoutePoint *pOtherRP) {
355  bool IsSame = false;
356 
357  if (this->m_MarkName == pOtherRP->m_MarkName) {
358  if (fabs(this->m_lat - pOtherRP->m_lat) < 1.e-6 &&
359  fabs(this->m_lon - pOtherRP->m_lon) < 1.e-6)
360  IsSame = true;
361  }
362  return IsSame;
363 }
364 
365 double RoutePoint::GetWaypointArrivalRadius() {
366  if ((m_WaypointArrivalRadius >= 0) && (m_WaypointArrivalRadius < 0.001)) {
367  SetWaypointArrivalRadius(g_n_arrival_circle_radius);
368  return m_WaypointArrivalRadius;
369  } else
370  return m_WaypointArrivalRadius;
371 }
372 
373 int RoutePoint::GetWaypointRangeRingsNumber() {
374  if (m_iWaypointRangeRingsNumber == -1)
375  return g_iWaypointRangeRingsNumber;
376  else
377  return m_iWaypointRangeRingsNumber;
378 }
379 
380 float RoutePoint::GetWaypointRangeRingsStep() {
381  if (m_fWaypointRangeRingsStep == -1)
382  return g_fWaypointRangeRingsStep;
383  else
384  return m_fWaypointRangeRingsStep;
385 }
386 
387 int RoutePoint::GetWaypointRangeRingsStepUnits() {
388  if (m_iWaypointRangeRingsStepUnits == -1)
389  return g_iWaypointRangeRingsStepUnits;
390  else
391  return m_iWaypointRangeRingsStepUnits;
392 }
393 
394 void RoutePoint::SetScaMin(long val) {
395  if (val < SCAMIN_MIN)
396  val = SCAMIN_MIN; // prevent from waypoints hiding always with a nonlogic
397  // value
398  if (val < (long)m_ScaMax * 5) val = (long)m_ScaMax * 5;
399  m_ScaMin = val;
400 }
401 void RoutePoint::SetScaMin(wxString str) {
402  long val;
403  if (!str.ToLong(&val)) val = MAX_INT_VAL;
404  SetScaMin(val);
405 }
406 
407 void RoutePoint::SetScaMax(long val) {
408  if (val > (int)m_ScaMin / 5)
409  m_ScaMax = (int)m_ScaMin /
410  5; // prevent from waypoints hiding always with a nonlogic value
411 }
412 void RoutePoint::SetScaMax(wxString str) {
413  long val;
414  if (!str.ToLong(&val)) val = 0;
415  SetScaMax(val);
416 }
417 
418 void RoutePoint::SetPlannedSpeed(double spd) {
419  if (spd >= 0.0 && spd <= 1000.0) m_PlannedSpeed = spd;
420 }
421 
422 double RoutePoint::GetPlannedSpeed() {
423  if (m_PlannedSpeed < 0.0001 &&
424  m_MarkDescription.Find(_T("VMG=")) != wxNOT_FOUND) {
425  // In case there was speed encoded in the name of the waypoint, do the
426  // conversion here.
427  wxString s_vmg =
428  (m_MarkDescription.Mid(m_MarkDescription.Find(_T("VMG=")) + 4))
429  .BeforeFirst(';');
430  double vmg;
431  if (!s_vmg.ToDouble(&vmg)) {
432  m_MarkDescription.Replace(_T("VMG=") + s_vmg + ";", wxEmptyString);
433  SetPlannedSpeed(vmg);
434  }
435  }
436  return m_PlannedSpeed;
437 }
438 
439 wxDateTime RoutePoint::GetETD() {
440  if (m_seg_etd.IsValid()) {
441  if (!GetETA().IsValid() || m_seg_etd > GetETA()) {
442  return m_seg_etd;
443  } else {
444  return GetETA();
445  }
446  } else {
447  if (m_MarkDescription.Find(_T("ETD=")) != wxNOT_FOUND) {
448  wxDateTime etd = wxInvalidDateTime;
449  wxString s_etd =
450  (m_MarkDescription.Mid(m_MarkDescription.Find(_T("ETD=")) + 4))
451  .BeforeFirst(';');
452  const wxChar *parse_return = etd.ParseDateTime(s_etd);
453  if (parse_return) {
454  wxString tz(parse_return);
455 
456  if (tz.Find(_T("UT")) != wxNOT_FOUND) {
457  m_seg_etd = etd;
458  } else {
459  if (tz.Find(_T("LMT")) != wxNOT_FOUND) {
460  m_seg_etd = etd;
461  long lmt_offset = (long)((m_lon * 3600.) / 15.);
462  wxTimeSpan lmt(0, 0, (int)lmt_offset, 0);
463  m_seg_etd -= lmt;
464  } else {
465  m_seg_etd = etd.ToUTC();
466  }
467  }
468  if (etd.IsValid() && (!GetETA().IsValid() || etd > GetETA())) {
469  m_MarkDescription.Replace(s_etd, wxEmptyString);
470  m_seg_etd = etd;
471  return m_seg_etd;
472  } else {
473  return GetETA();
474  }
475  }
476  }
477  }
478  return wxInvalidDateTime;
479 }
480 
481 wxDateTime RoutePoint::GetManualETD() {
482  if (m_manual_etd && m_seg_etd.IsValid()) {
483  return m_seg_etd;
484  }
485  return wxInvalidDateTime;
486 }
487 
488 wxDateTime RoutePoint::GetETA() {
489  if (m_seg_eta.IsValid()) {
490  return m_seg_eta;
491  }
492  return wxInvalidDateTime;
493 }
494 
495 wxString RoutePoint::GetETE() {
496  if (m_seg_ete != 0) {
497  return formatTimeDelta(m_seg_ete);
498  }
499  return wxEmptyString;
500 }
501 
502 void RoutePoint::SetETE(wxLongLong secs) { m_seg_ete = secs; }
503 
504 void RoutePoint::SetETD(const wxDateTime &etd) {
505  m_seg_etd = etd;
506  m_manual_etd = TRUE;
507 }
508 
509 bool RoutePoint::SetETD(const wxString &ts) {
510  if (ts.IsEmpty()) {
511  m_seg_etd = wxInvalidDateTime;
512  m_manual_etd = false;
513  return true;
514  }
515  wxDateTime tmp;
516  wxString::const_iterator end;
517  if (tmp.ParseISOCombined(ts)) {
518  SetETD(tmp);
519  return TRUE;
520  } else if (tmp.ParseDateTime(ts, &end)) {
521  SetETD(tmp);
522  return TRUE;
523  }
524  return FALSE;
525 }
static std::function< void(unsigned, const unsigned *)> delete_gl_textures
Horrible Hack (tm).
Definition: route_point.h:70
Definition: route.h:75