45#include "dialog_alert.h"
56extern wxColor GetDimColor(wxColor c);
58static int s_arrow_icon[] = {0, 0, 5, 2, 18, 6, 12, 0, 18, -6, 5, -2, 0, 0};
60static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
62 double clon = (min + max) / 2;
63 if (min - lon > 180) lon += 360;
71 }
else if (lon > max) {
84 LLBBox test_box = m_route.GetBBox();
85 if (box.IntersectOut(test_box))
88 int width = g_route_line_width;
96 }
else if (m_route.m_bVisible) {
97 wxPenStyle style = wxPENSTYLE_SOLID;
99 if (m_route.
m_style != wxPENSTYLE_INVALID) style = m_route.
m_style;
103 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
105 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
106 col = ::GpxxColors[i];
111 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
112 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
117 spen.SetWidth(width);
123 if (m_route.m_bVisible) DrawPointWhich(dc, canvas, 1, &rpt1);
128 if (m_route.m_bVisible || prp1->IsShared())
135 bool draw_arrow = !(prp2->
m_bIsActive && g_bAllowShipToActive);
137 if (m_route.m_bVisible || prp2->IsShared())
141 if (m_route.m_bVisible) {
143 bool b_2_on = vp.GetBBox().Contains(prp2->m_lat, prp2->m_lon);
144 bool b_1_on = vp.GetBBox().Contains(prp1->m_lat, prp1->m_lon);
147 if (b_1_on && b_2_on)
148 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp, draw_arrow,
155 double pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 *
158 pow((
double)(rpt1.x - rpt2.x), 2) + pow((
double)(rpt1.y - rpt2.y), 2);
161 if (b_1_on && !b_2_on) {
163 adder = (int)pix_full_circle;
165 adder = -(int)pix_full_circle;
167 dtest = pow((
double)(rpt1.x - (rpt2.x + adder)), 2) +
168 pow((
double)(rpt1.y - rpt2.y), 2);
170 if (dp < dtest) adder = 0;
172 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x + adder, rpt2.y, vp,
174 }
else if (!b_1_on) {
176 adder = (int)pix_full_circle;
178 adder = -(int)pix_full_circle;
180 float rxd = rpt2.x - (rpt1.x + adder);
181 float ryd = rpt1.y - rpt2.y;
182 dtest = rxd * rxd + ryd * ryd;
184 if (dp < dtest) adder = 0;
186 RenderSegment(dc, rpt1.x + adder, rpt1.y, rpt2.x, rpt2.y, vp,
196void RouteGui::RenderSegment(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
197 ViewPort &vp,
bool bdraw_arrow,
int hilite_width) {
200 dc.GetSize(&sx, &sy);
203 wxRect r(0, 0, sx, sy);
204 wxRect s(xa, ya, 1, 1);
205 wxRect t(xb, yb, 1, 1);
207 if (!r.Intersects(s))
return;
220 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy)) {
221 wxPen psave = dc.GetPen();
223 wxColour y = GetGlobalColor(
"YELO1");
224 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
226 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
229 dc.StrokeLine(x0, y0, x1, y1);
232 dc.StrokeLine(x0, y0, x1, y1);
236 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy))
237 dc.StrokeLine(x0, y0, x1, y1);
243 double theta = atan2((
double)(yb - ya), (
double)(xb - xa));
248 icon_scale_factor = fmin(icon_scale_factor, 1.5);
249 icon_scale_factor = fmax(icon_scale_factor, .10);
253 double nom_arrow_size = 20.;
254 double max_arrow_to_leg = .20;
255 double lpp = sqrt(pow((
double)(xa - xb), 2) + pow((
double)(ya - yb), 2));
257 double icon_size = icon_scale_factor * nom_arrow_size;
258 if (icon_size > (lpp * max_arrow_to_leg))
259 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
261 for (
int i = 0; i < 7; i++) {
263 double pxa = (double)(s_arrow_icon[j]);
264 double pya = (double)(s_arrow_icon[j + 1]);
266 pya *= icon_scale_factor;
267 pxa *= icon_scale_factor;
269 double px = (pxa * sin(theta)) + (pya * cos(theta));
270 double py = (pya * sin(theta)) - (pxa * cos(theta));
272 icon[i].x = (int)(px) + xb;
273 icon[i].y = (int)(py) + yb;
275 wxPen savePen = dc.GetPen();
276 dc.SetPen(*wxTRANSPARENT_PEN);
277 dc.StrokePolygon(6, &icon[0], 0, 0);
282void RouteGui::RenderSegmentArrowsGL(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
287 icon_scale_factor = fmin(icon_scale_factor, 1.5);
288 icon_scale_factor = fmax(icon_scale_factor, .10);
292 float nom_arrow_size = 20.;
293 float max_arrow_to_leg = (float).20;
294 float lpp = sqrtf(powf((
float)(xa - xb), 2) + powf((
float)(ya - yb), 2));
296 float icon_size = icon_scale_factor * nom_arrow_size;
297 if (icon_size > (lpp * max_arrow_to_leg))
298 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
300 float theta = atan2f((
float)yb - ya, (
float)xb - xa);
306 pts[0].x = s_arrow_icon[0];
307 pts[0].y = s_arrow_icon[1];
308 pts[1].x = s_arrow_icon[2];
309 pts[1].y = s_arrow_icon[3];
310 pts[2].x = s_arrow_icon[6];
311 pts[2].y = s_arrow_icon[7];
313 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
316 pts[0].x = s_arrow_icon[2];
317 pts[0].y = s_arrow_icon[3];
318 pts[1].x = s_arrow_icon[4];
319 pts[1].y = s_arrow_icon[5];
320 pts[2].x = s_arrow_icon[6];
321 pts[2].y = s_arrow_icon[7];
322 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
325 pts[0].x = s_arrow_icon[0];
326 pts[0].y = -s_arrow_icon[1];
327 pts[1].x = s_arrow_icon[2];
328 pts[1].y = -s_arrow_icon[3];
329 pts[2].x = s_arrow_icon[6];
330 pts[2].y = -s_arrow_icon[7];
331 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
334 pts[0].x = s_arrow_icon[2];
335 pts[0].y = -s_arrow_icon[3];
336 pts[1].x = s_arrow_icon[4];
337 pts[1].y = -s_arrow_icon[5];
338 pts[2].x = s_arrow_icon[6];
339 pts[2].y = -s_arrow_icon[7];
340 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
347 if (iPoint <= m_route.GetnPoints())
348 RoutePointGui(*m_route.GetPoint(iPoint)).Draw(dc, canvas, rpn);
352 wxPoint *rp2,
ViewPort &vp,
bool bdraw_arrow) {
360 RenderSegment(dc, rp1->x, rp1->y, rp2->x, rp2->y, vp, bdraw_arrow);
367 if (!vp.GetBBox().IntersectOut(m_route.GetBBox()) && m_route.m_bVisible)
368 DrawGLRouteLines(vp, canvas, dc);
371 for (
RoutePoint *prp : *m_route.pRoutePointList) {
377 if (vp.GetBBox().ContainsMarge(prp->m_lat, prp->m_lon, .5)) {
378 if (m_route.m_bVisible || prp->IsShared())
390 wxColour y = GetGlobalColor(
"YELO1");
391 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
397 DrawGLLines(vp, &dc, canvas);
403 int width =
g_pRouteMan->GetRoutePen()->GetWidth();
404 if (m_route.
m_width != wxPENSTYLE_INVALID) width = m_route.
m_width;
407 col =
g_pRouteMan->GetActiveRoutePen()->GetColour();
409 col =
g_pRouteMan->GetSelectedRoutePen()->GetColour();
414 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
416 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
417 col = ::GpxxColors[i];
424 wxPenStyle style = wxPENSTYLE_SOLID;
425 if (m_route.
m_style != wxPENSTYLE_INVALID) style = m_route.
m_style;
426 wxPen p = *wxThePenList->FindOrCreatePen(col, width, style);
427 if (glChartCanvas::dash_map.find(style) != glChartCanvas::dash_map.end()) {
428 p.SetDashes(2, &glChartCanvas::dash_map[style][0]);
431 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
433 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
437 DrawGLLines(vp, &dc, canvas);
439 glDisable(GL_LINE_STIPPLE);
442 dc.SetPen(*wxThePenList->FindOrCreatePen(col, 1, wxPENSTYLE_SOLID));
451 RenderSegmentArrowsGL(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp);
461 float pix_full_circle =
462 WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.
view_scale_ppm;
464 bool r1valid =
false;
466 wxPoint2DDouble lastpoint;
473 if (m_route.GetnPoints() == 1 && dc) {
475 dc->
DrawLine(r1.m_x, r1.m_y, r1.m_x + 2, r1.m_y + 2);
480 LLBBox bbox = vp.GetBBox();
493 if (std::isnan(r2.m_x)) {
503 bool lat1l = prp1->m_lat < bbox.GetMinLat(),
504 lat2l = prp2->m_lat < bbox.GetMinLat();
505 bool lat1r = prp1->m_lat > bbox.GetMaxLat(),
506 lat2r = prp2->m_lat > bbox.GetMaxLat();
507 if ((lat1l && lat2l) || (lat1r && lat2r)) {
514 if (!vp.ContainsIDL()) {
515 bool lon1l, lon1r, lon2l, lon2r;
516 TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l,
518 TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l,
520 if ((lon1l && lon2l) || (lon1r && lon2r)) {
529 if (std::isnan(r1.m_x))
continue;
540 if ((vp.m_projection_type == PROJECTION_MERCATOR ||
541 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
542 float olon = vp.
clon > 0 ? vp.
clon - 180 : vp.
clon + 180;
544 if (prp1->m_lon < prp2->m_lon) {
545 if (prp2->m_lon - prp1->m_lon < 180) {
546 if (olon > prp1->m_lon && olon < prp2->m_lon)
547 adder = pix_full_circle;
548 }
else if (olon < prp1->m_lon || olon > prp2->m_lon)
549 adder = -pix_full_circle;
550 }
else if (prp1->m_lon - prp2->m_lon < 180) {
551 if (olon < prp1->m_lon && olon > prp2->m_lon)
552 adder = -pix_full_circle;
553 }
else if (olon > prp1->m_lon || olon < prp2->m_lon)
554 adder = pix_full_circle;
559 float adderc = cos(vp.
rotation) * adder,
561 dc->
DrawLine(r1.m_x, r1.m_y, r2.m_x + adderc, r2.m_y + adders);
562 dc->
DrawLine(r1.m_x - adderc, r1.m_y - adders, r2.m_x, r2.m_y);
564 dc->
DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y);
576void RouteGui::CalculateDCRect(wxDC &dc_route,
ChartCanvas *canvas,
578 dc_route.ResetBoundingBox();
579 dc_route.DestroyClippingRegion();
587 if (m_route.m_bVisible) {
588 for (
RoutePoint *prp2 : *m_route.pRoutePointList) {
591 ocpnDC odc_route(dc_route);
592 odc_route.SetVP(canvas->GetVP());
600 update_rect.Union(r);
604 *prect = update_rect;
607int RouteGui::SendToGPS(
const wxString &com_name,
bool bsend_waypoints,
612 ::wxBeginBusyCursor();
613 result = SendRouteToGPS_N0183(&m_route, com_name, bsend_waypoints, *g_pMUX,
619 msg = _(
"Route Transmitted.");
623 msg = _(
"Error on Route Upload. Garmin GPS not connected");
626 msg = _(
"Error on Route Upload. GPS driver not available");
630 msg = _(
"Error on Route Upload. Please check logfiles...");
634 OCPNMessageBox(NULL, msg, _(
"OpenCPN Info"), wxOK | wxICON_INFORMATION);
636 return (result == 0);
640bool RouteGui::OnDelete(wxWindow *parent,
const int count) {
641 std::string title = _(
"Route Delete").ToStdString();
642 std::string action = _(
"Delete").ToStdString();
645 wxString str = wxString::Format(
646 _(
"Are you sure you want to delete %d routes?"), count);
649 msg = _(
"Are you sure you want to delete this route?").ToStdString();
653 dialog.SetMessage(msg);
654 int result = dialog.ShowModal();
655 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.