55extern wxColor GetDimColor(wxColor c);
57static int s_arrow_icon[] = {0, 0, 5, 2, 18, 6, 12, 0, 18, -6, 5, -2, 0, 0};
59static void TestLongitude(
double lon,
double min,
double max,
bool &lonl,
61 double clon = (min + max) / 2;
62 if (min - lon > 180) lon += 360;
70 }
else if (lon > max) {
80class ConfirmDeleteDialog :
public wxMessageDialog {
82 ConfirmDeleteDialog(wxWindow *parent,
int count)
83 : wxMessageDialog(parent, GetMessage(count), _(
"Route Delete"),
84 wxOK | wxCANCEL | wxICON_QUESTION) {}
87 std::string GetMessage(
int count) {
90 ss << _(
"Are you sure you want to delete ") << count << _(
" routes?");
92 ss << _(
"Are you sure you want to delete route?");
104 LLBBox test_box = m_route.GetBBox();
105 if (box.IntersectOut(test_box))
108 int width = g_route_line_width;
113 spen.SetWidth(width);
115 dc.SetBrush(*
g_pRouteMan->GetSelectedRouteBrush());
116 }
else if (m_route.m_bVisible) {
117 wxPenStyle style = wxPENSTYLE_SOLID;
119 if (m_route.
m_style != wxPENSTYLE_INVALID) style = m_route.
m_style;
123 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
125 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
126 col = ::GpxxColors[i];
131 dc.SetPen(*wxThePenList->FindOrCreatePen(col, width, style));
132 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
137 spen.SetWidth(width);
143 if (m_route.m_bVisible) DrawPointWhich(dc, canvas, 1, &rpt1);
148 if (m_route.m_bVisible || prp1->IsShared())
155 bool draw_arrow = !(prp2->
m_bIsActive && g_bAllowShipToActive);
157 if (m_route.m_bVisible || prp2->IsShared())
161 if (m_route.m_bVisible) {
163 bool b_2_on = vp.GetBBox().Contains(prp2->m_lat, prp2->m_lon);
164 bool b_1_on = vp.GetBBox().Contains(prp1->m_lat, prp1->m_lon);
167 if (b_1_on && b_2_on)
168 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp, draw_arrow,
175 double pix_full_circle = WGS84_semimajor_axis_meters * mercator_k0 * 2 *
178 pow((
double)(rpt1.x - rpt2.x), 2) + pow((
double)(rpt1.y - rpt2.y), 2);
181 if (b_1_on && !b_2_on) {
183 adder = (int)pix_full_circle;
185 adder = -(int)pix_full_circle;
187 dtest = pow((
double)(rpt1.x - (rpt2.x + adder)), 2) +
188 pow((
double)(rpt1.y - rpt2.y), 2);
190 if (dp < dtest) adder = 0;
192 RenderSegment(dc, rpt1.x, rpt1.y, rpt2.x + adder, rpt2.y, vp,
194 }
else if (!b_1_on) {
196 adder = (int)pix_full_circle;
198 adder = -(int)pix_full_circle;
200 float rxd = rpt2.x - (rpt1.x + adder);
201 float ryd = rpt1.y - rpt2.y;
202 dtest = rxd * rxd + ryd * ryd;
204 if (dp < dtest) adder = 0;
206 RenderSegment(dc, rpt1.x + adder, rpt1.y, rpt2.x, rpt2.y, vp,
216void RouteGui::RenderSegment(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
217 ViewPort &vp,
bool bdraw_arrow,
int hilite_width) {
220 dc.GetSize(&sx, &sy);
223 wxRect r(0, 0, sx, sy);
224 wxRect s(xa, ya, 1, 1);
225 wxRect t(xb, yb, 1, 1);
227 if (!r.Intersects(s))
return;
240 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy)) {
241 wxPen psave = dc.GetPen();
243 wxColour y = GetGlobalColor(
"YELO1");
244 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
246 wxPen HiPen(hilt, hilite_width, wxPENSTYLE_SOLID);
249 dc.StrokeLine(x0, y0, x1, y1);
252 dc.StrokeLine(x0, y0, x1, y1);
256 cohen_sutherland_line_clip_i(&x0, &y0, &x1, &y1, 0, sx, 0, sy))
257 dc.StrokeLine(x0, y0, x1, y1);
263 double theta = atan2((
double)(yb - ya), (
double)(xb - xa));
268 icon_scale_factor = fmin(icon_scale_factor, 1.5);
269 icon_scale_factor = fmax(icon_scale_factor, .10);
273 double nom_arrow_size = 20.;
274 double max_arrow_to_leg = .20;
275 double lpp = sqrt(pow((
double)(xa - xb), 2) + pow((
double)(ya - yb), 2));
277 double icon_size = icon_scale_factor * nom_arrow_size;
278 if (icon_size > (lpp * max_arrow_to_leg))
279 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
281 for (
int i = 0; i < 7; i++) {
283 double pxa = (double)(s_arrow_icon[j]);
284 double pya = (double)(s_arrow_icon[j + 1]);
286 pya *= icon_scale_factor;
287 pxa *= icon_scale_factor;
289 double px = (pxa * sin(theta)) + (pya * cos(theta));
290 double py = (pya * sin(theta)) - (pxa * cos(theta));
292 icon[i].x = (int)(px) + xb;
293 icon[i].y = (int)(py) + yb;
295 wxPen savePen = dc.GetPen();
296 dc.SetPen(*wxTRANSPARENT_PEN);
297 dc.StrokePolygon(6, &icon[0], 0, 0);
302void RouteGui::RenderSegmentArrowsGL(
ocpnDC &dc,
int xa,
int ya,
int xb,
int yb,
307 icon_scale_factor = fmin(icon_scale_factor, 1.5);
308 icon_scale_factor = fmax(icon_scale_factor, .10);
312 float nom_arrow_size = 20.;
313 float max_arrow_to_leg = (float).20;
314 float lpp = sqrtf(powf((
float)(xa - xb), 2) + powf((
float)(ya - yb), 2));
316 float icon_size = icon_scale_factor * nom_arrow_size;
317 if (icon_size > (lpp * max_arrow_to_leg))
318 icon_scale_factor = (lpp * max_arrow_to_leg) / nom_arrow_size;
320 float theta = atan2f((
float)yb - ya, (
float)xb - xa);
326 pts[0].x = s_arrow_icon[0];
327 pts[0].y = s_arrow_icon[1];
328 pts[1].x = s_arrow_icon[2];
329 pts[1].y = s_arrow_icon[3];
330 pts[2].x = s_arrow_icon[6];
331 pts[2].y = s_arrow_icon[7];
333 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
336 pts[0].x = s_arrow_icon[2];
337 pts[0].y = s_arrow_icon[3];
338 pts[1].x = s_arrow_icon[4];
339 pts[1].y = s_arrow_icon[5];
340 pts[2].x = s_arrow_icon[6];
341 pts[2].y = s_arrow_icon[7];
342 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
345 pts[0].x = s_arrow_icon[0];
346 pts[0].y = -s_arrow_icon[1];
347 pts[1].x = s_arrow_icon[2];
348 pts[1].y = -s_arrow_icon[3];
349 pts[2].x = s_arrow_icon[6];
350 pts[2].y = -s_arrow_icon[7];
351 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
354 pts[0].x = s_arrow_icon[2];
355 pts[0].y = -s_arrow_icon[3];
356 pts[1].x = s_arrow_icon[4];
357 pts[1].y = -s_arrow_icon[5];
358 pts[2].x = s_arrow_icon[6];
359 pts[2].y = -s_arrow_icon[7];
360 dc.DrawPolygon(3, pts, xb, yb, icon_scale_factor, theta);
367 if (iPoint <= m_route.GetnPoints())
368 RoutePointGui(*m_route.GetPoint(iPoint)).Draw(dc, canvas, rpn);
372 wxPoint *rp2,
ViewPort &vp,
bool bdraw_arrow) {
380 RenderSegment(dc, rp1->x, rp1->y, rp2->x, rp2->y, vp, bdraw_arrow);
387 if (!vp.GetBBox().IntersectOut(m_route.GetBBox()) && m_route.m_bVisible)
388 DrawGLRouteLines(vp, canvas, dc);
391 for (
RoutePoint *prp : *m_route.pRoutePointList) {
397 if (vp.GetBBox().ContainsMarge(prp->m_lat, prp->m_lon, .5)) {
398 if (m_route.m_bVisible || prp->IsShared())
410 wxColour y = GetGlobalColor(
"YELO1");
411 wxColour hilt(y.Red(), y.Green(), y.Blue(), 128);
417 DrawGLLines(vp, &dc, canvas);
423 int width =
g_pRouteMan->GetRoutePen()->GetWidth();
424 if (m_route.
m_width != wxPENSTYLE_INVALID) width = m_route.
m_width;
427 col =
g_pRouteMan->GetActiveRoutePen()->GetColour();
429 col =
g_pRouteMan->GetSelectedRoutePen()->GetColour();
434 for (
unsigned int i = 0; i <
sizeof(::GpxxColorNames) /
sizeof(wxString);
436 if (m_route.
m_Colour == ::GpxxColorNames[i]) {
437 col = ::GpxxColors[i];
444 wxPenStyle style = wxPENSTYLE_SOLID;
445 if (m_route.
m_style != wxPENSTYLE_INVALID) style = m_route.
m_style;
446 wxPen p = *wxThePenList->FindOrCreatePen(col, width, style);
447 if (glChartCanvas::dash_map.find(style) != glChartCanvas::dash_map.end()) {
448 p.SetDashes(2, &glChartCanvas::dash_map[style][0]);
451 dc.SetBrush(*wxTheBrushList->FindOrCreateBrush(col, wxBRUSHSTYLE_SOLID));
453 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
457 DrawGLLines(vp, &dc, canvas);
459 glDisable(GL_LINE_STIPPLE);
462 dc.SetPen(*wxThePenList->FindOrCreatePen(col, 1, wxPENSTYLE_SOLID));
471 RenderSegmentArrowsGL(dc, rpt1.x, rpt1.y, rpt2.x, rpt2.y, vp);
481 float pix_full_circle =
482 WGS84_semimajor_axis_meters * mercator_k0 * 2 * PI * vp.
view_scale_ppm;
484 bool r1valid =
false;
486 wxPoint2DDouble lastpoint;
493 if (m_route.GetnPoints() == 1 && dc) {
495 dc->
DrawLine(r1.m_x, r1.m_y, r1.m_x + 2, r1.m_y + 2);
500 LLBBox bbox = vp.GetBBox();
513 if (std::isnan(r2.m_x)) {
523 bool lat1l = prp1->m_lat < bbox.GetMinLat(),
524 lat2l = prp2->m_lat < bbox.GetMinLat();
525 bool lat1r = prp1->m_lat > bbox.GetMaxLat(),
526 lat2r = prp2->m_lat > bbox.GetMaxLat();
527 if ((lat1l && lat2l) || (lat1r && lat2r)) {
534 if (!vp.ContainsIDL()) {
535 bool lon1l, lon1r, lon2l, lon2r;
536 TestLongitude(prp1->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon1l,
538 TestLongitude(prp2->m_lon, bbox.GetMinLon(), bbox.GetMaxLon(), lon2l,
540 if ((lon1l && lon2l) || (lon1r && lon2r)) {
549 if (std::isnan(r1.m_x))
continue;
560 if ((vp.m_projection_type == PROJECTION_MERCATOR ||
561 vp.m_projection_type == PROJECTION_EQUIRECTANGULAR)) {
562 float olon = vp.
clon > 0 ? vp.
clon - 180 : vp.
clon + 180;
564 if (prp1->m_lon < prp2->m_lon) {
565 if (prp2->m_lon - prp1->m_lon < 180) {
566 if (olon > prp1->m_lon && olon < prp2->m_lon)
567 adder = pix_full_circle;
568 }
else if (olon < prp1->m_lon || olon > prp2->m_lon)
569 adder = -pix_full_circle;
570 }
else if (prp1->m_lon - prp2->m_lon < 180) {
571 if (olon < prp1->m_lon && olon > prp2->m_lon)
572 adder = -pix_full_circle;
573 }
else if (olon > prp1->m_lon || olon < prp2->m_lon)
574 adder = pix_full_circle;
579 float adderc = cos(vp.
rotation) * adder,
581 dc->
DrawLine(r1.m_x, r1.m_y, r2.m_x + adderc, r2.m_y + adders);
582 dc->
DrawLine(r1.m_x - adderc, r1.m_y - adders, r2.m_x, r2.m_y);
584 dc->
DrawLine(r1.m_x, r1.m_y, r2.m_x, r2.m_y);
596void RouteGui::CalculateDCRect(wxDC &dc_route,
ChartCanvas *canvas,
598 dc_route.ResetBoundingBox();
599 dc_route.DestroyClippingRegion();
607 if (m_route.m_bVisible) {
608 for (
RoutePoint *prp2 : *m_route.pRoutePointList) {
611 ocpnDC odc_route(dc_route);
612 odc_route.SetVP(canvas->GetVP());
620 update_rect.Union(r);
624 *prect = update_rect;
627int RouteGui::SendToGPS(
const wxString &com_name,
bool bsend_waypoints,
632 ::wxBeginBusyCursor();
633 result = SendRouteToGPS_N0183(&m_route, com_name, bsend_waypoints, *g_pMUX,
639 msg = _(
"Route Transmitted.");
643 msg = _(
"Error on Route Upload. Garmin GPS not connected");
646 msg = _(
"Error on Route Upload. GPS driver not available");
650 msg = _(
"Error on Route Upload. Please check logfiles...");
654 OCPNMessageBox(NULL, msg, _(
"OpenCPN Info"), wxOK | wxICON_INFORMATION);
656 return (result == 0);
660bool RouteGui::OnDelete(wxWindow *parent,
const int count) {
661 ConfirmDeleteDialog dlg(parent, count);
662 return dlg.ShowModal() == wxID_OK;
General chart base definitions.
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.