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