OpenCPN Partial API docs
route_point_gui.cpp
1 #if defined(__ANDROID__)
2 #include <qopengl.h>
3 #include <GL/gl_private.h> // this is a cut-down version of gl.h
4 #include <GLES2/gl2.h>
5 
6 #elif defined(ocpnUSE_GL)
7 
8 #if defined(__MSVC__)
9 #include "glew.h"
10 #include <GL/glu.h>
11 
12 #elif defined(__WXOSX__)
13 #include <OpenGL/gl.h>
14 #include <OpenGL/glu.h>
15 typedef void (* _GLUfuncptr)();
16 #define GL_COMPRESSED_RGB_FXT1_3DFX 0x86B0
17 
18 #elif defined(__WXQT__) || defined(__WXGTK__)
19 #include <GL/glew.h>
20 #include <GL/glu.h>
21 #endif // ocpnUSE_GL
22 #endif
23 
24 
25 #include <wx/colour.h>
26 #include <wx/gdicmn.h>
27 #include <wx/pen.h>
28 #include <wx/brush.h>
29 
30 #include "model/comm_n0183_output.h"
31 #include "model/georef.h"
32 #include "model/multiplexer.h"
33 #include "model/own_ship.h"
34 #include "model/route.h"
35 #include "model/routeman.h"
36 
37 #include "color_handler.h"
38 #include "FontMgr.h"
39 #include "glChartCanvas.h"
40 #include "n0183_ctx_factory.h"
41 #include "navutil.h"
42 #include "ocpn_frame.h"
43 #include "OCPNPlatform.h"
44 #include "ocpn_plugin.h"
45 #include "route_point_gui.h"
46 #include "styles.h"
47 #include "svg_utils.h"
48 #include "viewport.h"
49 #include "waypointman_gui.h"
50 
51 
52 extern Multiplexer* g_pMUX;
53 extern ocpnGLOptions g_GLOptions;
54 extern float g_MarkScaleFactorExp;
55 extern MyFrame* gFrame;
56 extern OCPNPlatform* g_Platform;
57 extern ocpnStyle::StyleManager* g_StyleManager;
58 
59 extern Routeman* g_pRouteMan;
60 
61 void RoutePointGui::Draw(ocpnDC& dc, ChartCanvas* canvas, wxPoint* rpn,
62  bool boverride_viz) {
63  wxPoint r;
64  wxRect hilitebox;
65 
66  canvas->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
67 
68  // return the home point in this dc to allow "connect the dots"
69  if (NULL != rpn) *rpn = r;
70 
71  if (!RoutePointGui(m_point).IsVisibleSelectable(canvas, boverride_viz)) return;
72 
73  // If waypoint is well off screen, skip the drawing
74  if( (abs(r.x) > canvas->GetCanvasWidth() * 4 ) ||
75  (abs(r.y) > canvas->GetCanvasHeight() * 4))
76  return;
77 
78  // If waypoint pixel location is invalid, skip the drawing
79  if ((abs(r.x) == INVALID_COORD ) ||
80  (abs(r.y) == INVALID_COORD) )
81  return;
82 
83 
84 
85  // Optimization, especially apparent on tracks in normal cases
86  if (m_point.m_IconName == _T("empty") && !m_point.m_bShowName
87  && !m_point.m_bPtIsSelected){
88  return;
89  }
90 
91  wxPen *pen;
92  if (m_point.m_bBlink)
93  pen = g_pRouteMan->GetActiveRoutePointPen();
94  else
95  pen = g_pRouteMan->GetRoutePointPen();
96 
97  // Substitue icon?
98  if (m_point.m_IconIsDirty) ReLoadIcon();
99  wxBitmap *pbm;
100  if ((m_point.m_bIsActive) && (m_point.m_IconName != _T("mob")))
101  pbm = pWayPointMan->GetIconBitmap(_T ( "activepoint" ));
102  else
103  pbm = m_point.m_pbmIcon;
104 
105  wxBitmap *pbms = NULL;
106  if ((g_MarkScaleFactorExp > 1.0) && !m_point.m_bPreScaled) {
107  if (m_point.m_IconScaleFactor != g_MarkScaleFactorExp) {
108  wxImage scaled_image = pbm->ConvertToImage();
109  int new_width = pbm->GetWidth() * g_MarkScaleFactorExp;
110  int new_height = pbm->GetHeight() * g_MarkScaleFactorExp;
111  m_point.m_ScaledBMP = wxBitmap(
112  scaled_image.Scale(new_width, new_height, wxIMAGE_QUALITY_HIGH));
113 
114  m_point.m_IconScaleFactor = g_MarkScaleFactorExp;
115  }
116  if (m_point.m_ScaledBMP.IsOk()) pbm = &m_point.m_ScaledBMP;
117  }
118 
119  int sx2 = pbm->GetWidth() / 2;
120  int sy2 = pbm->GetHeight() / 2;
121 
122  // Calculate the mark drawing extents
123  wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
124 
125  if (m_point.m_bShowName) {
126  if (0 == m_point.m_pMarkFont) {
127  wxFont *dFont = FontMgr::Get().GetFont(_("Marks"));
128  int font_size = wxMax(8, dFont->GetPointSize());
129  font_size /= OCPN_GetWinDIPScaleFactor();
130 
131  m_point.m_pMarkFont = FontMgr::Get().FindOrCreateFont(
132  font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
133  false, dFont->GetFaceName());
134 
135  m_point.m_FontColor = FontMgr::Get().GetFontColor(_("Marks"));
136  m_point.CalculateNameExtents();
137  }
138 
139  if (m_point.m_pMarkFont) {
140  wxRect r2(r.x + m_point.m_NameLocationOffsetX, r.y + m_point.m_NameLocationOffsetY,
141  m_point.m_NameExtents.x, m_point.m_NameExtents.y);
142  r1.Union(r2);
143  }
144  }
145 
146  hilitebox = r1;
147  hilitebox.x -= r.x;
148  hilitebox.y -= r.y;
149  float radius;
150  if (g_btouch) {
151  hilitebox.Inflate(20);
152  radius = 20.0f;
153  } else {
154  hilitebox.Inflate(4);
155  radius = 4.0f;
156  }
157 
158  wxColour hi_colour = pen->GetColour();
159  unsigned char transparency = 100;
160  if (m_point.m_bRPIsBeingEdited) {
161  hi_colour = GetGlobalColor(_T ( "YELO1" ));
162  transparency = 150;
163  }
164 
165  // Highlite any selected point
166  if (m_point.m_bPtIsSelected || m_point.m_bRPIsBeingEdited) {
167  AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
168  hilitebox.height, radius, hi_colour, transparency);
169  }
170 
171  bool bDrawHL = false;
172 
173  if (m_point.m_bBlink && (gFrame->nBlinkerTick & 1)) bDrawHL = true;
174 
175  if ((!bDrawHL) && (NULL != m_point.m_pbmIcon)) {
176  dc.DrawBitmap(*pbm, r.x - sx2, r.y - sy2, true);
177  // on MSW, the dc Bounding box is not updated on DrawBitmap() method.
178  // Do it explicitely here for all platforms.
179  dc.CalcBoundingBox(r.x - sx2, r.y - sy2);
180  dc.CalcBoundingBox(r.x + sx2, r.y + sy2);
181  }
182 
183  if (m_point.m_bShowName && m_point.m_MarkName.Length()) {
184  if (m_point.m_pMarkFont) {
185  dc.SetFont(*m_point.m_pMarkFont);
186  dc.SetTextForeground(m_point.m_FontColor);
187 
188  dc.DrawText(m_point.m_MarkName, r.x + m_point.m_NameLocationOffsetX,
189  r.y + m_point.m_NameLocationOffsetY);
190  }
191  }
192 
193  // Draw waypoint radar rings if activated
194  if (m_point.m_iWaypointRangeRingsNumber && m_point.m_bShowWaypointRangeRings) {
195  double factor = 1.00;
196  if (m_point.m_iWaypointRangeRingsStepUnits == 1) // nautical miles
197  factor = 1 / 1.852;
198 
199  factor *= m_point.m_fWaypointRangeRingsStep;
200 
201  double tlat, tlon;
202  wxPoint r1;
203  ll_gc_ll(m_point.m_lat, m_point.m_lon, 0, factor, &tlat, &tlon);
204  canvas->GetCanvasPointPix(tlat, tlon, &r1);
205 
206  double lpp =
207  sqrt(pow((double)(r.x - r1.x), 2) + pow((double)(r.y - r1.y), 2));
208  int pix_radius = (int)lpp;
209 
210  wxPen ppPen1(m_point.m_wxcWaypointRangeRingsColour, 2);
211  wxBrush saveBrush = dc.GetBrush();
212  wxPen savePen = dc.GetPen();
213  dc.SetPen(ppPen1);
214  dc.SetBrush(
215  wxBrush(m_point.m_wxcWaypointRangeRingsColour, wxBRUSHSTYLE_TRANSPARENT));
216 
217  for (int i = 1; i <= m_point.m_iWaypointRangeRingsNumber; i++)
218  dc.StrokeCircle(r.x, r.y, i * pix_radius);
219  dc.SetPen(savePen);
220  dc.SetBrush(saveBrush);
221  }
222 
223  // Save the current draw rectangle in the current DC
224  // This will be useful for fast icon redraws
225  m_point.CurrentRect_in_DC.x = r.x + hilitebox.x;
226  m_point.CurrentRect_in_DC.y = r.y + hilitebox.y;
227  m_point.CurrentRect_in_DC.width = hilitebox.width;
228  m_point.CurrentRect_in_DC.height = hilitebox.height;
229 
230  if (m_point.m_bBlink)
231  g_blink_rect = m_point.CurrentRect_in_DC; // also save for global blinker
232 
233  delete pbms; // the potentially scaled bitmap
234 }
235 
236 #ifdef ocpnUSE_GL
237 void RoutePointGui::DrawGL(ViewPort &vp, ChartCanvas *canvas, ocpnDC &dc,
238  bool use_cached_screen_coords, bool bVizOverride) {
239  if (!RoutePointGui(m_point).IsVisibleSelectable(canvas, bVizOverride)) return;
240 
241  // Optimization, especially apparent on tracks in normal cases
242  if (m_point.m_IconName == _T("empty") && !m_point.m_bShowName && !m_point.m_bPtIsSelected) return;
243 
244  if (m_point.m_wpBBox.GetValid() && vp.view_scale_ppm == m_point.m_wpBBox_view_scale_ppm &&
245  vp.rotation == m_point.m_wpBBox_rotation) {
246  /* see if this waypoint can intersect with bounding box */
247  LLBBox vpBBox = vp.GetBBox();
248  if (vpBBox.IntersectOut(m_point.m_wpBBox)) {
249  // Are Range Rings enabled?
250  if (m_point.m_bShowWaypointRangeRings && (m_point.m_iWaypointRangeRingsNumber > 0)) {
251  double factor = 1.00;
252  if (m_point.m_iWaypointRangeRingsStepUnits == 1) // convert kilometers to NMi
253  factor = 1 / 1.852;
254 
255  double radius = factor * m_point.m_iWaypointRangeRingsNumber *
256  m_point.m_fWaypointRangeRingsStep / 60.;
257 
258  LLBBox radar_box = m_point.m_wpBBox;
259  radar_box.EnLarge(radius * 2);
260  if (vpBBox.IntersectOut(radar_box)) {
261  return;
262  }
263  } else
264  return;
265  }
266  }
267 
268  wxPoint r;
269  wxRect hilitebox;
270  unsigned char transparency = 150;
271 
272  if (use_cached_screen_coords && m_point.m_pos_on_screen)
273  r.x = m_point.m_screen_pos.m_x, r.y = m_point.m_screen_pos.m_y;
274  else
275  canvas->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
276 
277  if (r.x == INVALID_COORD) return;
278 
279  // Substitute icon?
280  if (m_point.m_IconIsDirty) ReLoadIcon();
281  wxBitmap *pbm;
282  if ((m_point.m_bIsActive) && (m_point.m_IconName != _T("mob")))
283  pbm = pWayPointMan->GetIconBitmap(_T ( "activepoint" ));
284  else
285  pbm = m_point.m_pbmIcon;
286 
287  // If icon is corrupt, there is really nothing else to do...
288  if (!pbm || !pbm->IsOk()) return;
289 
290  int sx2 = pbm->GetWidth() / 2;
291  int sy2 = pbm->GetHeight() / 2;
292 
293  // Calculate the mark drawing extents
294  wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
295 
296  wxRect r3 = r1;
297  if (m_point.m_bShowName) {
298  if (!m_point.m_pMarkFont) {
299  wxFont *dFont = FontMgr::Get().GetFont(_("Marks"));
300  int font_size = wxMax(8, dFont->GetPointSize());
301  font_size /= OCPN_GetWinDIPScaleFactor();
302 
303  m_point.m_pMarkFont = FontMgr::Get().FindOrCreateFont(
304  font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
305  false, dFont->GetFaceName());
306 
307  m_point.m_FontColor = FontMgr::Get().GetFontColor(_("Marks"));
308  if (m_point.m_iTextTexture) {
309  glDeleteTextures(1, &m_point.m_iTextTexture);
310  m_point.m_iTextTexture = 0;
311  }
312 
313  m_point.CalculateNameExtents();
314  }
315 
316  if (m_point.m_pMarkFont) {
317  wxRect r2(r.x + m_point.m_NameLocationOffsetX, r.y + m_point.m_NameLocationOffsetY,
318  m_point.m_NameExtents.x, m_point.m_NameExtents.y);
319  r3.Union(r2);
320  }
321  }
322 
323  hilitebox = r3;
324  hilitebox.x -= r.x;
325  hilitebox.y -= r.y;
326 
327  if (!m_point.m_bPreScaled) {
328  hilitebox.x *= g_MarkScaleFactorExp;
329  hilitebox.y *= g_MarkScaleFactorExp;
330  hilitebox.width *= g_MarkScaleFactorExp;
331  hilitebox.height *= g_MarkScaleFactorExp;
332  }
333 
334  float radius;
335  if (g_btouch) {
336  hilitebox.Inflate(20);
337  radius = 20.0f;
338  } else {
339  hilitebox.Inflate(4);
340  radius = 4.0f;
341  }
342 
343  /* update bounding box */
344  if (!m_point.m_wpBBox.GetValid() || vp.view_scale_ppm != m_point.m_wpBBox_view_scale_ppm ||
345  vp.rotation != m_point.m_wpBBox_rotation) {
346  double lat1, lon1, lat2, lon2;
347  canvas->GetCanvasPixPoint(r.x + hilitebox.x,
348  r.y + hilitebox.y + hilitebox.height, lat1, lon1);
349  canvas->GetCanvasPixPoint(r.x + hilitebox.x + hilitebox.width,
350  r.y + hilitebox.y, lat2, lon2);
351 
352  if (lon1 > lon2)
353  m_point.m_wpBBox.Set(lat1, lon1, lat2, lon2 + 360);
354  else
355  m_point.m_wpBBox.Set(lat1, lon1, lat2, lon2);
356 
357  m_point.m_wpBBox_view_scale_ppm = vp.view_scale_ppm;
358  m_point.m_wpBBox_rotation = vp.rotation;
359  }
360 
361  // if(region.Contains(r3) == wxOutRegion)
362  // return;
363 
364  //ocpnDC dc;
365 
366  // Highlite any selected point
367  if (m_point.m_bPtIsSelected) {
368  wxColour hi_colour;
369  if (m_point.m_bBlink) {
370  wxPen *pen = g_pRouteMan->GetActiveRoutePointPen();
371  hi_colour = pen->GetColour();
372  } else {
373  hi_colour = GetGlobalColor(_T ( "YELO1" ));
374  }
375 
376  AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
377  hilitebox.height, radius, hi_colour, transparency);
378  }
379 
380  bool bDrawHL = false;
381 
382  if (m_point.m_bBlink && (gFrame->nBlinkerTick & 1)) bDrawHL = true;
383 
384  if ((!bDrawHL) && (NULL != m_point.m_pbmIcon)) {
385  int glw, glh;
386  unsigned int IconTexture =
387  WayPointmanGui(*pWayPointMan).GetIconTexture(pbm, glw, glh);
388 
389  glBindTexture(GL_TEXTURE_2D, IconTexture);
390 
391  glEnable(GL_TEXTURE_2D);
392  glEnable(GL_BLEND);
393 
394  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
395  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
396 
397  int w = r1.width, h = r1.height;
398 
399  float scale = 1.0;
400  if (!m_point.m_bPreScaled) {
401  scale = g_MarkScaleFactorExp;
402  }
403 
404  // Scale for MacOS Retina and GTK screen scaling
405  scale *= GetOCPNCanvasWindow()->GetContentScaleFactor();
406 
407  float ws = r1.width * scale;
408  float hs = r1.height * scale;
409  float xs = r.x - ws / 2.;
410  float ys = r.y - hs / 2.;
411  float u = (float)w / glw, v = (float)h / glh;
412 
413  float coords[8];
414  float uv[8];
415  // normal uv
416  uv[0] = 0;
417  uv[1] = 0;
418  uv[2] = u;
419  uv[3] = 0;
420  uv[4] = u;
421  uv[5] = v;
422  uv[6] = 0;
423  uv[7] = v;
424 
425  // pixels
426  coords[0] = xs;
427  coords[1] = ys;
428  coords[2] = xs + ws;
429  coords[3] = ys;
430  coords[4] = xs + ws;
431  coords[5] = ys + hs;
432  coords[6] = xs, coords[7] = ys + hs;
433 
434  glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
435 
436  glDisable(GL_BLEND);
437  glDisable(GL_TEXTURE_2D);
438  }
439 
440  if (m_point.m_bShowName && m_point.m_pMarkFont) {
441  int w = m_point.m_NameExtents.x, h = m_point.m_NameExtents.y;
442  if (!m_point.m_iTextTexture && w && h) {
443 #if 0
444  wxBitmap tbm(w, h); /* render text on dc */
445  wxMemoryDC dc;
446  dc.SelectObject(tbm);
447  dc.SetBackground(wxBrush(*wxBLACK));
448  dc.Clear();
449  dc.SetFont(*m_pMarkFont);
450  dc.SetTextForeground(*wxWHITE);
451  dc.DrawText(m_MarkName, 0, 0);
452  dc.SelectObject(wxNullBitmap);
453 
454  /* make alpha texture for text */
455  wxImage image = tbm.ConvertToImage();
456  unsigned char *d = image.GetData();
457  unsigned char *e = new unsigned char[w * h];
458  if (d && e) {
459  for (int p = 0; p < w * h; p++) e[p] = d[3 * p + 0];
460  }
461 
462  /* create texture for rendered text */
463  glGenTextures(1, &m_iTextTexture);
464  glBindTexture(GL_TEXTURE_2D, m_iTextTexture);
465 
466  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
467  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
468 
469  m_iTextTextureWidth = NextPow2(w);
470  m_iTextTextureHeight = NextPow2(h);
471  glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_iTextTextureWidth,
472  m_iTextTextureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
473  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_ALPHA, GL_UNSIGNED_BYTE,
474  e);
475  delete[] e;
476 #else
477  wxScreenDC sdc;
478  sdc.SetFont(*m_point.m_pMarkFont);
479 
480  /* create bitmap of appropriate size and select it */
481  wxBitmap bmp(w, h);
482  wxMemoryDC temp_dc;
483  temp_dc.SelectObject(bmp);
484 
485  /* fill bitmap with black */
486  temp_dc.SetBackground(wxBrush(wxColour(0, 0, 0)));
487  temp_dc.Clear();
488 
489  /* draw the text white */
490  temp_dc.SetFont(*m_point.m_pMarkFont);
491  temp_dc.SetTextForeground(wxColour(255, 255, 255));
492  temp_dc.DrawText(m_point.m_MarkName, 0, 0);
493  temp_dc.SelectObject(wxNullBitmap);
494 
495  /* use the data in the bitmap for alpha channel,
496  and set the color to text foreground */
497  wxImage image = bmp.ConvertToImage();
498 
499  unsigned char *data = new unsigned char[w * h * 4];
500  unsigned char *im = image.GetData();
501 
502  if (im) {
503  unsigned int r = m_point.m_FontColor.Red();
504  unsigned int g = m_point.m_FontColor.Green();
505  unsigned int b = m_point.m_FontColor.Blue();
506  for (int i = 0; i < h; i++) {
507  for (int j = 0; j < w; j++) {
508  unsigned int index = ((i * w) + j) * 4;
509  data[index] = r;
510  data[index + 1] = g;
511  data[index + 2] = b;
512  data[index + 3] = im[((i * w) + j) * 3];
513  }
514  }
515  }
516 
517  glGenTextures(1, &m_point.m_iTextTexture);
518 
519  glBindTexture(GL_TEXTURE_2D, m_point.m_iTextTexture);
520 
521  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
522  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
523 
524  m_point.m_iTextTextureWidth = NextPow2(w);
525  m_point.m_iTextTextureHeight = NextPow2(h);
526  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_point.m_iTextTextureWidth,
527  m_point.m_iTextTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
528  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
529  data);
530 
531  delete[] data;
532 
533  glEnable(GL_TEXTURE_2D);
534  glEnable(GL_BLEND);
535  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
536 
537 #endif
538  }
539 
540  if (m_point.m_iTextTexture) {
541  /* draw texture with text */
542  glBindTexture(GL_TEXTURE_2D, m_point.m_iTextTexture);
543 
544  glEnable(GL_TEXTURE_2D);
545  glEnable(GL_BLEND);
546 
547  int x = r.x + m_point.m_NameLocationOffsetX, y = r.y + m_point.m_NameLocationOffsetY;
548  float u = (float)w / m_point.m_iTextTextureWidth,
549  v = (float)h / m_point.m_iTextTextureHeight;
550  float coords[8];
551  float uv[8];
552  // normal uv
553  uv[0] = 0;
554  uv[1] = 0;
555  uv[2] = u;
556  uv[3] = 0;
557  uv[4] = u;
558  uv[5] = v;
559  uv[6] = 0;
560  uv[7] = v;
561 
562  // pixels
563  coords[0] = x;
564  coords[1] = y;
565  coords[2] = x + w;
566  coords[3] = y;
567  coords[4] = x + w;
568  coords[5] = y + h;
569  coords[6] = x, coords[7] = y + h;
570 
571  glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
572 
573  glDisable(GL_BLEND);
574  glDisable(GL_TEXTURE_2D);
575  }
576  }
577 
578  // Draw waypoint radar rings if activated
579  if (m_point.m_iWaypointRangeRingsNumber && m_point.m_bShowWaypointRangeRings) {
580  double factor = 1.00;
581  if (m_point.m_iWaypointRangeRingsStepUnits == 1) // nautical miles
582  factor = 1 / 1.852;
583 
584  factor *= m_point.m_fWaypointRangeRingsStep;
585 
586  double tlat, tlon;
587  wxPoint r1;
588  ll_gc_ll(m_point.m_lat, m_point.m_lon, 0, factor, &tlat, &tlon);
589  canvas->GetCanvasPointPix(tlat, tlon, &r1);
590 
591  double lpp =
592  sqrt(pow((double)(r.x - r1.x), 2) + pow((double)(r.y - r1.y), 2));
593  int pix_radius = (int)lpp;
594 
595  extern wxColor GetDimColor(wxColor c);
596  wxColor ring_dim_color = GetDimColor(m_point.m_wxcWaypointRangeRingsColour);
597 
598  // 0.5 mm nominal, but not less than 1 pixel
599  double platform_pen_width = wxRound(
600  wxMax(1.0, g_Platform->GetDisplayDPmm() / 2));
601  wxPen ppPen1(ring_dim_color, platform_pen_width);
602  wxBrush saveBrush = dc.GetBrush();
603  wxPen savePen = dc.GetPen();
604  dc.SetPen(ppPen1);
605  dc.SetBrush(wxBrush(ring_dim_color, wxBRUSHSTYLE_TRANSPARENT));
606 
607  for (int i = 1; i <= m_point.m_iWaypointRangeRingsNumber; i++)
608  dc.StrokeCircle(r.x, r.y, i * pix_radius);
609  dc.SetPen(savePen);
610  dc.SetBrush(saveBrush);
611  }
612 
613  // Render Drag handle if enabled
614  if (m_point.m_bDrawDragHandle) {
615  // A line, southeast, scaled to the size of the icon
616  double platform_pen_width = wxRound(
617  wxMax(1.0, g_Platform->GetDisplayDPmm() /
618  2)); // 0.5 mm nominal, but not less than 1 pixel
619 
620  wxColor dh_color = GetGlobalColor(_T ( "YELO1" ));
621  wxPen ppPen1(dh_color, 3 * platform_pen_width);
622  dc.SetPen(ppPen1);
623  dc.DrawLine(r.x + hilitebox.width / 4, r.y + hilitebox.height / 4,
624  r.x + m_point.m_drag_line_length_man, r.y + m_point.m_drag_line_length_man);
625 
626  dh_color = wxColor(0, 0, 0);
627  wxPen ppPen2(dh_color, platform_pen_width);
628  dc.SetPen(ppPen2);
629  dc.DrawLine(r.x + hilitebox.width / 4, r.y + hilitebox.height / 4,
630  r.x + m_point.m_drag_line_length_man, r.y + m_point.m_drag_line_length_man);
631 
632  // The drag handle
633  glBindTexture(GL_TEXTURE_2D, m_point.m_dragIconTexture);
634 
635  glEnable(GL_TEXTURE_2D);
636  glEnable(GL_BLEND);
637 
638  int x = r.x + m_point.m_drag_icon_offset, y = r.y + m_point.m_drag_icon_offset,
639  w = m_point.m_dragIcon.GetWidth(), h = m_point.m_dragIcon.GetHeight();
640 
641  float scale = 1.0;
642 
643  float ws = w * scale;
644  float hs = h * scale;
645  float xs = x - ws / 2.;
646  float ys = y - hs / 2.;
647  float u = (float)w / m_point.m_dragIconTextureWidth,
648  v = (float)h / m_point.m_dragIconTextureWidth;
649 
650  float coords[8];
651  float uv[8];
652  // normal uv
653  uv[0] = 0;
654  uv[1] = 0;
655  uv[2] = u;
656  uv[3] = 0;
657  uv[4] = u;
658  uv[5] = v;
659  uv[6] = 0;
660  uv[7] = v;
661 
662  // pixels
663  coords[0] = xs;
664  coords[1] = ys;
665  coords[2] = xs + ws;
666  coords[3] = ys;
667  coords[4] = xs + ws;
668  coords[5] = ys + hs;
669  coords[6] = xs, coords[7] = ys + hs;
670 
671  glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
672 
673  glDisable(GL_BLEND);
674  glDisable(GL_TEXTURE_2D);
675  }
676 
677  if (m_point.m_bBlink)
678  g_blink_rect =m_point. CurrentRect_in_DC; // also save for global blinker
679 
680  // This will be useful for fast icon redraws
681  m_point.CurrentRect_in_DC.x = r.x + hilitebox.x;
682  m_point.CurrentRect_in_DC.y = r.y + hilitebox.y;
683  m_point.CurrentRect_in_DC.width = hilitebox.width;
684  m_point.CurrentRect_in_DC.height = hilitebox.height;
685 
686  if (m_point.m_bBlink)
687  g_blink_rect = m_point.CurrentRect_in_DC; // also save for global blinker
688 }
689 #endif
690 
691 void RoutePointGui::CalculateDCRect(wxDC &dc, ChartCanvas *canvas, wxRect *prect) {
692  if (canvas) {
693  dc.ResetBoundingBox();
694  dc.DestroyClippingRegion();
695 
696  // Draw the mark on the dc
697  ocpnDC odc(dc);
698  odc.SetVP(canvas->GetVP());
699 
700  Draw(odc, canvas, NULL);
701 
702  // Retrieve the drawing extents
703  prect->x = dc.MinX() - 1;
704  prect->y = dc.MinY() - 1;
705  prect->width = dc.MaxX() - dc.MinX() + 2; // Mouse Poop?
706  prect->height = dc.MaxY() - dc.MinY() + 2;
707  }
708 }
709 
710 bool RoutePointGui::IsVisibleSelectable(ChartCanvas* cc, bool boverrideViz) {
711  return m_point.IsVisibleSelectable(cc->GetScaleValue(), boverrideViz);
712 }
713 
714 wxPoint2DDouble RoutePointGui::GetDragHandlePoint(ChartCanvas *canvas) {
715  if (!m_point.m_bDrawDragHandle)
716  return wxPoint2DDouble(m_point.m_lon, m_point.m_lat);
717  else {
718  return computeDragHandlePoint(canvas);
719  }
720 }
721 void RoutePointGui::SetPointFromDraghandlePoint(ChartCanvas *canvas, double lat,
722  double lon) {
723  wxPoint r;
724  canvas->GetCanvasPointPix(lat, lon, &r);
725  double tlat, tlon;
726  canvas->GetCanvasPixPoint(r.x - m_point.m_drag_icon_offset, r.y - m_point.m_drag_icon_offset,
727  tlat, tlon);
728  m_point.m_lat = tlat;
729  m_point.m_lon = tlon;
730 }
731 
732 void RoutePointGui::SetPointFromDraghandlePoint(ChartCanvas *canvas, int x,
733  int y) {
734  double tlat, tlon;
735  canvas->GetCanvasPixPoint(x - m_point.m_drag_icon_offset - m_point.m_draggingOffsetx,
736  y - m_point.m_drag_icon_offset - m_point.m_draggingOffsety, tlat,
737  tlon);
738  m_point.m_lat = tlat;
739  m_point.m_lon = tlon;
740 }
741 
742 void RoutePointGui::PresetDragOffset(ChartCanvas *canvas, int x, int y) {
743  wxPoint r;
744  canvas->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
745 
746  m_point.m_draggingOffsetx = x - (r.x + m_point.m_drag_icon_offset);
747  m_point.m_draggingOffsety = y - (r.y + m_point.m_drag_icon_offset);
748 }
749 
750 wxPoint2DDouble RoutePointGui::computeDragHandlePoint(ChartCanvas *canvas) {
751  wxPoint r;
752  canvas->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
753  double lat, lon;
754  canvas->GetCanvasPixPoint(r.x + m_point.m_drag_icon_offset, r.y + m_point.m_drag_icon_offset,
755  lat, lon);
756 
757  // Keep the members updated
758  m_point.m_dragHandleLat = lat;
759  m_point.m_dragHandleLon = lon;
760 
761  return wxPoint2DDouble(lon, lat);
762 }
763 
764 void RoutePointGui::ShowScaleWarningMessage(ChartCanvas *canvas) {
765  wxString strA = _("The ScaMin value for new waypoints is set to");
766  wxString strB = _("but current chartscale is");
767  wxString strC =
768  _("Therefore the new waypoint will not be visible at this zoom level.");
769  wxString MessStr =
770  wxString::Format(_T("%s %li,\n %s %.0f.\n%s"), strA, m_point.GetScaMin(), strB,
771  canvas->GetScaleValue(), strC);
772  OCPNMessageBox(canvas, MessStr);
773 }
774 
775 void RoutePointGui::EnableDragHandle(bool bEnable) {
776  m_point.m_bDrawDragHandle = bEnable;
777  if (bEnable) {
778  if (!m_point.m_dragIcon.IsOk()) {
779  // Get the icon
780  // What size?
781  int bm_size = g_Platform->GetDisplayDPmm() * 9; // 9 mm nominal
782 
783  // What icon?
784  wxString UserIconPath = g_Platform->GetSharedDataDir()
785  + _T("uidata") + wxFileName::GetPathSeparator();
786 
787  m_point.m_dragIcon = LoadSVG(UserIconPath + _T("DragHandle.svg"), bm_size,
788  bm_size, m_point.m_pbmIcon);
789 
790  // build a texture
791 #ifdef ocpnUSE_GL
792  /* make rgba texture */
793  if (m_point.m_dragIconTexture == 0) {
794  glGenTextures(1, &m_point.m_dragIconTexture);
795  glBindTexture(GL_TEXTURE_2D, m_point.m_dragIconTexture);
796 
797  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
798  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
799  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
800 
801  wxImage image = m_point.m_dragIcon.ConvertToImage();
802  int w = image.GetWidth(), h = image.GetHeight();
803 
804  m_point.m_dragIconTextureWidth = NextPow2(w);
805  m_point.m_dragIconTextureHeight = NextPow2(h);
806 
807  unsigned char *d = image.GetData();
808  unsigned char *a = image.GetAlpha();
809 
810  unsigned char mr, mg, mb;
811  image.GetOrFindMaskColour(&mr, &mg, &mb);
812 
813  unsigned char *e = new unsigned char[4 * w * h];
814  if (d && e) {
815  for (int y = 0; y < h; y++)
816  for (int x = 0; x < w; x++) {
817  unsigned char r, g, b;
818  int off = (y * image.GetWidth() + x);
819  r = d[off * 3 + 0];
820  g = d[off * 3 + 1];
821  b = d[off * 3 + 2];
822  e[off * 4 + 0] = r;
823  e[off * 4 + 1] = g;
824  e[off * 4 + 2] = b;
825 
826  e[off * 4 + 3] =
827  a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
828  }
829  }
830 
831  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_point.m_dragIconTextureWidth,
832  m_point.m_dragIconTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
833  NULL);
834  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
835  e);
836 
837  delete[] e;
838  }
839 #endif
840 
841  // set the drawing metrics
842  if (m_point.m_dragIcon.IsOk()) {
843  m_point.m_drag_line_length_man = bm_size;
844  m_point.m_drag_icon_offset = bm_size;
845  } else {
846  m_point.m_drag_line_length_man = 64;
847  m_point.m_drag_icon_offset = 64;
848  }
849  }
850  }
851 }
852 
853 void RoutePointGui::ReLoadIcon(void) {
854  if (!pWayPointMan) return;
855  bool icon_exists = pWayPointMan->DoesIconExist(m_point.m_IconName);
856 
857  wxString iconUse = m_point.m_IconName;
858  if (!icon_exists) {
859  // Try all lower case as a favor in the case where imported waypoints use
860  // mixed case names
861  wxString tentative_icon = m_point.m_IconName.Lower();
862  if (pWayPointMan->DoesIconExist(tentative_icon)) {
863  // if found, convert point's icon name permanently.
864  m_point.m_IconName = tentative_icon;
865  iconUse = m_point.m_IconName;
866  }
867  // Icon name is not in the standard or user lists, so add to the list a
868  // generic placeholder
869  else {
870  if (!pWayPointMan->DoesIconExist(_T("tempsub"))) {
871  ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
872  if (style) {
873  wxBitmap bmp = style->GetIcon(_T("circle"));
874  if (bmp.IsOk()) {
875  wxImage image = bmp.ConvertToImage();
876  WayPointmanGui(*pWayPointMan).ProcessIcon(image, "tempsub", "tempsub");
877  }
878  }
879  }
880  iconUse = _T("tempsub");
881  }
882  }
883 
884  m_point.m_pbmIcon = pWayPointMan->GetIconBitmap(iconUse);
885  m_point.m_bPreScaled = pWayPointMan->GetIconPrescaled(iconUse);
886 
887 #ifdef ocpnUSE_GL
888  m_point.m_wpBBox_view_scale_ppm = -1;
889 
890  m_point.m_iTextTexture = 0;
891 #endif
892 
893  m_point.m_IconScaleFactor = -1; // Force scaled icon reload
894  m_point.m_pMarkFont = 0; // Force Font color reload
895  m_point.m_IconIsDirty = false;
896 }
897 
898 bool RoutePointGui::SendToGPS(const wxString &com_name, SendToGpsDlg *dialog) {
899 
900  N0183DlgCtx dlg_ctx = GetDialogCtx(dialog);
901  ::wxBeginBusyCursor();
902  int result = SendWaypointToGPS_N0183(&m_point, com_name, *g_pMUX, dlg_ctx);
903  ::wxEndBusyCursor();
904 
905  wxString msg;
906  if (0 == result)
907  msg = _("Waypoint(s) Transmitted.");
908  else {
909  if (result == ERR_GARMIN_INITIALIZE)
910  msg = _("Error on Waypoint Upload. Garmin GPS not connected");
911  else
912  msg = _("Error on Waypoint Upload. Please check logfiles...");
913  }
914 
915  OCPNMessageBox(NULL, msg, _("OpenCPN Info"), wxOK | wxICON_INFORMATION);
916 
917  return (result == 0);
918 }
919 
920 int RoutePointGui::GetIconImageIndex() {
921  if (m_point.IsShared()) {
922  // Get an array of all routes using this point
923  wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(&m_point);
924 
925  // Use route array (if any) to determine actual visibility for this point
926  bool brp_viz = false;
927  if (proute_array) {
928  for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
929  Route *pr = (Route *)proute_array->Item(ir);
930  if (pr->IsVisible()) {
931  brp_viz = true;
932  break;
933  }
934  }
935  }
936 
937  if (brp_viz)
938  return (pWayPointMan->GetFIconImageListIndex(GetIconBitmap()));
939  else {
940  if (m_point.IsVisible())
941  return (pWayPointMan->GetIconImageListIndex(GetIconBitmap()));
942  else
943  return (pWayPointMan->GetXIconImageListIndex(GetIconBitmap()));
944  }
945  }
946 
947  else { // point is not shared
948  if (m_point.IsVisible())
949  return (pWayPointMan->GetIconImageListIndex(GetIconBitmap()));
950  else
951  return (pWayPointMan->GetXIconImageListIndex(GetIconBitmap()));
952  }
953 }
Definition: route.h:75
Route "Send to GPS..." Dialog Definition.
Definition: SendToGpsDlg.h:51
Definition: ocpndc.h:58
Definition: Quilt.cpp:867