OpenCPN Partial API docs
Loading...
Searching...
No Matches
RoutePoint.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/wxprec.h"
25
26#include <wx/dcscreen.h>
27#include <wx/tokenzr.h>
28
29#include "routeman.h"
30#include "chcanv.h"
31#include "RoutePoint.h"
32#include "multiplexer.h"
33#include "navutil.h"
34#include "FontMgr.h"
35#include "cutil.h"
36#include "georef.h"
37#include "wx28compat.h"
38#include "OCPNPlatform.h"
39#include "glChartCanvas.h"
40#include "Select.h"
41#include "gui_lib.h"
42#include "Route.h"
43
44extern WayPointman *pWayPointMan;
45extern bool g_bIsNewLayer;
46extern int g_LayerIdx;
47extern Routeman *g_pRouteMan;
48extern wxRect g_blink_rect;
49extern Multiplexer *g_pMUX;
50extern MyFrame *gFrame;
51extern bool g_btouch;
52extern ocpnStyle::StyleManager *g_StyleManager;
53extern double g_n_arrival_circle_radius;
54extern int g_iWaypointRangeRingsNumber;
55extern float g_fWaypointRangeRingsStep;
56extern int g_iWaypointRangeRingsStepUnits;
57extern wxColour g_colourWaypointRangeRingsColour;
58extern OCPNPlatform *g_Platform;
59extern float g_ChartScaleFactorExp;
60extern int g_iWpt_ScaMin;
61extern bool g_bUseWptScaMin;
62extern bool g_bOverruleScaMin;
63
64extern wxImage LoadSVGIcon(wxString filename, int width, int height);
65
66#include <wx/listimpl.cpp>
67WX_DEFINE_LIST(RoutePointList);
68
69RoutePoint::RoutePoint() {
70 m_pbmIcon = NULL;
71
72 // Nice defaults
73 m_seg_len = 0.0;
74 m_seg_vmg = 0.0;
75
76 m_seg_etd = wxInvalidDateTime;
77 m_manual_etd = false;
78
79 m_seg_eta = wxInvalidDateTime;
80 m_bDynamicName = false;
81 m_bPtIsSelected = false;
82 m_bRPIsBeingEdited = false;
83 m_bIsActive = false;
84 m_bBlink = false;
85 m_bIsInRoute = false;
86 m_CreateTimeX = wxDateTime::Now();
87 m_bIsolatedMark = false;
88 m_bShowName = true;
89 SetShared(false);
90 m_bIsVisible = true;
91 m_bIsListed = true;
92 CurrentRect_in_DC = wxRect(0, 0, 0, 0);
93 m_NameLocationOffsetX = -10;
94 m_NameLocationOffsetY = 8;
95 m_pMarkFont = NULL;
96 m_btemp = false;
97 m_SelectNode = NULL;
98 m_ManagerNode = NULL;
99
100 m_iTextTexture = 0;
101
102 m_HyperlinkList = new HyperlinkList;
103
104 m_GUID = pWayPointMan->CreateGUID(this);
105
106 m_IconName = wxEmptyString;
107 ReLoadIcon();
108
109 m_MarkName = wxEmptyString;
110
111 m_bIsInLayer = false;
112 m_LayerID = 0;
113
114 m_WaypointArrivalRadius = g_n_arrival_circle_radius;
115
116 m_bShowWaypointRangeRings = (bool)g_iWaypointRangeRingsNumber;
117
118 m_iWaypointRangeRingsNumber = g_iWaypointRangeRingsNumber;
119 m_fWaypointRangeRingsStep = g_fWaypointRangeRingsStep;
120 m_iWaypointRangeRingsStepUnits = g_iWaypointRangeRingsStepUnits;
121 m_wxcWaypointRangeRingsColour = g_colourWaypointRangeRingsColour;
122 m_ScaMin = g_iWpt_ScaMin;
123 m_ScaMax = 0;
124 b_UseScamin = g_bUseWptScaMin;
125
126#ifdef ocpnUSE_GL
127 m_pos_on_screen = false;
128#endif
129 m_bDrawDragHandle = false;
130 m_dragIconTexture = 0;
131 m_draggingOffsetx = m_draggingOffsety = 0;
132
133 m_PlannedSpeed = 0.;
134}
135
136// Copy Constructor
137RoutePoint::RoutePoint(RoutePoint *orig) {
138 m_MarkName = orig->GetName();
139 m_lat = orig->m_lat;
140 m_lon = orig->m_lon;
141 m_seg_len = orig->m_seg_len;
142 m_seg_vmg = orig->m_seg_vmg;
143
144 m_seg_etd = orig->m_seg_etd;
145 m_manual_etd = false;
146
147 m_bDynamicName = orig->m_bDynamicName;
148 m_bPtIsSelected = orig->m_bPtIsSelected;
149 m_bRPIsBeingEdited = orig->m_bRPIsBeingEdited;
150 m_bIsActive = orig->m_bIsActive;
151 m_bBlink = orig->m_bBlink;
152 m_bIsInRoute = orig->m_bIsInRoute;
153 m_CreateTimeX = orig->m_CreateTimeX;
154 m_bIsolatedMark = orig->m_bIsolatedMark;
155 m_bShowName = orig->m_bShowName;
156 SetShared(orig->IsShared());
157 m_bIsVisible = orig->m_bIsVisible;
158 m_bIsListed = orig->m_bIsListed;
159 CurrentRect_in_DC = orig->CurrentRect_in_DC;
160 m_NameLocationOffsetX = orig->m_NameLocationOffsetX;
161 m_NameLocationOffsetY = orig->m_NameLocationOffsetY;
162 m_pMarkFont = orig->m_pMarkFont;
163 m_MarkDescription = orig->m_MarkDescription;
164 m_btemp = orig->m_btemp;
165 m_ScaMin = orig->m_ScaMin;
166 m_ScaMax = orig->m_ScaMax;
167 m_HyperlinkList = new HyperlinkList;
168 m_IconName = orig->m_IconName;
169 m_TideStation = orig->m_TideStation;
170 SetPlannedSpeed(orig->GetPlannedSpeed());
171 ReLoadIcon();
172
173 m_bIsInLayer = orig->m_bIsInLayer;
174 m_GUID = pWayPointMan->CreateGUID(this);
175
176 m_SelectNode = NULL;
177 m_ManagerNode = NULL;
178
179 m_WaypointArrivalRadius = orig->GetWaypointArrivalRadius();
180 m_bShowWaypointRangeRings = orig->m_bShowWaypointRangeRings;
181 m_iWaypointRangeRingsNumber = orig->m_iWaypointRangeRingsNumber;
182 m_fWaypointRangeRingsStep = orig->m_fWaypointRangeRingsStep;
183 m_iWaypointRangeRingsStepUnits = orig->m_iWaypointRangeRingsStepUnits;
184 m_wxcWaypointRangeRingsColour = orig->m_wxcWaypointRangeRingsColour;
185 m_ScaMin = orig->m_ScaMin;
186 m_ScaMax = orig->m_ScaMax;
187 b_UseScamin = orig->b_UseScamin;
188
189 m_bDrawDragHandle = false;
190 m_dragIconTexture = 0;
191 m_draggingOffsetx = m_draggingOffsety = 0;
192}
193
194RoutePoint::RoutePoint(double lat, double lon, const wxString &icon_ident,
195 const wxString &name, const wxString &pGUID,
196 bool bAddToList) {
197 // Establish points
198 m_lat = lat;
199 m_lon = lon;
200
201 // Normalize the longitude, to fix any old poorly formed points
202 if (m_lon < -180.)
203 m_lon += 360.;
204 else if (m_lon > 180.)
205 m_lon -= 360.;
206
207 // Nice defaults
208 m_seg_len = 0.0;
209 m_seg_vmg = 0.0;
210
211 m_seg_etd = wxInvalidDateTime;
212 m_manual_etd = false;
213
214 m_bDynamicName = false;
215 m_bPtIsSelected = false;
216 m_bRPIsBeingEdited = false;
217 m_bIsActive = false;
218 m_bBlink = false;
219 m_bIsInRoute = false;
220 m_CreateTimeX = wxDateTime::Now();
221 m_bIsolatedMark = false;
222 m_bShowName = true;
223 SetShared(false);
224 m_bIsVisible = true;
225 m_bIsListed = true;
226 CurrentRect_in_DC = wxRect(0, 0, 0, 0);
227 m_NameLocationOffsetX = -10;
228 m_NameLocationOffsetY = 8;
229 m_pMarkFont = NULL;
230 m_btemp = false;
231 m_bPreScaled = false;
232
233 m_SelectNode = NULL;
234 m_ManagerNode = NULL;
235 m_IconScaleFactor = 1.0;
236 m_ScaMin = MAX_INT_VAL;
237 m_ScaMax = 0;
238 m_HyperlinkList = new HyperlinkList;
239
240 if (!pGUID.IsEmpty())
241 m_GUID = pGUID;
242 else
243 m_GUID = pWayPointMan->CreateGUID(this);
244
245 // Get Icon bitmap
246 m_IconName = icon_ident;
247 ReLoadIcon();
248
249 SetName(name);
250
251 // Possibly add the waypoint to the global list maintained by the waypoint
252 // manager
253
254 if (bAddToList && NULL != pWayPointMan) pWayPointMan->AddRoutePoint(this);
255
256 m_bIsInLayer = g_bIsNewLayer;
257 if (m_bIsInLayer) {
258 m_LayerID = g_LayerIdx;
259 m_bIsListed = false;
260 } else
261 m_LayerID = 0;
262
263 SetWaypointArrivalRadius(g_n_arrival_circle_radius);
264
265 m_bShowWaypointRangeRings = (bool)g_iWaypointRangeRingsNumber;
266
267 m_iWaypointRangeRingsNumber = g_iWaypointRangeRingsNumber;
268 m_fWaypointRangeRingsStep = g_fWaypointRangeRingsStep;
269 m_iWaypointRangeRingsStepUnits = g_iWaypointRangeRingsStepUnits;
270 m_wxcWaypointRangeRingsColour = g_colourWaypointRangeRingsColour;
271 m_ScaMin = g_iWpt_ScaMin;
272 m_ScaMax = 0;
273 b_UseScamin = g_bUseWptScaMin;
274
275 m_bDrawDragHandle = false;
276 m_dragIconTexture = 0;
277 m_draggingOffsetx = m_draggingOffsety = 0;
278
279 m_PlannedSpeed = 0.;
280}
281
282RoutePoint::~RoutePoint() {
283 // Remove this point from the global waypoint list
284 if (NULL != pWayPointMan) pWayPointMan->RemoveRoutePoint(this);
285
286 if (m_HyperlinkList) {
287 m_HyperlinkList->DeleteContents(true);
288 delete m_HyperlinkList;
289 }
290#ifdef ocpnUSE_GL
291 if (m_dragIconTexture > 0) glDeleteTextures(1, &m_dragIconTexture);
292#endif
293}
294
295wxPoint2DDouble RoutePoint::GetDragHandlePoint(ChartCanvas *canvas) {
296 if (!m_bDrawDragHandle)
297 return wxPoint2DDouble(m_lon, m_lat);
298 else {
299 return computeDragHandlePoint(canvas);
300 }
301}
302
303wxPoint2DDouble RoutePoint::computeDragHandlePoint(ChartCanvas *canvas) {
304 wxPoint r;
305 canvas->GetCanvasPointPix(m_lat, m_lon, &r);
306 double lat, lon;
307 canvas->GetCanvasPixPoint(r.x + m_drag_icon_offset, r.y + m_drag_icon_offset,
308 lat, lon);
309
310 // Keep the members updated
311 m_dragHandleLat = lat;
312 m_dragHandleLon = lon;
313
314 return wxPoint2DDouble(lon, lat);
315}
316
317void RoutePoint::SetPointFromDraghandlePoint(ChartCanvas *canvas, double lat,
318 double lon) {
319 wxPoint r;
320 canvas->GetCanvasPointPix(lat, lon, &r);
321 double tlat, tlon;
322 canvas->GetCanvasPixPoint(r.x - m_drag_icon_offset, r.y - m_drag_icon_offset,
323 tlat, tlon);
324 m_lat = tlat;
325 m_lon = tlon;
326}
327
328void RoutePoint::SetPointFromDraghandlePoint(ChartCanvas *canvas, int x,
329 int y) {
330 double tlat, tlon;
331 canvas->GetCanvasPixPoint(x - m_drag_icon_offset - m_draggingOffsetx,
332 y - m_drag_icon_offset - m_draggingOffsety, tlat,
333 tlon);
334 m_lat = tlat;
335 m_lon = tlon;
336}
337
338void RoutePoint::PresetDragOffset(ChartCanvas *canvas, int x, int y) {
339 wxPoint r;
340 canvas->GetCanvasPointPix(m_lat, m_lon, &r);
341
342 m_draggingOffsetx = x - (r.x + m_drag_icon_offset);
343 m_draggingOffsety = y - (r.y + m_drag_icon_offset);
344}
345
346void RoutePoint::EnableDragHandle(bool bEnable) {
347 m_bDrawDragHandle = bEnable;
348 if (bEnable) {
349 if (!m_dragIcon.IsOk()) {
350 // Get the icon
351 // What size?
352 int bm_size = g_Platform->GetDisplayDPmm() * 9; // 9 mm nominal
353
354 // What icon?
355 wxString UserIconPath = g_Platform->GetSharedDataDir() + _T("uidata") +
356 wxFileName::GetPathSeparator();
357
358 wxImage iconSVG =
359 LoadSVGIcon(UserIconPath + _T("DragHandle.svg"), bm_size, bm_size);
360 if (iconSVG.IsOk())
361 m_dragIcon = wxBitmap(iconSVG);
362 else
363 m_dragIcon = *m_pbmIcon; // Drag handle icon not found
364
365 // build a texture
366#ifdef ocpnUSE_GL
367 /* make rgba texture */
368 if (m_dragIconTexture == 0) {
369 glGenTextures(1, &m_dragIconTexture);
370 glBindTexture(GL_TEXTURE_2D, m_dragIconTexture);
371
372 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
373 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
374 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
375
376 wxImage image = iconSVG;
377 int w = image.GetWidth(), h = image.GetHeight();
378
379 m_dragIconTextureWidth = NextPow2(w);
380 m_dragIconTextureHeight = NextPow2(h);
381
382 unsigned char *d = image.GetData();
383 unsigned char *a = image.GetAlpha();
384
385 unsigned char mr, mg, mb;
386 image.GetOrFindMaskColour(&mr, &mg, &mb);
387
388 unsigned char *e = new unsigned char[4 * w * h];
389 if (d && e) {
390 for (int y = 0; y < h; y++)
391 for (int x = 0; x < w; x++) {
392 unsigned char r, g, b;
393 int off = (y * image.GetWidth() + x);
394 r = d[off * 3 + 0];
395 g = d[off * 3 + 1];
396 b = d[off * 3 + 2];
397 e[off * 4 + 0] = r;
398 e[off * 4 + 1] = g;
399 e[off * 4 + 2] = b;
400
401 e[off * 4 + 3] =
402 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
403 }
404 }
405
406 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_dragIconTextureWidth,
407 m_dragIconTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
408 NULL);
409 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
410 e);
411
412 delete[] e;
413 }
414#endif
415
416 // set the drawing metrics
417 if (iconSVG.IsOk()) {
418 m_drag_line_length_man = bm_size;
419 m_drag_icon_offset = bm_size;
420 } else {
421 m_drag_line_length_man = 64;
422 m_drag_icon_offset = 64;
423 }
424 }
425 }
426}
427
428wxDateTime RoutePoint::GetCreateTime() {
429 if (!m_CreateTimeX.IsValid()) {
430 if (m_timestring.Len()) ParseGPXDateTime(m_CreateTimeX, m_timestring);
431 }
432 return m_CreateTimeX;
433}
434
435void RoutePoint::SetCreateTime(wxDateTime dt) { m_CreateTimeX = dt; }
436
437void RoutePoint::SetName(const wxString &name) {
438#ifdef ocpnUSE_GL
439 if (m_iTextTexture) {
440 glDeleteTextures(1, &m_iTextTexture);
441 m_iTextTexture = 0;
442 }
443#endif
444 m_MarkName = name;
445 CalculateNameExtents();
446}
447
448void RoutePoint::CalculateNameExtents(void) {
449 if (m_pMarkFont) {
450 wxScreenDC dc;
451
452#ifdef __WXQT__ // avoiding "painter not active" warning
453 int w, h;
454 dc.GetTextExtent(m_MarkName, &w, &h, NULL, NULL, m_pMarkFont);
455 m_NameExtents = wxSize(w, h);
456#else
457 dc.SetFont(*m_pMarkFont);
458 m_NameExtents = dc.GetMultiLineTextExtent(m_MarkName);
459#endif
460 } else
461 m_NameExtents = wxSize(0, 0);
462}
463
464void RoutePoint::ReLoadIcon(void) {
465 if (!pWayPointMan) return;
466 bool icon_exists = pWayPointMan->DoesIconExist(m_IconName);
467
468 wxString iconUse = m_IconName;
469 if (!icon_exists) {
470 // Try all lower case as a favor in the case where imported waypoints use
471 // mixed case names
472 wxString tentative_icon = m_IconName.Lower();
473 if (pWayPointMan->DoesIconExist(tentative_icon)) {
474 // if found, convert point's icon name permanently.
475 m_IconName = tentative_icon;
476 iconUse = m_IconName;
477 }
478 // Icon name is not in the standard or user lists, so add to the list a
479 // generic placeholder
480 else {
481 if (!pWayPointMan->DoesIconExist(_T("tempsub"))) {
482 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
483 if (style) {
484 wxBitmap bmp = style->GetIcon(_T("circle"));
485 if (bmp.IsOk())
486 pWayPointMan->ProcessIcon(bmp, _T("tempsub"), _T("tempsub"));
487 }
488 }
489 iconUse = _T("tempsub");
490 }
491 }
492
493 m_pbmIcon = pWayPointMan->GetIconBitmap(iconUse);
494 m_bPreScaled = pWayPointMan->GetIconPrescaled(iconUse);
495
496#ifdef ocpnUSE_GL
497 m_wpBBox_view_scale_ppm = -1;
498
499 m_iTextTexture = 0;
500#endif
501
502 m_IconScaleFactor = -1; // Force scaled icon reload
503 m_pMarkFont = 0; // Force Font color reload
504}
505
506bool RoutePoint::IsVisibleSelectable(ChartCanvas *canvas, bool boverrideViz) {
507 if (m_bIsActive) // An active route point must always be visible
508 return true;
509
510 if (!boverrideViz) {
511 if (!m_bIsVisible) // if not visible nevermind the rest.
512 return false;
513 }
514
515 if (b_UseScamin) {
516 if (g_bOverruleScaMin)
517 return true;
518 else if (canvas->GetScaleValue() >= (double)(m_ScaMin + 1))
519 return false;
520 }
521 return true;
522}
523
524int RoutePoint::GetIconImageIndex() {
525 if (IsShared()) {
526 // Get an array of all routes using this point
527 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(this);
528
529 // Use route array (if any) to determine actual visibility for this point
530 bool brp_viz = false;
531 if (proute_array) {
532 for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
533 Route *pr = (Route *)proute_array->Item(ir);
534 if (pr->IsVisible()) {
535 brp_viz = true;
536 break;
537 }
538 }
539 }
540
541 if (brp_viz)
542 return (pWayPointMan->GetFIconImageListIndex(GetIconBitmap()));
543 else {
544 if (IsVisible())
545 return (pWayPointMan->GetIconImageListIndex(GetIconBitmap()));
546 else
547 return (pWayPointMan->GetXIconImageListIndex(GetIconBitmap()));
548 }
549 }
550
551 else { // point is not shared
552 if (IsVisible())
553 return (pWayPointMan->GetIconImageListIndex(GetIconBitmap()));
554 else
555 return (pWayPointMan->GetXIconImageListIndex(GetIconBitmap()));
556 }
557}
558
559bool RoutePoint::IsSharedInVisibleRoute() {
560 if (IsShared()) {
561 // Get an array of all routes using this point
562 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(this);
563
564 // Use route array (if any) to determine actual visibility for this point
565 bool brp_viz = false;
566 if (proute_array) {
567 for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
568 Route *pr = (Route *)proute_array->Item(ir);
569 if (pr->IsVisible()) {
570 brp_viz = true;
571 break;
572 }
573 }
574 }
575
576 return brp_viz;
577 } else // point is not shared
578 return false;
579}
580
581void RoutePoint::Draw(ocpnDC &dc, ChartCanvas *canvas, wxPoint *rpn,
582 bool boverride_viz) {
583 wxPoint r;
584 wxRect hilitebox;
585
586 canvas->GetCanvasPointPix(m_lat, m_lon, &r);
587
588 // return the home point in this dc to allow "connect the dots"
589 if (NULL != rpn) *rpn = r;
590
591 /*if( !m_bIsVisible ) // pjotrc 2010.02.13, 2011.02.24
592 return;
593 if( !m_bIsActive) // An active route point must always be visible
594 if( !IsScaVisible( canvas) )
595 return; */
596 if (!IsVisibleSelectable(canvas, boverride_viz)) return;
597
598 // Optimization, especially apparent on tracks in normal cases
599 if (m_IconName == _T("empty") && !m_bShowName && !m_bPtIsSelected) return;
600
601 wxPen *pen;
602 if (m_bBlink)
603 pen = g_pRouteMan->GetActiveRoutePointPen();
604 else
605 pen = g_pRouteMan->GetRoutePointPen();
606
607 // Substitue icon?
608 wxBitmap *pbm;
609 if ((m_bIsActive) && (m_IconName != _T("mob")))
610 pbm = pWayPointMan->GetIconBitmap(_T ( "activepoint" ));
611 else
612 pbm = m_pbmIcon;
613
614 wxBitmap *pbms = NULL;
615 if ((g_MarkScaleFactorExp > 1.0) && !m_bPreScaled) {
616 if (m_IconScaleFactor != g_MarkScaleFactorExp) {
617 wxImage scaled_image = pbm->ConvertToImage();
618 int new_width = pbm->GetWidth() * g_MarkScaleFactorExp;
619 int new_height = pbm->GetHeight() * g_MarkScaleFactorExp;
620 m_ScaledBMP = wxBitmap(
621 scaled_image.Scale(new_width, new_height, wxIMAGE_QUALITY_HIGH));
622
623 m_IconScaleFactor = g_MarkScaleFactorExp;
624 }
625 if (m_ScaledBMP.IsOk()) pbm = &m_ScaledBMP;
626 }
627
628 int sx2 = pbm->GetWidth() / 2;
629 int sy2 = pbm->GetHeight() / 2;
630
631 // Calculate the mark drawing extents
632 wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
633
634 if (m_bShowName) {
635 if (0 == m_pMarkFont) {
636 m_pMarkFont = FontMgr::Get().GetFont(_("Marks"));
637 m_FontColor = FontMgr::Get().GetFontColor(_("Marks"));
638 CalculateNameExtents();
639 }
640
641 if (m_pMarkFont) {
642 wxRect r2(r.x + m_NameLocationOffsetX, r.y + m_NameLocationOffsetY,
643 m_NameExtents.x, m_NameExtents.y);
644 r1.Union(r2);
645 }
646 }
647
648 hilitebox = r1;
649 hilitebox.x -= r.x;
650 hilitebox.y -= r.y;
651 float radius;
652 if (g_btouch) {
653 hilitebox.Inflate(20);
654 radius = 20.0f;
655 } else {
656 hilitebox.Inflate(4);
657 radius = 4.0f;
658 }
659
660 wxColour hi_colour = pen->GetColour();
661 unsigned char transparency = 100;
662 if (m_bRPIsBeingEdited) {
663 hi_colour = GetGlobalColor(_T ( "YELO1" ));
664 transparency = 150;
665 }
666
667 // Highlite any selected point
668 if (m_bPtIsSelected || m_bRPIsBeingEdited) {
669 AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
670 hilitebox.height, radius, hi_colour, transparency);
671 }
672
673 bool bDrawHL = false;
674
675 if (m_bBlink && (gFrame->nBlinkerTick & 1)) bDrawHL = true;
676
677 if ((!bDrawHL) && (NULL != m_pbmIcon)) {
678 dc.DrawBitmap(*pbm, r.x - sx2, r.y - sy2, true);
679 // on MSW, the dc Bounding box is not updated on DrawBitmap() method.
680 // Do it explicitely here for all platforms.
681 dc.CalcBoundingBox(r.x - sx2, r.y - sy2);
682 dc.CalcBoundingBox(r.x + sx2, r.y + sy2);
683 }
684
685 if (m_bShowName) {
686 if (m_pMarkFont) {
687 dc.SetFont(*m_pMarkFont);
688 dc.SetTextForeground(m_FontColor);
689
690 dc.DrawText(m_MarkName, r.x + m_NameLocationOffsetX,
691 r.y + m_NameLocationOffsetY);
692 }
693 }
694
695 // Draw waypoint radar rings if activated
696 if (m_iWaypointRangeRingsNumber && m_bShowWaypointRangeRings) {
697 double factor = 1.00;
698 if (m_iWaypointRangeRingsStepUnits == 1) // nautical miles
699 factor = 1 / 1.852;
700
701 factor *= m_fWaypointRangeRingsStep;
702
703 double tlat, tlon;
704 wxPoint r1;
705 ll_gc_ll(m_lat, m_lon, 0, factor, &tlat, &tlon);
706 canvas->GetCanvasPointPix(tlat, tlon, &r1);
707
708 double lpp =
709 sqrt(pow((double)(r.x - r1.x), 2) + pow((double)(r.y - r1.y), 2));
710 int pix_radius = (int)lpp;
711
712 wxPen ppPen1(m_wxcWaypointRangeRingsColour, 2);
713 wxBrush saveBrush = dc.GetBrush();
714 wxPen savePen = dc.GetPen();
715 dc.SetPen(ppPen1);
716 dc.SetBrush(
717 wxBrush(m_wxcWaypointRangeRingsColour, wxBRUSHSTYLE_TRANSPARENT));
718
719 for (int i = 1; i <= m_iWaypointRangeRingsNumber; i++)
720 dc.StrokeCircle(r.x, r.y, i * pix_radius);
721 dc.SetPen(savePen);
722 dc.SetBrush(saveBrush);
723 }
724
725 // Save the current draw rectangle in the current DC
726 // This will be useful for fast icon redraws
727 CurrentRect_in_DC.x = r.x + hilitebox.x;
728 CurrentRect_in_DC.y = r.y + hilitebox.y;
729 CurrentRect_in_DC.width = hilitebox.width;
730 CurrentRect_in_DC.height = hilitebox.height;
731
732 if (m_bBlink)
733 g_blink_rect = CurrentRect_in_DC; // also save for global blinker
734
735 delete pbms; // the potentially scaled bitmap
736}
737
738#ifdef ocpnUSE_GL
739void RoutePoint::DrawGL(ViewPort &vp, ChartCanvas *canvas, ocpnDC &dc,
740 bool use_cached_screen_coords, bool bVizOverride) {
741 if (!IsVisibleSelectable(canvas, bVizOverride)) return;
742
743 // Optimization, especially apparent on tracks in normal cases
744 if (m_IconName == _T("empty") && !m_bShowName && !m_bPtIsSelected) return;
745
746 if (m_wpBBox.GetValid() && vp.view_scale_ppm == m_wpBBox_view_scale_ppm &&
747 vp.rotation == m_wpBBox_rotation) {
748 /* see if this waypoint can intersect with bounding box */
749 LLBBox vpBBox = vp.GetBBox();
750 if (vpBBox.IntersectOut(m_wpBBox)) {
751 // Are Range Rings enabled?
752 if (m_bShowWaypointRangeRings && (m_iWaypointRangeRingsNumber > 0)) {
753 double factor = 1.00;
754 if (m_iWaypointRangeRingsStepUnits == 1) // convert kilometers to NMi
755 factor = 1 / 1.852;
756
757 double radius = factor * m_iWaypointRangeRingsNumber *
758 m_fWaypointRangeRingsStep / 60.;
759
760 LLBBox radar_box = m_wpBBox;
761 radar_box.EnLarge(radius * 2);
762 if (vpBBox.IntersectOut(radar_box)) {
763 return;
764 }
765 } else
766 return;
767 }
768 }
769
770 wxPoint r;
771 wxRect hilitebox;
772 unsigned char transparency = 150;
773
774 if (use_cached_screen_coords && m_pos_on_screen)
775 r.x = m_screen_pos.m_x, r.y = m_screen_pos.m_y;
776 else
777 canvas->GetCanvasPointPix(m_lat, m_lon, &r);
778
779 if (r.x == INVALID_COORD) return;
780
781 // Substitute icon?
782 wxBitmap *pbm;
783 if ((m_bIsActive) && (m_IconName != _T("mob")))
784 pbm = pWayPointMan->GetIconBitmap(_T ( "activepoint" ));
785 else
786 pbm = m_pbmIcon;
787
788 // If icon is corrupt, there is really nothing else to do...
789 if (!pbm->IsOk()) return;
790
791 int sx2 = pbm->GetWidth() / 2;
792 int sy2 = pbm->GetHeight() / 2;
793
794 // Calculate the mark drawing extents
795 wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
796
797 wxRect r3 = r1;
798 if (m_bShowName) {
799 if (!m_pMarkFont) {
800 m_pMarkFont = FontMgr::Get().GetFont(_("Marks"));
801 m_FontColor = FontMgr::Get().GetFontColor(_("Marks"));
802 if (m_iTextTexture) {
803 glDeleteTextures(1, &m_iTextTexture);
804 m_iTextTexture = 0;
805 }
806
807 CalculateNameExtents();
808 }
809
810 if (m_pMarkFont) {
811 wxRect r2(r.x + m_NameLocationOffsetX, r.y + m_NameLocationOffsetY,
812 m_NameExtents.x, m_NameExtents.y);
813 r3.Union(r2);
814 }
815 }
816
817 hilitebox = r3;
818 hilitebox.x -= r.x;
819 hilitebox.y -= r.y;
820
821 if (!m_bPreScaled) {
822 hilitebox.x *= g_MarkScaleFactorExp;
823 hilitebox.y *= g_MarkScaleFactorExp;
824 hilitebox.width *= g_MarkScaleFactorExp;
825 hilitebox.height *= g_MarkScaleFactorExp;
826 }
827
828 float radius;
829 if (g_btouch) {
830 hilitebox.Inflate(20);
831 radius = 20.0f;
832 } else {
833 hilitebox.Inflate(4);
834 radius = 4.0f;
835 }
836
837 /* update bounding box */
838 if (!m_wpBBox.GetValid() || vp.view_scale_ppm != m_wpBBox_view_scale_ppm ||
839 vp.rotation != m_wpBBox_rotation) {
840 double lat1, lon1, lat2, lon2;
841 canvas->GetCanvasPixPoint(r.x + hilitebox.x,
842 r.y + hilitebox.y + hilitebox.height, lat1, lon1);
843 canvas->GetCanvasPixPoint(r.x + hilitebox.x + hilitebox.width,
844 r.y + hilitebox.y, lat2, lon2);
845
846 if (lon1 > lon2)
847 m_wpBBox.Set(lat1, lon1, lat2, lon2 + 360);
848 else
849 m_wpBBox.Set(lat1, lon1, lat2, lon2);
850
851 m_wpBBox_view_scale_ppm = vp.view_scale_ppm;
852 m_wpBBox_rotation = vp.rotation;
853 }
854
855 // if(region.Contains(r3) == wxOutRegion)
856 // return;
857
858 // Highlite any selected point
859 if (m_bPtIsSelected) {
860 wxColour hi_colour;
861 if (m_bBlink) {
862 wxPen *pen = g_pRouteMan->GetActiveRoutePointPen();
863 hi_colour = pen->GetColour();
864 } else {
865 hi_colour = GetGlobalColor(_T ( "YELO1" ));
866 }
867
868 AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
869 hilitebox.height, radius, hi_colour, transparency);
870 }
871
872 bool bDrawHL = false;
873
874 if (m_bBlink && (gFrame->nBlinkerTick & 1)) bDrawHL = true;
875
876 if ((!bDrawHL) && (NULL != m_pbmIcon)) {
877 int glw, glh;
878 unsigned int IconTexture = pWayPointMan->GetIconTexture(pbm, glw, glh);
879
880 glBindTexture(GL_TEXTURE_2D, IconTexture);
881
882 glEnable(GL_TEXTURE_2D);
883 glEnable(GL_BLEND);
884
885 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
886 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
887
888 int w = r1.width, h = r1.height;
889
890 float scale = 1.0;
891 if (!m_bPreScaled) {
892 scale = g_MarkScaleFactorExp;
893 }
894
895 float ws = r1.width * scale;
896 float hs = r1.height * scale;
897 float xs = r.x - ws / 2.;
898 float ys = r.y - hs / 2.;
899 float u = (float)w / glw, v = (float)h / glh;
900
901#if defined(USE_ANDROID_GLES2) || defined(ocpnUSE_GLSL)
902 float coords[8];
903 float uv[8];
904 // normal uv
905 uv[0] = 0;
906 uv[1] = 0;
907 uv[2] = u;
908 uv[3] = 0;
909 uv[4] = u;
910 uv[5] = v;
911 uv[6] = 0;
912 uv[7] = v;
913
914 // pixels
915 coords[0] = xs;
916 coords[1] = ys;
917 coords[2] = xs + ws;
918 coords[3] = ys;
919 coords[4] = xs + ws;
920 coords[5] = ys + hs;
921 coords[6] = xs, coords[7] = ys + hs;
922
923 glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
924
925#else
926 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
927
928 glColor3f(1, 1, 1);
929
930 glBegin(GL_QUADS);
931 glTexCoord2f(0, 0);
932 glVertex2f(xs, ys);
933 glTexCoord2f(u, 0);
934 glVertex2f(xs + ws, ys);
935 glTexCoord2f(u, v);
936 glVertex2f(xs + ws, ys + hs);
937 glTexCoord2f(0, v);
938 glVertex2f(xs, ys + hs);
939 glEnd();
940
941#endif
942
943 glDisable(GL_BLEND);
944 glDisable(GL_TEXTURE_2D);
945 }
946
947 if (m_bShowName && m_pMarkFont) {
948 int w = m_NameExtents.x, h = m_NameExtents.y;
949 if (!m_iTextTexture && w && h) {
950#if 0
951 wxBitmap tbm(w, h); /* render text on dc */
952 wxMemoryDC dc;
953 dc.SelectObject(tbm);
954 dc.SetBackground(wxBrush(*wxBLACK));
955 dc.Clear();
956 dc.SetFont(*m_pMarkFont);
957 dc.SetTextForeground(*wxWHITE);
958 dc.DrawText(m_MarkName, 0, 0);
959 dc.SelectObject(wxNullBitmap);
960
961 /* make alpha texture for text */
962 wxImage image = tbm.ConvertToImage();
963 unsigned char *d = image.GetData();
964 unsigned char *e = new unsigned char[w * h];
965 if (d && e) {
966 for (int p = 0; p < w * h; p++) e[p] = d[3 * p + 0];
967 }
968
969 /* create texture for rendered text */
970 glGenTextures(1, &m_iTextTexture);
971 glBindTexture(GL_TEXTURE_2D, m_iTextTexture);
972
973 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
974 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
975
976 m_iTextTextureWidth = NextPow2(w);
977 m_iTextTextureHeight = NextPow2(h);
978 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_iTextTextureWidth,
979 m_iTextTextureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
980 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_ALPHA, GL_UNSIGNED_BYTE,
981 e);
982 delete[] e;
983#else
984 wxScreenDC sdc;
985 sdc.SetFont(*m_pMarkFont);
986 sdc.GetTextExtent(m_MarkName, &w, &h, NULL, NULL, m_pMarkFont);
987
988 /* create bitmap of appropriate size and select it */
989 wxBitmap bmp( w, h );
990 wxMemoryDC temp_dc;
991 temp_dc.SelectObject( bmp );
992
993 /* fill bitmap with black */
994 temp_dc.SetBackground( wxBrush( wxColour( 0, 0, 0 ) ) );
995 temp_dc.Clear();
996
997 /* draw the text white */
998 temp_dc.SetFont( *m_pMarkFont );
999 temp_dc.SetTextForeground( wxColour( 255, 255, 255 ) );
1000 temp_dc.DrawText( m_MarkName, 0, 0 );
1001 temp_dc.SelectObject( wxNullBitmap );
1002
1003 /* use the data in the bitmap for alpha channel,
1004 and set the color to text foreground */
1005 wxImage image = bmp.ConvertToImage();
1006
1007 unsigned char *data = new unsigned char[w * h * 4];
1008 unsigned char *im = image.GetData();
1009
1010
1011 if(im){
1012 unsigned int r = m_FontColor.Red();
1013 unsigned int g = m_FontColor.Green();
1014 unsigned int b = m_FontColor.Blue();
1015 for( int i = 0; i < h; i++ ){
1016 for(int j=0 ; j < w ; j++){
1017 unsigned int index = ((i*w) + j) * 4;
1018 data[index] = r;
1019 data[index+1] = g;
1020 data[index+2] = b;
1021 data[index+3] = im[((i*w) + j) * 3];
1022 }
1023 }
1024 }
1025
1026 glGenTextures(1, &m_iTextTexture);
1027
1028 glBindTexture(GL_TEXTURE_2D, m_iTextTexture);
1029
1030 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
1031 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
1032
1033 m_iTextTextureWidth = NextPow2(w);
1034 m_iTextTextureHeight = NextPow2(h);
1035 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_iTextTextureWidth, m_iTextTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1036 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
1037
1038 glEnable(GL_TEXTURE_2D);
1039 glEnable(GL_BLEND);
1040 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1041
1042#endif
1043 }
1044
1045 if (m_iTextTexture) {
1046 /* draw texture with text */
1047 glBindTexture(GL_TEXTURE_2D, m_iTextTexture);
1048
1049 glEnable(GL_TEXTURE_2D);
1050 glEnable(GL_BLEND);
1051
1052 int x = r.x + m_NameLocationOffsetX, y = r.y + m_NameLocationOffsetY;
1053 float u = (float)w / m_iTextTextureWidth,
1054 v = (float)h / m_iTextTextureHeight;
1055#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1056 glColor3ub(255, 255, 255);
1057
1058 glBegin(GL_QUADS);
1059 glTexCoord2f(0, 0);
1060 glVertex2f(x, y);
1061 glTexCoord2f(u, 0);
1062 glVertex2f(x + w, y);
1063 glTexCoord2f(u, v);
1064 glVertex2f(x + w, y + h);
1065 glTexCoord2f(0, v);
1066 glVertex2f(x, y + h);
1067 glEnd();
1068
1069#else
1070 float coords[8];
1071 float uv[8];
1072 // normal uv
1073 uv[0] = 0;
1074 uv[1] = 0;
1075 uv[2] = u;
1076 uv[3] = 0;
1077 uv[4] = u;
1078 uv[5] = v;
1079 uv[6] = 0;
1080 uv[7] = v;
1081
1082 // pixels
1083 coords[0] = x;
1084 coords[1] = y;
1085 coords[2] = x + w;
1086 coords[3] = y;
1087 coords[4] = x + w;
1088 coords[5] = y + h;
1089 coords[6] = x, coords[7] = y + h;
1090
1091 glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
1092
1093#endif
1094 glDisable(GL_BLEND);
1095 glDisable(GL_TEXTURE_2D);
1096 }
1097 }
1098
1099 // Draw waypoint radar rings if activated
1100 if (m_iWaypointRangeRingsNumber && m_bShowWaypointRangeRings) {
1101 double factor = 1.00;
1102 if (m_iWaypointRangeRingsStepUnits == 1) // nautical miles
1103 factor = 1 / 1.852;
1104
1105 factor *= m_fWaypointRangeRingsStep;
1106
1107 double tlat, tlon;
1108 wxPoint r1;
1109 ll_gc_ll(m_lat, m_lon, 0, factor, &tlat, &tlon);
1110 canvas->GetCanvasPointPix(tlat, tlon, &r1);
1111
1112 double lpp =
1113 sqrt(pow((double)(r.x - r1.x), 2) + pow((double)(r.y - r1.y), 2));
1114 int pix_radius = (int)lpp;
1115
1116 extern wxColor GetDimColor(wxColor c);
1117 wxColor ring_dim_color = GetDimColor(m_wxcWaypointRangeRingsColour);
1118
1119 double platform_pen_width = wxRound(
1120 wxMax(1.0, g_Platform->GetDisplayDPmm() /
1121 2)); // 0.5 mm nominal, but not less than 1 pixel
1122 wxPen ppPen1(ring_dim_color, platform_pen_width);
1123 wxBrush saveBrush = dc.GetBrush();
1124 wxPen savePen = dc.GetPen();
1125 dc.SetPen(ppPen1);
1126 dc.SetBrush(wxBrush(ring_dim_color, wxBRUSHSTYLE_TRANSPARENT));
1127
1128 for (int i = 1; i <= m_iWaypointRangeRingsNumber; i++)
1129 dc.StrokeCircle(r.x, r.y, i * pix_radius);
1130 dc.SetPen(savePen);
1131 dc.SetBrush(saveBrush);
1132 }
1133
1134 // Render Drag handle if enabled
1135 if (m_bDrawDragHandle) {
1136 // A line, southeast, scaled to the size of the icon
1137 double platform_pen_width = wxRound(
1138 wxMax(1.0, g_Platform->GetDisplayDPmm() /
1139 2)); // 0.5 mm nominal, but not less than 1 pixel
1140
1141 wxColor dh_color = GetGlobalColor(_T ( "YELO1" ));
1142 wxPen ppPen1(dh_color, 3 * platform_pen_width);
1143 dc.SetPen(ppPen1);
1144 dc.DrawLine(r.x + hilitebox.width / 4, r.y + hilitebox.height / 4,
1145 r.x + m_drag_line_length_man, r.y + m_drag_line_length_man);
1146
1147 dh_color = wxColor(0, 0, 0);
1148 wxPen ppPen2(dh_color, platform_pen_width);
1149 dc.SetPen(ppPen2);
1150 dc.DrawLine(r.x + hilitebox.width / 4, r.y + hilitebox.height / 4,
1151 r.x + m_drag_line_length_man, r.y + m_drag_line_length_man);
1152
1153 // The drag handle
1154 glBindTexture(GL_TEXTURE_2D, m_dragIconTexture);
1155
1156 glEnable(GL_TEXTURE_2D);
1157 glEnable(GL_BLEND);
1158
1159 int x = r.x + m_drag_icon_offset, y = r.y + m_drag_icon_offset,
1160 w = m_dragIcon.GetWidth(), h = m_dragIcon.GetHeight();
1161
1162 float scale = 1.0;
1163
1164 float ws = w * scale;
1165 float hs = h * scale;
1166 float xs = x - ws / 2.;
1167 float ys = y - hs / 2.;
1168 float u = (float)w / m_dragIconTextureWidth,
1169 v = (float)h / m_dragIconTextureWidth;
1170
1171#if !defined(USE_ANDROID_GLES2) && !defined(ocpnUSE_GLSL)
1172 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1173
1174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1176
1177 glColor3f(1, 1, 1);
1178
1179 glBegin(GL_QUADS);
1180 glTexCoord2f(0, 0);
1181 glVertex2f(xs, ys);
1182 glTexCoord2f(u, 0);
1183 glVertex2f(xs + ws, ys);
1184 glTexCoord2f(u, v);
1185 glVertex2f(xs + ws, ys + hs);
1186 glTexCoord2f(0, v);
1187 glVertex2f(xs, ys + hs);
1188 glEnd();
1189
1190#else
1191 float coords[8];
1192 float uv[8];
1193 // normal uv
1194 uv[0] = 0;
1195 uv[1] = 0;
1196 uv[2] = u;
1197 uv[3] = 0;
1198 uv[4] = u;
1199 uv[5] = v;
1200 uv[6] = 0;
1201 uv[7] = v;
1202
1203 // pixels
1204 coords[0] = xs;
1205 coords[1] = ys;
1206 coords[2] = xs + ws;
1207 coords[3] = ys;
1208 coords[4] = xs + ws;
1209 coords[5] = ys + hs;
1210 coords[6] = xs, coords[7] = ys + hs;
1211
1212 glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
1213
1214#endif
1215 glDisable(GL_BLEND);
1216 glDisable(GL_TEXTURE_2D);
1217 }
1218
1219 if (m_bBlink)
1220 g_blink_rect = CurrentRect_in_DC; // also save for global blinker
1221
1222 // This will be useful for fast icon redraws
1223 CurrentRect_in_DC.x = r.x + hilitebox.x;
1224 CurrentRect_in_DC.y = r.y + hilitebox.y;
1225 CurrentRect_in_DC.width = hilitebox.width;
1226 CurrentRect_in_DC.height = hilitebox.height;
1227
1228 if (m_bBlink)
1229 g_blink_rect = CurrentRect_in_DC; // also save for global blinker
1230}
1231#endif
1232
1233void RoutePoint::SetPosition(double lat, double lon) {
1234 m_lat = lat;
1235 m_lon = lon;
1236}
1237
1238void RoutePoint::CalculateDCRect(wxDC &dc, ChartCanvas *canvas, wxRect *prect) {
1239 dc.ResetBoundingBox();
1240 dc.DestroyClippingRegion();
1241
1242 // Draw the mark on the dc
1243 ocpnDC odc(dc);
1244 Draw(odc, canvas, NULL);
1245
1246 // Retrieve the drawing extents
1247 prect->x = dc.MinX() - 1;
1248 prect->y = dc.MinY() - 1;
1249 prect->width = dc.MaxX() - dc.MinX() + 2; // Mouse Poop?
1250 prect->height = dc.MaxY() - dc.MinY() + 2;
1251}
1252
1253bool RoutePoint::IsSame(RoutePoint *pOtherRP) {
1254 bool IsSame = false;
1255
1256 if (this->m_MarkName == pOtherRP->m_MarkName) {
1257 if (fabs(this->m_lat - pOtherRP->m_lat) < 1.e-6 &&
1258 fabs(this->m_lon - pOtherRP->m_lon) < 1.e-6)
1259 IsSame = true;
1260 }
1261 return IsSame;
1262}
1263
1264bool RoutePoint::SendToGPS(const wxString &com_name, SendToGpsDlg *dialog) {
1265 int result = 0;
1266 if (g_pMUX) result = g_pMUX->SendWaypointToGPS(this, com_name, dialog);
1267
1268 wxString msg;
1269 if (0 == result)
1270 msg = _("Waypoint(s) Transmitted.");
1271 else {
1272 if (result == ERR_GARMIN_INITIALIZE)
1273 msg = _("Error on Waypoint Upload. Garmin GPS not connected");
1274 else
1275 msg = _("Error on Waypoint Upload. Please check logfiles...");
1276 }
1277
1278 OCPNMessageBox(NULL, msg, _("OpenCPN Info"), wxOK | wxICON_INFORMATION);
1279
1280 return (result == 0);
1281}
1282
1283double RoutePoint::GetWaypointArrivalRadius() {
1284 if ((m_WaypointArrivalRadius >= 0) && (m_WaypointArrivalRadius < 0.001)) {
1285 SetWaypointArrivalRadius(g_n_arrival_circle_radius);
1286 return m_WaypointArrivalRadius;
1287 } else
1288 return m_WaypointArrivalRadius;
1289}
1290
1291int RoutePoint::GetWaypointRangeRingsNumber() {
1292 if (m_iWaypointRangeRingsNumber == -1)
1293 return g_iWaypointRangeRingsNumber;
1294 else
1295 return m_iWaypointRangeRingsNumber;
1296}
1297
1298float RoutePoint::GetWaypointRangeRingsStep() {
1299 if (m_fWaypointRangeRingsStep == -1)
1300 return g_fWaypointRangeRingsStep;
1301 else
1302 return m_fWaypointRangeRingsStep;
1303}
1304
1305int RoutePoint::GetWaypointRangeRingsStepUnits() {
1306 if (m_iWaypointRangeRingsStepUnits == -1)
1307 return g_iWaypointRangeRingsStepUnits;
1308 else
1309 return m_iWaypointRangeRingsStepUnits;
1310}
1311
1312wxColour RoutePoint::GetWaypointRangeRingsColour(void) {
1313 if (m_wxcWaypointRangeRingsColour.GetAsString(wxC2S_HTML_SYNTAX) ==
1314 _T("#FFFFFF"))
1315 return g_colourWaypointRangeRingsColour;
1316 else
1317 return m_wxcWaypointRangeRingsColour;
1318}
1319
1320void RoutePoint::SetScaMin(long val) {
1321 if (val < SCAMIN_MIN)
1322 val = SCAMIN_MIN; // prevent from waypoints hiding always with a nonlogic
1323 // value
1324 if (val < (long)m_ScaMax * 5) val = (long)m_ScaMax * 5;
1325 m_ScaMin = val;
1326}
1327void RoutePoint::SetScaMin(wxString str) {
1328 long val;
1329 if (!str.ToLong(&val)) val = MAX_INT_VAL;
1330 SetScaMin(val);
1331}
1332
1333void RoutePoint::SetScaMax(long val) {
1334 if (val > (int)m_ScaMin / 5)
1335 m_ScaMax = (int)m_ScaMin /
1336 5; // prevent from waypoints hiding always with a nonlogic value
1337}
1338void RoutePoint::SetScaMax(wxString str) {
1339 long val;
1340 if (!str.ToLong(&val)) val = 0;
1341 SetScaMax(val);
1342}
1343
1344void RoutePoint::ShowScaleWarningMessage(ChartCanvas *canvas) {
1345 wxString strA = _("The ScaMin value for new waypoints is set to");
1346 wxString strB = _("but current chartscale is");
1347 wxString strC =
1348 _("Therefore the new waypoint will not be visible at this zoom level.");
1349 wxString MessStr =
1350 wxString::Format(_T("%s %li,\n %s %.0f.\n%s"), strA, GetScaMin(), strB,
1351 canvas->GetScaleValue(), strC);
1352 OCPNMessageBox(canvas, MessStr);
1353}
1354
1355void RoutePoint::SetPlannedSpeed(double spd) {
1356 if (spd >= 0.0 && spd <= 1000.0) m_PlannedSpeed = spd;
1357}
1358
1359double RoutePoint::GetPlannedSpeed() {
1360 if (m_PlannedSpeed < 0.0001 &&
1361 m_MarkDescription.Find(_T("VMG=")) != wxNOT_FOUND) {
1362 // In case there was speed encoded in the name of the waypoint, do the
1363 // conversion here.
1364 wxString s_vmg =
1365 (m_MarkDescription.Mid(m_MarkDescription.Find(_T("VMG=")) + 4))
1366 .BeforeFirst(';');
1367 double vmg;
1368 if (!s_vmg.ToDouble(&vmg)) {
1369 m_MarkDescription.Replace(_T("VMG=") + s_vmg + ";", wxEmptyString);
1370 SetPlannedSpeed(vmg);
1371 }
1372 }
1373 return m_PlannedSpeed;
1374}
1375
1376wxDateTime RoutePoint::GetETD() {
1377 if (m_seg_etd.IsValid()) {
1378 if (!GetETA().IsValid() || m_seg_etd > GetETA()) {
1379 return m_seg_etd;
1380 } else {
1381 return GetETA();
1382 }
1383 } else {
1384 if (m_MarkDescription.Find(_T("ETD=")) != wxNOT_FOUND) {
1385 wxDateTime etd = wxInvalidDateTime;
1386 wxString s_etd =
1387 (m_MarkDescription.Mid(m_MarkDescription.Find(_T("ETD=")) + 4))
1388 .BeforeFirst(';');
1389 const wxChar *parse_return = etd.ParseDateTime(s_etd);
1390 if (parse_return) {
1391 wxString tz(parse_return);
1392
1393 if (tz.Find(_T("UT")) != wxNOT_FOUND) {
1394 m_seg_etd = etd;
1395 } else {
1396 if (tz.Find(_T("LMT")) != wxNOT_FOUND) {
1397 m_seg_etd = etd;
1398 long lmt_offset = (long)((m_lon * 3600.) / 15.);
1399 wxTimeSpan lmt(0, 0, (int)lmt_offset, 0);
1400 m_seg_etd -= lmt;
1401 } else {
1402 m_seg_etd = etd.ToUTC();
1403 }
1404 }
1405 if (etd.IsValid() && (!GetETA().IsValid() || etd > GetETA())) {
1406 m_MarkDescription.Replace(s_etd, wxEmptyString);
1407 m_seg_etd = etd;
1408 return m_seg_etd;
1409 } else {
1410 return GetETA();
1411 }
1412 }
1413 }
1414 }
1415 return wxInvalidDateTime;
1416}
1417
1418wxDateTime RoutePoint::GetManualETD() {
1419 if (m_manual_etd && m_seg_etd.IsValid()) {
1420 return m_seg_etd;
1421 }
1422 return wxInvalidDateTime;
1423}
1424
1425wxDateTime RoutePoint::GetETA() {
1426 if (m_seg_eta.IsValid()) {
1427 return m_seg_eta;
1428 }
1429 return wxInvalidDateTime;
1430}
1431
1432wxString RoutePoint::GetETE() {
1433 if (m_seg_ete != 0) {
1434 return formatTimeDelta(m_seg_ete);
1435 }
1436 return wxEmptyString;
1437}
1438
1439void RoutePoint::SetETE(wxLongLong secs) { m_seg_ete = secs; }
1440
1441void RoutePoint::SetETD(const wxDateTime &etd) {
1442 m_seg_etd = etd;
1443 m_manual_etd = TRUE;
1444}
1445
1446bool RoutePoint::SetETD(const wxString &ts) {
1447 if (ts.IsEmpty()) {
1448 m_seg_etd = wxInvalidDateTime;
1449 m_manual_etd = false;
1450 return true;
1451 }
1452 wxDateTime tmp;
1453 wxString::const_iterator end;
1454 if (tmp.ParseISOCombined(ts)) {
1455 SetETD(tmp);
1456 return TRUE;
1457 } else if (tmp.ParseDateTime(ts, &end)) {
1458 SetETD(tmp);
1459 return TRUE;
1460 }
1461 return FALSE;
1462}
Definition: route.h:70
Route "Send to GPS..." Dialog Definition.
Definition: SendToGpsDlg.h:56
Definition: ocpndc.h:55
Definition: Quilt.cpp:864