8#include "color_handler.h"
10#include "comm_n0183_output.h"
17#include "route_point_gui.h"
18#include "glChartCanvas.h"
23extern wxColour g_colourTrackLineColour;
24extern int g_route_line_width;
26extern wxColor GetDimColor(wxColor c);
27extern bool g_bHighliteTracks;
28extern float g_GLMinSymbolLineWidth;
29extern bool g_bAllowShipToActive;
33extern int s_arrow_icon[];
35static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
37 double clon = (min + max) / 2;
38 if (min - lon > 180) lon += 360;
46 }
else if (lon > max) {
55 if (m_route.pRoutePointList->empty())
return;
59 LLBBox test_box = m_route.GetBBox();
60 if (box.IntersectOut(test_box))
63 int width = g_route_line_width;
64 if (m_route.m_width != WIDTH_UNDEFINED) width = m_route.m_width;
66 if (m_route.m_bVisible && m_route.m_bRtIsSelected) {
67 wxPen spen = *g_pRouteMan->GetSelectedRoutePen();
70 dc.SetBrush(*g_pRouteMan->GetSelectedRouteBrush());
71 }
else if (m_route.m_bVisible) {
72 wxPenStyle style = wxPENSTYLE_SOLID;
74 if (m_route.m_style != wxPENSTYLE_INVALID) style = m_route.m_style;
75 if (m_route.m_Colour == wxEmptyString) {
76 col = g_pRouteMan->GetRoutePen()->GetColour();
78 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
80 if (m_route.m_Colour == ::GpxxColorNames[i]) {
81 col = ::GpxxColors[i];
86 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
87 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
90 if (m_route.m_bVisible && m_route.m_bRtIsActive) {
91 wxPen spen = *g_pRouteMan->GetActiveRoutePen();
94 dc.SetBrush(*g_pRouteMan->GetActiveRouteBrush());
98 if (m_route.m_bVisible) DrawPointWhich(dc, canvas, 1, &rpt1);
100 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
102 node = node->GetNext();
104 if (m_route.m_bVisible || prp1->IsShared())
RoutePointGui(*prp1).Draw(dc, canvas, NULL);
109 bool draw_arrow = !(prp2->m_bIsActive && g_bAllowShipToActive);
111 if (m_route.m_bVisible || prp2->IsShared())
RoutePointGui(*prp2).Draw(dc, canvas, &rpt2);
113 if (m_route.m_bVisible) {
115 bool b_2_on = vp.GetBBox().Contains(prp2->m_lat, prp2->m_lon);
116 bool b_1_on = vp.GetBBox().Contains(prp1->m_lat, prp1->m_lon);
119 if (b_1_on && b_2_on)
120 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp, draw_arrow,
121 m_route.m_hiliteWidth);
127 double pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 *
128 PI * vp.view_scale_ppm;
130 pow((
double)(rpt1.x - rpt2.x), 2) + pow((
double)(rpt1.y - rpt2.y), 2);
133 if (b_1_on && !b_2_on) {
135 adder = (int)pix_full_circle;
137 adder = -(int)pix_full_circle;
139 dtest = pow((
double)(rpt1.x - (rpt2.x + adder)), 2) +
140 pow((
double)(rpt1.y - rpt2.y), 2);
142 if (dp < dtest) adder = 0;
144 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x + adder, rpt2.y, vp,
145 draw_arrow, m_route.m_hiliteWidth);
146 }
else if (!b_1_on) {
148 adder = (int)pix_full_circle;
150 adder = -(int)pix_full_circle;
152 float rxd = rpt2.x - (rpt1.x + adder);
153 float ryd = rpt1.y - rpt2.y;
154 dtest = rxd * rxd + ryd * ryd;
156 if (dp < dtest) adder = 0;
158 RenderSegment(dc, rpt1.x + adder, rpt1.y, rpt2.x, rpt2.y, vp,
159 draw_arrow, m_route.m_hiliteWidth);
166 node = node->GetNext();
170void RouteGui::RenderSegment(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
171 ViewPort &vp,
bool bdraw_arrow,
int hilite_width) {
174 dc.GetSize(&sx, &sy);
177 wxRect r(0, 0, sx, sy);
178 wxRect s(xa, ya, 1, 1);
179 wxRect t(xb, yb, 1, 1);
181 if (!r.Intersects(s))
return;
194 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy)) {
195 wxPen psave = dc.GetPen();
197 wxColour y = GetGlobalColor(_T (
"YELO1" ));
198 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
200 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
203 dc.StrokeLine(x0, y0, x1, y1);
206 dc.StrokeLine(x0, y0, x1, y1);
210 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy))
211 dc.StrokeLine(x0, y0, x1, y1);
217 double theta = atan2((
double)(yb - ya), (
double)(xb - xa));
221 double icon_scale_factor = 100 * vp.view_scale_ppm;
222 icon_scale_factor = fmin(icon_scale_factor, 1.5);
223 icon_scale_factor = fmax(icon_scale_factor, .10);
227 double nom_arrow_size = 20.;
228 double max_arrow_to_leg = .20;
229 double lpp = sqrt(pow((
double)(xa - xb), 2) + pow((
double)(ya - yb), 2));
231 double icon_size = icon_scale_factor * nom_arrow_size;
232 if (icon_size > (lpp * max_arrow_to_leg))
233 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
235 for (
int i = 0; i < 7; i++) {
237 double pxa = (double)(s_arrow_icon[j]);
238 double pya = (double)(s_arrow_icon[j + 1]);
240 pya *= icon_scale_factor;
241 pxa *= icon_scale_factor;
243 double px = (pxa * sin(theta)) + (pya * cos(theta));
244 double py = (pya * sin(theta)) - (pxa * cos(theta));
246 icon[i].x = (int)(px) + xb;
247 icon[i].y = (int)(py) + yb;
249 wxPen savePen = dc.GetPen();
250 dc.SetPen(*wxTRANSPARENT_PEN);
251 dc.StrokePolygon(6, &icon[0], 0, 0);
256void RouteGui::RenderSegmentArrowsGL(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
260 float icon_scale_factor = 100 * vp.view_scale_ppm;
261 icon_scale_factor = fmin(icon_scale_factor, 1.5);
262 icon_scale_factor = fmax(icon_scale_factor, .10);
266 float nom_arrow_size = 20.;
267 float max_arrow_to_leg = (float).20;
268 float lpp = sqrtf(powf((
float)(xa - xb), 2) + powf((
float)(ya - yb), 2));
270 float icon_size = icon_scale_factor * nom_arrow_size;
271 if (icon_size > (lpp * max_arrow_to_leg))
272 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
274 float theta = atan2f((
float)yb - ya, (
float)xb - xa);
280 pts[0].x = s_arrow_icon[0];
281 pts[0].y = s_arrow_icon[1];
282 pts[1].x = s_arrow_icon[2];
283 pts[1].y = s_arrow_icon[3];
284 pts[2].x = s_arrow_icon[6];
285 pts[2].y = s_arrow_icon[7];
287 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
290 pts[0].x = s_arrow_icon[2];
291 pts[0].y = s_arrow_icon[3];
292 pts[1].x = s_arrow_icon[4];
293 pts[1].y = s_arrow_icon[5];
294 pts[2].x = s_arrow_icon[6];
295 pts[2].y = s_arrow_icon[7];
296 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
299 pts[0].x = s_arrow_icon[0];
300 pts[0].y = -s_arrow_icon[1];
301 pts[1].x = s_arrow_icon[2];
302 pts[1].y = -s_arrow_icon[3];
303 pts[2].x = s_arrow_icon[6];
304 pts[2].y = -s_arrow_icon[7];
305 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
308 pts[0].x = s_arrow_icon[2];
309 pts[0].y = -s_arrow_icon[3];
310 pts[1].x = s_arrow_icon[4];
311 pts[1].y = -s_arrow_icon[5];
312 pts[2].x = s_arrow_icon[6];
313 pts[2].y = -s_arrow_icon[7];
314 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
322 if (iPoint <= m_route.GetnPoints())
323 RoutePointGui(*m_route.GetPoint(iPoint)).Draw(dc, canvas, rpn);
327 wxPoint *rp2,
ViewPort &vp,
bool bdraw_arrow) {
328 if (m_route.m_bRtIsSelected)
329 dc.SetPen(*g_pRouteMan->GetSelectedRoutePen());
330 else if (m_route.m_bRtIsActive)
331 dc.SetPen(*g_pRouteMan->GetActiveRoutePen());
333 dc.SetPen(*g_pRouteMan->GetRoutePen());
335 RenderSegment(dc, rp1->x, rp1->y, rp2->x, rp2->y, vp, bdraw_arrow);
340 if (m_route.pRoutePointList->empty())
return;
342 if (!vp.GetBBox().IntersectOut(m_route.GetBBox()) && m_route.m_bVisible)
343 DrawGLRouteLines(vp, canvas, dc);
346 for (wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst(); node;
347 node = node->GetNext()) {
354 if (vp.GetBBox().ContainsMarge(prp->m_lat, prp->m_lon, .5)) {
355 if (m_route.m_bVisible || prp->IsShared())
RoutePointGui(*prp).DrawGL(vp, canvas, dc);
365 if (m_route.m_hiliteWidth) {
366 wxColour y = GetGlobalColor(_T (
"YELO1" ));
367 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
369 wxPen HiPen(hilt, m_route.m_hiliteWidth, wxPENSTYLE_SOLID);
373 DrawGLLines(vp, &dc, canvas);
379 int width = g_pRouteMan->GetRoutePen()->GetWidth();
380 if (m_route.m_width != wxPENSTYLE_INVALID) width = m_route.m_width;
382 if (m_route.m_bRtIsActive) {
383 col = g_pRouteMan->GetActiveRoutePen()->GetColour();
384 }
else if (m_route.m_bRtIsSelected) {
385 col = g_pRouteMan->GetSelectedRoutePen()->GetColour();
387 if (m_route.m_Colour == wxEmptyString) {
388 col = g_pRouteMan->GetRoutePen()->GetColour();
390 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
392 if (m_route.m_Colour == ::GpxxColorNames[i]) {
393 col = ::GpxxColors[i];
400 wxPenStyle style = wxPENSTYLE_SOLID;
401 if (m_route.m_style != wxPENSTYLE_INVALID) style = m_route.m_style;
402 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
403 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
405 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
409 DrawGLLines(vp, &dc, canvas);
411 glDisable(GL_LINE_STIPPLE);
414 dc.SetPen(*wxThePenList->FindOrCreatePen(col, 1, wxPENSTYLE_SOLID));
416 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
420 canvas->GetCanvasPointPix(prp->m_lat, prp->m_lon, &rpt2);
421 if (node != m_route.pRoutePointList->GetFirst()) {
422 if (!prp->m_bIsActive || !g_bAllowShipToActive)
423 RenderSegmentArrowsGL(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp);
426 node = node->GetNext();
433 float pix_full_circle =
434 WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.view_scale_ppm;
436 bool r1valid =
false;
438 wxPoint2DDouble lastpoint;
440 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
442 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &lastpoint);
445 if (m_route.GetnPoints() == 1 && dc) {
446 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &r1);
447 dc->DrawLine(r1.m_x, r1.m_y, r1.m_x + 2, r1.m_y + 2);
452 LLBBox bbox = vp.GetBBox();
456 for (node = node->GetNext(); node; node = node->GetNext()) {
458 prp2 = node->GetData();
461 prp2->m_pos_on_screen =
false;
464 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &r2);
465 if (std::isnan(r2.m_x)) {
475 bool lat1l = prp1->m_lat < bbox.GetMinLat(),
476 lat2l = prp2->m_lat < bbox.GetMinLat();
477 bool lat1r = prp1->m_lat > bbox.GetMaxLat(),
478 lat2r = prp2->m_lat > bbox.GetMaxLat();
479 if ((lat1l && lat2l) || (lat1r && lat2r)) {
481 prp1->m_pos_on_screen =
false;
485 bool lon1l, lon1r, lon2l, lon2r;
486 TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l,
488 TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l,
490 if ((lon1l && lon2l) || (lon1r && lon2r)) {
492 prp1->m_pos_on_screen =
false;
497 canvas->GetDoubleCanvasPointPix(prp1->m_lat, prp1->m_lon, &r1);
498 if (std::isnan(r1.m_x))
continue;
509 if ((vp.m_projection_type == PROJECTION_MERCATOR ||
510 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
511 float olon = vp.clon > 0 ? vp.clon - 180 : vp.clon + 180;
513 if (prp1->m_lon < prp2->m_lon) {
514 if (prp2->m_lon - prp1->m_lon < 180) {
515 if (olon > prp1->m_lon && olon < prp2->m_lon)
516 adder = pix_full_circle;
517 }
else if (olon < prp1->m_lon || olon > prp2->m_lon)
518 adder = -pix_full_circle;
519 }
else if (prp1->m_lon - prp2->m_lon < 180) {
520 if (olon < prp1->m_lon && olon > prp2->m_lon)
521 adder = -pix_full_circle;
522 }
else if (olon > prp1->m_lon || olon < prp2->m_lon)
523 adder = pix_full_circle;
528 float adderc = cos(vp.rotation) * adder,
529 adders = sin(vp.rotation) * adder;
530 dc->DrawLine(r1.m_x, r1.m_y, r2.m_x + adderc, r2.m_y + adders);
531 dc->DrawLine(r1.m_x - adderc, r1.m_y - adders, r2.m_x, r2.m_y);
533 dc->DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y);
546void RouteGui::CalculateDCRect(wxDC &dc_route,
ChartCanvas *canvas,
548 dc_route.ResetBoundingBox();
549 dc_route.DestroyClippingRegion();
557 if (m_route.m_bVisible) {
558 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
561 bool blink_save = prp2->m_bBlink;
562 prp2->m_bBlink =
false;
563 ocpnDC odc_route(dc_route);
565 prp2->m_bBlink = blink_save;
567 wxRect r = prp2->CurrentRect_in_DC;
569 r.Inflate(m_route.m_hiliteWidth, m_route.m_hiliteWidth);
571 update_rect.Union(r);
572 node = node->GetNext();
576 *prect = update_rect;
580int RouteGui::SendToGPS(
const wxString& com_name,
bool bsend_waypoints,
584 ::wxBeginBusyCursor();
585 result = SendRouteToGPS_N0183(&m_route, com_name, bsend_waypoints);
590 msg = _(
"Route Transmitted.");
592 if (result == ERR_GARMIN_INITIALIZE)
593 msg = _(
"Error on Route Upload. Garmin GPS not connected");
595 msg = _(
"Error on Route Upload. Please check logfiles...");
597 OCPNMessageBox(NULL, msg, _(
"OpenCPN Info"), wxOK | wxICON_INFORMATION);
599 return (result == 0);
Route "Send to GPS..." Dialog Definition.