OpenCPN Partial API docs
Loading...
Searching...
No Matches
route_gui.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2022 by David Register *
3 * Copyright (C) 2022 Alec Leamas *
4 * Copyright (C) 2025 NoCodeHummel *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
18 **************************************************************************/
19
26#include <string>
27
28#include "gl_headers.h" // Must be included before anything using GL stuff
29
30#include <wx/colour.h>
31#include <wx/gdicmn.h>
32#include <wx/pen.h>
33#include <wx/string.h>
34#include <wx/utils.h>
35
37#include "model/georef.h"
38#include "model/multiplexer.h"
39#include "model/own_ship.h"
40#include "model/route.h"
41#include "model/routeman.h"
42
43#include "chartbase.h"
44#include "color_handler.h"
45#include "dialog_alert.h"
46#include "gl_chart_canvas.h"
47#include "gui_lib.h"
48#include "line_clip.h"
49#include "n0183_ctx_factory.h"
50#include "navutil.h"
51#include "ocpn_gl_options.h"
52#include "route_gui.h"
53#include "route_point_gui.h"
54
55// In ocpn_frame FIXME (leamas) find new home
56extern wxColor GetDimColor(wxColor c);
57
58static int s_arrow_icon[] = {0, 0, 5, 2, 18, 6, 12, 0, 18, -6, 5, -2, 0, 0};
59
60static void TestLongitude(double lon, double min, double max, bool &lonl,
61 bool &lonr) {
62 double clon = (min + max) / 2;
63 if (min - lon > 180) lon += 360;
64
65 lonl = lonr = false;
66 if (lon < min) {
67 if (lon < clon - 180)
68 lonr = true;
69 else
70 lonl = true;
71 } else if (lon > max) {
72 if (lon > clon + 180)
73 lonl = true;
74 else
75 lonr = true;
76 }
77}
78
79void RouteGui::Draw(ocpnDC &dc, ChartCanvas *canvas, const LLBBox &box) {
80 if (m_route.pRoutePointList->empty()) return;
81
82 ViewPort vp = canvas->GetVP();
83
84 LLBBox test_box = m_route.GetBBox();
85 if (box.IntersectOut(test_box)) // Route is wholly outside window
86 return;
87
88 int width = g_route_line_width;
89 if (m_route.m_width != WIDTH_UNDEFINED) width = m_route.m_width;
90
91 if (m_route.m_bVisible && m_route.m_bRtIsSelected) {
92 wxPen spen = *g_pRouteMan->GetSelectedRoutePen();
93 spen.SetWidth(width);
94 dc.SetPen(spen);
95 dc.SetBrush(*g_pRouteMan->GetSelectedRouteBrush());
96 } else if (m_route.m_bVisible) {
97 wxPenStyle style = wxPENSTYLE_SOLID;
98 wxColour col;
99 if (m_route.m_style != wxPENSTYLE_INVALID) style = m_route.m_style;
100 if (m_route.m_Colour == "") {
101 col = g_pRouteMan->GetRoutePen()->GetColour();
102 } else {
103 for (unsigned int i = 0; i < sizeof(::GpxxColorNames) / sizeof(wxString);
104 i++) {
105 if (m_route.m_Colour == ::GpxxColorNames[i]) {
106 col = ::GpxxColors[i];
107 break;
108 }
109 }
110 }
111 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
112 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
113 }
114
115 if (m_route.m_bVisible && m_route.m_bRtIsActive) {
116 wxPen spen = *g_pRouteMan->GetActiveRoutePen();
117 spen.SetWidth(width);
118 dc.SetPen(spen);
119 dc.SetBrush(*g_pRouteMan->GetActiveRouteBrush());
120 }
121
122 wxPoint rpt1, rpt2;
123 if (m_route.m_bVisible) DrawPointWhich(dc, canvas, 1, &rpt1);
124
125 auto node = m_route.pRoutePointList->begin();
126 RoutePoint *prp1 = *node;
127
128 if (m_route.m_bVisible || prp1->IsShared())
129 RoutePointGui(*prp1).Draw(dc, canvas,
130 NULL); // prp1->Draw(dc, canvas, NULL);
131
132 for (++node; node != m_route.pRoutePointList->end(); ++node) {
133 RoutePoint *prp2 = *node;
134
135 bool draw_arrow = !(prp2->m_bIsActive && g_bAllowShipToActive);
136
137 if (m_route.m_bVisible || prp2->IsShared())
138 RoutePointGui(*prp2).Draw(dc, canvas,
139 &rpt2); // prp2->Draw(dc, canvas, &rpt2);
140
141 if (m_route.m_bVisible) {
142 // Handle offscreen points
143 bool b_2_on = vp.GetBBox().Contains(prp2->m_lat, prp2->m_lon);
144 bool b_1_on = vp.GetBBox().Contains(prp1->m_lat, prp1->m_lon);
145
146 // Simple case
147 if (b_1_on && b_2_on)
148 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp, draw_arrow,
149 m_route.m_hiliteWidth); // with arrows
150
151 // In the cases where one point is on, and one off
152 // we must decide which way to go in longitude
153 // Arbitrarily, we will go the shortest way
154
155 double pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 *
156 PI * vp.view_scale_ppm;
157 double dp =
158 pow((double)(rpt1.x - rpt2.x), 2) + pow((double)(rpt1.y - rpt2.y), 2);
159 double dtest;
160 int adder;
161 if (b_1_on && !b_2_on) {
162 if (rpt2.x < rpt1.x)
163 adder = (int)pix_full_circle;
164 else
165 adder = -(int)pix_full_circle;
166
167 dtest = pow((double)(rpt1.x - (rpt2.x + adder)), 2) +
168 pow((double)(rpt1.y - rpt2.y), 2);
169
170 if (dp < dtest) adder = 0;
171
172 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x + adder, rpt2.y, vp,
173 draw_arrow, m_route.m_hiliteWidth);
174 } else if (!b_1_on) {
175 if (rpt1.x < rpt2.x)
176 adder = (int)pix_full_circle;
177 else
178 adder = -(int)pix_full_circle;
179
180 float rxd = rpt2.x - (rpt1.x + adder);
181 float ryd = rpt1.y - rpt2.y;
182 dtest = rxd * rxd + ryd * ryd;
183
184 if (dp < dtest) adder = 0;
185
186 RenderSegment(dc, rpt1.x + adder, rpt1.y, rpt2.x, rpt2.y, vp,
187 draw_arrow, m_route.m_hiliteWidth);
188 }
189 }
190
191 rpt1 = rpt2;
192 prp1 = prp2;
193 }
194}
195
196void RouteGui::RenderSegment(ocpnDC &dc, int xa, int ya, int xb, int yb,
197 ViewPort &vp, bool bdraw_arrow, int hilite_width) {
198 // Get the dc boundary
199 int sx, sy;
200 dc.GetSize(&sx, &sy);
201
202 // Try to exit early if the segment is nowhere near the screen
203 wxRect r(0, 0, sx, sy);
204 wxRect s(xa, ya, 1, 1);
205 wxRect t(xb, yb, 1, 1);
206 s.Union(t);
207 if (!r.Intersects(s)) return;
208
209 // Clip the line segment to the dc boundary
210 int x0 = xa;
211 int y0 = ya;
212 int x1 = xb;
213 int y1 = yb;
214
215 // If hilite is desired, use a Native Graphics context to render alpha
216 // colours That is, if wxGraphicsContext is available.....
217
218 if (hilite_width) {
219 if (Visible ==
220 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy)) {
221 wxPen psave = dc.GetPen();
222
223 wxColour y = GetGlobalColor("YELO1");
224 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
225
226 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
227
228 dc.SetPen(HiPen);
229 dc.StrokeLine(x0, y0, x1, y1);
230
231 dc.SetPen(psave);
232 dc.StrokeLine(x0, y0, x1, y1);
233 }
234 } else {
235 if (Visible ==
236 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy))
237 dc.StrokeLine(x0, y0, x1, y1);
238 }
239
240 if (bdraw_arrow) {
241 // Draw a direction arrow
242
243 double theta = atan2((double)(yb - ya), (double)(xb - xa));
244 theta -= PI / 2.;
245
246 wxPoint icon[10];
247 double icon_scale_factor = 100 * vp.view_scale_ppm;
248 icon_scale_factor = fmin(icon_scale_factor, 1.5); // Sets the max size
249 icon_scale_factor = fmax(icon_scale_factor, .10);
250
251 // Get the absolute line length
252 // and constrain the arrow to be no more than xx% of the line length
253 double nom_arrow_size = 20.;
254 double max_arrow_to_leg = .20;
255 double lpp = sqrt(pow((double)(xa - xb), 2) + pow((double)(ya - yb), 2));
256
257 double icon_size = icon_scale_factor * nom_arrow_size;
258 if (icon_size > (lpp * max_arrow_to_leg))
259 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
260
261 for (int i = 0; i < 7; i++) {
262 int j = i * 2;
263 double pxa = (double)(s_arrow_icon[j]);
264 double pya = (double)(s_arrow_icon[j + 1]);
265
266 pya *= icon_scale_factor;
267 pxa *= icon_scale_factor;
268
269 double px = (pxa * sin(theta)) + (pya * cos(theta));
270 double py = (pya * sin(theta)) - (pxa * cos(theta));
271
272 icon[i].x = (int)(px) + xb;
273 icon[i].y = (int)(py) + yb;
274 }
275 wxPen savePen = dc.GetPen();
276 dc.SetPen(*wxTRANSPARENT_PEN);
277 dc.StrokePolygon(6, &icon[0], 0, 0);
278 dc.SetPen(savePen);
279 }
280}
281
282void RouteGui::RenderSegmentArrowsGL(ocpnDC &dc, int xa, int ya, int xb, int yb,
283 ViewPort &vp) {
284#ifdef ocpnUSE_GL
285 // Draw a direction arrow
286 float icon_scale_factor = 100 * vp.view_scale_ppm;
287 icon_scale_factor = fmin(icon_scale_factor, 1.5); // Sets the max size
288 icon_scale_factor = fmax(icon_scale_factor, .10);
289
290 // Get the absolute line length
291 // and constrain the arrow to be no more than xx% of the line length
292 float nom_arrow_size = 20.;
293 float max_arrow_to_leg = (float).20;
294 float lpp = sqrtf(powf((float)(xa - xb), 2) + powf((float)(ya - yb), 2));
295
296 float icon_size = icon_scale_factor * nom_arrow_size;
297 if (icon_size > (lpp * max_arrow_to_leg))
298 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
299
300 float theta = atan2f((float)yb - ya, (float)xb - xa);
301 theta -= (float)PI;
302
303 // icon_scale_factor = 5;
304 wxPoint pts[3];
305 // 0
306 pts[0].x = s_arrow_icon[0];
307 pts[0].y = s_arrow_icon[1];
308 pts[1].x = s_arrow_icon[2];
309 pts[1].y = s_arrow_icon[3];
310 pts[2].x = s_arrow_icon[6];
311 pts[2].y = s_arrow_icon[7];
312
313 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
314
315 // 1
316 pts[0].x = s_arrow_icon[2];
317 pts[0].y = s_arrow_icon[3];
318 pts[1].x = s_arrow_icon[4];
319 pts[1].y = s_arrow_icon[5];
320 pts[2].x = s_arrow_icon[6];
321 pts[2].y = s_arrow_icon[7];
322 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
323
324 // 2
325 pts[0].x = s_arrow_icon[0];
326 pts[0].y = -s_arrow_icon[1];
327 pts[1].x = s_arrow_icon[2];
328 pts[1].y = -s_arrow_icon[3];
329 pts[2].x = s_arrow_icon[6];
330 pts[2].y = -s_arrow_icon[7];
331 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
332
333 // 3
334 pts[0].x = s_arrow_icon[2];
335 pts[0].y = -s_arrow_icon[3];
336 pts[1].x = s_arrow_icon[4];
337 pts[1].y = -s_arrow_icon[5];
338 pts[2].x = s_arrow_icon[6];
339 pts[2].y = -s_arrow_icon[7];
340 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
341
342#endif
343}
344
345void RouteGui::DrawPointWhich(ocpnDC &dc, ChartCanvas *canvas, int iPoint,
346 wxPoint *rpn) {
347 if (iPoint <= m_route.GetnPoints())
348 RoutePointGui(*m_route.GetPoint(iPoint)).Draw(dc, canvas, rpn);
349}
350
351void RouteGui::DrawSegment(ocpnDC &dc, ChartCanvas *canvas, wxPoint *rp1,
352 wxPoint *rp2, ViewPort &vp, bool bdraw_arrow) {
353 if (m_route.m_bRtIsSelected)
354 dc.SetPen(*g_pRouteMan->GetSelectedRoutePen());
355 else if (m_route.m_bRtIsActive)
356 dc.SetPen(*g_pRouteMan->GetActiveRoutePen());
357 else
358 dc.SetPen(*g_pRouteMan->GetRoutePen());
359
360 RenderSegment(dc, rp1->x, rp1->y, rp2->x, rp2->y, vp, bdraw_arrow);
361}
362
363void RouteGui::DrawGL(ViewPort &vp, ChartCanvas *canvas, ocpnDC &dc) {
364#ifdef ocpnUSE_GL
365 if (m_route.pRoutePointList->empty()) return;
366
367 if (!vp.GetBBox().IntersectOut(m_route.GetBBox()) && m_route.m_bVisible)
368 DrawGLRouteLines(vp, canvas, dc);
369
370 /* Route points */
371 for (RoutePoint *prp : *m_route.pRoutePointList) {
372 // Inflate the bounding box a bit to ensure full drawing in accelerated pan
373 // mode.
374 // TODO this is a little extravagant, assumming a mark is always a large
375 // fixed lat/lon extent.
376 // Maybe better to use the mark's drawn box, once it is known.
377 if (vp.GetBBox().ContainsMarge(prp->m_lat, prp->m_lon, .5)) {
378 if (m_route.m_bVisible || prp->IsShared())
379 RoutePointGui(*prp).DrawGL(vp, canvas, dc);
380 }
381 }
382#endif
383}
384
385void RouteGui::DrawGLRouteLines(ViewPort &vp, ChartCanvas *canvas, ocpnDC &dc) {
386#ifdef ocpnUSE_GL
387 // Hiliting first
388 // Being special case to draw something for a 1 point route....
389 if (m_route.m_hiliteWidth) {
390 wxColour y = GetGlobalColor("YELO1");
391 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
392
393 wxPen HiPen(hilt, m_route.m_hiliteWidth, wxPENSTYLE_SOLID);
394
395 dc.SetPen(HiPen);
396
397 DrawGLLines(vp, &dc, canvas);
398 }
399
400 /* determine color and width */
401 wxColour col;
402
403 int width = g_pRouteMan->GetRoutePen()->GetWidth(); // g_route_line_width;
404 if (m_route.m_width != wxPENSTYLE_INVALID) width = m_route.m_width;
405
406 if (m_route.m_bRtIsActive) {
407 col = g_pRouteMan->GetActiveRoutePen()->GetColour();
408 } else if (m_route.m_bRtIsSelected) {
409 col = g_pRouteMan->GetSelectedRoutePen()->GetColour();
410 } else {
411 if (m_route.m_Colour == "") {
412 col = g_pRouteMan->GetRoutePen()->GetColour();
413 } else {
414 for (unsigned int i = 0; i < sizeof(::GpxxColorNames) / sizeof(wxString);
415 i++) {
416 if (m_route.m_Colour == ::GpxxColorNames[i]) {
417 col = ::GpxxColors[i];
418 break;
419 }
420 }
421 }
422 }
423
424 wxPenStyle style = wxPENSTYLE_SOLID;
425 if (m_route.m_style != wxPENSTYLE_INVALID) style = m_route.m_style;
426 wxPen p = *wxThePenList->FindOrCreatePen(col, width, style);
427 if (glChartCanvas::dash_map.find(style) != glChartCanvas::dash_map.end()) {
428 p.SetDashes(2, &glChartCanvas::dash_map[style][0]);
429 }
430 dc.SetPen(p);
431 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
432
433 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
434
435 dc.SetGLStipple();
436
437 DrawGLLines(vp, &dc, canvas);
438
439 glDisable(GL_LINE_STIPPLE);
440
441 /* direction arrows.. could probably be further optimized for opengl */
442 dc.SetPen(*wxThePenList->FindOrCreatePen(col, 1, wxPENSTYLE_SOLID));
443
444 auto node = m_route.pRoutePointList->begin();
445 wxPoint rpt1, rpt2;
446 while (node != m_route.pRoutePointList->end()) {
447 RoutePoint *prp = *node;
448 canvas->GetCanvasPointPix(prp->m_lat, prp->m_lon, &rpt2);
449 if (node != m_route.pRoutePointList->begin()) {
450 if (!prp->m_bIsActive || !g_bAllowShipToActive)
451 RenderSegmentArrowsGL(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp);
452 }
453 rpt1 = rpt2;
454 ++node;
455 }
456#endif
457}
458
459void RouteGui::DrawGLLines(ViewPort &vp, ocpnDC *dc, ChartCanvas *canvas) {
460#ifdef ocpnUSE_GL
461 float pix_full_circle =
462 WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.view_scale_ppm;
463
464 bool r1valid = false;
465 wxPoint2DDouble r1;
466 wxPoint2DDouble lastpoint;
467
468 auto node = m_route.pRoutePointList->begin();
469 RoutePoint *prp2 = *node;
470 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &lastpoint);
471
472 // single point.. make sure it shows up for highlighting
473 if (m_route.GetnPoints() == 1 && dc) {
474 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &r1);
475 dc->DrawLine(r1.m_x, r1.m_y, r1.m_x + 2, r1.m_y + 2);
476 return;
477 }
478
479 // Handle offscreen points
480 LLBBox bbox = vp.GetBBox();
481
482 // dc is passed for thicker highlighted lines (performance not very important)
483
484 for (++node; node != m_route.pRoutePointList->end(); ++node) {
485 RoutePoint *prp1 = prp2;
486 prp2 = *node;
487
488 // Provisional, to properly set status of last point in route
489 prp2->m_pos_on_screen = false;
490 {
491 wxPoint2DDouble r2;
492 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &r2);
493 if (std::isnan(r2.m_x)) {
494 r1valid = false;
495 continue;
496 }
497
498 lastpoint = r2; // For active track segment to ownship
499
500 // don't need to perform calculations or render segment
501 // if both points are past any edge of the vp
502 // TODO: use these optimizations for dc mode
503 bool lat1l = prp1->m_lat < bbox.GetMinLat(),
504 lat2l = prp2->m_lat < bbox.GetMinLat();
505 bool lat1r = prp1->m_lat > bbox.GetMaxLat(),
506 lat2r = prp2->m_lat > bbox.GetMaxLat();
507 if ((lat1l && lat2l) || (lat1r && lat2r)) {
508 r1valid = false;
509 prp1->m_pos_on_screen = false;
510 continue;
511 }
512
513 // Possible optimization, not usable if vp crosses IDL (180 E)
514 if (!vp.ContainsIDL()) {
515 bool lon1l, lon1r, lon2l, lon2r;
516 TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l,
517 lon1r);
518 TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l,
519 lon2r);
520 if ((lon1l && lon2l) || (lon1r && lon2r)) {
521 r1valid = false;
522 prp1->m_pos_on_screen = false;
523 continue;
524 }
525 }
526
527 if (!r1valid) {
528 canvas->GetDoubleCanvasPointPix(prp1->m_lat, prp1->m_lon, &r1);
529 if (std::isnan(r1.m_x)) continue;
530 }
531
532 // we must decide which way to go in longitude
533 // for projections which wrap, in this case, we will render two lines
534 // (one may often be off screen which would be nice to fix but complicate
535 // things here anyway, in some cases both points are on screen, but the
536 // route wraps to either side so two lines are needed to draw this
537 // properly
538
539 double adder = 0;
540 if ((vp.m_projection_type == PROJECTION_MERCATOR ||
541 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
542 float olon = vp.clon > 0 ? vp.clon - 180 : vp.clon + 180;
543
544 if (prp1->m_lon < prp2->m_lon) {
545 if (prp2->m_lon - prp1->m_lon < 180) {
546 if (olon > prp1->m_lon && olon < prp2->m_lon)
547 adder = pix_full_circle;
548 } else if (olon < prp1->m_lon || olon > prp2->m_lon)
549 adder = -pix_full_circle;
550 } else if (prp1->m_lon - prp2->m_lon < 180) {
551 if (olon < prp1->m_lon && olon > prp2->m_lon)
552 adder = -pix_full_circle;
553 } else if (olon > prp1->m_lon || olon < prp2->m_lon)
554 adder = pix_full_circle;
555 }
556
557 if (dc)
558 if (adder) {
559 float adderc = cos(vp.rotation) * adder,
560 adders = sin(vp.rotation) * adder;
561 dc->DrawLine(r1.m_x, r1.m_y, r2.m_x + adderc, r2.m_y + adders);
562 dc->DrawLine(r1.m_x - adderc, r1.m_y - adders, r2.m_x, r2.m_y);
563 } else
564 dc->DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y);
565 else {
566 }
567
568 r1 = r2;
569 r1valid = true;
570 }
571 }
572
573#endif
574}
575
576void RouteGui::CalculateDCRect(wxDC &dc_route, ChartCanvas *canvas,
577 wxRect *prect) {
578 dc_route.ResetBoundingBox();
579 dc_route.DestroyClippingRegion();
580
581 wxRect update_rect;
582
583 // Draw the route in skeleton form on the dc
584 // That is, draw only the route points, assuming that the segements will
585 // always be fully contained within the resulting rectangle.
586 // Can we prove this?
587 if (m_route.m_bVisible) {
588 for (RoutePoint *prp2 : *m_route.pRoutePointList) {
589 bool blink_save = prp2->m_bBlink;
590 prp2->m_bBlink = false;
591 ocpnDC odc_route(dc_route);
592 odc_route.SetVP(canvas->GetVP());
593 RoutePointGui(*prp2).Draw(odc_route, canvas, NULL);
594 prp2->m_bBlink = blink_save;
595
596 wxRect r = prp2->CurrentRect_in_DC;
597 // allow for large hilite circles at segment ends
598 r.Inflate(m_route.m_hiliteWidth, m_route.m_hiliteWidth);
599
600 update_rect.Union(r);
601 }
602 }
603
604 *prect = update_rect;
605}
606
607int RouteGui::SendToGPS(const wxString &com_name, bool bsend_waypoints,
608 SendToGpsDlg *dialog) {
609 int result = 0;
610
611 N0183DlgCtx dlg_ctx = GetDialogCtx(dialog);
612 ::wxBeginBusyCursor();
613 result = SendRouteToGPS_N0183(&m_route, com_name, bsend_waypoints, *g_pMUX,
614 dlg_ctx);
615 ::wxEndBusyCursor();
616
617 wxString msg;
618 if (0 == result)
619 msg = _("Route Transmitted.");
620 else {
621 switch (result) {
623 msg = _("Error on Route Upload. Garmin GPS not connected");
624 break;
626 msg = _("Error on Route Upload. GPS driver not available");
627 break;
629 default:
630 msg = _("Error on Route Upload. Please check logfiles...");
631 break;
632 }
633 }
634 OCPNMessageBox(NULL, msg, _("OpenCPN Info"), wxOK | wxICON_INFORMATION);
635
636 return (result == 0);
637}
638
639// Delete the route.
640bool RouteGui::OnDelete(wxWindow *parent, const int count) {
641 std::string title = _("Route Delete").ToStdString();
642 std::string action = _("Delete").ToStdString();
643 std::string msg;
644 if (count > 1) {
645 wxString str = wxString::Format(
646 _("Are you sure you want to delete %d routes?"), count);
647 msg = str.c_str();
648 } else {
649 msg = _("Are you sure you want to delete this route?").ToStdString();
650 }
651
652 AlertDialog dialog(parent, title, action);
653 dialog.SetMessage(msg);
654 int result = dialog.ShowModal();
655 return result == wxID_OK;
656}
General chart base definitions.
A modal message dialog with confirmation button and cancel button.
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:4514
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
Definition chcanv.cpp:4459
Represents a waypoint or mark within the navigation system.
Definition route_point.h:71
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
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.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
int m_hiliteWidth
Width in pixels for highlighting the route when selected.
Definition route.h:356
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
Definition route.h:203
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
Definition route.h:336
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
Definition route.h:208
wxString m_Colour
Color name for rendering the route on the chart.
Definition route.h:346
wxPenStyle m_style
Style of the route line when rendered on the chart.
Definition route.h:293
int m_width
Width of the route line in pixels when rendered on the chart.
Definition route.h:288
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
double clon
Center longitude of the viewport in degrees.
Definition viewport.h:199
Device context class that can use either wxDC or OpenGL for drawing.
Definition ocpndc.h:60
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Definition ocpndc.cpp:474
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.
OpenCPN Georef utility.
OpenGL chart rendering canvas.
Platform independent GL includes.
General purpose GUI support.
Multiplexer class and helpers.
Wrapper creating a N0183DlgCtx based on a SendToGpsDlg instance.
Utility functions.
OpenGL runtime options.
Position, course, speed, etc.
Route abstraction.
Route drawing stuff.
Purpose: Track and Trackpoint drawing stuff.
Routeman * g_pRouteMan
Global instance.
Definition routeman.cpp:60
Route Manager.