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