35#include "dialog_alert.h"
37#include "color_handler.h"
39#include "model/comm_n0183_output.h"
40#include "model/georef.h"
42#include "model/multiplexer.h"
43#include "n0183_ctx_factory.h"
45#include "model/own_ship.h"
46#include "model/routeman.h"
48#include "route_point_gui.h"
49#include "glChartCanvas.h"
51#include "model/route.h"
54extern wxColour g_colourTrackLineColour;
57extern wxColor GetDimColor(wxColor c);
58extern bool g_bHighliteTracks;
62extern int s_arrow_icon[];
64static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
66 double clon = (min + max) / 2;
67 if (min - lon > 180) lon += 360;
75 }
else if (lon > max) {
88 LLBBox test_box = m_route.GetBBox();
89 if (box.IntersectOut(test_box))
92 int width = g_route_line_width;
96 wxPen spen = *g_pRouteMan->GetSelectedRoutePen();
99 dc.SetBrush(*g_pRouteMan->GetSelectedRouteBrush());
100 }
else if (m_route.m_bVisible) {
101 wxPenStyle style = wxPENSTYLE_SOLID;
103 if (m_route.
m_style != wxPENSTYLE_INVALID) style = m_route.
m_style;
104 if (m_route.
m_Colour == wxEmptyString) {
105 col = g_pRouteMan->GetRoutePen()->GetColour();
107 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
109 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
110 col = ::GpxxColors[i];
115 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
116 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
120 wxPen spen = *g_pRouteMan->GetActiveRoutePen();
121 spen.SetWidth(width);
123 dc.SetBrush(*g_pRouteMan->GetActiveRouteBrush());
127 if (m_route.m_bVisible) DrawPointWhich(dc, canvas, 1, &rpt1);
131 node = node->GetNext();
133 if (m_route.m_bVisible || prp1->IsShared())
140 bool draw_arrow = !(prp2->
m_bIsActive && g_bAllowShipToActive);
142 if (m_route.m_bVisible || prp2->IsShared())
146 if (m_route.m_bVisible) {
148 bool b_2_on = vp.GetBBox().Contains(prp2->m_lat, prp2->m_lon);
149 bool b_1_on = vp.GetBBox().Contains(prp1->m_lat, prp1->m_lon);
152 if (b_1_on && b_2_on)
153 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp, draw_arrow,
160 double pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 *
163 pow((
double)(rpt1.x - rpt2.x), 2) + pow((
double)(rpt1.y - rpt2.y), 2);
166 if (b_1_on && !b_2_on) {
168 adder = (int)pix_full_circle;
170 adder = -(int)pix_full_circle;
172 dtest = pow((
double)(rpt1.x - (rpt2.x + adder)), 2) +
173 pow((
double)(rpt1.y - rpt2.y), 2);
175 if (dp < dtest) adder = 0;
177 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x + adder, rpt2.y, vp,
179 }
else if (!b_1_on) {
181 adder = (int)pix_full_circle;
183 adder = -(int)pix_full_circle;
185 float rxd = rpt2.x - (rpt1.x + adder);
186 float ryd = rpt1.y - rpt2.y;
187 dtest = rxd * rxd + ryd * ryd;
189 if (dp < dtest) adder = 0;
191 RenderSegment(dc, rpt1.x + adder, rpt1.y, rpt2.x, rpt2.y, vp,
199 node = node->GetNext();
203void RouteGui::RenderSegment(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
204 ViewPort &vp,
bool bdraw_arrow,
int hilite_width) {
207 dc.GetSize(&sx, &sy);
210 wxRect r(0, 0, sx, sy);
211 wxRect s(xa, ya, 1, 1);
212 wxRect t(xb, yb, 1, 1);
214 if (!r.Intersects(s))
return;
227 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy)) {
228 wxPen psave = dc.GetPen();
230 wxColour y = GetGlobalColor(_T (
"YELO1" ));
231 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
233 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
236 dc.StrokeLine(x0, y0, x1, y1);
239 dc.StrokeLine(x0, y0, x1, y1);
243 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy))
244 dc.StrokeLine(x0, y0, x1, y1);
250 double theta = atan2((
double)(yb - ya), (
double)(xb - xa));
255 icon_scale_factor = fmin(icon_scale_factor, 1.5);
256 icon_scale_factor = fmax(icon_scale_factor, .10);
260 double nom_arrow_size = 20.;
261 double max_arrow_to_leg = .20;
262 double lpp = sqrt(pow((
double)(xa - xb), 2) + pow((
double)(ya - yb), 2));
264 double icon_size = icon_scale_factor * nom_arrow_size;
265 if (icon_size > (lpp * max_arrow_to_leg))
266 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
268 for (
int i = 0; i < 7; i++) {
270 double pxa = (double)(s_arrow_icon[j]);
271 double pya = (double)(s_arrow_icon[j + 1]);
273 pya *= icon_scale_factor;
274 pxa *= icon_scale_factor;
276 double px = (pxa * sin(theta)) + (pya * cos(theta));
277 double py = (pya * sin(theta)) - (pxa * cos(theta));
279 icon[i].x = (int)(px) + xb;
280 icon[i].y = (int)(py) + yb;
282 wxPen savePen = dc.GetPen();
283 dc.SetPen(*wxTRANSPARENT_PEN);
284 dc.StrokePolygon(6, &icon[0], 0, 0);
289void RouteGui::RenderSegmentArrowsGL(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
294 icon_scale_factor = fmin(icon_scale_factor, 1.5);
295 icon_scale_factor = fmax(icon_scale_factor, .10);
299 float nom_arrow_size = 20.;
300 float max_arrow_to_leg = (float).20;
301 float lpp = sqrtf(powf((
float)(xa - xb), 2) + powf((
float)(ya - yb), 2));
303 float icon_size = icon_scale_factor * nom_arrow_size;
304 if (icon_size > (lpp * max_arrow_to_leg))
305 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
307 float theta = atan2f((
float)yb - ya, (
float)xb - xa);
313 pts[0].x = s_arrow_icon[0];
314 pts[0].y = s_arrow_icon[1];
315 pts[1].x = s_arrow_icon[2];
316 pts[1].y = s_arrow_icon[3];
317 pts[2].x = s_arrow_icon[6];
318 pts[2].y = s_arrow_icon[7];
320 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
323 pts[0].x = s_arrow_icon[2];
324 pts[0].y = s_arrow_icon[3];
325 pts[1].x = s_arrow_icon[4];
326 pts[1].y = s_arrow_icon[5];
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);
332 pts[0].x = s_arrow_icon[0];
333 pts[0].y = -s_arrow_icon[1];
334 pts[1].x = s_arrow_icon[2];
335 pts[1].y = -s_arrow_icon[3];
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);
341 pts[0].x = s_arrow_icon[2];
342 pts[0].y = -s_arrow_icon[3];
343 pts[1].x = s_arrow_icon[4];
344 pts[1].y = -s_arrow_icon[5];
345 pts[2].x = s_arrow_icon[6];
346 pts[2].y = -s_arrow_icon[7];
347 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
354 if (iPoint <= m_route.GetnPoints())
355 RoutePointGui(*m_route.GetPoint(iPoint)).Draw(dc, canvas, rpn);
359 wxPoint *rp2,
ViewPort &vp,
bool bdraw_arrow) {
361 dc.SetPen(*g_pRouteMan->GetSelectedRoutePen());
363 dc.SetPen(*g_pRouteMan->GetActiveRoutePen());
365 dc.SetPen(*g_pRouteMan->GetRoutePen());
367 RenderSegment(dc, rp1->x, rp1->y, rp2->x, rp2->y, vp, bdraw_arrow);
374 if (!vp.GetBBox().IntersectOut(m_route.GetBBox()) && m_route.m_bVisible)
375 DrawGLRouteLines(vp, canvas, dc);
378 for (wxRoutePointListNode *node = m_route.
pRoutePointList->GetFirst(); node;
379 node = node->GetNext()) {
386 if (vp.GetBBox().ContainsMarge(prp->m_lat, prp->m_lon, .5)) {
387 if (m_route.m_bVisible || prp->IsShared())
399 wxColour y = GetGlobalColor(_T (
"YELO1" ));
400 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
406 DrawGLLines(vp, &dc, canvas);
412 int width = g_pRouteMan->GetRoutePen()->GetWidth();
413 if (m_route.
m_width != wxPENSTYLE_INVALID) width = m_route.
m_width;
416 col = g_pRouteMan->GetActiveRoutePen()->GetColour();
418 col = g_pRouteMan->GetSelectedRoutePen()->GetColour();
420 if (m_route.
m_Colour == wxEmptyString) {
421 col = g_pRouteMan->GetRoutePen()->GetColour();
423 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
425 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
426 col = ::GpxxColors[i];
433 wxPenStyle style = wxPENSTYLE_SOLID;
434 if (m_route.
m_style != wxPENSTYLE_INVALID) style = m_route.
m_style;
435 wxPen p = *wxThePenList->FindOrCreatePen(col, width, style);
436 if (glChartCanvas::dash_map.find(style) != glChartCanvas::dash_map.end()) {
437 p.SetDashes(2, &glChartCanvas::dash_map[style][0]);
440 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
442 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
446 DrawGLLines(vp, &dc, canvas);
448 glDisable(GL_LINE_STIPPLE);
451 dc.SetPen(*wxThePenList->FindOrCreatePen(col, 1, wxPENSTYLE_SOLID));
460 RenderSegmentArrowsGL(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp);
463 node = node->GetNext();
470 float pix_full_circle =
471 WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.
view_scale_ppm;
473 bool r1valid =
false;
475 wxPoint2DDouble lastpoint;
482 if (m_route.GetnPoints() == 1 && dc) {
484 dc->
DrawLine(r1.m_x, r1.m_y, r1.m_x + 2, r1.m_y + 2);
489 LLBBox bbox = vp.GetBBox();
493 for (node = node->GetNext(); node; node = node->GetNext()) {
495 prp2 = node->GetData();
502 if (std::isnan(r2.m_x)) {
512 bool lat1l = prp1->m_lat < bbox.GetMinLat(),
513 lat2l = prp2->m_lat < bbox.GetMinLat();
514 bool lat1r = prp1->m_lat > bbox.GetMaxLat(),
515 lat2r = prp2->m_lat > bbox.GetMaxLat();
516 if ((lat1l && lat2l) || (lat1r && lat2r)) {
523 if (!vp.ContainsIDL()) {
524 bool lon1l, lon1r, lon2l, lon2r;
525 TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l,
527 TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l,
529 if ((lon1l && lon2l) || (lon1r && lon2r)) {
538 if (std::isnan(r1.m_x))
continue;
549 if ((vp.m_projection_type == PROJECTION_MERCATOR ||
550 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
551 float olon = vp.
clon > 0 ? vp.
clon - 180 : vp.
clon + 180;
553 if (prp1->m_lon < prp2->m_lon) {
554 if (prp2->m_lon - prp1->m_lon < 180) {
555 if (olon > prp1->m_lon && olon < prp2->m_lon)
556 adder = pix_full_circle;
557 }
else if (olon < prp1->m_lon || olon > prp2->m_lon)
558 adder = -pix_full_circle;
559 }
else if (prp1->m_lon - prp2->m_lon < 180) {
560 if (olon < prp1->m_lon && olon > prp2->m_lon)
561 adder = -pix_full_circle;
562 }
else if (olon > prp1->m_lon || olon < prp2->m_lon)
563 adder = pix_full_circle;
568 float adderc = cos(vp.
rotation) * adder,
570 dc->
DrawLine(r1.m_x, r1.m_y, r2.m_x + adderc, r2.m_y + adders);
571 dc->
DrawLine(r1.m_x - adderc, r1.m_y - adders, r2.m_x, r2.m_y);
573 dc->
DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y);
585void RouteGui::CalculateDCRect(wxDC &dc_route,
ChartCanvas *canvas,
587 dc_route.ResetBoundingBox();
588 dc_route.DestroyClippingRegion();
596 if (m_route.m_bVisible) {
602 ocpnDC odc_route(dc_route);
603 odc_route.SetVP(canvas->GetVP());
611 update_rect.Union(r);
612 node = node->GetNext();
616 *prect = update_rect;
619int RouteGui::SendToGPS(
const wxString &com_name,
bool bsend_waypoints,
624 ::wxBeginBusyCursor();
625 result = SendRouteToGPS_N0183(&m_route, com_name, bsend_waypoints, *g_pMUX,
631 msg = _(
"Route Transmitted.");
634 case ERR_GARMIN_INITIALIZE:
635 msg = _(
"Error on Route Upload. Garmin GPS not connected");
637 case ERR_GPS_DRIVER_NOT_AVAILAIBLE:
638 msg = _(
"Error on Route Upload. GPS driver not available");
640 case ERR_GARMIN_SEND_MESSAGE:
642 msg = _(
"Error on Route Upload. Please check logfiles...");
646 OCPNMessageBox(NULL, msg, _(
"OpenCPN Info"), wxOK | wxICON_INFORMATION);
648 return (result == 0);
652bool RouteGui::OnDelete(wxWindow *parent,
const int count) {
653 std::string title = _(
"Route Delete").ToStdString();
654 std::string action = _(
"Delete").ToStdString();
657 wxString str = wxString::Format(
658 _(
"Are you sure you want to delete %d routes?"), count);
661 msg = _(
"Are you sure you want to delete this route?").ToStdString();
665 dialog.SetMessage(msg);
666 int result = dialog.ShowModal();
667 return result == wxID_OK;
A modal message dialog with confirmation button and cancel button.
ChartCanvas - Main chart display and interaction component.
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
Represents a waypoint or mark within the navigation system.
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.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
wxString m_Colour
Color name for rendering the route on the chart.
wxPenStyle m_style
Style of the route line when rendered on the chart.
int m_width
Width of the route line in pixels when rendered on the chart.
Dialog for sending routes/waypoints to a GPS device.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double rotation
Rotation angle of the viewport in radians.
double clon
Center longitude of the viewport in degrees.
Device context class that can use either wxDC or OpenGL for drawing.
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.
General purpose GUI support.