36#include <wx/jsonval.h>
37#include <wx/listimpl.cpp>
38#include <wx/tokenzr.h>
40#include "model/ais_decoder.h"
41#include "model/autopilot_output.h"
42#include "model/base_platform.h"
43#include "model/comm_n0183_output.h"
44#include "model/comm_vars.h"
45#include "model/config_vars.h"
46#include "model/cutil.h"
47#include "model/georef.h"
48#include "model/nav_object_database.h"
49#include "model/navutil_base.h"
50#include "model/nmea_ctx_factory.h"
51#include "model/own_ship.h"
52#include "model/route.h"
53#include "model/routeman.h"
54#include "model/track.h"
56#include "observable_globvar.h"
61#include "androidUTIL.h"
64bool g_bPluginHandleAutopilotRoute;
74float g_ChartScaleFactorExp;
77WX_DECLARE_LIST(wxBitmap, markicon_bitmap_list_type);
78WX_DECLARE_LIST(wxString, markicon_key_list_type);
79WX_DECLARE_LIST(wxString, markicon_description_list_type);
82#include <wx/listimpl.cpp>
83WX_DEFINE_LIST(markicon_bitmap_list_type);
84WX_DEFINE_LIST(markicon_key_list_type);
85WX_DEFINE_LIST(markicon_description_list_type);
88void appendOSDirSlash(wxString *pString);
90static void ActivatePersistedRoute(
Routeman *routeman) {
91 if (g_active_route ==
"") {
92 wxLogWarning(
"\"Persist route\" but no persisted route configured");
95 Route *route = routeman->FindRouteByGUID(g_active_route);
97 wxLogWarning(
"Persisted route GUID not available");
111 pRouteActivatePoint(0),
112 m_NMEA0183(NmeaCtxFactory()),
114 m_route_dlg_ctx(route_dlg_ctx),
115 m_nmea_log(nmea_log) {
117 auto route_action = [&](wxCommandEvent) {
118 if (g_persist_active_route) ActivatePersistedRoute(
this);
120 active_route_listener.Init(active_route, route_action);
123Routeman::~Routeman() {
124 if (pRouteActivatePoint)
delete pRouteActivatePoint;
127bool Routeman::IsRouteValid(
Route *pRoute) {
128 wxRouteListNode *node = pRouteList->GetFirst();
130 if (pRoute == node->GetData())
return true;
131 node = node->GetNext();
138 wxRouteListNode *node = pRouteList->GetFirst();
140 Route *proute = node->GetData();
142 wxRoutePointListNode *pnode = (proute->pRoutePointList)->GetFirst();
145 if (prp == pWP)
return proute;
146 pnode = pnode->GetNext();
149 node = node->GetNext();
157 wxRouteListNode *node = pRouteList->GetFirst();
159 Route *proute = node->GetData();
160 if (proute->IsVisible()) {
161 wxRoutePointListNode *pnode = (proute->pRoutePointList)->GetFirst();
164 if (prp == pWP)
return proute;
165 pnode = pnode->GetNext();
169 node = node->GetNext();
176 wxArrayPtrVoid *pArray =
new wxArrayPtrVoid;
178 wxRouteListNode *route_node = pRouteList->GetFirst();
180 Route *proute = route_node->GetData();
182 wxRoutePointListNode *waypoint_node = (proute->pRoutePointList)->GetFirst();
183 while (waypoint_node) {
186 pArray->Add((
void *)proute);
191 waypoint_node = waypoint_node->GetNext();
194 route_node = route_node->GetNext();
197 if (pArray->GetCount())
209 pSelect->DeleteAllSelectableRoutePoints(route);
210 pSelect->DeleteAllSelectableRouteSegments(route);
212 route->RemovePoint(point);
216 if (route->GetnPoints() <= 1 && route_state == 0) {
217 NavObjectChanges::getInstance()->DeleteConfigRoute(route);
218 g_pRouteMan->
DeleteRoute(route, NavObjectChanges::getInstance());
222 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
227 m_prop_dlg_ctx.set_route_and_update(route);
230RoutePoint *Routeman::FindBestActivatePoint(
Route *pR,
double lat,
double lon,
231 double cog,
double sog) {
232 if (!pR)
return NULL;
236 double min_time_found = 1e6;
238 wxRoutePointListNode *node = (pR->pRoutePointList)->GetFirst();
243 DistanceBearingMercator(pn->m_lat, pn->m_lon, lat, lon, &brg, &dist);
245 double angle = brg - cog;
246 double soa = cos(angle * PI / 180.);
248 double time_to_wp = dist / soa;
250 if (time_to_wp > 0) {
251 if (time_to_wp < min_time_found) {
252 min_time_found = time_to_wp;
256 node = node->GetNext();
262 g_bAllowShipToActive =
false;
264 v[_T(
"Route_activated")] = pRouteToActivate->m_RouteNameString;
265 v[_T(
"GUID")] = pRouteToActivate->m_GUID;
266 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_ACTIVATED");
267 if (g_bPluginHandleAutopilotRoute)
return true;
271 m_have_n0183_out =
false;
272 m_have_n2000_out =
false;
274 m_output_drivers.clear();
277 if (attributes.find(
"protocol") == attributes.end())
continue;
278 if (attributes.at(
"protocol") ==
"nmea0183") {
279 if (attributes.find(
"ioDirection") != attributes.end()) {
280 if ((attributes.at(
"ioDirection") ==
"IN/OUT") ||
281 (attributes.at(
"ioDirection") ==
"OUT")) {
282 m_output_drivers.push_back(handle);
283 m_have_n0183_out =
true;
289 if (attributes.at(
"protocol") ==
"nmea2000") {
290 m_output_drivers.push_back(handle);
291 m_have_n2000_out =
true;
296 pActiveRoute = pRouteToActivate;
297 g_active_route = pActiveRoute->GetGUID();
300 pActivePoint = pStartPoint;
302 wxRoutePointListNode *node = (pActiveRoute->pRoutePointList)->GetFirst();
303 pActivePoint = node->GetData();
312 pRouteToActivate->m_bRtIsActive =
true;
314 m_bDataValid =
false;
316 m_route_dlg_ctx.show_with_fresh_fonts();
321 g_bAllowShipToActive =
false;
323 v[_T(
"GUID")] = pRP_target->m_GUID;
324 v[_T(
"WP_activated")] = pRP_target->GetName();
326 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_WPT_ACTIVATED");
328 if (g_bPluginHandleAutopilotRoute)
return true;
332 pActivePoint = pRP_target;
333 pActiveRoute->m_pRouteActivePoint = pRP_target;
335 wxRoutePointListNode *node = (pActiveRoute->pRoutePointList)->GetFirst();
338 pn->m_bBlink =
false;
339 pn->m_bIsActive =
false;
341 node = node->GetNext();
344 node = (pActiveRoute->pRoutePointList)->GetFirst();
349 if (pRP_target == prp_first) {
350 if (pRouteActivatePoint)
delete pRouteActivatePoint;
352 pRouteActivatePoint =
353 new RoutePoint(gLat, gLon, wxString(_T(
"")), wxString(_T(
"Begin")),
354 wxEmptyString,
false);
355 pRouteActivatePoint->m_bShowName =
false;
357 pActiveRouteSegmentBeginPoint = pRouteActivatePoint;
361 prp_first->m_bBlink =
false;
362 node = node->GetNext();
366 if (pnext == pRP_target) {
367 pActiveRouteSegmentBeginPoint = np_prev;
372 node = node->GetNext();
376 pRP_target->m_bBlink =
true;
377 pRP_target->m_bIsActive =
true;
379 g_blink_rect = pRP_target->CurrentRect_in_DC;
391 m_prop_dlg_ctx.set_enroute_point(pA, pActivePoint);
396 g_bAllowShipToActive =
false;
400 pActivePoint->m_bBlink =
false;
401 pActivePoint->m_bIsActive =
false;
403 v[_T(
"isSkipped")] = skipped;
404 v[_T(
"GUID")] = pActivePoint->m_GUID;
405 v[_T(
"GUID_WP_arrived")] = pActivePoint->m_GUID;
406 v[_T(
"WP_arrived")] = pActivePoint->GetName();
408 int n_index_active = pActiveRoute->GetIndexOf(pActivePoint);
410 while (n_index_active == pActiveRoute->GetIndexOf(pActivePoint)) {
411 if ((n_index_active + step) <= pActiveRoute->GetnPoints()) {
412 pActiveRouteSegmentBeginPoint = pActivePoint;
413 pActiveRoute->m_pRouteActivePoint =
414 pActiveRoute->GetPoint(n_index_active + step);
415 pActivePoint = pActiveRoute->GetPoint(n_index_active + step);
424 v[_T(
"Next_WP")] = pActivePoint->GetName();
425 v[_T(
"GUID_Next_WP")] = pActivePoint->m_GUID;
427 pActivePoint->m_bBlink =
true;
428 pActivePoint->m_bIsActive =
true;
429 g_blink_rect = pActivePoint->CurrentRect_in_DC;
440 m_prop_dlg_ctx.set_enroute_point(pr, pActivePoint);
442 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_WPT_ARRIVED");
447bool Routeman::DeactivateRoute(
bool b_arrival) {
449 pActivePoint->m_bBlink =
false;
450 pActivePoint->m_bIsActive =
false;
454 pActiveRoute->m_bRtIsActive =
false;
455 pActiveRoute->m_pRouteActivePoint = NULL;
456 g_active_route.Clear();
460 v[_T(
"Route_deactivated")] = pActiveRoute->m_RouteNameString;
461 v[_T(
"GUID")] = pActiveRoute->m_GUID;
462 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_DEACTIVATED");
464 v[_T(
"GUID")] = pActiveRoute->m_GUID;
465 v[_T(
"Route_ended")] = pActiveRoute->m_RouteNameString;
466 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_ENDED");
472 if (pRouteActivatePoint)
delete pRouteActivatePoint;
473 pRouteActivatePoint = NULL;
477 m_route_dlg_ctx.clear_console_background();
478 m_bDataValid =
false;
483bool Routeman::UpdateAutopilot() {
484 if (!bGPSValid)
return false;
489 if ((g_maxWPNameLength >= 3) && (g_maxWPNameLength <= 32))
490 maxName = g_maxWPNameLength;
494 auto& registry = CommDriverRegistry::GetInstance();
495 const std::vector<DriverPtr>& drivers = registry.GetDrivers();
498 bool have_n0183 =
false;
499 bool have_n2000 =
false;
502 for (
auto key : m_output_drivers) {
503 for (
auto &d : drivers) {
504 if (d->Key() == key) {
505 std::unordered_map<std::string, std::string> attributes =
507 auto protocol_it = attributes.find(
"protocol");
508 if (protocol_it != attributes.end()) {
509 std::string protocol = protocol_it->second;
511 if (protocol ==
"nmea0183") {
513 }
else if (protocol ==
"nmea2000") {
522 if (m_have_n0183_out) rv |= UpdateAutopilotN0183(*
this);
524 if (m_have_n2000_out) rv |= UpdateAutopilotN2K(*
this);
529 leg_info.Btw = CurrentBrgToActivePoint;
530 leg_info.Dtw = CurrentRngToActivePoint;
531 leg_info.Xte = CurrentXTEToActivePoint;
533 leg_info.Xte = -leg_info.Xte;
535 leg_info.wp_name = pActivePoint->GetName().Truncate(maxName);
536 leg_info.arrival = m_bArrival;
547 if ((g_maxWPNameLength >= 3) && (g_maxWPNameLength <= 32))
548 maxName = g_maxWPNameLength;
552 double r_Sog(0.0), r_Cog(0.0);
553 if (!std::isnan(gSog)) r_Sog = gSog;
554 if (!std::isnan(gCog)) r_Cog = gCog;
559 leg_info.Btw = CurrentBrgToActivePoint;
560 leg_info.Dtw = CurrentRngToActivePoint;
561 leg_info.Xte = CurrentXTEToActivePoint;
563 leg_info.Xte = -leg_info.Xte;
565 leg_info.wp_name = pActivePoint->GetName().Truncate(maxName);
566 leg_info.arrival = m_bArrival;
572 m_NMEA0183.TalkerID =
"EC";
574 m_NMEA0183.Rmb.IsDataValid = bGPSValid ? NTrue : NFalse;
575 m_NMEA0183.Rmb.CrossTrackError = CurrentXTEToActivePoint;
576 m_NMEA0183.Rmb.DirectionToSteer = XTEDir < 0 ? Left : Right;
577 m_NMEA0183.Rmb.RangeToDestinationNauticalMiles = CurrentRngToActivePoint;
578 m_NMEA0183.Rmb.BearingToDestinationDegreesTrue = CurrentBrgToActivePoint;
580 if (pActivePoint->m_lat < 0.)
581 m_NMEA0183.Rmb.DestinationPosition.Latitude.Set(-pActivePoint->m_lat,
584 m_NMEA0183.Rmb.DestinationPosition.Latitude.Set(pActivePoint->m_lat,
"N");
586 if (pActivePoint->m_lon < 0.)
587 m_NMEA0183.Rmb.DestinationPosition.Longitude.Set(-pActivePoint->m_lon,
590 m_NMEA0183.Rmb.DestinationPosition.Longitude.Set(pActivePoint->m_lon,
593 m_NMEA0183.Rmb.DestinationClosingVelocityKnots =
594 r_Sog * cos((r_Cog - CurrentBrgToActivePoint) * PI / 180.0);
595 m_NMEA0183.Rmb.IsArrivalCircleEntered = m_bArrival ? NTrue : NFalse;
596 m_NMEA0183.Rmb.FAAModeIndicator = bGPSValid ?
"A" :
"N";
599 int wp_len = maxName;
601 m_NMEA0183.Rmb.To = pActivePoint->GetName().Truncate(wp_len);
602 m_NMEA0183.Rmb.From =
603 pActiveRouteSegmentBeginPoint->GetName().Truncate(wp_len);
604 m_NMEA0183.Rmb.Write(snt);
606 }
while (snt.Sentence.size() > 82 && wp_len > 0);
613 m_NMEA0183.TalkerID = _T(
"EC");
616 m_NMEA0183.Rmc.IsDataValid = NTrue;
617 if (!bGPSValid) m_NMEA0183.Rmc.IsDataValid = NFalse;
620 m_NMEA0183.Rmc.Position.Latitude.Set(-gLat, _T(
"S"));
622 m_NMEA0183.Rmc.Position.Latitude.Set(gLat, _T(
"N"));
625 m_NMEA0183.Rmc.Position.Longitude.Set(-gLon, _T(
"W"));
627 m_NMEA0183.Rmc.Position.Longitude.Set(gLon, _T(
"E"));
629 m_NMEA0183.Rmc.SpeedOverGroundKnots = r_Sog;
630 m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue = r_Cog;
632 if (!std::isnan(gVar)) {
634 m_NMEA0183.Rmc.MagneticVariation = -gVar;
635 m_NMEA0183.Rmc.MagneticVariationDirection = West;
637 m_NMEA0183.Rmc.MagneticVariation = gVar;
638 m_NMEA0183.Rmc.MagneticVariationDirection = East;
641 m_NMEA0183.Rmc.MagneticVariation =
645 if (!gRmcTime.IsEmpty() && !gRmcDate.IsEmpty()) {
646 m_NMEA0183.Rmc.UTCTime = gRmcTime;
647 m_NMEA0183.Rmc.Date = gRmcDate;
649 wxDateTime now = wxDateTime::Now();
650 wxDateTime utc = now.ToUTC();
651 wxString time = utc.Format(_T(
"%H%M%S"));
652 m_NMEA0183.Rmc.UTCTime = time;
653 wxString date = utc.Format(_T(
"%d%m%y"));
654 m_NMEA0183.Rmc.Date = date;
657 m_NMEA0183.Rmc.FAAModeIndicator =
"A";
658 if (!bGPSValid) m_NMEA0183.Rmc.FAAModeIndicator =
"N";
660 m_NMEA0183.Rmc.Write(snt);
667 m_NMEA0183.TalkerID = _T(
"EC");
671 m_NMEA0183.Apb.IsLoranBlinkOK =
673 if (!bGPSValid) m_NMEA0183.Apb.IsLoranBlinkOK = NFalse;
675 m_NMEA0183.Apb.IsLoranCCycleLockOK = NTrue;
676 if (!bGPSValid) m_NMEA0183.Apb.IsLoranCCycleLockOK = NFalse;
678 m_NMEA0183.Apb.CrossTrackErrorMagnitude = CurrentXTEToActivePoint;
681 m_NMEA0183.Apb.DirectionToSteer = Left;
683 m_NMEA0183.Apb.DirectionToSteer = Right;
685 m_NMEA0183.Apb.CrossTrackUnits = _T(
"N");
688 m_NMEA0183.Apb.IsArrivalCircleEntered = NTrue;
690 m_NMEA0183.Apb.IsArrivalCircleEntered = NFalse;
694 m_NMEA0183.Apb.IsPerpendicular = NFalse;
696 m_NMEA0183.Apb.To = pActivePoint->GetName().Truncate(maxName);
699 DistanceBearingMercator(pActivePoint->m_lat, pActivePoint->m_lon,
700 pActiveRouteSegmentBeginPoint->m_lat,
701 pActiveRouteSegmentBeginPoint->m_lon, &brg1,
704 if (g_bMagneticAPB && !std::isnan(gVar)) {
706 ((brg1 - gVar) >= 0.) ? (brg1 - gVar) : (brg1 - gVar + 360.);
707 double bapm = ((CurrentBrgToActivePoint - gVar) >= 0.)
708 ? (CurrentBrgToActivePoint - gVar)
709 : (CurrentBrgToActivePoint - gVar + 360.);
711 m_NMEA0183.Apb.BearingOriginToDestination = brg1m;
712 m_NMEA0183.Apb.BearingOriginToDestinationUnits = _T(
"M");
714 m_NMEA0183.Apb.BearingPresentPositionToDestination = bapm;
715 m_NMEA0183.Apb.BearingPresentPositionToDestinationUnits = _T(
"M");
717 m_NMEA0183.Apb.HeadingToSteer = bapm;
718 m_NMEA0183.Apb.HeadingToSteerUnits = _T(
"M");
720 m_NMEA0183.Apb.BearingOriginToDestination = brg1;
721 m_NMEA0183.Apb.BearingOriginToDestinationUnits = _T(
"T");
723 m_NMEA0183.Apb.BearingPresentPositionToDestination =
724 CurrentBrgToActivePoint;
725 m_NMEA0183.Apb.BearingPresentPositionToDestinationUnits = _T(
"T");
727 m_NMEA0183.Apb.HeadingToSteer = CurrentBrgToActivePoint;
728 m_NMEA0183.Apb.HeadingToSteerUnits = _T(
"T");
731 m_NMEA0183.Apb.Write(snt);
737 m_NMEA0183.TalkerID = _T(
"EC");
741 m_NMEA0183.Xte.IsLoranBlinkOK =
743 if (!bGPSValid) m_NMEA0183.Xte.IsLoranBlinkOK = NFalse;
745 m_NMEA0183.Xte.IsLoranCCycleLockOK = NTrue;
746 if (!bGPSValid) m_NMEA0183.Xte.IsLoranCCycleLockOK = NFalse;
748 m_NMEA0183.Xte.CrossTrackErrorDistance = CurrentXTEToActivePoint;
751 m_NMEA0183.Xte.DirectionToSteer = Left;
753 m_NMEA0183.Xte.DirectionToSteer = Right;
755 m_NMEA0183.Xte.CrossTrackUnits = _T(
"N");
757 m_NMEA0183.Xte.Write(snt);
765bool Routeman::DoesRouteContainSharedPoints(
Route *pRoute) {
769 wxRoutePointListNode *pnode = (pRoute->pRoutePointList)->GetFirst();
777 for (
unsigned int ir = 0; ir < pRA->GetCount(); ir++) {
787 if (pnode) pnode = pnode->GetNext();
791 pnode = (pRoute->pRoutePointList)->GetFirst();
794 if (prp->IsShared())
return true;
796 if (pnode) pnode = pnode->GetNext();
803bool Routeman::DeleteTrack(
Track *pTrack) {
804 if (pTrack && !pTrack->m_bIsInLayer) {
805 ::wxBeginBusyCursor();
821 pSelect->DeleteAllSelectableTrackSegments(pTrack);
822 auto it = std::find(g_TrackList.begin(), g_TrackList.end(), pTrack);
823 if (it != g_TrackList.end()) {
824 g_TrackList.erase(it);
838 if (pRoute == pAISMOBRoute) {
839 if (!m_route_dlg_ctx.confirm_delete_ais_mob()) {
844 ::wxBeginBusyCursor();
846 if (GetpActiveRoute() == pRoute) DeactivateRoute();
848 if (pRoute->m_bIsInLayer) {
856 m_prop_dlg_ctx.hide(pRoute);
858 nav_obj_changes->DeleteConfigRoute(pRoute);
861 pSelect->DeleteAllSelectableRouteSegments(pRoute);
862 pRouteList->DeleteObject(pRoute);
864 m_route_dlg_ctx.route_mgr_dlg_update_list_ctrl();
868 wxRoutePointListNode *pnode = (pRoute->pRoutePointList)->GetFirst();
873 Route *pcontainer_route = FindRouteContainingWaypoint(prp);
875 if (pcontainer_route == NULL && prp->m_bIsInRoute) {
878 if (!prp->IsShared()) {
883 pSelect->DeleteSelectablePoint(prp, SELTYPE_ROUTEPOINT);
886 wxRoutePointListNode *pdnode = pnode;
888 pRoute->pRoutePointList->DeleteNode(pdnode);
889 pdnode = pRoute->pRoutePointList->Find(prp);
896 prp->SetShared(
false);
900 pnode = pnode->GetNext();
902 pnode = pRoute->pRoutePointList->GetFirst();
913 ::wxBeginBusyCursor();
916 wxRouteListNode *node = pRouteList->GetFirst();
918 Route *proute = node->GetData();
919 if (proute == pAISMOBRoute) {
920 if (!m_route_dlg_ctx.confirm_delete_ais_mob()) {
924 ::wxBeginBusyCursor();
927 node = node->GetNext();
928 if (proute->m_bIsInLayer)
continue;
930 nav_obj_changes->m_bSkipChangeSetUpdate =
true;
931 nav_obj_changes->DeleteConfigRoute(proute);
933 nav_obj_changes->m_bSkipChangeSetUpdate =
false;
939void Routeman::SetColorScheme(ColorScheme cs,
double displayDPmm) {
942 int scaled_line_width = g_route_line_width;
943 int track_scaled_line_width = g_track_line_width;
946 double nominal_line_width_pix = wxMax(1.5, floor(displayDPmm / 5.0));
948 double sline_width = wxMax(nominal_line_width_pix, g_route_line_width);
949 sline_width *= g_ChartScaleFactorExp;
950 scaled_line_width = wxMax(sline_width, 2);
952 double tsline_width = wxMax(nominal_line_width_pix, g_track_line_width);
953 tsline_width *= g_ChartScaleFactorExp;
954 track_scaled_line_width = wxMax(tsline_width, 2);
957 m_pActiveRoutePointPen = wxThePenList->FindOrCreatePen(
958 wxColour(0, 0, 255), scaled_line_width, wxPENSTYLE_SOLID);
959 m_pRoutePointPen = wxThePenList->FindOrCreatePen(
960 wxColour(0, 0, 255), scaled_line_width, wxPENSTYLE_SOLID);
965 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"UINFB"),
966 scaled_line_width, wxPENSTYLE_SOLID);
967 m_pSelectedRoutePen =
968 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"UINFO"),
969 scaled_line_width, wxPENSTYLE_SOLID);
971 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"UARTE"),
972 scaled_line_width, wxPENSTYLE_SOLID);
974 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"CHMGD"),
975 track_scaled_line_width, wxPENSTYLE_SOLID);
976 m_pRouteBrush = wxTheBrushList->FindOrCreateBrush(
977 m_route_dlg_ctx.get_global_colour(
"UINFB"), wxBRUSHSTYLE_SOLID);
978 m_pSelectedRouteBrush = wxTheBrushList->FindOrCreateBrush(
979 m_route_dlg_ctx.get_global_colour(
"UINFO"), wxBRUSHSTYLE_SOLID);
980 m_pActiveRouteBrush = wxTheBrushList->FindOrCreateBrush(
981 m_route_dlg_ctx.get_global_colour(
"PLRTE"), wxBRUSHSTYLE_SOLID);
984wxString Routeman::GetRouteReverseMessage(
void) {
986 _(
"Waypoints can be renamed to reflect the new order, the names will be "
987 "'001', '002' etc.\n\nDo you want to rename the waypoints?"));
990wxString Routeman::GetRouteResequenceMessage(
void) {
992 _(
"Waypoints will be renamed to reflect the natural order, the names "
993 "will be '001', '002' etc.\n\nDo you want to rename the waypoints?"));
996Route *Routeman::FindRouteByGUID(
const wxString &guid) {
997 wxRouteListNode *node1 = pRouteList->GetFirst();
999 Route *pRoute = node1->GetData();
1001 if (pRoute->m_GUID == guid)
return pRoute;
1002 node1 = node1->GetNext();
1008Track *Routeman::FindTrackByGUID(
const wxString &guid) {
1009 for (
Track *pTrack : g_TrackList) {
1010 if (pTrack->m_GUID == guid)
return pTrack;
1016void Routeman::ZeroCurrentXTEToActivePoint() {
1018 if (pRouteActivatePoint)
delete pRouteActivatePoint;
1019 pRouteActivatePoint =
1020 new RoutePoint(gLat, gLon, wxString(_T(
"")), wxString(_T(
"")),
1021 wxEmptyString,
false);
1022 pRouteActivatePoint->m_bShowName =
false;
1024 pActiveRouteSegmentBeginPoint = pRouteActivatePoint;
1025 m_arrival_min = 1e6;
1032WayPointman::WayPointman(GlobalColourFunc color_func)
1033 : m_get_global_colour(color_func) {
1034 m_pWayPointList =
new RoutePointList;
1036 pmarkicon_image_list = NULL;
1039 m_pIconArray =
new ArrayOfMarkIcon;
1040 m_pLegacyIconArray = NULL;
1041 m_pExtendedIconArray = NULL;
1043 m_cs = (ColorScheme)-1;
1046 m_iconListScale = -999.0;
1047 m_iconListHeight = -1;
1050WayPointman::~WayPointman() {
1056 RoutePointList temp_list;
1058 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1062 temp_list.Append(pr);
1063 node = node->GetNext();
1066 temp_list.DeleteContents(
true);
1069 m_pWayPointList->Clear();
1070 delete m_pWayPointList;
1072 for (
unsigned int i = 0; i < m_pIconArray->GetCount(); i++) {
1074 delete pmi->piconBitmap;
1078 m_pIconArray->Clear();
1079 delete m_pIconArray;
1081 if (pmarkicon_image_list) pmarkicon_image_list->RemoveAll();
1082 delete pmarkicon_image_list;
1083 m_pLegacyIconArray->Clear();
1084 delete m_pLegacyIconArray;
1085 m_pExtendedIconArray->Clear();
1086 delete m_pExtendedIconArray;
1090 if (!prp)
return false;
1092 wxRoutePointListNode *prpnode = m_pWayPointList->Append(prp);
1093 prp->SetManagerListNode(prpnode);
1099 if (!prp)
return false;
1101 wxRoutePointListNode *prpnode =
1102 (wxRoutePointListNode *)prp->GetManagerListNode();
1107 m_pWayPointList->DeleteObject(prp);
1109 prp->SetManagerListNode(NULL);
1114wxImageList *WayPointman::Getpmarkicon_image_list(
int nominal_height) {
1116 if (pmarkicon_image_list && (nominal_height == m_iconListHeight)) {
1117 return pmarkicon_image_list;
1121 if (NULL != pmarkicon_image_list) {
1122 pmarkicon_image_list->RemoveAll();
1123 delete pmarkicon_image_list;
1125 pmarkicon_image_list =
new wxImageList(nominal_height, nominal_height);
1127 m_iconListHeight = nominal_height;
1128 m_bitmapSizeForList = nominal_height;
1130 return pmarkicon_image_list;
1133wxBitmap *WayPointman::CreateDimBitmap(wxBitmap *pBitmap,
double factor) {
1134 wxImage img = pBitmap->ConvertToImage();
1135 int sx = img.GetWidth();
1136 int sy = img.GetHeight();
1138 wxImage new_img(img);
1140 for (
int i = 0; i < sx; i++) {
1141 for (
int j = 0; j < sy; j++) {
1142 if (!img.IsTransparent(i, j)) {
1143 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
1144 (
unsigned char)(img.GetGreen(i, j) * factor),
1145 (
unsigned char)(img.GetBlue(i, j) * factor));
1150 wxBitmap *pret =
new wxBitmap(new_img);
1155wxImage WayPointman::CreateDimImage(wxImage &image,
double factor) {
1156 int sx = image.GetWidth();
1157 int sy = image.GetHeight();
1159 wxImage new_img(image);
1161 for (
int i = 0; i < sx; i++) {
1162 for (
int j = 0; j < sy; j++) {
1163 if (!image.IsTransparent(i, j)) {
1164 new_img.SetRGB(i, j, (
unsigned char)(image.GetRed(i, j) * factor),
1165 (
unsigned char)(image.GetGreen(i, j) * factor),
1166 (
unsigned char)(image.GetBlue(i, j) * factor));
1171 return wxImage(new_img);
1174bool WayPointman::DoesIconExist(
const wxString &icon_key)
const {
1178 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1179 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1180 if (pmi->icon_name.IsSameAs(icon_key))
return true;
1186wxBitmap *WayPointman::GetIconBitmap(
const wxString &icon_key)
const {
1187 wxBitmap *pret = NULL;
1191 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1192 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1193 if (pmi->icon_name.IsSameAs(icon_key))
break;
1196 if (i == m_pIconArray->GetCount())
1199 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1200 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1206 if (i == m_pIconArray->GetCount())
1207 pmi = (
MarkIcon *)m_pIconArray->Item(0);
1210 if (pmi->piconBitmap)
1211 pret = pmi->piconBitmap;
1213 if (pmi->iconImage.IsOk()) {
1214 pmi->piconBitmap =
new wxBitmap(pmi->iconImage);
1215 pret = pmi->piconBitmap;
1222bool WayPointman::GetIconPrescaled(
const wxString &icon_key)
const {
1226 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1227 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1228 if (pmi->icon_name.IsSameAs(icon_key))
break;
1231 if (i == m_pIconArray->GetCount())
1234 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1235 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1241 if (i == m_pIconArray->GetCount())
1242 pmi = (
MarkIcon *)m_pIconArray->Item(0);
1245 return pmi->preScaled;
1250wxBitmap WayPointman::GetIconBitmapForList(
int index,
int height)
const {
1255 pmi = (
MarkIcon *)m_pIconArray->Item(index);
1257 if (pmi->iconImage.GetHeight() != height) {
1260 int w0 = pmi->iconImage.GetWidth();
1261 int h0 = pmi->iconImage.GetHeight();
1263 wxImage icon_resized = pmi->iconImage;
1264 if (h0 <= h && w0 <= w) {
1265 icon_resized = pmi->iconImage.Resize(
1266 wxSize(w, h), wxPoint(w / 2 - w0 / 2, h / 2 - h0 / 2));
1273 w1 = wxRound((
double)w0 * ((
double)h / (
double)h0));
1276 h1 = wxRound((
double)h0 * ((
double)w / (
double)w0));
1278 icon_resized = pmi->iconImage.Rescale(w1, h1);
1279 icon_resized = pmi->iconImage.Resize(
1280 wxSize(w, h), wxPoint(w / 2 - w1 / 2, h / 2 - h1 / 2));
1283 pret = wxBitmap(icon_resized);
1286 pret = wxBitmap(pmi->iconImage);
1292wxString *WayPointman::GetIconDescription(
int index)
const {
1293 wxString *pret = NULL;
1297 pret = &pmi->icon_description;
1302wxString WayPointman::GetIconDescription(wxString icon_key)
const {
1306 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1307 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1308 if (pmi->icon_name.IsSameAs(icon_key))
1309 return wxString(pmi->icon_description);
1312 return wxEmptyString;
1315wxString *WayPointman::GetIconKey(
int index)
const {
1316 wxString *pret = NULL;
1318 if ((index >= 0) && ((
unsigned int)index < m_pIconArray->GetCount())) {
1320 pret = &pmi->icon_name;
1325int WayPointman::GetIconIndex(
const wxBitmap *pbm)
const {
1326 unsigned int ret = 0;
1329 wxASSERT(m_pIconArray->GetCount() >= 1);
1330 for (
unsigned int i = 0; i < m_pIconArray->GetCount(); i++) {
1331 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1332 if (pmi->piconBitmap == pbm) {
1341int WayPointman::GetIconImageListIndex(
const wxBitmap *pbm)
const {
1345 if (pmarkicon_image_list && !pmi->m_blistImageOK) {
1346 int h0 = pmi->iconImage.GetHeight();
1347 int w0 = pmi->iconImage.GetWidth();
1348 int h = m_bitmapSizeForList;
1349 int w = m_bitmapSizeForList;
1351 wxImage icon_larger = pmi->iconImage;
1352 if (h0 <= h && w0 <= w) {
1353 icon_larger = pmi->iconImage.Resize(
1354 wxSize(w, h), wxPoint(w / 2 - w0 / 2, h / 2 - h0 / 2));
1363 w1 = wxRound((
double)w0 * ((
double)h / (
double)h0));
1366 h1 = wxRound((
double)h0 * ((
double)w / (
double)w0));
1368 icon_larger = pmi->iconImage.Rescale(w1, h1).Resize(
1369 wxSize(w, h), wxPoint(w / 2 - w1 / 2, h / 2 - h1 / 2));
1372 int index = pmarkicon_image_list->Add(wxBitmap(icon_larger));
1377 icon_larger.ConvertAlphaToMask(128);
1379 unsigned char r, g, b;
1380 icon_larger.GetOrFindMaskColour(&r, &g, &b);
1381 wxColour unused_color(r, g, b);
1384 wxBitmap xIcon(icon_larger);
1386 wxBitmap xbmp(w, h, -1);
1387 wxMemoryDC mdc(xbmp);
1388 mdc.SetBackground(wxBrush(unused_color));
1390 mdc.DrawBitmap(xIcon, 0, 0);
1391 int xm = xbmp.GetWidth() / 2;
1392 int ym = xbmp.GetHeight() / 2;
1394 int width = wxMax(xm / 10, 2);
1395 wxPen red(m_get_global_colour(
"URED"), width);
1397 mdc.DrawLine(xm - dp, ym - dp, xm + dp, ym + dp);
1398 mdc.DrawLine(xm - dp, ym + dp, xm + dp, ym - dp);
1399 mdc.SelectObject(wxNullBitmap);
1401 wxMask *pmask =
new wxMask(xbmp, unused_color);
1402 xbmp.SetMask(pmask);
1404 pmarkicon_image_list->Add(xbmp);
1407 wxBitmap fIcon(icon_larger);
1409 wxBitmap fbmp(w, h, -1);
1410 wxMemoryDC fmdc(fbmp);
1411 fmdc.SetBackground(wxBrush(unused_color));
1413 fmdc.DrawBitmap(xIcon, 0, 0);
1414 xm = fbmp.GetWidth() / 2;
1415 ym = fbmp.GetHeight() / 2;
1417 width = wxMax(xm / 10, 2);
1418 wxPen fred(m_get_global_colour(
"UGREN"), width);
1420 fmdc.DrawLine(xm - dp, ym + dp, xm + dp, ym + dp);
1421 fmdc.SelectObject(wxNullBitmap);
1423 wxMask *pfmask =
new wxMask(fbmp, unused_color);
1424 fbmp.SetMask(pfmask);
1426 pmarkicon_image_list->Add(fbmp);
1428 pmi->m_blistImageOK =
true;
1429 pmi->listIndex = index;
1432 return pmi->listIndex;
1436 return GetIconImageListIndex(pbm) + 1;
1440 return GetIconImageListIndex(pbm) + 2;
1444wxString WayPointman::CreateGUID(
RoutePoint *pRP) {
1448RoutePoint *WayPointman::FindRoutePointByGUID(
const wxString &guid) {
1449 wxRoutePointListNode *prpnode = m_pWayPointList->GetFirst();
1453 if (prp->m_GUID == guid)
return (prp);
1455 prpnode = prpnode->GetNext();
1461RoutePoint *WayPointman::GetNearbyWaypoint(
double lat,
double lon,
1462 double radius_meters) {
1465 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1469 double a = lat - pr->m_lat;
1470 double b = lon - pr->m_lon;
1471 double l = sqrt((a * a) + (b * b));
1473 if ((l * 60. * 1852.) < radius_meters)
return pr;
1475 node = node->GetNext();
1480RoutePoint *WayPointman::GetOtherNearbyWaypoint(
double lat,
double lon,
1481 double radius_meters,
1482 const wxString &guid) {
1485 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1489 double a = lat - pr->m_lat;
1490 double b = lon - pr->m_lon;
1491 double l = sqrt((a * a) + (b * b));
1493 if ((l * 60. * 1852.) < radius_meters)
1494 if (pr->m_GUID != guid)
return pr;
1496 node = node->GetNext();
1501bool WayPointman::IsReallyVisible(
RoutePoint *pWP) {
1503 return pWP->IsVisible();
1505 wxRouteListNode *node = pRouteList->GetFirst();
1507 Route *proute = node->GetData();
1508 if (proute && proute->pRoutePointList) {
1509 if (proute->pRoutePointList->IndexOf(pWP) != wxNOT_FOUND) {
1510 if (proute->IsVisible())
return true;
1513 node = node->GetNext();
1516 if (pWP->IsShared())
1518 return pWP->IsVisible();
1523void WayPointman::ClearRoutePointFonts(
void) {
1527 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1531 pr->m_pMarkFont = NULL;
1532 node = node->GetNext();
1536bool WayPointman::SharedWptsExist() {
1537 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1540 if (prp->IsShared() && (prp->m_bIsInRoute || prp == pAnchorWatchPoint1 ||
1541 prp == pAnchorWatchPoint2))
1543 node = node->GetNext();
1548void WayPointman::DeleteAllWaypoints(
bool b_delete_used) {
1550 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1554 if (!prp->m_bIsInLayer && (prp->GetIconName() != _T(
"mob")) &&
1555 ((b_delete_used && prp->IsShared()) ||
1556 ((!prp->m_bIsInRoute) && !(prp == pAnchorWatchPoint1) &&
1557 !(prp == pAnchorWatchPoint2)))) {
1558 DestroyWaypoint(prp);
1560 node = m_pWayPointList->GetFirst();
1562 node = node->GetNext();
1567RoutePoint *WayPointman::FindWaypointByGuid(
const std::string &guid) {
1568 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1571 if (guid == rp->m_GUID)
return rp;
1572 node = node->GetNext();
1576void WayPointman::DestroyWaypoint(
RoutePoint *pRp,
bool b_update_changeset) {
1577 if (!b_update_changeset)
1578 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
true;
1586 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
1593 pr->RemovePoint(pRp);
1597 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
1599 if (pr->GetnPoints() < 2) {
1601 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate;
1602 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
true;
1603 NavObjectChanges::getInstance()->DeleteConfigRoute(pr);
1604 g_pRouteMan->
DeleteRoute(pr, NavObjectChanges::getInstance());
1605 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate = prev_bskip;
1609 delete proute_array;
1613 NavObjectChanges::getInstance()->DeleteWayPoint(pRp);
1614 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
false;
1616 pSelect->DeleteSelectableRoutePoint(pRp);
1619 if (pRp == pAnchorWatchPoint1) pAnchorWatchPoint1 = NULL;
1620 if (pRp == pAnchorWatchPoint2) pAnchorWatchPoint2 = NULL;
const void Notify()
Notify all listeners, no data supplied.
Wrapper for global variable, supports notification events when value changes.
static wxString GetUUID(void)
Return a unique RFC4122 version 4 compliant GUID string.
Represents a waypoint or mark within the navigation system.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
Represents a navigational route in the navigation system.
bool ActivateRoutePoint(Route *pA, RoutePoint *pRP)
Activates a specific waypoint within a route for navigation.
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
bool ActivateRoute(Route *pRouteToActivate, RoutePoint *pStartPoint=NULL)
Activates a route for navigation.
EventVar json_msg
Notified with message targeting all plugins.
EventVar json_leg_info
Notified with a shared_ptr<ActiveLegDat>, leg info to all plugins.
EventVar on_message_sent
Notified when a message available as GetString() is sent to garmin.
Represents a track, which is a series of connected track points.
int GetXIconImageListIndex(const wxBitmap *pbm) const
index of "X-ed out" icon in the image list
int GetFIconImageListIndex(const wxBitmap *pbm) const
index of "fixed viz" icon in the image list
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
The JSON value class implementation.
Driver registration container, a singleton.
std::vector< DriverHandle > GetActiveDrivers()
Comm port plugin TX support methods
const std::unordered_map< std::string, std::string > GetAttributes(DriverHandle handle)
Query a specific driver for attributes.
Callbacks for RoutePropDlg.