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