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