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