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 &&
191 m_point.m_bShowWaypointRangeRings) {
192 double factor = 1.00;
193 if (m_point.m_iWaypointRangeRingsStepUnits == 1) // nautical miles
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 ==
254 1) // convert kilometers to NMi
255 factor = 1 / 1.852;
256
257 double radius = factor * m_point.m_iWaypointRangeRingsNumber *
258 m_point.m_fWaypointRangeRingsStep / 60.;
259
260 LLBBox radar_box = m_point.m_wpBBox;
261 radar_box.EnLarge(radius * 2);
262 if (vpBBox.IntersectOut(radar_box)) {
263 return;
264 }
265 } else
266 return;
267 }
268 }
269
270 wxPoint r;
271 wxRect hilitebox;
272 unsigned char transparency = 150;
273
274 if (use_cached_screen_coords && m_point.m_pos_on_screen)
275 r.x = m_point.m_screen_pos.m_x, r.y = m_point.m_screen_pos.m_y;
276 else
277 canvas->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
278
279 if (r.x == INVALID_COORD) return;
280
281 // Substitute icon?
282 if (m_point.m_IconIsDirty) ReLoadIcon();
283 wxBitmap *pbm;
284 if ((m_point.m_bIsActive) && (m_point.m_IconName != _T("mob")))
285 pbm = pWayPointMan->GetIconBitmap(_T ( "activepoint" ));
286 else
287 pbm = m_point.m_pbmIcon;
288
289 // If icon is corrupt, there is really nothing else to do...
290 if (!pbm || !pbm->IsOk()) return;
291
292 int sx2 = pbm->GetWidth() / 2;
293 int sy2 = pbm->GetHeight() / 2;
294
295 // Calculate the mark drawing extents
296 wxRect r1(r.x - sx2, r.y - sy2, sx2 * 2, sy2 * 2); // the bitmap extents
297
298 wxRect r3 = r1;
299 if (m_point.m_bShowName) {
300 if (!m_point.m_pMarkFont) {
301 wxFont *dFont = FontMgr::Get().GetFont(_("Marks"));
302 int font_size = wxMax(8, dFont->GetPointSize());
303 font_size /= OCPN_GetWinDIPScaleFactor();
304
305 m_point.m_pMarkFont = FontMgr::Get().FindOrCreateFont(
306 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
307 false, dFont->GetFaceName());
308
309 m_point.m_FontColor = FontMgr::Get().GetFontColor(_("Marks"));
310 if (m_point.m_iTextTexture) {
311 glDeleteTextures(1, &m_point.m_iTextTexture);
312 m_point.m_iTextTexture = 0;
313 }
314
315 m_point.CalculateNameExtents();
316 }
317
318 if (m_point.m_pMarkFont) {
319 wxRect r2(r.x + m_point.m_NameLocationOffsetX,
320 r.y + m_point.m_NameLocationOffsetY, m_point.m_NameExtents.x,
321 m_point.m_NameExtents.y);
322 r3.Union(r2);
323 }
324 }
325
326 hilitebox = r3;
327 hilitebox.x -= r.x;
328 hilitebox.y -= r.y;
329
330 if (!m_point.m_bPreScaled) {
331 hilitebox.x *= g_MarkScaleFactorExp;
332 hilitebox.y *= g_MarkScaleFactorExp;
333 hilitebox.width *= g_MarkScaleFactorExp;
334 hilitebox.height *= g_MarkScaleFactorExp;
335 }
336
337 float radius;
338 if (g_btouch) {
339 hilitebox.Inflate(20);
340 radius = 20.0f;
341 } else {
342 hilitebox.Inflate(4);
343 radius = 4.0f;
344 }
345
346 /* update bounding box */
347 if (!m_point.m_wpBBox.GetValid() ||
348 vp.view_scale_ppm != m_point.m_wpBBox_view_scale_ppm ||
349 vp.rotation != m_point.m_wpBBox_rotation) {
350 double lat1, lon1, lat2, lon2;
351 canvas->GetCanvasPixPoint(r.x + hilitebox.x,
352 r.y + hilitebox.y + hilitebox.height, lat1, lon1);
353 canvas->GetCanvasPixPoint(r.x + hilitebox.x + hilitebox.width,
354 r.y + hilitebox.y, lat2, lon2);
355
356 if (lon1 > lon2)
357 m_point.m_wpBBox.Set(lat1, lon1, lat2, lon2 + 360);
358 else
359 m_point.m_wpBBox.Set(lat1, lon1, lat2, lon2);
360
361 m_point.m_wpBBox_view_scale_ppm = vp.view_scale_ppm;
362 m_point.m_wpBBox_rotation = vp.rotation;
363 }
364
365 // if(region.Contains(r3) == wxOutRegion)
366 // return;
367
368 // ocpnDC dc;
369
370 // Highlite any selected point
371 if (m_point.m_bPtIsSelected) {
372 wxColour hi_colour;
373 if (m_point.m_bBlink) {
374 wxPen *pen = g_pRouteMan->GetActiveRoutePointPen();
375 hi_colour = pen->GetColour();
376 } else {
377 hi_colour = GetGlobalColor(_T ( "YELO1" ));
378 }
379
380 AlphaBlending(dc, r.x + hilitebox.x, r.y + hilitebox.y, hilitebox.width,
381 hilitebox.height, radius, hi_colour, transparency);
382 }
383
384 bool bDrawHL = false;
385
386 if (m_point.m_bBlink && (gFrame->nBlinkerTick & 1)) bDrawHL = true;
387
388 if ((!bDrawHL) && (NULL != m_point.m_pbmIcon)) {
389 int glw, glh;
390 unsigned int IconTexture =
391 WayPointmanGui(*pWayPointMan).GetIconTexture(pbm, glw, glh);
392
393 glBindTexture(GL_TEXTURE_2D, IconTexture);
394
395 glEnable(GL_TEXTURE_2D);
396 glEnable(GL_BLEND);
397
398 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
399 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
400
401 int w = r1.width, h = r1.height;
402
403 float scale = 1.0;
404 if (!m_point.m_bPreScaled) {
405 scale = g_MarkScaleFactorExp;
406 }
407
408 // Scale for MacOS Retina and GTK screen scaling
409 scale *= GetOCPNCanvasWindow()->GetContentScaleFactor();
410
411 float ws = r1.width * scale;
412 float hs = r1.height * scale;
413 float xs = r.x - ws / 2.;
414 float ys = r.y - hs / 2.;
415 float u = (float)w / glw, v = (float)h / glh;
416
417 float coords[8];
418 float uv[8];
419 // normal uv
420 uv[0] = 0;
421 uv[1] = 0;
422 uv[2] = u;
423 uv[3] = 0;
424 uv[4] = u;
425 uv[5] = v;
426 uv[6] = 0;
427 uv[7] = v;
428
429 // pixels
430 coords[0] = xs;
431 coords[1] = ys;
432 coords[2] = xs + ws;
433 coords[3] = ys;
434 coords[4] = xs + ws;
435 coords[5] = ys + hs;
436 coords[6] = xs, coords[7] = ys + hs;
437
438 glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
439
440 glDisable(GL_BLEND);
441 glDisable(GL_TEXTURE_2D);
442 }
443
444 if (m_point.m_bShowName && m_point.m_pMarkFont) {
445 int w = m_point.m_NameExtents.x, h = m_point.m_NameExtents.y;
446 if (!m_point.m_iTextTexture && w && h) {
447#if 0
448 wxBitmap tbm(w, h); /* render text on dc */
449 wxMemoryDC dc;
450 dc.SelectObject(tbm);
451 dc.SetBackground(wxBrush(*wxBLACK));
452 dc.Clear();
453 dc.SetFont(*m_pMarkFont);
454 dc.SetTextForeground(*wxWHITE);
455 dc.DrawText(m_MarkName, 0, 0);
456 dc.SelectObject(wxNullBitmap);
457
458 /* make alpha texture for text */
459 wxImage image = tbm.ConvertToImage();
460 unsigned char *d = image.GetData();
461 unsigned char *e = new unsigned char[w * h];
462 if (d && e) {
463 for (int p = 0; p < w * h; p++) e[p] = d[3 * p + 0];
464 }
465
466 /* create texture for rendered text */
467 glGenTextures(1, &m_iTextTexture);
468 glBindTexture(GL_TEXTURE_2D, m_iTextTexture);
469
470 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
471 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
472
473 m_iTextTextureWidth = NextPow2(w);
474 m_iTextTextureHeight = NextPow2(h);
475 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_iTextTextureWidth,
476 m_iTextTextureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
477 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_ALPHA, GL_UNSIGNED_BYTE,
478 e);
479 delete[] e;
480#else
481 wxScreenDC sdc;
482 sdc.SetFont(*m_point.m_pMarkFont);
483
484 /* create bitmap of appropriate size and select it */
485 wxBitmap bmp(w, h);
486 wxMemoryDC temp_dc;
487 temp_dc.SelectObject(bmp);
488
489 /* fill bitmap with black */
490 temp_dc.SetBackground(wxBrush(wxColour(0, 0, 0)));
491 temp_dc.Clear();
492
493 /* draw the text white */
494 temp_dc.SetFont(*m_point.m_pMarkFont);
495 temp_dc.SetTextForeground(wxColour(255, 255, 255));
496 temp_dc.DrawText(m_point.m_MarkName, 0, 0);
497 temp_dc.SelectObject(wxNullBitmap);
498
499 /* use the data in the bitmap for alpha channel,
500 and set the color to text foreground */
501 wxImage image = bmp.ConvertToImage();
502
503 unsigned char *data = new unsigned char[w * h * 4];
504 unsigned char *im = image.GetData();
505
506 if (im) {
507 unsigned int r = m_point.m_FontColor.Red();
508 unsigned int g = m_point.m_FontColor.Green();
509 unsigned int b = m_point.m_FontColor.Blue();
510 for (int i = 0; i < h; i++) {
511 for (int j = 0; j < w; j++) {
512 unsigned int index = ((i * w) + j) * 4;
513 data[index] = r;
514 data[index + 1] = g;
515 data[index + 2] = b;
516 data[index + 3] = im[((i * w) + j) * 3];
517 }
518 }
519 }
520
521 glGenTextures(1, &m_point.m_iTextTexture);
522
523 glBindTexture(GL_TEXTURE_2D, m_point.m_iTextTexture);
524
525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
526 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
527
528 m_point.m_iTextTextureWidth = NextPow2(w);
529 m_point.m_iTextTextureHeight = NextPow2(h);
530 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_point.m_iTextTextureWidth,
531 m_point.m_iTextTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
532 NULL);
533 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
534 data);
535
536 delete[] data;
537
538 glEnable(GL_TEXTURE_2D);
539 glEnable(GL_BLEND);
540 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
541
542#endif
543 }
544
545 if (m_point.m_iTextTexture) {
546 /* draw texture with text */
547 glBindTexture(GL_TEXTURE_2D, m_point.m_iTextTexture);
548
549 glEnable(GL_TEXTURE_2D);
550 glEnable(GL_BLEND);
551
552 int x = r.x + m_point.m_NameLocationOffsetX,
553 y = r.y + m_point.m_NameLocationOffsetY;
554 float u = (float)w / m_point.m_iTextTextureWidth,
555 v = (float)h / m_point.m_iTextTextureHeight;
556 float coords[8];
557 float uv[8];
558 // normal uv
559 uv[0] = 0;
560 uv[1] = 0;
561 uv[2] = u;
562 uv[3] = 0;
563 uv[4] = u;
564 uv[5] = v;
565 uv[6] = 0;
566 uv[7] = v;
567
568 // pixels
569 coords[0] = x;
570 coords[1] = y;
571 coords[2] = x + w;
572 coords[3] = y;
573 coords[4] = x + w;
574 coords[5] = y + h;
575 coords[6] = x, coords[7] = y + h;
576
577 glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
578
579 glDisable(GL_BLEND);
580 glDisable(GL_TEXTURE_2D);
581 }
582 }
583
584 // Draw waypoint radar rings if activated
585 if (m_point.m_iWaypointRangeRingsNumber &&
586 m_point.m_bShowWaypointRangeRings) {
587 double factor = 1.00;
588 if (m_point.m_iWaypointRangeRingsStepUnits == 1) // nautical miles
589 factor = 1 / 1.852;
590
591 factor *= m_point.m_fWaypointRangeRingsStep;
592
593 double tlat, tlon;
594 wxPoint r1;
595 ll_gc_ll(m_point.m_lat, m_point.m_lon, 0, factor, &tlat, &tlon);
596 canvas->GetCanvasPointPix(tlat, tlon, &r1);
597
598 double lpp =
599 sqrt(pow((double)(r.x - r1.x), 2) + pow((double)(r.y - r1.y), 2));
600 int pix_radius = (int)lpp;
601
602 extern wxColor GetDimColor(wxColor c);
603 wxColor ring_dim_color = GetDimColor(m_point.m_wxcWaypointRangeRingsColour);
604
605 // 0.5 mm nominal, but not less than 1 pixel
606 double platform_pen_width =
607 wxRound(wxMax(1.0, g_Platform->GetDisplayDPmm() / 2));
608 wxPen ppPen1(ring_dim_color, platform_pen_width);
609 wxBrush saveBrush = dc.GetBrush();
610 wxPen savePen = dc.GetPen();
611 dc.SetPen(ppPen1);
612 dc.SetBrush(wxBrush(ring_dim_color, wxBRUSHSTYLE_TRANSPARENT));
613
614 for (int i = 1; i <= m_point.m_iWaypointRangeRingsNumber; i++)
615 dc.StrokeCircle(r.x, r.y, i * pix_radius);
616 dc.SetPen(savePen);
617 dc.SetBrush(saveBrush);
618 }
619
620 // Render Drag handle if enabled
621 if (m_point.m_bDrawDragHandle) {
622 // A line, southeast, scaled to the size of the icon
623 double platform_pen_width = wxRound(
624 wxMax(1.0, g_Platform->GetDisplayDPmm() /
625 2)); // 0.5 mm nominal, but not less than 1 pixel
626
627 wxColor dh_color = GetGlobalColor(_T ( "YELO1" ));
628 wxPen ppPen1(dh_color, 3 * platform_pen_width);
629 dc.SetPen(ppPen1);
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 dh_color = wxColor(0, 0, 0);
635 wxPen ppPen2(dh_color, platform_pen_width);
636 dc.SetPen(ppPen2);
637 dc.DrawLine(r.x + hilitebox.width / 4, r.y + hilitebox.height / 4,
638 r.x + m_point.m_drag_line_length_man,
639 r.y + m_point.m_drag_line_length_man);
640
641 // The drag handle
642 glBindTexture(GL_TEXTURE_2D, m_point.m_dragIconTexture);
643
644 glEnable(GL_TEXTURE_2D);
645 glEnable(GL_BLEND);
646
647 int x = r.x + m_point.m_drag_icon_offset,
648 y = r.y + m_point.m_drag_icon_offset, w = m_point.m_dragIcon.GetWidth(),
649 h = m_point.m_dragIcon.GetHeight();
650
651 float scale = 1.0;
652
653 float ws = w * scale;
654 float hs = h * scale;
655 float xs = x - ws / 2.;
656 float ys = y - hs / 2.;
657 float u = (float)w / m_point.m_dragIconTextureWidth,
658 v = (float)h / m_point.m_dragIconTextureWidth;
659
660 float coords[8];
661 float uv[8];
662 // normal uv
663 uv[0] = 0;
664 uv[1] = 0;
665 uv[2] = u;
666 uv[3] = 0;
667 uv[4] = u;
668 uv[5] = v;
669 uv[6] = 0;
670 uv[7] = v;
671
672 // pixels
673 coords[0] = xs;
674 coords[1] = ys;
675 coords[2] = xs + ws;
676 coords[3] = ys;
677 coords[4] = xs + ws;
678 coords[5] = ys + hs;
679 coords[6] = xs, coords[7] = ys + hs;
680
681 glChartCanvas::RenderSingleTexture(dc, coords, uv, &vp, 0, 0, 0);
682
683 glDisable(GL_BLEND);
684 glDisable(GL_TEXTURE_2D);
685 }
686
687 if (m_point.m_bBlink)
688 g_blink_rect = m_point.CurrentRect_in_DC; // also save for global blinker
689
690 // This will be useful for fast icon redraws
691 m_point.CurrentRect_in_DC.x = r.x + hilitebox.x;
692 m_point.CurrentRect_in_DC.y = r.y + hilitebox.y;
693 m_point.CurrentRect_in_DC.width = hilitebox.width;
694 m_point.CurrentRect_in_DC.height = hilitebox.height;
695
696 if (m_point.m_bBlink)
697 g_blink_rect = m_point.CurrentRect_in_DC; // also save for global blinker
698}
699#endif
700
701void RoutePointGui::CalculateDCRect(wxDC &dc, ChartCanvas *canvas,
702 wxRect *prect) {
703 if (canvas) {
704 dc.ResetBoundingBox();
705 dc.DestroyClippingRegion();
706
707 // Draw the mark on the dc
708 ocpnDC odc(dc);
709 odc.SetVP(canvas->GetVP());
710
711 Draw(odc, canvas, NULL);
712
713 // Retrieve the drawing extents
714 prect->x = dc.MinX() - 1;
715 prect->y = dc.MinY() - 1;
716 prect->width = dc.MaxX() - dc.MinX() + 2; // Mouse Poop?
717 prect->height = dc.MaxY() - dc.MinY() + 2;
718 }
719}
720
721bool RoutePointGui::IsVisibleSelectable(ChartCanvas *cc, bool boverrideViz) {
722 return m_point.IsVisibleSelectable(cc->GetScaleValue(), boverrideViz);
723}
724
725wxPoint2DDouble RoutePointGui::GetDragHandlePoint(ChartCanvas *canvas) {
726 if (!m_point.m_bDrawDragHandle)
727 return wxPoint2DDouble(m_point.m_lon, m_point.m_lat);
728 else {
729 return computeDragHandlePoint(canvas);
730 }
731}
732void RoutePointGui::SetPointFromDraghandlePoint(ChartCanvas *canvas, double lat,
733 double lon) {
734 wxPoint r;
735 canvas->GetCanvasPointPix(lat, lon, &r);
736 double tlat, tlon;
737 canvas->GetCanvasPixPoint(r.x - m_point.m_drag_icon_offset,
738 r.y - m_point.m_drag_icon_offset, tlat, tlon);
739 m_point.m_lat = tlat;
740 m_point.m_lon = tlon;
741}
742
743void RoutePointGui::SetPointFromDraghandlePoint(ChartCanvas *canvas, int x,
744 int y) {
745 double tlat, tlon;
746 canvas->GetCanvasPixPoint(
747 x - m_point.m_drag_icon_offset - m_point.m_draggingOffsetx,
748 y - m_point.m_drag_icon_offset - m_point.m_draggingOffsety, tlat, tlon);
749 m_point.m_lat = tlat;
750 m_point.m_lon = tlon;
751}
752
753void RoutePointGui::PresetDragOffset(ChartCanvas *canvas, int x, int y) {
754 wxPoint r;
755 canvas->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
756
757 m_point.m_draggingOffsetx = x - (r.x + m_point.m_drag_icon_offset);
758 m_point.m_draggingOffsety = y - (r.y + m_point.m_drag_icon_offset);
759}
760
761wxPoint2DDouble RoutePointGui::computeDragHandlePoint(ChartCanvas *canvas) {
762 wxPoint r;
763 canvas->GetCanvasPointPix(m_point.m_lat, m_point.m_lon, &r);
764 double lat, lon;
765 canvas->GetCanvasPixPoint(r.x + m_point.m_drag_icon_offset,
766 r.y + m_point.m_drag_icon_offset, lat, lon);
767
768 // Keep the members updated
769 m_point.m_dragHandleLat = lat;
770 m_point.m_dragHandleLon = lon;
771
772 return wxPoint2DDouble(lon, lat);
773}
774
775void RoutePointGui::ShowScaleWarningMessage(ChartCanvas *canvas) {
776 wxString strA = _("The ScaMin value for new waypoints is set to");
777 wxString strB = _("but current chartscale is");
778 wxString strC =
779 _("Therefore the new waypoint will not be visible at this zoom level.");
780 wxString MessStr =
781 wxString::Format(_T("%s %li,\n %s %.0f.\n%s"), strA, m_point.GetScaMin(),
782 strB, canvas->GetScaleValue(), strC);
783 OCPNMessageBox(canvas, MessStr);
784}
785
786void RoutePointGui::EnableDragHandle(bool bEnable) {
787 m_point.m_bDrawDragHandle = bEnable;
788 if (bEnable) {
789 if (!m_point.m_dragIcon.IsOk()) {
790 // Get the icon
791 // What size?
792 int bm_size = g_Platform->GetDisplayDPmm() * 9; // 9 mm nominal
793
794 // What icon?
795 wxString UserIconPath = g_Platform->GetSharedDataDir() + _T("uidata") +
796 wxFileName::GetPathSeparator();
797
798 m_point.m_dragIcon = LoadSVG(UserIconPath + _T("DragHandle.svg"), bm_size,
799 bm_size, m_point.m_pbmIcon);
800
801 // build a texture
802#ifdef ocpnUSE_GL
803 /* make rgba texture */
804 if (m_point.m_dragIconTexture == 0) {
805 glGenTextures(1, &m_point.m_dragIconTexture);
806 glBindTexture(GL_TEXTURE_2D, m_point.m_dragIconTexture);
807
808 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
809 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
810 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
811
812 wxImage image = m_point.m_dragIcon.ConvertToImage();
813 int w = image.GetWidth(), h = image.GetHeight();
814
815 m_point.m_dragIconTextureWidth = NextPow2(w);
816 m_point.m_dragIconTextureHeight = NextPow2(h);
817
818 unsigned char *d = image.GetData();
819 unsigned char *a = image.GetAlpha();
820
821 unsigned char mr, mg, mb;
822 image.GetOrFindMaskColour(&mr, &mg, &mb);
823
824 unsigned char *e = new unsigned char[4 * w * h];
825 if (d && e) {
826 for (int y = 0; y < h; y++)
827 for (int x = 0; x < w; x++) {
828 unsigned char r, g, b;
829 int off = (y * image.GetWidth() + x);
830 r = d[off * 3 + 0];
831 g = d[off * 3 + 1];
832 b = d[off * 3 + 2];
833 e[off * 4 + 0] = r;
834 e[off * 4 + 1] = g;
835 e[off * 4 + 2] = b;
836
837 e[off * 4 + 3] =
838 a ? a[off] : ((r == mr) && (g == mg) && (b == mb) ? 0 : 255);
839 }
840 }
841
842 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_point.m_dragIconTextureWidth,
843 m_point.m_dragIconTextureHeight, 0, GL_RGBA,
844 GL_UNSIGNED_BYTE, NULL);
845 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE,
846 e);
847
848 delete[] e;
849 }
850#endif
851
852 // set the drawing metrics
853 if (m_point.m_dragIcon.IsOk()) {
854 m_point.m_drag_line_length_man = bm_size;
855 m_point.m_drag_icon_offset = bm_size;
856 } else {
857 m_point.m_drag_line_length_man = 64;
858 m_point.m_drag_icon_offset = 64;
859 }
860 }
861 }
862}
863
864void RoutePointGui::ReLoadIcon(void) {
865 if (!pWayPointMan) return;
866 bool icon_exists = pWayPointMan->DoesIconExist(m_point.m_IconName);
867
868 wxString iconUse = m_point.m_IconName;
869 if (!icon_exists) {
870 // Try all lower case as a favor in the case where imported waypoints use
871 // mixed case names
872 wxString tentative_icon = m_point.m_IconName.Lower();
873 if (pWayPointMan->DoesIconExist(tentative_icon)) {
874 // if found, convert point's icon name permanently.
875 m_point.m_IconName = tentative_icon;
876 iconUse = m_point.m_IconName;
877 }
878 // Icon name is not in the standard or user lists, so add to the list a
879 // generic placeholder
880 else {
881 if (!pWayPointMan->DoesIconExist(_T("tempsub"))) {
882 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
883 if (style) {
884 wxBitmap bmp = style->GetIcon(_T("circle"));
885 if (bmp.IsOk()) {
886 wxImage image = bmp.ConvertToImage();
887 WayPointmanGui(*pWayPointMan)
888 .ProcessIcon(image, "tempsub", "tempsub");
889 }
890 }
891 }
892 iconUse = _T("tempsub");
893 }
894 }
895
896 m_point.m_pbmIcon = pWayPointMan->GetIconBitmap(iconUse);
897 m_point.m_bPreScaled = pWayPointMan->GetIconPrescaled(iconUse);
898
899#ifdef ocpnUSE_GL
900 m_point.m_wpBBox_view_scale_ppm = -1;
901
902 m_point.m_iTextTexture = 0;
903#endif
904
905 m_point.m_IconScaleFactor = -1; // Force scaled icon reload
906 m_point.m_pMarkFont = 0; // Force Font color reload
907 m_point.m_IconIsDirty = false;
908}
909
910bool RoutePointGui::SendToGPS(const wxString &com_name, SendToGpsDlg *dialog) {
911 N0183DlgCtx dlg_ctx = GetDialogCtx(dialog);
912 ::wxBeginBusyCursor();
913 int result = SendWaypointToGPS_N0183(&m_point, com_name, *g_pMUX, dlg_ctx);
914 ::wxEndBusyCursor();
915
916 wxString msg;
917 if (0 == result)
918 msg = _("Waypoint(s) Transmitted.");
919 else {
920 if (result == ERR_GARMIN_INITIALIZE)
921 msg = _("Error on Waypoint Upload. Garmin GPS not connected");
922 else
923 msg = _("Error on Waypoint Upload. Please check logfiles...");
924 }
925
926 OCPNMessageBox(NULL, msg, _("OpenCPN Info"), wxOK | wxICON_INFORMATION);
927
928 return (result == 0);
929}
930
931int RoutePointGui::GetIconImageIndex() {
932 if (m_point.IsShared()) {
933 // Get an array of all routes using this point
934 wxArrayPtrVoid *proute_array =
935 g_pRouteMan->GetRouteArrayContaining(&m_point);
936
937 // Use route array (if any) to determine actual visibility for this point
938 bool brp_viz = false;
939 if (proute_array) {
940 for (unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
941 Route *pr = (Route *)proute_array->Item(ir);
942 if (pr->IsVisible()) {
943 brp_viz = true;
944 break;
945 }
946 }
947 }
948
949 if (brp_viz)
950 return (pWayPointMan->GetFIconImageListIndex(GetIconBitmap()));
951 else {
952 if (m_point.IsVisible())
953 return (pWayPointMan->GetIconImageListIndex(GetIconBitmap()));
954 else
955 return (pWayPointMan->GetXIconImageListIndex(GetIconBitmap()));
956 }
957 }
958
959 else { // point is not shared
960 if (m_point.IsVisible())
961 return (pWayPointMan->GetIconImageListIndex(GetIconBitmap()));
962 else
963 return (pWayPointMan->GetXIconImageListIndex(GetIconBitmap()));
964 }
965}
Chart display canvas.
Definition chcanv.h:135
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4518
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
Definition chcanv.cpp:4543
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.
Definition route.h:75
Dialog for sending routes/waypoints to a GPS device.
Represents the view port for chart display in OpenCPN.
Definition viewport.h:84
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
Definition viewport.h:199
double rotation
Rotation angle of the viewport in radians.
Definition viewport.h:209
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.