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