43#include "dialog_alert.h"
54extern wxColor GetDimColor(wxColor c);
56static int s_arrow_icon[] = {0, 0, 5, 2, 18, 6, 12, 0, 18, -6, 5, -2, 0, 0};
58static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
60 double clon = (min + max) / 2;
61 if (min - lon > 180) lon += 360;
69 }
else if (lon > max) {
82 LLBBox test_box = m_route.GetBBox();
83 if (box.IntersectOut(test_box))
86 int width = g_route_line_width;
94 }
else if (m_route.m_bVisible) {
95 wxPenStyle style = wxPENSTYLE_SOLID;
97 if (m_route.
m_style != wxPENSTYLE_INVALID) style = m_route.
m_style;
101 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
103 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
104 col = ::GpxxColors[i];
109 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
110 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
115 spen.SetWidth(width);
121 if (m_route.m_bVisible) DrawPointWhich(dc, canvas, 1, &rpt1);
126 if (m_route.m_bVisible || prp1->IsShared())
133 bool draw_arrow = !(prp2->
m_bIsActive && g_bAllowShipToActive);
135 if (m_route.m_bVisible || prp2->IsShared())
139 if (m_route.m_bVisible) {
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);
145 if (b_1_on && b_2_on)
146 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp, draw_arrow,
153 double pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 *
156 pow((
double)(rpt1.x - rpt2.x), 2) + pow((
double)(rpt1.y - rpt2.y), 2);
159 if (b_1_on && !b_2_on) {
161 adder = (int)pix_full_circle;
163 adder = -(int)pix_full_circle;
165 dtest = pow((
double)(rpt1.x - (rpt2.x + adder)), 2) +
166 pow((
double)(rpt1.y - rpt2.y), 2);
168 if (dp < dtest) adder = 0;
170 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x + adder, rpt2.y, vp,
172 }
else if (!b_1_on) {
174 adder = (int)pix_full_circle;
176 adder = -(int)pix_full_circle;
178 float rxd = rpt2.x - (rpt1.x + adder);
179 float ryd = rpt1.y - rpt2.y;
180 dtest = rxd * rxd + ryd * ryd;
182 if (dp < dtest) adder = 0;
184 RenderSegment(dc, rpt1.x + adder, rpt1.y, rpt2.x, rpt2.y, vp,
194void RouteGui::RenderSegment(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
195 ViewPort &vp,
bool bdraw_arrow,
int hilite_width) {
198 dc.GetSize(&sx, &sy);
201 wxRect r(0, 0, sx, sy);
202 wxRect s(xa, ya, 1, 1);
203 wxRect t(xb, yb, 1, 1);
205 if (!r.Intersects(s))
return;
218 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy)) {
219 wxPen psave = dc.GetPen();
221 wxColour y = GetGlobalColor(
"YELO1");
222 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
224 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
227 dc.StrokeLine(x0, y0, x1, y1);
230 dc.StrokeLine(x0, y0, x1, y1);
234 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy))
235 dc.StrokeLine(x0, y0, x1, y1);
241 double theta = atan2((
double)(yb - ya), (
double)(xb - xa));
246 icon_scale_factor = fmin(icon_scale_factor, 1.5);
247 icon_scale_factor = fmax(icon_scale_factor, .10);
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));
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;
259 for (
int i = 0; i < 7; i++) {
261 double pxa = (double)(s_arrow_icon[j]);
262 double pya = (double)(s_arrow_icon[j + 1]);
264 pya *= icon_scale_factor;
265 pxa *= icon_scale_factor;
267 double px = (pxa * sin(theta)) + (pya * cos(theta));
268 double py = (pya * sin(theta)) - (pxa * cos(theta));
270 icon[i].x = (int)(px) + xb;
271 icon[i].y = (int)(py) + yb;
273 wxPen savePen = dc.GetPen();
274 dc.SetPen(*wxTRANSPARENT_PEN);
275 dc.StrokePolygon(6, &icon[0], 0, 0);
280void RouteGui::RenderSegmentArrowsGL(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
285 icon_scale_factor = fmin(icon_scale_factor, 1.5);
286 icon_scale_factor = fmax(icon_scale_factor, .10);
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));
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;
298 float theta = atan2f((
float)yb - ya, (
float)xb - xa);
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];
311 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
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);
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);
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);
345 if (iPoint <= m_route.GetnPoints())
346 RoutePointGui(*m_route.GetPoint(iPoint)).Draw(dc, canvas, rpn);
350 wxPoint *rp2,
ViewPort &vp,
bool bdraw_arrow) {
358 RenderSegment(dc, rp1->x, rp1->y, rp2->x, rp2->y, vp, bdraw_arrow);
365 if (!vp.GetBBox().IntersectOut(m_route.GetBBox()) && m_route.m_bVisible)
366 DrawGLRouteLines(vp, canvas, dc);
369 for (
RoutePoint *prp : *m_route.pRoutePointList) {
375 if (vp.GetBBox().ContainsMarge(prp->m_lat, prp->m_lon, .5)) {
376 if (m_route.m_bVisible || prp->IsShared())
388 wxColour y = GetGlobalColor(
"YELO1");
389 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
395 DrawGLLines(vp, &dc, canvas);
401 int width =
g_pRouteMan->GetRoutePen()->GetWidth();
402 if (m_route.
m_width != wxPENSTYLE_INVALID) width = m_route.
m_width;
405 col =
g_pRouteMan->GetActiveRoutePen()->GetColour();
407 col =
g_pRouteMan->GetSelectedRoutePen()->GetColour();
412 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
414 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
415 col = ::GpxxColors[i];
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]);
429 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
431 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
435 DrawGLLines(vp, &dc, canvas);
437 glDisable(GL_LINE_STIPPLE);
440 dc.SetPen(*wxThePenList->FindOrCreatePen(col, 1, wxPENSTYLE_SOLID));
449 RenderSegmentArrowsGL(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp);
459 float pix_full_circle =
460 WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.
view_scale_ppm;
462 bool r1valid =
false;
464 wxPoint2DDouble lastpoint;
471 if (m_route.GetnPoints() == 1 && dc) {
473 dc->
DrawLine(r1.m_x, r1.m_y, r1.m_x + 2, r1.m_y + 2);
478 LLBBox bbox = vp.GetBBox();
491 if (std::isnan(r2.m_x)) {
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)) {
512 if (!vp.ContainsIDL()) {
513 bool lon1l, lon1r, lon2l, lon2r;
514 TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l,
516 TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l,
518 if ((lon1l && lon2l) || (lon1r && lon2r)) {
527 if (std::isnan(r1.m_x))
continue;
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;
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;
557 float adderc = cos(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);
562 dc->
DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y);
574void RouteGui::CalculateDCRect(wxDC &dc_route,
ChartCanvas *canvas,
576 dc_route.ResetBoundingBox();
577 dc_route.DestroyClippingRegion();
585 if (m_route.m_bVisible) {
586 for (
RoutePoint *prp2 : *m_route.pRoutePointList) {
589 ocpnDC odc_route(dc_route);
590 odc_route.SetVP(canvas->GetVP());
598 update_rect.Union(r);
602 *prect = update_rect;
605int RouteGui::SendToGPS(
const wxString &com_name,
bool bsend_waypoints,
610 ::wxBeginBusyCursor();
611 result = SendRouteToGPS_N0183(&m_route, com_name, bsend_waypoints, *g_pMUX,
617 msg = _(
"Route Transmitted.");
621 msg = _(
"Error on Route Upload. Garmin GPS not connected");
624 msg = _(
"Error on Route Upload. GPS driver not available");
628 msg = _(
"Error on Route Upload. Please check logfiles...");
632 OCPNMessageBox(NULL, msg, _(
"OpenCPN Info"), wxOK | wxICON_INFORMATION);
634 return (result == 0);
638bool RouteGui::OnDelete(wxWindow *parent,
const int count) {
639 std::string title = _(
"Route Delete").ToStdString();
640 std::string action = _(
"Delete").ToStdString();
643 wxString str = wxString::Format(
644 _(
"Are you sure you want to delete %d routes?"), count);
647 msg = _(
"Are you sure you want to delete this route?").ToStdString();
651 dialog.SetMessage(msg);
652 int result = dialog.ShowModal();
653 return result == wxID_OK;
General chart base definitions.
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.
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.
OpenGL chart rendering canvas.
General purpose GUI support.
Multiplexer class and helpers.
Wrapper creating a N0183DlgCtx based on a SendToGpsDlg instance.
Position, course, speed, etc.
Purpose: Track and Trackpoint drawing stuff.
Routeman * g_pRouteMan
Global instance.