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