9 #include "color_handler.h"
10 #include "chartbase.h"
11 #include "model/comm_n0183_output.h"
12 #include "model/georef.h"
14 #include "model/multiplexer.h"
15 #include "n0183_ctx_factory.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"
26 extern wxColour g_colourTrackLineColour;
29 extern wxColor GetDimColor(wxColor c);
30 extern bool g_bHighliteTracks;
34 extern int s_arrow_icon[];
36 static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
38 double clon = (min + max) / 2;
39 if (min - lon > 180) lon += 360;
47 }
else if (lon > max) {
56 if (m_route.pRoutePointList->empty())
return;
60 LLBBox test_box = m_route.GetBBox();
61 if (box.IntersectOut(test_box))
64 int width = g_route_line_width;
65 if (m_route.m_width != WIDTH_UNDEFINED) width = m_route.m_width;
67 if (m_route.m_bVisible && m_route.m_bRtIsSelected) {
68 wxPen spen = *g_pRouteMan->GetSelectedRoutePen();
71 dc.SetBrush(*g_pRouteMan->GetSelectedRouteBrush());
72 }
else if (m_route.m_bVisible) {
73 wxPenStyle style = wxPENSTYLE_SOLID;
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();
79 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
81 if (m_route.m_Colour == ::GpxxColorNames[i]) {
82 col = ::GpxxColors[i];
87 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
88 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
91 if (m_route.m_bVisible && m_route.m_bRtIsActive) {
92 wxPen spen = *g_pRouteMan->GetActiveRoutePen();
95 dc.SetBrush(*g_pRouteMan->GetActiveRouteBrush());
99 if (m_route.m_bVisible) DrawPointWhich(dc, canvas, 1, &rpt1);
101 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
103 node = node->GetNext();
105 if (m_route.m_bVisible || prp1->IsShared())
RoutePointGui(*prp1).Draw(dc, canvas, NULL);
110 bool draw_arrow = !(prp2->m_bIsActive && g_bAllowShipToActive);
112 if (m_route.m_bVisible || prp2->IsShared())
RoutePointGui(*prp2).Draw(dc, canvas, &rpt2);
114 if (m_route.m_bVisible) {
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);
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);
128 double pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 *
129 PI * vp.view_scale_ppm;
131 pow((
double)(rpt1.x - rpt2.x), 2) + pow((
double)(rpt1.y - rpt2.y), 2);
134 if (b_1_on && !b_2_on) {
136 adder = (int)pix_full_circle;
138 adder = -(int)pix_full_circle;
140 dtest = pow((
double)(rpt1.x - (rpt2.x + adder)), 2) +
141 pow((
double)(rpt1.y - rpt2.y), 2);
143 if (dp < dtest) adder = 0;
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) {
149 adder = (int)pix_full_circle;
151 adder = -(int)pix_full_circle;
153 float rxd = rpt2.x - (rpt1.x + adder);
154 float ryd = rpt1.y - rpt2.y;
155 dtest = rxd * rxd + ryd * ryd;
157 if (dp < dtest) adder = 0;
159 RenderSegment(dc, rpt1.x + adder, rpt1.y, rpt2.x, rpt2.y, vp,
160 draw_arrow, m_route.m_hiliteWidth);
167 node = node->GetNext();
171 void RouteGui::RenderSegment(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
172 ViewPort &vp,
bool bdraw_arrow,
int hilite_width) {
175 dc.GetSize(&sx, &sy);
178 wxRect r(0, 0, sx, sy);
179 wxRect s(xa, ya, 1, 1);
180 wxRect t(xb, yb, 1, 1);
182 if (!r.Intersects(s))
return;
195 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy)) {
196 wxPen psave = dc.GetPen();
198 wxColour y = GetGlobalColor(_T (
"YELO1" ));
199 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
201 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
204 dc.StrokeLine(x0, y0, x1, y1);
207 dc.StrokeLine(x0, y0, x1, y1);
211 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy))
212 dc.StrokeLine(x0, y0, x1, y1);
218 double theta = atan2((
double)(yb - ya), (
double)(xb - xa));
222 double icon_scale_factor = 100 * vp.view_scale_ppm;
223 icon_scale_factor = fmin(icon_scale_factor, 1.5);
224 icon_scale_factor = fmax(icon_scale_factor, .10);
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));
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;
236 for (
int i = 0; i < 7; i++) {
238 double pxa = (double)(s_arrow_icon[j]);
239 double pya = (double)(s_arrow_icon[j + 1]);
241 pya *= icon_scale_factor;
242 pxa *= icon_scale_factor;
244 double px = (pxa * sin(theta)) + (pya * cos(theta));
245 double py = (pya * sin(theta)) - (pxa * cos(theta));
247 icon[i].x = (int)(px) + xb;
248 icon[i].y = (int)(py) + yb;
250 wxPen savePen = dc.GetPen();
251 dc.SetPen(*wxTRANSPARENT_PEN);
252 dc.StrokePolygon(6, &icon[0], 0, 0);
257 void RouteGui::RenderSegmentArrowsGL(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
261 float icon_scale_factor = 100 * vp.view_scale_ppm;
262 icon_scale_factor = fmin(icon_scale_factor, 1.5);
263 icon_scale_factor = fmax(icon_scale_factor, .10);
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));
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;
275 float theta = atan2f((
float)yb - ya, (
float)xb - xa);
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];
288 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
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);
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);
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);
323 if (iPoint <= m_route.GetnPoints())
324 RoutePointGui(*m_route.GetPoint(iPoint)).Draw(dc, canvas, rpn);
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());
334 dc.SetPen(*g_pRouteMan->GetRoutePen());
336 RenderSegment(dc, rp1->x, rp1->y, rp2->x, rp2->y, vp, bdraw_arrow);
341 if (m_route.pRoutePointList->empty())
return;
343 if (!vp.GetBBox().IntersectOut(m_route.GetBBox()) && m_route.m_bVisible)
344 DrawGLRouteLines(vp, canvas, dc);
347 for (wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst(); node;
348 node = node->GetNext()) {
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);
366 if (m_route.m_hiliteWidth) {
367 wxColour y = GetGlobalColor(_T (
"YELO1" ));
368 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
370 wxPen HiPen(hilt, m_route.m_hiliteWidth, wxPENSTYLE_SOLID);
374 DrawGLLines(vp, &dc, canvas);
380 int width = g_pRouteMan->GetRoutePen()->GetWidth();
381 if (m_route.m_width != wxPENSTYLE_INVALID) width = m_route.m_width;
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();
388 if (m_route.m_Colour == wxEmptyString) {
389 col = g_pRouteMan->GetRoutePen()->GetColour();
391 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
393 if (m_route.m_Colour == ::GpxxColorNames[i]) {
394 col = ::GpxxColors[i];
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]);
408 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
410 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
414 DrawGLLines(vp, &dc, canvas);
416 glDisable(GL_LINE_STIPPLE);
419 dc.SetPen(*wxThePenList->FindOrCreatePen(col, 1, wxPENSTYLE_SOLID));
421 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
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);
431 node = node->GetNext();
438 float pix_full_circle =
439 WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.view_scale_ppm;
441 bool r1valid =
false;
443 wxPoint2DDouble lastpoint;
445 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
447 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &lastpoint);
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);
457 LLBBox bbox = vp.GetBBox();
461 for (node = node->GetNext(); node; node = node->GetNext()) {
463 prp2 = node->GetData();
466 prp2->m_pos_on_screen =
false;
469 canvas->GetDoubleCanvasPointPix(prp2->m_lat, prp2->m_lon, &r2);
470 if (std::isnan(r2.m_x)) {
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)) {
486 prp1->m_pos_on_screen =
false;
491 if (!vp.ContainsIDL()) {
492 bool lon1l, lon1r, lon2l, lon2r;
493 TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l,
495 TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l,
497 if ((lon1l && lon2l) || (lon1r && lon2r)) {
499 prp1->m_pos_on_screen =
false;
506 canvas->GetDoubleCanvasPointPix(prp1->m_lat, prp1->m_lon, &r1);
507 if (std::isnan(r1.m_x))
continue;
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;
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;
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);
542 dc->DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y);
555 void RouteGui::CalculateDCRect(wxDC &dc_route,
ChartCanvas *canvas,
557 dc_route.ResetBoundingBox();
558 dc_route.DestroyClippingRegion();
566 if (m_route.m_bVisible) {
567 wxRoutePointListNode *node = m_route.pRoutePointList->GetFirst();
570 bool blink_save = prp2->m_bBlink;
571 prp2->m_bBlink =
false;
572 ocpnDC odc_route(dc_route);
573 odc_route.SetVP(canvas->GetVP());
575 prp2->m_bBlink = blink_save;
577 wxRect r = prp2->CurrentRect_in_DC;
579 r.Inflate(m_route.m_hiliteWidth, m_route.m_hiliteWidth);
581 update_rect.Union(r);
582 node = node->GetNext();
586 *prect = update_rect;
589 int RouteGui::SendToGPS(
const wxString& com_name,
bool bsend_waypoints,
594 ::wxBeginBusyCursor();
595 result = SendRouteToGPS_N0183(&m_route, com_name, bsend_waypoints, *g_pMUX,
601 msg = _(
"Route Transmitted.");
603 if (result == ERR_GARMIN_INITIALIZE)
604 msg = _(
"Error on Route Upload. Garmin GPS not connected");
606 msg = _(
"Error on Route Upload. Please check logfiles...");
608 OCPNMessageBox(NULL, msg, _(
"OpenCPN Info"), wxOK | wxICON_INFORMATION);
610 return (result == 0);
Route "Send to GPS..." Dialog Definition.
General purpose GUI support.