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 "concanv.h"
51#include "navutil.h"
52#include "ocpn_frame.h"
53#include "routemanagerdialog.h"
54#include "routeman_gui.h"
55#include "track_prop_dlg.h"
56#include "vector2D.h"
57
58static bool ConfirmDeleteAisMob() {
59 int r = OCPNMessageBox(NULL,
60 _("You are trying to delete an active AIS MOB "
61 "route, are you REALLY sure?"),
62 _("OpenCPN Warning"), wxYES_NO);
63
64 return r == wxID_YES;
65}
66
67RoutemanDlgCtx RoutemanGui::GetDlgCtx() {
69 ctx.confirm_delete_ais_mob = []() { return ConfirmDeleteAisMob(); };
70 ctx.get_global_colour = [](wxString c) { return GetGlobalColor(c); };
71 ctx.show_with_fresh_fonts = [] {
72 if (console && !g_bhide_route_console) console->ShowWithFreshFonts();
73 };
74 ctx.clear_console_background = []() {
75 console->GetCDI()->ClearBackground();
76 console->Show(false);
77 };
78 ctx.route_mgr_dlg_update_list_ctrl = []() {
79 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
80 pRouteManagerDialog->UpdateRouteListCtrl();
81 };
82 return ctx;
83}
84
85bool RoutemanGui::UpdateProgress() {
86 bool bret_val = false;
87
88 if (m_routeman.pActiveRoute) {
89 // Update bearing, range, and crosstrack error
90
91 // Bearing is calculated as Mercator Sailing, i.e. a cartographic
92 // "bearing"
93 double north, east;
94 toSM(m_routeman.pActivePoint->m_lat, m_routeman.pActivePoint->m_lon, gLat,
95 gLon, &east, &north);
96 double a = atan(north / east);
97 if (fabs(m_routeman.pActivePoint->m_lon - gLon) < 180.) {
98 if (m_routeman.pActivePoint->m_lon >= gLon)
99 m_routeman.CurrentBrgToActivePoint = 90. - (a * 180 / PI);
100 else
101 m_routeman.CurrentBrgToActivePoint = 270. - (a * 180 / PI);
102 } else {
103 if (m_routeman.pActivePoint->m_lon >= gLon)
104 m_routeman.CurrentBrgToActivePoint = 270. - (a * 180 / PI);
105 else
106 m_routeman.CurrentBrgToActivePoint = 90. - (a * 180 / PI);
107 }
108
109 // Calculate range using Great Circle Formula
110
111 double d5 = DistGreatCircle(gLat, gLon, m_routeman.pActivePoint->m_lat,
112 m_routeman.pActivePoint->m_lon);
113 m_routeman.CurrentRngToActivePoint = d5;
114
115 // Get the XTE vector, normal to current segment
116 vector2D va, vb, vn;
117
118 double brg1, dist1, brg2, dist2;
119 DistanceBearingMercator(
120 m_routeman.pActivePoint->m_lat, m_routeman.pActivePoint->m_lon,
121 m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
122 m_routeman.pActiveRouteSegmentBeginPoint->m_lon, &brg1, &dist1);
123 vb.x = dist1 * sin(brg1 * PI / 180.);
124 vb.y = dist1 * cos(brg1 * PI / 180.);
125
126 DistanceBearingMercator(m_routeman.pActivePoint->m_lat,
127 m_routeman.pActivePoint->m_lon, gLat, gLon, &brg2,
128 &dist2);
129 va.x = dist2 * sin(brg2 * PI / 180.);
130 va.y = dist2 * cos(brg2 * PI / 180.);
131
132 double sdelta = vGetLengthOfNormal(&va, &vb, &vn); // NM
133 m_routeman.CurrentXTEToActivePoint = sdelta;
134
135 // Calculate the distance to the arrival line, which is perpendicular to
136 // the current route segment Taking advantage of the calculated normal
137 // from current position to route segment vn
138 vector2D vToArriveNormal;
139 vSubtractVectors(&va, &vn, &vToArriveNormal);
140
141 m_routeman.CurrentRangeToActiveNormalCrossing =
142 vVectorMagnitude(&vToArriveNormal);
143
144 // Compute current segment course
145 // Using simple Mercater projection
146 double x1, y1, x2, y2;
147 toSM(m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
148 m_routeman.pActiveRouteSegmentBeginPoint->m_lon,
149 m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
150 m_routeman.pActiveRouteSegmentBeginPoint->m_lon, &x1, &y1);
151
152 toSM(m_routeman.pActivePoint->m_lat, m_routeman.pActivePoint->m_lon,
153 m_routeman.pActiveRouteSegmentBeginPoint->m_lat,
154 m_routeman.pActiveRouteSegmentBeginPoint->m_lon, &x2, &y2);
155
156 double e1 = atan2((x2 - x1), (y2 - y1));
157 m_routeman.CurrentSegmentCourse = e1 * 180 / PI;
158 if (m_routeman.CurrentSegmentCourse < 0)
159 m_routeman.CurrentSegmentCourse += 360;
160
161 // Compute XTE direction
162 double h = atan(vn.y / vn.x);
163 if (vn.x > 0)
164 m_routeman.CourseToRouteSegment = 90. - (h * 180 / PI);
165 else
166 m_routeman.CourseToRouteSegment = 270. - (h * 180 / PI);
167
168 h = m_routeman.CurrentBrgToActivePoint - m_routeman.CourseToRouteSegment;
169 if (h < 0) h = h + 360;
170
171 if (h > 180)
172 m_routeman.XTEDir = 1;
173 else
174 m_routeman.XTEDir = -1;
175
176 // Allow DirectShipToActivePoint line (distance XTE in mm is > 3 (arbitrary)
177 // or when active point is the first
178 if (g_bShowShipToActive) {
179 if (m_routeman.pActiveRoute->GetIndexOf(m_routeman.pActivePoint) == 1)
180 g_bAllowShipToActive = true;
181 else {
182 // compute XTE in pixels
183 double tlat, tlon;
184 wxPoint r, r1;
185 ll_gc_ll(gLat, gLon, m_routeman.CourseToRouteSegment,
186 (m_routeman.CurrentXTEToActivePoint / 1.852), &tlat, &tlon);
187 gFrame->GetFocusCanvas()->GetCanvasPointPix(gLat, gLon, &r1);
188 gFrame->GetFocusCanvas()->GetCanvasPointPix(tlat, tlon, &r);
189 double xtepix =
190 sqrt(pow((double)(r1.x - r.x), 2) + pow((double)(r1.y - r.y), 2));
191 // xte in mm
192 double xtemm = xtepix / gFrame->GetFocusCanvas()->GetPixPerMM();
193 // allow display (or not)
194 g_bAllowShipToActive = (xtemm > 3.0) ? true : false;
195 }
196 }
197
198 // Determine Arrival
199
200 bool bDidArrival = false;
201
202 // Duplicate points can result in NaN for normal crossing range.
203 if (isnan(m_routeman.CurrentRangeToActiveNormalCrossing)) {
204 m_routeman.CurrentRangeToActiveNormalCrossing =
205 m_routeman.CurrentRngToActivePoint;
206 }
207
208 // Special signal: if ArrivalRadius < 0, NEVER arrive...
209 // Used for MOB auto-created routes.
210 if (m_routeman.pActivePoint->GetWaypointArrivalRadius() > 0) {
211 if (m_routeman.CurrentRangeToActiveNormalCrossing <=
212 m_routeman.pActivePoint->GetWaypointArrivalRadius()) {
213 m_routeman.m_bArrival = true;
214 m_routeman.UpdateAutopilot();
215
216 bDidArrival = true;
217 DoAdvance();
218
219 } else {
220 // Test to see if we are moving away from the arrival point, and
221 // have been moving away for 2 seconds.
222 // If so, we should declare "Arrival"
223 if ((m_routeman.CurrentRangeToActiveNormalCrossing -
224 m_routeman.m_arrival_min) >
225 m_routeman.pActivePoint->GetWaypointArrivalRadius()) {
226 if (++m_routeman.m_arrival_test > 2 &&
227 !g_bAdvanceRouteWaypointOnArrivalOnly) {
228 m_routeman.m_bArrival = true;
229 m_routeman.UpdateAutopilot();
230
231 bDidArrival = true;
232 DoAdvance();
233 }
234 } else
235 m_routeman.m_arrival_test = 0;
236 }
237 }
238 if (!bDidArrival)
239 m_routeman.m_arrival_min =
240 wxMin(m_routeman.m_arrival_min,
241 m_routeman.CurrentRangeToActiveNormalCrossing);
242 // Only once on arrival
243 if (!bDidArrival) m_routeman.UpdateAutopilot();
244 bret_val = true; // a route is active
245 }
246 m_routeman.m_bDataValid = true;
247 return bret_val;
248}
249
250void RoutemanGui::DeleteTrack(Track *pTrack) {
251 if (pTrack) {
252 if (pTrack->m_bIsInLayer) return;
253
254 ::wxBeginBusyCursor();
255
256 wxGenericProgressDialog *pprog = nullptr;
257
258 int count = pTrack->GetnPoints();
259 if (count > 10000) {
260 pprog = new wxGenericProgressDialog(
261 _("OpenCPN Track Delete"), "0/0", count, NULL,
262 wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
263 wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);
264 pprog->SetSize(400, wxDefaultCoord);
265 pprog->Centre();
266 }
267 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog &&
268 (pTrackPropDialog->IsShown()) &&
269 (pTrack == pTrackPropDialog->GetTrack())) {
270 pTrackPropDialog->Hide();
271 }
272
273 if ((pTrack == g_pActiveTrack) && pTrack->IsRunning()) {
274 pTrack = gFrame->TrackOff();
275 }
276 // Remove the track from associated lists
277 pSelect->DeleteAllSelectableTrackSegments(pTrack);
278 auto it = std::find(g_TrackList.begin(), g_TrackList.end(), pTrack);
279 if (it != g_TrackList.end()) {
280 g_TrackList.erase(it);
281 }
282 delete pTrack;
283
284 ::wxEndBusyCursor();
285
286 delete pprog;
287 }
288}
289
290void RoutemanGui::DeleteAllTracks() {
291 gFrame->TrackOff();
292
293 ::wxBeginBusyCursor();
294
295 // Iterate on the RouteList, we delete from g_TrackList in DeleteTrack,
296 // bigger refactoring is viable, but for now, we simply make a copy
297 // that goes out of scope soon.
298 std::vector<Track *> to_del = g_TrackList;
299 for (Track *ptrack : to_del) {
300 if (ptrack->m_bIsInLayer) continue;
301
302 g_pAIS->DeletePersistentTrack(ptrack);
303 NavObj_dB::GetInstance().DeleteTrack(ptrack);
304 DeleteTrack(ptrack);
305 }
306 ::wxEndBusyCursor();
307}
308
309void RoutemanGui::DoAdvance() {
310 if (!m_routeman.ActivateNextPoint(m_routeman.pActiveRoute,
311 false)) // at the end?
312 {
313 Route *pthis_route = m_routeman.pActiveRoute;
314 m_routeman.DeactivateRoute(true); // this is an arrival
315
316 if (pthis_route->m_bDeleteOnArrival && !pthis_route->m_bIsBeingEdited) {
317 m_routeman.DeleteRoute(pthis_route);
318 }
319
320 if (pRouteManagerDialog) pRouteManagerDialog->UpdateRouteListCtrl();
321 }
322}
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Generic Chart canvas base.
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
Definition chcanv.cpp:4535
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Definition chcanv.h:516
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:762
Represents a track, which is a series of connected track points.
Definition track.h:117
APConsole * console
Global instance.
Definition concanv.cpp:54
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.
OpenCPN top window.
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.
Manage routes dialog.
Select * pSelect
Global instance.
Definition select.cpp:36
Selected route, segment, waypoint, etc.
Routeman callbacks.
Definition routeman.h:92
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.