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