36#include <wx/jsonval.h>
37#include <wx/listimpl.cpp>
38#include <wx/tokenzr.h>
40#include "model/ais_decoder.h"
41#include "model/base_platform.h"
42#include "model/comm_n0183_output.h"
43#include "model/comm_vars.h"
44#include "model/config_vars.h"
45#include "model/cutil.h"
46#include "model/georef.h"
47#include "model/nav_object_database.h"
48#include "model/navutil_base.h"
49#include "model/nmea_ctx_factory.h"
50#include "model/own_ship.h"
51#include "model/route.h"
52#include "model/routeman.h"
53#include "model/track.h"
55#include "observable_globvar.h"
58#include "androidUTIL.h"
61bool g_bPluginHandleAutopilotRoute;
71float g_ChartScaleFactorExp;
74WX_DECLARE_LIST(wxBitmap, markicon_bitmap_list_type);
75WX_DECLARE_LIST(wxString, markicon_key_list_type);
76WX_DECLARE_LIST(wxString, markicon_description_list_type);
79#include <wx/listimpl.cpp>
80WX_DEFINE_LIST(markicon_bitmap_list_type);
81WX_DEFINE_LIST(markicon_key_list_type);
82WX_DEFINE_LIST(markicon_description_list_type);
85void appendOSDirSlash(wxString *pString);
87static void ActivatePersistedRoute(
Routeman *routeman) {
88 if (g_active_route ==
"") {
89 wxLogWarning(
"\"Persist route\" but no persisted route configured");
92 Route *route = routeman->FindRouteByGUID(g_active_route);
94 wxLogWarning(
"Persisted route GUID not available");
97 routeman->ActivateRoute(route);
108 pRouteActivatePoint(0),
109 m_NMEA0183(NmeaCtxFactory()),
111 m_route_dlg_ctx(route_dlg_ctx),
112 m_nmea_log(nmea_log) {
114 auto route_action = [&](wxCommandEvent) {
115 if (g_persist_active_route) ActivatePersistedRoute(
this);
117 active_route_listener.Init(active_route, route_action);
120Routeman::~Routeman() {
121 if (pRouteActivatePoint)
delete pRouteActivatePoint;
124bool Routeman::IsRouteValid(
Route *pRoute) {
125 wxRouteListNode *node = pRouteList->GetFirst();
127 if (pRoute == node->GetData())
return true;
128 node = node->GetNext();
135 wxRouteListNode *node = pRouteList->GetFirst();
137 Route *proute = node->GetData();
139 wxRoutePointListNode *pnode = (proute->pRoutePointList)->GetFirst();
142 if (prp == pWP)
return proute;
143 pnode = pnode->GetNext();
146 node = node->GetNext();
154 wxRouteListNode *node = pRouteList->GetFirst();
156 Route *proute = node->GetData();
157 if (proute->IsVisible()) {
158 wxRoutePointListNode *pnode = (proute->pRoutePointList)->GetFirst();
161 if (prp == pWP)
return proute;
162 pnode = pnode->GetNext();
166 node = node->GetNext();
172wxArrayPtrVoid *Routeman::GetRouteArrayContaining(
RoutePoint *pWP) {
173 wxArrayPtrVoid *pArray =
new wxArrayPtrVoid;
175 wxRouteListNode *route_node = pRouteList->GetFirst();
177 Route *proute = route_node->GetData();
179 wxRoutePointListNode *waypoint_node = (proute->pRoutePointList)->GetFirst();
180 while (waypoint_node) {
183 pArray->Add((
void *)proute);
188 waypoint_node = waypoint_node->GetNext();
191 route_node = route_node->GetNext();
194 if (pArray->GetCount())
206 pSelect->DeleteAllSelectableRoutePoints(route);
207 pSelect->DeleteAllSelectableRouteSegments(route);
209 route->RemovePoint(point);
213 if (route->GetnPoints() <= 1 && route_state == 0) {
214 NavObjectChanges::getInstance()->DeleteConfigRoute(route);
215 g_pRouteMan->
DeleteRoute(route, NavObjectChanges::getInstance());
219 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
224 m_prop_dlg_ctx.set_route_and_update(route);
227RoutePoint *Routeman::FindBestActivatePoint(
Route *pR,
double lat,
double lon,
228 double cog,
double sog) {
229 if (!pR)
return NULL;
233 double min_time_found = 1e6;
235 wxRoutePointListNode *node = (pR->pRoutePointList)->GetFirst();
240 DistanceBearingMercator(pn->m_lat, pn->m_lon, lat, lon, &brg, &dist);
242 double angle = brg - cog;
243 double soa = cos(angle * PI / 180.);
245 double time_to_wp = dist / soa;
247 if (time_to_wp > 0) {
248 if (time_to_wp < min_time_found) {
249 min_time_found = time_to_wp;
253 node = node->GetNext();
258bool Routeman::ActivateRoute(
Route *pRouteToActivate,
RoutePoint *pStartPoint) {
259 g_bAllowShipToActive =
false;
261 v[_T(
"Route_activated")] = pRouteToActivate->m_RouteNameString;
262 v[_T(
"GUID")] = pRouteToActivate->m_GUID;
263 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_ACTIVATED");
264 if (g_bPluginHandleAutopilotRoute)
return true;
266 pActiveRoute = pRouteToActivate;
267 g_active_route = pActiveRoute->GetGUID();
270 pActivePoint = pStartPoint;
272 wxRoutePointListNode *node = (pActiveRoute->pRoutePointList)->GetFirst();
273 pActivePoint = node->GetData();
282 pRouteToActivate->m_bRtIsActive =
true;
284 m_bDataValid =
false;
286 m_route_dlg_ctx.show_with_fresh_fonts();
291 g_bAllowShipToActive =
false;
293 v[_T(
"GUID")] = pRP_target->m_GUID;
294 v[_T(
"WP_activated")] = pRP_target->GetName();
296 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_WPT_ACTIVATED");
298 if (g_bPluginHandleAutopilotRoute)
return true;
302 pActivePoint = pRP_target;
303 pActiveRoute->m_pRouteActivePoint = pRP_target;
305 wxRoutePointListNode *node = (pActiveRoute->pRoutePointList)->GetFirst();
308 pn->m_bBlink =
false;
309 pn->m_bIsActive =
false;
311 node = node->GetNext();
314 node = (pActiveRoute->pRoutePointList)->GetFirst();
319 if (pRP_target == prp_first) {
320 if (pRouteActivatePoint)
delete pRouteActivatePoint;
322 pRouteActivatePoint =
323 new RoutePoint(gLat, gLon, wxString(_T(
"")), wxString(_T(
"")),
324 wxEmptyString,
false);
325 pRouteActivatePoint->m_bShowName =
false;
327 pActiveRouteSegmentBeginPoint = pRouteActivatePoint;
331 prp_first->m_bBlink =
false;
332 node = node->GetNext();
336 if (pnext == pRP_target) {
337 pActiveRouteSegmentBeginPoint = np_prev;
342 node = node->GetNext();
346 pRP_target->m_bBlink =
true;
347 pRP_target->m_bIsActive =
true;
349 g_blink_rect = pRP_target->CurrentRect_in_DC;
361 m_prop_dlg_ctx.set_enroute_point(pA, pActivePoint);
366 g_bAllowShipToActive =
false;
370 pActivePoint->m_bBlink =
false;
371 pActivePoint->m_bIsActive =
false;
373 v[_T(
"isSkipped")] = skipped;
374 v[_T(
"GUID")] = pActivePoint->m_GUID;
375 v[_T(
"GUID_WP_arrived")] = pActivePoint->m_GUID;
376 v[_T(
"WP_arrived")] = pActivePoint->GetName();
378 int n_index_active = pActiveRoute->GetIndexOf(pActivePoint);
380 while (n_index_active == pActiveRoute->GetIndexOf(pActivePoint)) {
381 if ((n_index_active + step) <= pActiveRoute->GetnPoints()) {
382 pActiveRouteSegmentBeginPoint = pActivePoint;
383 pActiveRoute->m_pRouteActivePoint =
384 pActiveRoute->GetPoint(n_index_active + step);
385 pActivePoint = pActiveRoute->GetPoint(n_index_active + step);
394 v[_T(
"Next_WP")] = pActivePoint->GetName();
395 v[_T(
"GUID_Next_WP")] = pActivePoint->m_GUID;
397 pActivePoint->m_bBlink =
true;
398 pActivePoint->m_bIsActive =
true;
399 g_blink_rect = pActivePoint->CurrentRect_in_DC;
410 m_prop_dlg_ctx.set_enroute_point(pr, pActivePoint);
412 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_WPT_ARRIVED");
417bool Routeman::DeactivateRoute(
bool b_arrival) {
419 pActivePoint->m_bBlink =
false;
420 pActivePoint->m_bIsActive =
false;
424 pActiveRoute->m_bRtIsActive =
false;
425 pActiveRoute->m_pRouteActivePoint = NULL;
426 g_active_route.Clear();
430 v[_T(
"Route_deactivated")] = pActiveRoute->m_RouteNameString;
431 v[_T(
"GUID")] = pActiveRoute->m_GUID;
432 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_DEACTIVATED");
434 v[_T(
"GUID")] = pActiveRoute->m_GUID;
435 v[_T(
"Route_ended")] = pActiveRoute->m_RouteNameString;
436 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_ENDED");
442 if (pRouteActivatePoint)
delete pRouteActivatePoint;
443 pRouteActivatePoint = NULL;
447 m_route_dlg_ctx.clear_console_background();
448 m_bDataValid =
false;
453bool Routeman::UpdateAutopilot() {
454 if (!bGPSValid)
return false;
460 if ((g_maxWPNameLength >= 3) && (g_maxWPNameLength <= 32))
461 maxName = g_maxWPNameLength;
465 double r_Sog(0.0), r_Cog(0.0);
466 if (!std::isnan(gSog)) r_Sog = gSog;
467 if (!std::isnan(gCog)) r_Cog = gCog;
472 leg_info.Btw = CurrentBrgToActivePoint;
473 leg_info.Dtw = CurrentRngToActivePoint;
474 leg_info.Xte = CurrentXTEToActivePoint;
476 leg_info.Xte = -leg_info.Xte;
478 leg_info.wp_name = pActivePoint->GetName().Truncate(maxName);
479 leg_info.arrival = m_bArrival;
485 m_NMEA0183.TalkerID =
"EC";
487 m_NMEA0183.Rmb.IsDataValid = bGPSValid ? NTrue : NFalse;
488 m_NMEA0183.Rmb.CrossTrackError = CurrentXTEToActivePoint;
489 m_NMEA0183.Rmb.DirectionToSteer = XTEDir < 0 ? Left : Right;
490 m_NMEA0183.Rmb.RangeToDestinationNauticalMiles = CurrentRngToActivePoint;
491 m_NMEA0183.Rmb.BearingToDestinationDegreesTrue = CurrentBrgToActivePoint;
493 if (pActivePoint->m_lat < 0.)
494 m_NMEA0183.Rmb.DestinationPosition.Latitude.Set(-pActivePoint->m_lat,
497 m_NMEA0183.Rmb.DestinationPosition.Latitude.Set(pActivePoint->m_lat,
"N");
499 if (pActivePoint->m_lon < 0.)
500 m_NMEA0183.Rmb.DestinationPosition.Longitude.Set(-pActivePoint->m_lon,
503 m_NMEA0183.Rmb.DestinationPosition.Longitude.Set(pActivePoint->m_lon,
506 m_NMEA0183.Rmb.DestinationClosingVelocityKnots =
507 r_Sog * cos((r_Cog - CurrentBrgToActivePoint) * PI / 180.0);
508 m_NMEA0183.Rmb.IsArrivalCircleEntered = m_bArrival ? NTrue : NFalse;
509 m_NMEA0183.Rmb.FAAModeIndicator = bGPSValid ?
"A" :
"N";
512 int wp_len = maxName;
514 m_NMEA0183.Rmb.To = pActivePoint->GetName().Truncate(wp_len);
515 m_NMEA0183.Rmb.From =
516 pActiveRouteSegmentBeginPoint->GetName().Truncate(wp_len);
517 m_NMEA0183.Rmb.Write(snt);
519 }
while (snt.Sentence.size() > 82 && wp_len > 0);
526 m_NMEA0183.TalkerID = _T(
"EC");
529 m_NMEA0183.Rmc.IsDataValid = NTrue;
530 if (!bGPSValid) m_NMEA0183.Rmc.IsDataValid = NFalse;
533 m_NMEA0183.Rmc.Position.Latitude.Set(-gLat, _T(
"S"));
535 m_NMEA0183.Rmc.Position.Latitude.Set(gLat, _T(
"N"));
538 m_NMEA0183.Rmc.Position.Longitude.Set(-gLon, _T(
"W"));
540 m_NMEA0183.Rmc.Position.Longitude.Set(gLon, _T(
"E"));
542 m_NMEA0183.Rmc.SpeedOverGroundKnots = r_Sog;
543 m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue = r_Cog;
545 if (!std::isnan(gVar)) {
547 m_NMEA0183.Rmc.MagneticVariation = -gVar;
548 m_NMEA0183.Rmc.MagneticVariationDirection = West;
550 m_NMEA0183.Rmc.MagneticVariation = gVar;
551 m_NMEA0183.Rmc.MagneticVariationDirection = East;
554 m_NMEA0183.Rmc.MagneticVariation =
558 if (!gRmcTime.IsEmpty() && !gRmcDate.IsEmpty()) {
559 m_NMEA0183.Rmc.UTCTime = gRmcTime;
560 m_NMEA0183.Rmc.Date = gRmcDate;
562 wxDateTime now = wxDateTime::Now();
563 wxDateTime utc = now.ToUTC();
564 wxString time = utc.Format(_T(
"%H%M%S"));
565 m_NMEA0183.Rmc.UTCTime = time;
566 wxString date = utc.Format(_T(
"%d%m%y"));
567 m_NMEA0183.Rmc.Date = date;
570 m_NMEA0183.Rmc.FAAModeIndicator =
"A";
571 if (!bGPSValid) m_NMEA0183.Rmc.FAAModeIndicator =
"N";
573 m_NMEA0183.Rmc.Write(snt);
580 m_NMEA0183.TalkerID = _T(
"EC");
584 m_NMEA0183.Apb.IsLoranBlinkOK =
586 if (!bGPSValid) m_NMEA0183.Apb.IsLoranBlinkOK = NFalse;
588 m_NMEA0183.Apb.IsLoranCCycleLockOK = NTrue;
589 if (!bGPSValid) m_NMEA0183.Apb.IsLoranCCycleLockOK = NFalse;
591 m_NMEA0183.Apb.CrossTrackErrorMagnitude = CurrentXTEToActivePoint;
594 m_NMEA0183.Apb.DirectionToSteer = Left;
596 m_NMEA0183.Apb.DirectionToSteer = Right;
598 m_NMEA0183.Apb.CrossTrackUnits = _T(
"N");
601 m_NMEA0183.Apb.IsArrivalCircleEntered = NTrue;
603 m_NMEA0183.Apb.IsArrivalCircleEntered = NFalse;
607 m_NMEA0183.Apb.IsPerpendicular = NFalse;
609 m_NMEA0183.Apb.To = pActivePoint->GetName().Truncate(maxName);
612 DistanceBearingMercator(pActivePoint->m_lat, pActivePoint->m_lon,
613 pActiveRouteSegmentBeginPoint->m_lat,
614 pActiveRouteSegmentBeginPoint->m_lon, &brg1,
617 if (g_bMagneticAPB && !std::isnan(gVar)) {
619 ((brg1 - gVar) >= 0.) ? (brg1 - gVar) : (brg1 - gVar + 360.);
620 double bapm = ((CurrentBrgToActivePoint - gVar) >= 0.)
621 ? (CurrentBrgToActivePoint - gVar)
622 : (CurrentBrgToActivePoint - gVar + 360.);
624 m_NMEA0183.Apb.BearingOriginToDestination = brg1m;
625 m_NMEA0183.Apb.BearingOriginToDestinationUnits = _T(
"M");
627 m_NMEA0183.Apb.BearingPresentPositionToDestination = bapm;
628 m_NMEA0183.Apb.BearingPresentPositionToDestinationUnits = _T(
"M");
630 m_NMEA0183.Apb.HeadingToSteer = bapm;
631 m_NMEA0183.Apb.HeadingToSteerUnits = _T(
"M");
633 m_NMEA0183.Apb.BearingOriginToDestination = brg1;
634 m_NMEA0183.Apb.BearingOriginToDestinationUnits = _T(
"T");
636 m_NMEA0183.Apb.BearingPresentPositionToDestination =
637 CurrentBrgToActivePoint;
638 m_NMEA0183.Apb.BearingPresentPositionToDestinationUnits = _T(
"T");
640 m_NMEA0183.Apb.HeadingToSteer = CurrentBrgToActivePoint;
641 m_NMEA0183.Apb.HeadingToSteerUnits = _T(
"T");
644 m_NMEA0183.Apb.Write(snt);
650 m_NMEA0183.TalkerID = _T(
"EC");
654 m_NMEA0183.Xte.IsLoranBlinkOK =
656 if (!bGPSValid) m_NMEA0183.Xte.IsLoranBlinkOK = NFalse;
658 m_NMEA0183.Xte.IsLoranCCycleLockOK = NTrue;
659 if (!bGPSValid) m_NMEA0183.Xte.IsLoranCCycleLockOK = NFalse;
661 m_NMEA0183.Xte.CrossTrackErrorDistance = CurrentXTEToActivePoint;
664 m_NMEA0183.Xte.DirectionToSteer = Left;
666 m_NMEA0183.Xte.DirectionToSteer = Right;
668 m_NMEA0183.Xte.CrossTrackUnits = _T(
"N");
670 m_NMEA0183.Xte.Write(snt);
677bool Routeman::DoesRouteContainSharedPoints(
Route *pRoute) {
681 wxRoutePointListNode *pnode = (pRoute->pRoutePointList)->GetFirst();
686 wxArrayPtrVoid *pRA = GetRouteArrayContaining(prp);
689 for (
unsigned int ir = 0; ir < pRA->GetCount(); ir++) {
698 if (pnode) pnode = pnode->GetNext();
702 pnode = (pRoute->pRoutePointList)->GetFirst();
705 if (prp->IsShared())
return true;
707 if (pnode) pnode = pnode->GetNext();
714bool Routeman::DeleteTrack(
Track *pTrack) {
715 if (pTrack && !pTrack->m_bIsInLayer) {
716 ::wxBeginBusyCursor();
732 pSelect->DeleteAllSelectableTrackSegments(pTrack);
733 auto it = std::find(g_TrackList.begin(), g_TrackList.end(), pTrack);
734 if (it != g_TrackList.end()) {
735 g_TrackList.erase(it);
749 if (pRoute == pAISMOBRoute) {
750 if (!m_route_dlg_ctx.confirm_delete_ais_mob()) {
755 ::wxBeginBusyCursor();
757 if (GetpActiveRoute() == pRoute) DeactivateRoute();
759 if (pRoute->m_bIsInLayer) {
767 m_prop_dlg_ctx.hide(pRoute);
769 nav_obj_changes->DeleteConfigRoute(pRoute);
772 pSelect->DeleteAllSelectableRouteSegments(pRoute);
773 pRouteList->DeleteObject(pRoute);
775 m_route_dlg_ctx.route_mgr_dlg_update_list_ctrl();
779 wxRoutePointListNode *pnode = (pRoute->pRoutePointList)->GetFirst();
784 Route *pcontainer_route = FindRouteContainingWaypoint(prp);
786 if (pcontainer_route == NULL && prp->m_bIsInRoute) {
789 if (!prp->IsShared()) {
794 pSelect->DeleteSelectablePoint(prp, SELTYPE_ROUTEPOINT);
797 wxRoutePointListNode *pdnode = pnode;
799 pRoute->pRoutePointList->DeleteNode(pdnode);
800 pdnode = pRoute->pRoutePointList->Find(prp);
806 prp->m_bIsolatedMark =
true;
807 prp->SetShared(
false);
811 pnode = pnode->GetNext();
813 pnode = pRoute->pRoutePointList->GetFirst();
824 ::wxBeginBusyCursor();
827 wxRouteListNode *node = pRouteList->GetFirst();
829 Route *proute = node->GetData();
830 if (proute == pAISMOBRoute) {
831 if (!m_route_dlg_ctx.confirm_delete_ais_mob()) {
835 ::wxBeginBusyCursor();
838 node = node->GetNext();
839 if (proute->m_bIsInLayer)
continue;
841 nav_obj_changes->m_bSkipChangeSetUpdate =
true;
842 nav_obj_changes->DeleteConfigRoute(proute);
844 nav_obj_changes->m_bSkipChangeSetUpdate =
false;
850void Routeman::SetColorScheme(ColorScheme cs,
double displayDPmm) {
853 int scaled_line_width = g_route_line_width;
854 int track_scaled_line_width = g_track_line_width;
857 double nominal_line_width_pix = wxMax(1.5, floor(displayDPmm / 5.0));
859 double sline_width = wxMax(nominal_line_width_pix, g_route_line_width);
860 sline_width *= g_ChartScaleFactorExp;
861 scaled_line_width = wxMax(sline_width, 2);
863 double tsline_width = wxMax(nominal_line_width_pix, g_track_line_width);
864 tsline_width *= g_ChartScaleFactorExp;
865 track_scaled_line_width = wxMax(tsline_width, 2);
868 m_pActiveRoutePointPen = wxThePenList->FindOrCreatePen(
869 wxColour(0, 0, 255), scaled_line_width, wxPENSTYLE_SOLID);
870 m_pRoutePointPen = wxThePenList->FindOrCreatePen(
871 wxColour(0, 0, 255), scaled_line_width, wxPENSTYLE_SOLID);
876 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"UINFB"),
877 scaled_line_width, wxPENSTYLE_SOLID);
878 m_pSelectedRoutePen =
879 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"UINFO"),
880 scaled_line_width, wxPENSTYLE_SOLID);
882 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"UARTE"),
883 scaled_line_width, wxPENSTYLE_SOLID);
885 wxThePenList->FindOrCreatePen(m_route_dlg_ctx.get_global_colour(
"CHMGD"),
886 track_scaled_line_width, wxPENSTYLE_SOLID);
887 m_pRouteBrush = wxTheBrushList->FindOrCreateBrush(
888 m_route_dlg_ctx.get_global_colour(
"UINFB"), wxBRUSHSTYLE_SOLID);
889 m_pSelectedRouteBrush = wxTheBrushList->FindOrCreateBrush(
890 m_route_dlg_ctx.get_global_colour(
"UINFO"), wxBRUSHSTYLE_SOLID);
891 m_pActiveRouteBrush = wxTheBrushList->FindOrCreateBrush(
892 m_route_dlg_ctx.get_global_colour(
"PLRTE"), wxBRUSHSTYLE_SOLID);
895wxString Routeman::GetRouteReverseMessage(
void) {
897 _(
"Waypoints can be renamed to reflect the new order, the names will be "
898 "'001', '002' etc.\n\nDo you want to rename the waypoints?"));
901wxString Routeman::GetRouteResequenceMessage(
void) {
903 _(
"Waypoints will be renamed to reflect the natural order, the names "
904 "will be '001', '002' etc.\n\nDo you want to rename the waypoints?"));
907Route *Routeman::FindRouteByGUID(
const wxString &guid) {
908 wxRouteListNode *node1 = pRouteList->GetFirst();
910 Route *pRoute = node1->GetData();
912 if (pRoute->m_GUID == guid)
return pRoute;
913 node1 = node1->GetNext();
919Track *Routeman::FindTrackByGUID(
const wxString &guid) {
920 for (
Track *pTrack : g_TrackList) {
921 if (pTrack->m_GUID == guid)
return pTrack;
927void Routeman::ZeroCurrentXTEToActivePoint() {
929 if (pRouteActivatePoint)
delete pRouteActivatePoint;
930 pRouteActivatePoint =
931 new RoutePoint(gLat, gLon, wxString(_T(
"")), wxString(_T(
"")),
932 wxEmptyString,
false);
933 pRouteActivatePoint->m_bShowName =
false;
935 pActiveRouteSegmentBeginPoint = pRouteActivatePoint;
943WayPointman::WayPointman(GlobalColourFunc color_func)
944 : m_get_global_colour(color_func) {
945 m_pWayPointList =
new RoutePointList;
947 pmarkicon_image_list = NULL;
950 m_pIconArray =
new ArrayOfMarkIcon;
951 m_pLegacyIconArray = NULL;
952 m_pExtendedIconArray = NULL;
954 m_cs = (ColorScheme)-1;
957 m_iconListScale = -999.0;
958 m_iconListHeight = -1;
961WayPointman::~WayPointman() {
967 RoutePointList temp_list;
969 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
973 temp_list.Append(pr);
974 node = node->GetNext();
977 temp_list.DeleteContents(
true);
980 m_pWayPointList->Clear();
981 delete m_pWayPointList;
983 for (
unsigned int i = 0; i < m_pIconArray->GetCount(); i++) {
985 delete pmi->piconBitmap;
989 m_pIconArray->Clear();
992 if (pmarkicon_image_list) pmarkicon_image_list->RemoveAll();
993 delete pmarkicon_image_list;
994 m_pLegacyIconArray->Clear();
995 delete m_pLegacyIconArray;
996 m_pExtendedIconArray->Clear();
997 delete m_pExtendedIconArray;
1001 if (!prp)
return false;
1003 wxRoutePointListNode *prpnode = m_pWayPointList->Append(prp);
1004 prp->SetManagerListNode(prpnode);
1010 if (!prp)
return false;
1012 wxRoutePointListNode *prpnode =
1013 (wxRoutePointListNode *)prp->GetManagerListNode();
1018 m_pWayPointList->DeleteObject(prp);
1020 prp->SetManagerListNode(NULL);
1025wxImageList *WayPointman::Getpmarkicon_image_list(
int nominal_height) {
1027 if (pmarkicon_image_list && (nominal_height == m_iconListHeight)) {
1028 return pmarkicon_image_list;
1032 if (NULL != pmarkicon_image_list) {
1033 pmarkicon_image_list->RemoveAll();
1034 delete pmarkicon_image_list;
1036 pmarkicon_image_list =
new wxImageList(nominal_height, nominal_height);
1038 m_iconListHeight = nominal_height;
1039 m_bitmapSizeForList = nominal_height;
1041 return pmarkicon_image_list;
1044wxBitmap *WayPointman::CreateDimBitmap(wxBitmap *pBitmap,
double factor) {
1045 wxImage img = pBitmap->ConvertToImage();
1046 int sx = img.GetWidth();
1047 int sy = img.GetHeight();
1049 wxImage new_img(img);
1051 for (
int i = 0; i < sx; i++) {
1052 for (
int j = 0; j < sy; j++) {
1053 if (!img.IsTransparent(i, j)) {
1054 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
1055 (
unsigned char)(img.GetGreen(i, j) * factor),
1056 (
unsigned char)(img.GetBlue(i, j) * factor));
1061 wxBitmap *pret =
new wxBitmap(new_img);
1066wxImage WayPointman::CreateDimImage(wxImage &image,
double factor) {
1067 int sx = image.GetWidth();
1068 int sy = image.GetHeight();
1070 wxImage new_img(image);
1072 for (
int i = 0; i < sx; i++) {
1073 for (
int j = 0; j < sy; j++) {
1074 if (!image.IsTransparent(i, j)) {
1075 new_img.SetRGB(i, j, (
unsigned char)(image.GetRed(i, j) * factor),
1076 (
unsigned char)(image.GetGreen(i, j) * factor),
1077 (
unsigned char)(image.GetBlue(i, j) * factor));
1082 return wxImage(new_img);
1085bool WayPointman::DoesIconExist(
const wxString &icon_key)
const {
1089 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1090 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1091 if (pmi->icon_name.IsSameAs(icon_key))
return true;
1097wxBitmap *WayPointman::GetIconBitmap(
const wxString &icon_key)
const {
1098 wxBitmap *pret = NULL;
1102 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1103 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1104 if (pmi->icon_name.IsSameAs(icon_key))
break;
1107 if (i == m_pIconArray->GetCount())
1110 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1111 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1117 if (i == m_pIconArray->GetCount())
1118 pmi = (
MarkIcon *)m_pIconArray->Item(0);
1121 if (pmi->piconBitmap)
1122 pret = pmi->piconBitmap;
1124 if (pmi->iconImage.IsOk()) {
1125 pmi->piconBitmap =
new wxBitmap(pmi->iconImage);
1126 pret = pmi->piconBitmap;
1133bool WayPointman::GetIconPrescaled(
const wxString &icon_key)
const {
1137 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1138 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1139 if (pmi->icon_name.IsSameAs(icon_key))
break;
1142 if (i == m_pIconArray->GetCount())
1145 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1146 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1152 if (i == m_pIconArray->GetCount())
1153 pmi = (
MarkIcon *)m_pIconArray->Item(0);
1156 return pmi->preScaled;
1161wxBitmap WayPointman::GetIconBitmapForList(
int index,
int height)
const {
1166 pmi = (
MarkIcon *)m_pIconArray->Item(index);
1168 if (pmi->iconImage.GetHeight() != height) {
1171 int w0 = pmi->iconImage.GetWidth();
1172 int h0 = pmi->iconImage.GetHeight();
1174 wxImage icon_resized = pmi->iconImage;
1175 if (h0 <= h && w0 <= w) {
1176 icon_resized = pmi->iconImage.Resize(
1177 wxSize(w, h), wxPoint(w / 2 - w0 / 2, h / 2 - h0 / 2));
1184 w1 = wxRound((
double)w0 * ((
double)h / (
double)h0));
1187 h1 = wxRound((
double)h0 * ((
double)w / (
double)w0));
1189 icon_resized = pmi->iconImage.Rescale(w1, h1);
1190 icon_resized = pmi->iconImage.Resize(
1191 wxSize(w, h), wxPoint(w / 2 - w1 / 2, h / 2 - h1 / 2));
1194 pret = wxBitmap(icon_resized);
1197 pret = wxBitmap(pmi->iconImage);
1203wxString *WayPointman::GetIconDescription(
int index)
const {
1204 wxString *pret = NULL;
1208 pret = &pmi->icon_description;
1213wxString WayPointman::GetIconDescription(wxString icon_key)
const {
1217 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1218 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1219 if (pmi->icon_name.IsSameAs(icon_key))
1220 return wxString(pmi->icon_description);
1223 return wxEmptyString;
1226wxString *WayPointman::GetIconKey(
int index)
const {
1227 wxString *pret = NULL;
1229 if ((index >= 0) && ((
unsigned int)index < m_pIconArray->GetCount())) {
1231 pret = &pmi->icon_name;
1236int WayPointman::GetIconIndex(
const wxBitmap *pbm)
const {
1237 unsigned int ret = 0;
1240 wxASSERT(m_pIconArray->GetCount() >= 1);
1241 for (
unsigned int i = 0; i < m_pIconArray->GetCount(); i++) {
1242 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1243 if (pmi->piconBitmap == pbm) {
1252int WayPointman::GetIconImageListIndex(
const wxBitmap *pbm)
const {
1256 if (pmarkicon_image_list && !pmi->m_blistImageOK) {
1257 int h0 = pmi->iconImage.GetHeight();
1258 int w0 = pmi->iconImage.GetWidth();
1259 int h = m_bitmapSizeForList;
1260 int w = m_bitmapSizeForList;
1262 wxImage icon_larger = pmi->iconImage;
1263 if (h0 <= h && w0 <= w) {
1264 icon_larger = pmi->iconImage.Resize(
1265 wxSize(w, h), wxPoint(w / 2 - w0 / 2, h / 2 - h0 / 2));
1274 w1 = wxRound((
double)w0 * ((
double)h / (
double)h0));
1277 h1 = wxRound((
double)h0 * ((
double)w / (
double)w0));
1279 icon_larger = pmi->iconImage.Rescale(w1, h1).Resize(
1280 wxSize(w, h), wxPoint(w / 2 - w1 / 2, h / 2 - h1 / 2));
1283 int index = pmarkicon_image_list->Add(wxBitmap(icon_larger));
1288 icon_larger.ConvertAlphaToMask(128);
1290 unsigned char r, g, b;
1291 icon_larger.GetOrFindMaskColour(&r, &g, &b);
1292 wxColour unused_color(r, g, b);
1295 wxBitmap xIcon(icon_larger);
1297 wxBitmap xbmp(w, h, -1);
1298 wxMemoryDC mdc(xbmp);
1299 mdc.SetBackground(wxBrush(unused_color));
1301 mdc.DrawBitmap(xIcon, 0, 0);
1302 int xm = xbmp.GetWidth() / 2;
1303 int ym = xbmp.GetHeight() / 2;
1305 int width = wxMax(xm / 10, 2);
1306 wxPen red(m_get_global_colour(
"URED"), width);
1308 mdc.DrawLine(xm - dp, ym - dp, xm + dp, ym + dp);
1309 mdc.DrawLine(xm - dp, ym + dp, xm + dp, ym - dp);
1310 mdc.SelectObject(wxNullBitmap);
1312 wxMask *pmask =
new wxMask(xbmp, unused_color);
1313 xbmp.SetMask(pmask);
1315 pmarkicon_image_list->Add(xbmp);
1318 wxBitmap fIcon(icon_larger);
1320 wxBitmap fbmp(w, h, -1);
1321 wxMemoryDC fmdc(fbmp);
1322 fmdc.SetBackground(wxBrush(unused_color));
1324 fmdc.DrawBitmap(xIcon, 0, 0);
1325 xm = fbmp.GetWidth() / 2;
1326 ym = fbmp.GetHeight() / 2;
1328 width = wxMax(xm / 10, 2);
1329 wxPen fred(m_get_global_colour(
"UGREN"), width);
1331 fmdc.DrawLine(xm - dp, ym + dp, xm + dp, ym + dp);
1332 fmdc.SelectObject(wxNullBitmap);
1334 wxMask *pfmask =
new wxMask(fbmp, unused_color);
1335 fbmp.SetMask(pfmask);
1337 pmarkicon_image_list->Add(fbmp);
1339 pmi->m_blistImageOK =
true;
1340 pmi->listIndex = index;
1343 return pmi->listIndex;
1347 return GetIconImageListIndex(pbm) + 1;
1351 return GetIconImageListIndex(pbm) + 2;
1355wxString WayPointman::CreateGUID(
RoutePoint *pRP) {
1356 return GpxDocument::GetUUID();
1359RoutePoint *WayPointman::FindRoutePointByGUID(
const wxString &guid) {
1360 wxRoutePointListNode *prpnode = m_pWayPointList->GetFirst();
1364 if (prp->m_GUID == guid)
return (prp);
1366 prpnode = prpnode->GetNext();
1372RoutePoint *WayPointman::GetNearbyWaypoint(
double lat,
double lon,
1373 double radius_meters) {
1376 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1380 double a = lat - pr->m_lat;
1381 double b = lon - pr->m_lon;
1382 double l = sqrt((a * a) + (b * b));
1384 if ((l * 60. * 1852.) < radius_meters)
return pr;
1386 node = node->GetNext();
1391RoutePoint *WayPointman::GetOtherNearbyWaypoint(
double lat,
double lon,
1392 double radius_meters,
1393 const wxString &guid) {
1396 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1400 double a = lat - pr->m_lat;
1401 double b = lon - pr->m_lon;
1402 double l = sqrt((a * a) + (b * b));
1404 if ((l * 60. * 1852.) < radius_meters)
1405 if (pr->m_GUID != guid)
return pr;
1407 node = node->GetNext();
1412bool WayPointman::IsReallyVisible(
RoutePoint *pWP) {
1413 if (pWP->m_bIsolatedMark)
1414 return pWP->IsVisible();
1416 wxRouteListNode *node = pRouteList->GetFirst();
1418 Route *proute = node->GetData();
1419 if (proute && proute->pRoutePointList) {
1420 if (proute->pRoutePointList->IndexOf(pWP) != wxNOT_FOUND) {
1421 if (proute->IsVisible())
return true;
1424 node = node->GetNext();
1427 if (pWP->IsShared())
1429 return pWP->IsVisible();
1434void WayPointman::ClearRoutePointFonts(
void) {
1438 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1442 pr->m_pMarkFont = NULL;
1443 node = node->GetNext();
1447bool WayPointman::SharedWptsExist() {
1448 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1451 if (prp->IsShared() && (prp->m_bIsInRoute || prp == pAnchorWatchPoint1 ||
1452 prp == pAnchorWatchPoint2))
1454 node = node->GetNext();
1459void WayPointman::DeleteAllWaypoints(
bool b_delete_used) {
1461 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1465 if (!prp->m_bIsInLayer && (prp->GetIconName() != _T(
"mob")) &&
1466 ((b_delete_used && prp->IsShared()) ||
1467 ((!prp->m_bIsInRoute) && !(prp == pAnchorWatchPoint1) &&
1468 !(prp == pAnchorWatchPoint2)))) {
1469 DestroyWaypoint(prp);
1471 node = m_pWayPointList->GetFirst();
1473 node = node->GetNext();
1478RoutePoint *WayPointman::FindWaypointByGuid(
const std::string &guid) {
1479 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1482 if (guid == rp->m_GUID)
return rp;
1483 node = node->GetNext();
1487void WayPointman::DestroyWaypoint(
RoutePoint *pRp,
bool b_update_changeset) {
1488 if (!b_update_changeset)
1489 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
true;
1495 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(pRp);
1497 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
1504 pr->RemovePoint(pRp);
1508 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
1510 if (pr->GetnPoints() < 2) {
1512 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate;
1513 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
true;
1514 NavObjectChanges::getInstance()->DeleteConfigRoute(pr);
1515 g_pRouteMan->
DeleteRoute(pr, NavObjectChanges::getInstance());
1516 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate = prev_bskip;
1520 delete proute_array;
1524 NavObjectChanges::getInstance()->DeleteWayPoint(pRp);
1525 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
false;
1527 pSelect->DeleteSelectableRoutePoint(pRp);
1530 if (pRp == pAnchorWatchPoint1) pAnchorWatchPoint1 = NULL;
1531 if (pRp == pAnchorWatchPoint2) pAnchorWatchPoint2 = NULL;
const void Notify()
Notify all listeners, no data supplied.
Wrapper for global variable, supports notification events when value changes.
bool ActivateRoutePoint(Route *pA, RoutePoint *pRP)
bool ActivateNextPoint(Route *pr, bool skipped)
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
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.
Callbacks for RoutePropDlg.