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