OpenCPN Partial API docs
Loading...
Searching...
No Matches
routeman_gui.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2022 by David Register *
3 * Copyright (C) 2022 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
17 ******************A********************************************************/
18
25#include "gl_headers.h" // Must be included before anything using GL stuff
26
27// For compilers that support precompilation, includes "wx.h".
28#include <wx/wxprec.h>
29
30#ifndef WX_PRECOMP
31#include <wx/wx.h>
32#endif
33
34#include <wx/gdicmn.h>
35#include <wx/utils.h>
36
37#include "model/ais_decoder.h"
38#include "model/config_vars.h"
39#include "model/georef.h"
40#include "model/gui_vars.h"
41#include "model/navobj_db.h"
42#include "model/nav_object_database.h"
43#include "model/own_ship.h"
44#include "model/route.h"
45#include "model/route_point.h"
46#include "model/select.h"
47#include "model/track.h"
48
49#include "chcanv.h"
50#include "color_handler.h"
51#include "concanv.h"
52#include "navutil.h"
53#include "routemanagerdialog.h"
54#include "routeman_gui.h"
55#include "top_frame.h"
56#include "track_prop_dlg.h"
57#include "vector2D.h"
58
59static bool ConfirmDeleteAisMob() {
60 int r = OCPNMessageBox(NULL,
61 _("You are trying to delete an active AIS MOB "
62 "route, are you REALLY sure?"),
63 _("OpenCPN Warning"), wxYES_NO);
64
65 return r == wxID_YES;
66}
67
68RoutemanDlgCtx RoutemanGui::GetDlgCtx() {
70 ctx.confirm_delete_ais_mob = []() { return ConfirmDeleteAisMob(); };
71 ctx.get_global_colour = [](wxString c) { return GetGlobalColor(c); };
72 ctx.show_with_fresh_fonts = [] {
73 if (console && !g_bhide_route_console) console->ShowWithFreshFonts();
74 };
75 ctx.clear_console_background = []() {
76 console->GetCDI()->ClearBackground();
77 console->Show(false);
78 };
79 ctx.route_mgr_dlg_update_list_ctrl = []() {
81 pRouteManagerDialog->UpdateRouteListCtrl();
82 };
83 return ctx;
84}
85
86bool RoutemanGui::UpdateProgress() {
87 bool bret_val = false;
88
89 if (m_routeman.pActiveRoute) {
90 // Update bearing, range, and crosstrack error
91
92 // Bearing is calculated as Mercator Sailing, i.e. a cartographic
93 // "bearing"
94 double north, east;
95 toSM(m_routeman.pActivePoint->m_lat, m_routeman.pActivePoint->m_lon, gLat,
96 gLon, &east, &north);
97 double a = atan(north / east);
98 if (fabs(m_routeman.pActivePoint->m_lon - gLon) < 180.) {
99 if (m_routeman.pActivePoint->m_lon >= gLon)
100 m_routeman.CurrentBrgToActivePoint = 90. - (a * 180 / PI);
101 else
102 m_routeman.CurrentBrgToActivePoint = 270. - (a * 180 / PI);
103 } else {
104 if (m_routeman.pActivePoint->m_lon >= gLon)
105 m_routeman.CurrentBrgToActivePoint = 270. - (a * 180 / PI);
106 else
107 m_routeman.CurrentBrgToActivePoint = 90. - (a * 180 / PI);
108 }
109
110 // Calculate range using Great Circle Formula
111
112 double d5 = DistGreatCircle(gLat, gLon, m_routeman.pActivePoint->m_lat,
113 m_routeman.pActivePoint->m_lon);
114 m_routeman.CurrentRngToActivePoint = d5;
115
116 // Get the XTE vector, normal to current segment
117 vector2D va, vb, vn;
118
119 double brg1, dist1, brg2, dist2;
120 DistanceBearingMercator(
121 m_routeman.pActivePoint->m_lat, m_routeman.pActivePoint->m_lon,
122 m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
123 m_routeman.pActiveRouteSegmentBeginPoint->m_lon, &brg1, &dist1);
124 vb.x = dist1 * sin(brg1 * PI / 180.);
125 vb.y = dist1 * cos(brg1 * PI / 180.);
126
127 DistanceBearingMercator(m_routeman.pActivePoint->m_lat,
128 m_routeman.pActivePoint->m_lon, gLat, gLon, &brg2,
129 &dist2);
130 va.x = dist2 * sin(brg2 * PI / 180.);
131 va.y = dist2 * cos(brg2 * PI / 180.);
132
133 double sdelta = vGetLengthOfNormal(&va, &vb, &vn); // NM
134 m_routeman.CurrentXTEToActivePoint = sdelta;
135
136 // Calculate the distance to the arrival line, which is perpendicular to
137 // the current route segment Taking advantage of the calculated normal
138 // from current position to route segment vn
139 vector2D vToArriveNormal;
140 vSubtractVectors(&va, &vn, &vToArriveNormal);
141
142 m_routeman.CurrentRangeToActiveNormalCrossing =
143 vVectorMagnitude(&vToArriveNormal);
144
145 // Compute current segment course
146 // Using simple Mercater projection
147 double x1, y1, x2, y2;
148 toSM(m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
149 m_routeman.pActiveRouteSegmentBeginPoint->m_lon,
150 m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
151 m_routeman.pActiveRouteSegmentBeginPoint->m_lon, &x1, &y1);
152
153 toSM(m_routeman.pActivePoint->m_lat, m_routeman.pActivePoint->m_lon,
154 m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
155 m_routeman.pActiveRouteSegmentBeginPoint->m_lon, &x2, &y2);
156
157 double e1 = atan2((x2 - x1), (y2 - y1));
158 m_routeman.CurrentSegmentCourse = e1 * 180 / PI;
159 if (m_routeman.CurrentSegmentCourse < 0)
160 m_routeman.CurrentSegmentCourse += 360;
161
162 // Compute XTE direction
163 double h = atan(vn.y / vn.x);
164 if (vn.x > 0)
165 m_routeman.CourseToRouteSegment = 90. - (h * 180 / PI);
166 else
167 m_routeman.CourseToRouteSegment = 270. - (h * 180 / PI);
168
169 h = m_routeman.CurrentBrgToActivePoint - m_routeman.CourseToRouteSegment;
170 if (h < 0) h = h + 360;
171
172 if (h > 180)
173 m_routeman.XTEDir = 1;
174 else
175 m_routeman.XTEDir = -1;
176
177 // Allow DirectShipToActivePoint line (distance XTE in mm is > 3 (arbitrary)
178 // or when active point is the first
179 if (g_bShowShipToActive) {
180 int active_index =
181 m_routeman.pActiveRoute->GetIndexOf(m_routeman.pActivePoint);
182 if (active_index < 0)
183 g_bAllowShipToActive = false;
184 else if (active_index == 0)
185 g_bAllowShipToActive = true;
186 else {
187 // compute XTE in pixels
188 double tlat, tlon;
189 wxPoint r, r1;
190 ll_gc_ll(gLat, gLon, m_routeman.CourseToRouteSegment,
191 (m_routeman.CurrentXTEToActivePoint / 1.852), &tlat, &tlon);
192 top_frame::Get()->GetCanvasPointPix(gLat, gLon, &r1);
193 top_frame::Get()->GetCanvasPointPix(tlat, tlon, &r);
194 double xtepix =
195 sqrt(pow((double)(r1.x - r.x), 2) + pow((double)(r1.y - r.y), 2));
196 // xte in mm
197 double xtemm = xtepix / top_frame::Get()->GetPixPerMM();
198 // allow display (or not)
199 g_bAllowShipToActive = (xtemm > 3.0) ? true : false;
200 }
201 }
202
203 // Determine Arrival
204
205 bool bDidArrival = false;
206
207 // Duplicate points can result in NaN for normal crossing range.
208 if (isnan(m_routeman.CurrentRangeToActiveNormalCrossing)) {
209 m_routeman.CurrentRangeToActiveNormalCrossing =
210 m_routeman.CurrentRngToActivePoint;
211 }
212
213 // Special signal: if ArrivalRadius < 0, NEVER arrive...
214 // Used for MOB auto-created routes.
215 if (m_routeman.pActivePoint->GetWaypointArrivalRadius() > 0) {
216 if (m_routeman.CurrentRangeToActiveNormalCrossing <=
217 m_routeman.pActivePoint->GetWaypointArrivalRadius()) {
218 m_routeman.m_bArrival = true;
219 m_routeman.UpdateAutopilot();
220
221 bDidArrival = true;
222 DoAdvance();
223
224 } else {
225 // Test to see if we are moving away from the arrival point, and
226 // have been moving away for 2 seconds.
227 // If so, we should declare "Arrival"
228 if ((m_routeman.CurrentRangeToActiveNormalCrossing -
229 m_routeman.m_arrival_min) >
230 m_routeman.pActivePoint->GetWaypointArrivalRadius()) {
231 if (++m_routeman.m_arrival_test > 2 &&
232 !g_bAdvanceRouteWaypointOnArrivalOnly) {
233 m_routeman.m_bArrival = true;
234 m_routeman.UpdateAutopilot();
235
236 bDidArrival = true;
237 DoAdvance();
238 }
239 } else
240 m_routeman.m_arrival_test = 0;
241 }
242 }
243 if (!bDidArrival)
244 m_routeman.m_arrival_min =
245 wxMin(m_routeman.m_arrival_min,
246 m_routeman.CurrentRangeToActiveNormalCrossing);
247 // Only once on arrival
248 if (!bDidArrival) m_routeman.UpdateAutopilot();
249 bret_val = true; // a route is active
250 }
251 m_routeman.m_bDataValid = true;
252 return bret_val;
253}
254
255void RoutemanGui::DeleteTrack(Track *pTrack) {
256 if (pTrack) {
257 if (pTrack->m_bIsInLayer) return;
258
259 ::wxBeginBusyCursor();
260
261 wxGenericProgressDialog *pprog = nullptr;
262
263 int count = pTrack->GetnPoints();
264 if (count > 10000) {
265 pprog = new wxGenericProgressDialog(
266 _("OpenCPN Track Delete"), "0/0", count, NULL,
267 wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
268 wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);
269 pprog->SetSize(400, wxDefaultCoord);
270 pprog->Centre();
271 }
272 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog &&
273 (pTrackPropDialog->IsShown()) &&
274 (pTrack == pTrackPropDialog->GetTrack())) {
275 pTrackPropDialog->Hide();
276 }
277
278 if ((pTrack == g_pActiveTrack) && pTrack->IsRunning()) {
279 pTrack = top_frame::Get()->TrackOff();
280 }
281 // Remove the track from associated lists
282 pSelect->DeleteAllSelectableTrackSegments(pTrack);
283 auto it = std::find(g_TrackList.begin(), g_TrackList.end(), pTrack);
284 if (it != g_TrackList.end()) {
285 g_TrackList.erase(it);
286 }
287 delete pTrack;
288
289 ::wxEndBusyCursor();
290
291 delete pprog;
292 }
293}
294
295void RoutemanGui::DeleteAllTracks() {
296 top_frame::Get()->TrackOff();
297
298 ::wxBeginBusyCursor();
299
300 // Iterate on the RouteList, we delete from g_TrackList in DeleteTrack,
301 // bigger refactoring is viable, but for now, we simply make a copy
302 // that goes out of scope soon.
303 std::vector<Track *> to_del = g_TrackList;
304 for (Track *ptrack : to_del) {
305 if (ptrack->m_bIsInLayer) continue;
306
307 g_pAIS->DeletePersistentTrack(ptrack);
308 NavObj_dB::GetInstance().DeleteTrack(ptrack);
309 DeleteTrack(ptrack);
310 }
311 ::wxEndBusyCursor();
312}
313
314void RoutemanGui::DoAdvance() {
315 if (!m_routeman.ActivateNextPoint(m_routeman.pActiveRoute,
316 false)) // at the end?
317 {
318 Route *pthis_route = m_routeman.pActiveRoute;
319 m_routeman.DeactivateRoute(true); // this is an arrival
320
321 if (pthis_route->m_bDeleteOnArrival && !pthis_route->m_bIsBeingEdited) {
322 m_routeman.DeleteRoute(pthis_route);
323 }
324
325 if (pRouteManagerDialog) pRouteManagerDialog->UpdateRouteListCtrl();
326 }
327}
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Generic Chart canvas base.
Represents a navigational route in the navigation system.
Definition route.h:99
bool m_bDeleteOnArrival
Flag indicating whether the route should be deleted once navigation reaches the end.
Definition route.h:268
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
Definition route.h:224
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
Definition routeman.cpp:357
bool DeleteRoute(Route *pRoute)
Definition routeman.cpp:765
Represents a track, which is a series of connected track points.
Definition track.h:117
Global color handling by name.
APConsole * console
Global instance.
Definition concanv.cpp:55
Primary navigation console display for route and vessel tracking.
Global variables stored in configuration file.
OpenCPN Georef utility.
Platform independent GL includes.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
MySQL based storage for routes, tracks, etc.
Utility functions.
double gLat
Vessel's current latitude in decimal degrees.
Definition own_ship.cpp:26
double gLon
Vessel's current longitude in decimal degrees.
Definition own_ship.cpp:27
Position, course, speed, etc.
Route abstraction.
Waypoint or mark abstraction.
Routeman drawing stuff.
RouteManagerDialog * pRouteManagerDialog
Global instance.
Manage routes dialog.
Select * pSelect
Global instance.
Definition select.cpp:36
Selected route, segment, waypoint, etc.
Routeman callbacks.
Definition routeman.h:92
Abstract gFrame/MyFrame interface.
ActiveTrack * g_pActiveTrack
global instance
Definition track.cpp:99
std::vector< Track * > g_TrackList
Global instance.
Definition track.cpp:96
Recorded track abstraction.
TrackPropDlg * pTrackPropDialog
Global instance.
Track Properties Dialog.