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_app.h"
53#include "ocpn_frame.h"
54#include "routemanagerdialog.h"
55#include "routeman_gui.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 = []() {
80 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
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 if (m_routeman.pActiveRoute->GetIndexOf(m_routeman.pActivePoint) == 1)
181 g_bAllowShipToActive = true;
182 else {
183 // compute XTE in pixels
184 double tlat, tlon;
185 wxPoint r, r1;
186 ll_gc_ll(gLat, gLon, m_routeman.CourseToRouteSegment,
187 (m_routeman.CurrentXTEToActivePoint / 1.852), &tlat, &tlon);
188 gFrame->GetFocusCanvas()->GetCanvasPointPix(gLat, gLon, &r1);
189 gFrame->GetFocusCanvas()->GetCanvasPointPix(tlat, tlon, &r);
190 double xtepix =
191 sqrt(pow((double)(r1.x - r.x), 2) + pow((double)(r1.y - r.y), 2));
192 // xte in mm
193 double xtemm = xtepix / gFrame->GetFocusCanvas()->GetPixPerMM();
194 // allow display (or not)
195 g_bAllowShipToActive = (xtemm > 3.0) ? true : false;
196 }
197 }
198
199 // Determine Arrival
200
201 bool bDidArrival = false;
202
203 // Duplicate points can result in NaN for normal crossing range.
204 if (isnan(m_routeman.CurrentRangeToActiveNormalCrossing)) {
205 m_routeman.CurrentRangeToActiveNormalCrossing =
206 m_routeman.CurrentRngToActivePoint;
207 }
208
209 // Special signal: if ArrivalRadius < 0, NEVER arrive...
210 // Used for MOB auto-created routes.
211 if (m_routeman.pActivePoint->GetWaypointArrivalRadius() > 0) {
212 if (m_routeman.CurrentRangeToActiveNormalCrossing <=
213 m_routeman.pActivePoint->GetWaypointArrivalRadius()) {
214 m_routeman.m_bArrival = true;
215 m_routeman.UpdateAutopilot();
216
217 bDidArrival = true;
218 DoAdvance();
219
220 } else {
221 // Test to see if we are moving away from the arrival point, and
222 // have been moving away for 2 seconds.
223 // If so, we should declare "Arrival"
224 if ((m_routeman.CurrentRangeToActiveNormalCrossing -
225 m_routeman.m_arrival_min) >
226 m_routeman.pActivePoint->GetWaypointArrivalRadius()) {
227 if (++m_routeman.m_arrival_test > 2 &&
228 !g_bAdvanceRouteWaypointOnArrivalOnly) {
229 m_routeman.m_bArrival = true;
230 m_routeman.UpdateAutopilot();
231
232 bDidArrival = true;
233 DoAdvance();
234 }
235 } else
236 m_routeman.m_arrival_test = 0;
237 }
238 }
239 if (!bDidArrival)
240 m_routeman.m_arrival_min =
241 wxMin(m_routeman.m_arrival_min,
242 m_routeman.CurrentRangeToActiveNormalCrossing);
243 // Only once on arrival
244 if (!bDidArrival) m_routeman.UpdateAutopilot();
245 bret_val = true; // a route is active
246 }
247 m_routeman.m_bDataValid = true;
248 return bret_val;
249}
250
251void RoutemanGui::DeleteTrack(Track *pTrack) {
252 if (pTrack) {
253 if (pTrack->m_bIsInLayer) return;
254
255 ::wxBeginBusyCursor();
256
257 wxGenericProgressDialog *pprog = nullptr;
258
259 int count = pTrack->GetnPoints();
260 if (count > 10000) {
261 pprog = new wxGenericProgressDialog(
262 _("OpenCPN Track Delete"), "0/0", count, NULL,
263 wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_ELAPSED_TIME |
264 wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME);
265 pprog->SetSize(400, wxDefaultCoord);
266 pprog->Centre();
267 }
268 if (TrackPropDlg::getInstanceFlag() && pTrackPropDialog &&
269 (pTrackPropDialog->IsShown()) &&
270 (pTrack == pTrackPropDialog->GetTrack())) {
271 pTrackPropDialog->Hide();
272 }
273
274 if ((pTrack == g_pActiveTrack) && pTrack->IsRunning()) {
275 pTrack = gFrame->TrackOff();
276 }
277 // Remove the track from associated lists
278 pSelect->DeleteAllSelectableTrackSegments(pTrack);
279 auto it = std::find(g_TrackList.begin(), g_TrackList.end(), pTrack);
280 if (it != g_TrackList.end()) {
281 g_TrackList.erase(it);
282 }
283 delete pTrack;
284
285 ::wxEndBusyCursor();
286
287 delete pprog;
288 }
289}
290
291void RoutemanGui::DeleteAllTracks() {
292 gFrame->TrackOff();
293
294 ::wxBeginBusyCursor();
295
296 // Iterate on the RouteList, we delete from g_TrackList in DeleteTrack,
297 // bigger refactoring is viable, but for now, we simply make a copy
298 // that goes out of scope soon.
299 std::vector<Track *> to_del = g_TrackList;
300 for (Track *ptrack : to_del) {
301 if (ptrack->m_bIsInLayer) continue;
302
303 g_pAIS->DeletePersistentTrack(ptrack);
304 NavObj_dB::GetInstance().DeleteTrack(ptrack);
305 DeleteTrack(ptrack);
306 }
307 ::wxEndBusyCursor();
308}
309
310void RoutemanGui::DoAdvance() {
311 if (!m_routeman.ActivateNextPoint(m_routeman.pActiveRoute,
312 false)) // at the end?
313 {
314 Route *pthis_route = m_routeman.pActiveRoute;
315 m_routeman.DeactivateRoute(true); // this is an arrival
316
317 if (pthis_route->m_bDeleteOnArrival && !pthis_route->m_bIsBeingEdited) {
318 m_routeman.DeleteRoute(pthis_route);
319 }
320
321 if (pRouteManagerDialog) pRouteManagerDialog->UpdateRouteListCtrl();
322 }
323}
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:4495
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
Definition chcanv.h:515
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 main program.
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.