33 #include <wx/wxprec.h>
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"
62 bool g_bPluginHandleAutopilotRoute;
70 RouteList *pRouteList;
72 float g_ChartScaleFactorExp;
75 WX_DECLARE_LIST(wxBitmap, markicon_bitmap_list_type);
76 WX_DECLARE_LIST(wxString, markicon_key_list_type);
77 WX_DECLARE_LIST(wxString, markicon_description_list_type);
80 #include <wx/listimpl.cpp>
81 WX_DEFINE_LIST(markicon_bitmap_list_type);
82 WX_DEFINE_LIST(markicon_key_list_type);
83 WX_DEFINE_LIST(markicon_description_list_type);
86 void appendOSDirSlash(wxString *pString);
88 static void ActivatePersistedRoute(
Routeman* routeman) {
89 if (g_active_route ==
"") {
90 wxLogWarning(
"\"Persist route\" but no persisted route configured");
93 Route* route = routeman->FindRouteByGUID(g_active_route);
95 wxLogWarning(
"Persisted route GUID not available");
98 routeman->ActivateRoute(route);
111 pRouteActivatePoint(0),
112 m_NMEA0183(NmeaCtxFactory()),
114 m_route_dlg_ctx(route_dlg_ctx),
115 m_nmea_log(nmea_log) {
118 auto route_action = [&] (wxCommandEvent) {
119 if (g_persist_active_route) ActivatePersistedRoute(
this); };
120 active_route_listener.Init(active_route, route_action);
123 Routeman::~Routeman() {
124 if (pRouteActivatePoint)
delete pRouteActivatePoint;
127 bool 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();
175 wxArrayPtrVoid *Routeman::GetRouteArrayContaining(
RoutePoint *pWP) {
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);
231 RoutePoint *Routeman::FindBestActivatePoint(
Route *pR,
double lat,
double lon,
232 double cog,
double sog) {
233 if (!pR)
return NULL;
237 double min_time_found = 1e6;
239 wxRoutePointListNode *node = (pR->pRoutePointList)->GetFirst();
244 DistanceBearingMercator(pn->m_lat, pn->m_lon, lat, lon, &brg, &dist);
246 double angle = brg - cog;
247 double soa = cos(angle * PI / 180.);
249 double time_to_wp = dist / soa;
251 if (time_to_wp > 0) {
252 if (time_to_wp < min_time_found) {
253 min_time_found = time_to_wp;
257 node = node->GetNext();
262 bool Routeman::ActivateRoute(
Route *pRouteToActivate,
RoutePoint *pStartPoint) {
263 g_bAllowShipToActive =
false;
265 v[_T(
"Route_activated")] = pRouteToActivate->m_RouteNameString;
266 v[_T(
"GUID")] = pRouteToActivate->m_GUID;
267 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_ACTIVATED");
268 if (g_bPluginHandleAutopilotRoute)
return true;
270 pActiveRoute = pRouteToActivate;
271 g_active_route = pActiveRoute->GetGUID();
274 pActivePoint = pStartPoint;
276 wxRoutePointListNode *node = (pActiveRoute->pRoutePointList)->GetFirst();
277 pActivePoint = node->GetData();
286 pRouteToActivate->m_bRtIsActive =
true;
288 m_bDataValid =
false;
290 m_route_dlg_ctx.show_with_fresh_fonts();
295 g_bAllowShipToActive =
false;
297 v[_T(
"GUID")] = pRP_target->m_GUID;
298 v[_T(
"WP_activated")] = pRP_target->GetName();
300 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_WPT_ACTIVATED");
302 if (g_bPluginHandleAutopilotRoute)
return true;
306 pActivePoint = pRP_target;
307 pActiveRoute->m_pRouteActivePoint = pRP_target;
309 wxRoutePointListNode *node = (pActiveRoute->pRoutePointList)->GetFirst();
312 pn->m_bBlink =
false;
313 pn->m_bIsActive =
false;
315 node = node->GetNext();
318 node = (pActiveRoute->pRoutePointList)->GetFirst();
323 if (pRP_target == prp_first) {
324 if (pRouteActivatePoint)
delete pRouteActivatePoint;
326 pRouteActivatePoint =
327 new RoutePoint(gLat, gLon, wxString(_T(
"")), wxString(_T(
"")),
328 wxEmptyString,
false);
329 pRouteActivatePoint->m_bShowName =
false;
331 pActiveRouteSegmentBeginPoint = pRouteActivatePoint;
335 prp_first->m_bBlink =
false;
336 node = node->GetNext();
340 if (pnext == pRP_target) {
341 pActiveRouteSegmentBeginPoint = np_prev;
346 node = node->GetNext();
350 pRP_target->m_bBlink =
true;
351 pRP_target->m_bIsActive =
true;
353 g_blink_rect = pRP_target->CurrentRect_in_DC;
365 m_prop_dlg_ctx.set_enroute_point(pA, pActivePoint);
370 g_bAllowShipToActive =
false;
373 pActivePoint->m_bBlink =
false;
374 pActivePoint->m_bIsActive =
false;
376 v[_T(
"isSkipped")] = skipped;
377 v[_T(
"GUID")] = pActivePoint->m_GUID;
378 v[_T(
"GUID_WP_arrived")] = pActivePoint->m_GUID;
379 v[_T(
"WP_arrived")] = pActivePoint->GetName();
381 int n_index_active = pActiveRoute->GetIndexOf(pActivePoint);
382 if ((n_index_active + 1) <= pActiveRoute->GetnPoints()) {
383 pActiveRouteSegmentBeginPoint = pActivePoint;
385 pActiveRoute->m_pRouteActivePoint =
386 pActiveRoute->GetPoint(n_index_active + 1);
388 pActivePoint = pActiveRoute->GetPoint(n_index_active + 1);
389 v[_T(
"Next_WP")] = pActivePoint->GetName();
390 v[_T(
"GUID_Next_WP")] = pActivePoint->m_GUID;
392 pActivePoint->m_bBlink =
true;
393 pActivePoint->m_bIsActive =
true;
394 g_blink_rect = pActivePoint->CurrentRect_in_DC;
406 m_prop_dlg_ctx.set_enroute_point(pr, pActivePoint);
408 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_WPT_ARRIVED");
415 bool Routeman::DeactivateRoute(
bool b_arrival) {
417 pActivePoint->m_bBlink =
false;
418 pActivePoint->m_bIsActive =
false;
422 pActiveRoute->m_bRtIsActive =
false;
423 pActiveRoute->m_pRouteActivePoint = NULL;
424 g_active_route.Clear();
428 v[_T(
"Route_deactivated")] = pActiveRoute->m_RouteNameString;
429 v[_T(
"GUID")] = pActiveRoute->m_GUID;
430 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_DEACTIVATED");
432 v[_T(
"GUID")] = pActiveRoute->m_GUID;
433 v[_T(
"Route_ended")] = pActiveRoute->m_RouteNameString;
434 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_RTE_ENDED");
440 if (pRouteActivatePoint)
delete pRouteActivatePoint;
441 pRouteActivatePoint = NULL;
445 m_route_dlg_ctx.clear_console_background();
446 m_bDataValid =
false;
451 bool Routeman::UpdateAutopilot() {
459 if ((g_maxWPNameLength >= 3) && (g_maxWPNameLength <= 32))
460 maxName = g_maxWPNameLength;
464 double r_Sog(0.0), r_Cog(0.0);
465 if (!std::isnan(gSog)) r_Sog = gSog;
466 if (!std::isnan(gCog)) r_Cog = gCog;
471 leg_info.Btw = CurrentBrgToActivePoint;
472 leg_info.Dtw = CurrentRngToActivePoint;
473 leg_info.Xte = CurrentXTEToActivePoint;
475 leg_info.Xte = -leg_info.Xte;
477 leg_info.wp_name = pActivePoint->GetName().Truncate(maxName);
478 leg_info.arrival = m_bArrival;
484 m_NMEA0183.TalkerID =
"EC";
486 m_NMEA0183.Rmb.IsDataValid = bGPSValid ? NTrue : NFalse;
487 m_NMEA0183.Rmb.CrossTrackError = CurrentXTEToActivePoint;
488 m_NMEA0183.Rmb.DirectionToSteer = XTEDir < 0 ? Left : Right;
489 m_NMEA0183.Rmb.RangeToDestinationNauticalMiles = CurrentRngToActivePoint;
490 m_NMEA0183.Rmb.BearingToDestinationDegreesTrue = CurrentBrgToActivePoint;
492 if (pActivePoint->m_lat < 0.)
493 m_NMEA0183.Rmb.DestinationPosition.Latitude.Set(
494 -pActivePoint->m_lat,
"S");
496 m_NMEA0183.Rmb.DestinationPosition.Latitude.Set(
497 pActivePoint->m_lat,
"N");
499 if (pActivePoint->m_lon < 0.)
500 m_NMEA0183.Rmb.DestinationPosition.Longitude.Set(
501 -pActivePoint->m_lon,
"W");
503 m_NMEA0183.Rmb.DestinationPosition.Longitude.Set(
504 pActivePoint->m_lon,
"E");
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;
531 m_NMEA0183.Rmc.IsDataValid = NFalse;
534 m_NMEA0183.Rmc.Position.Latitude.Set(-gLat, _T(
"S"));
536 m_NMEA0183.Rmc.Position.Latitude.Set(gLat, _T(
"N"));
539 m_NMEA0183.Rmc.Position.Longitude.Set(-gLon, _T(
"W"));
541 m_NMEA0183.Rmc.Position.Longitude.Set(gLon, _T(
"E"));
543 m_NMEA0183.Rmc.SpeedOverGroundKnots = r_Sog;
544 m_NMEA0183.Rmc.TrackMadeGoodDegreesTrue = r_Cog;
546 if (!std::isnan(gVar)) {
548 m_NMEA0183.Rmc.MagneticVariation = -gVar;
549 m_NMEA0183.Rmc.MagneticVariationDirection = West;
551 m_NMEA0183.Rmc.MagneticVariation = gVar;
552 m_NMEA0183.Rmc.MagneticVariationDirection = East;
555 m_NMEA0183.Rmc.MagneticVariation =
559 if (!gRmcTime.IsEmpty() && !gRmcDate.IsEmpty()) {
560 m_NMEA0183.Rmc.UTCTime = gRmcTime;
561 m_NMEA0183.Rmc.Date = gRmcDate;
563 wxDateTime now = wxDateTime::Now();
564 wxDateTime utc = now.ToUTC();
565 wxString time = utc.Format(_T(
"%H%M%S"));
566 m_NMEA0183.Rmc.UTCTime = time;
567 wxString date = utc.Format(_T(
"%d%m%y"));
568 m_NMEA0183.Rmc.Date = date;
571 m_NMEA0183.Rmc.FAAModeIndicator =
"A";
573 m_NMEA0183.Rmc.FAAModeIndicator =
"N";
575 m_NMEA0183.Rmc.Write(snt);
582 m_NMEA0183.TalkerID = _T(
"EC");
586 m_NMEA0183.Apb.IsLoranBlinkOK = NTrue;
588 m_NMEA0183.Apb.IsLoranBlinkOK = NFalse;
590 m_NMEA0183.Apb.IsLoranCCycleLockOK = NTrue;
592 m_NMEA0183.Apb.IsLoranCCycleLockOK = NFalse;
594 m_NMEA0183.Apb.CrossTrackErrorMagnitude = CurrentXTEToActivePoint;
597 m_NMEA0183.Apb.DirectionToSteer = Left;
599 m_NMEA0183.Apb.DirectionToSteer = Right;
601 m_NMEA0183.Apb.CrossTrackUnits = _T(
"N");
604 m_NMEA0183.Apb.IsArrivalCircleEntered = NTrue;
606 m_NMEA0183.Apb.IsArrivalCircleEntered = NFalse;
610 m_NMEA0183.Apb.IsPerpendicular = NFalse;
612 m_NMEA0183.Apb.To = pActivePoint->GetName().Truncate(maxName);
615 DistanceBearingMercator(pActivePoint->m_lat, pActivePoint->m_lon,
616 pActiveRouteSegmentBeginPoint->m_lat,
617 pActiveRouteSegmentBeginPoint->m_lon, &brg1,
620 if (g_bMagneticAPB && !std::isnan(gVar)) {
622 ((brg1 - gVar) >= 0.) ? (brg1 - gVar) : (brg1 - gVar + 360.);
623 double bapm = ((CurrentBrgToActivePoint - gVar) >= 0.)
624 ? (CurrentBrgToActivePoint - gVar)
625 : (CurrentBrgToActivePoint - gVar + 360.);
627 m_NMEA0183.Apb.BearingOriginToDestination = brg1m;
628 m_NMEA0183.Apb.BearingOriginToDestinationUnits = _T(
"M");
630 m_NMEA0183.Apb.BearingPresentPositionToDestination = bapm;
631 m_NMEA0183.Apb.BearingPresentPositionToDestinationUnits = _T(
"M");
633 m_NMEA0183.Apb.HeadingToSteer = bapm;
634 m_NMEA0183.Apb.HeadingToSteerUnits = _T(
"M");
636 m_NMEA0183.Apb.BearingOriginToDestination = brg1;
637 m_NMEA0183.Apb.BearingOriginToDestinationUnits = _T(
"T");
639 m_NMEA0183.Apb.BearingPresentPositionToDestination =
640 CurrentBrgToActivePoint;
641 m_NMEA0183.Apb.BearingPresentPositionToDestinationUnits = _T(
"T");
643 m_NMEA0183.Apb.HeadingToSteer = CurrentBrgToActivePoint;
644 m_NMEA0183.Apb.HeadingToSteerUnits = _T(
"T");
647 m_NMEA0183.Apb.Write(snt);
653 m_NMEA0183.TalkerID = _T(
"EC");
657 m_NMEA0183.Xte.IsLoranBlinkOK = NTrue;
659 m_NMEA0183.Xte.IsLoranBlinkOK = NFalse;
661 m_NMEA0183.Xte.IsLoranCCycleLockOK = NTrue;
663 m_NMEA0183.Xte.IsLoranCCycleLockOK = NFalse;
665 m_NMEA0183.Xte.CrossTrackErrorDistance = CurrentXTEToActivePoint;
668 m_NMEA0183.Xte.DirectionToSteer = Left;
670 m_NMEA0183.Xte.DirectionToSteer = Right;
672 m_NMEA0183.Xte.CrossTrackUnits = _T(
"N");
674 m_NMEA0183.Xte.Write(snt);
681 bool Routeman::DoesRouteContainSharedPoints(
Route *pRoute) {
685 wxRoutePointListNode *pnode = (pRoute->pRoutePointList)->GetFirst();
690 wxArrayPtrVoid *pRA = GetRouteArrayContaining(prp);
693 for (
unsigned int ir = 0; ir < pRA->GetCount(); ir++) {
702 if (pnode) pnode = pnode->GetNext();
706 pnode = (pRoute->pRoutePointList)->GetFirst();
709 if (prp->IsShared())
return true;
711 if (pnode) pnode = pnode->GetNext();
718 bool Routeman::DeleteTrack(
Track *pTrack) {
719 if (pTrack && !pTrack->m_bIsInLayer) {
720 ::wxBeginBusyCursor();
736 pSelect->DeleteAllSelectableTrackSegments(pTrack);
737 auto it = std::find(g_TrackList.begin(), g_TrackList.end(), pTrack);
738 if (it != g_TrackList.end()) {
739 g_TrackList.erase(it);
753 if (pRoute == pAISMOBRoute) {
754 if (!m_route_dlg_ctx.confirm_delete_ais_mob()) {
759 ::wxBeginBusyCursor();
761 if (GetpActiveRoute() == pRoute) DeactivateRoute();
763 if (pRoute->m_bIsInLayer) {
771 m_prop_dlg_ctx.hide(pRoute);
773 nav_obj_changes->DeleteConfigRoute(pRoute);
776 pSelect->DeleteAllSelectableRouteSegments(pRoute);
777 pRouteList->DeleteObject(pRoute);
779 m_route_dlg_ctx.route_mgr_dlg_update_list_ctrl();
783 wxRoutePointListNode *pnode = (pRoute->pRoutePointList)->GetFirst();
788 Route *pcontainer_route = FindRouteContainingWaypoint(prp);
790 if (pcontainer_route == NULL && prp->m_bIsInRoute) {
793 if (!prp->IsShared()) {
798 pSelect->DeleteSelectablePoint(prp, SELTYPE_ROUTEPOINT);
801 wxRoutePointListNode *pdnode = pnode;
803 pRoute->pRoutePointList->DeleteNode(pdnode);
804 pdnode = pRoute->pRoutePointList->Find(prp);
810 prp->m_bDynamicName =
false;
811 prp->m_bIsolatedMark =
true;
812 prp->SetShared(
false);
816 pnode = pnode->GetNext();
818 pnode = pRoute->pRoutePointList->GetFirst();
829 ::wxBeginBusyCursor();
832 wxRouteListNode *node = pRouteList->GetFirst();
834 Route *proute = node->GetData();
835 if (proute == pAISMOBRoute) {
836 if (!m_route_dlg_ctx.confirm_delete_ais_mob()) {
840 ::wxBeginBusyCursor();
843 node = node->GetNext();
844 if (proute->m_bIsInLayer)
continue;
846 nav_obj_changes->m_bSkipChangeSetUpdate =
true;
847 nav_obj_changes->DeleteConfigRoute(proute);
849 nav_obj_changes->m_bSkipChangeSetUpdate =
false;
856 void Routeman::SetColorScheme(ColorScheme cs,
double displayDPmm) {
859 int scaled_line_width = g_route_line_width;
860 int track_scaled_line_width = g_track_line_width;
863 double nominal_line_width_pix = wxMax(1.5, floor(displayDPmm / 5.0));
865 double sline_width = wxMax(nominal_line_width_pix, g_route_line_width);
866 sline_width *= g_ChartScaleFactorExp;
867 scaled_line_width = wxMax(sline_width, 2);
869 double tsline_width = wxMax(nominal_line_width_pix, g_track_line_width);
870 tsline_width *= g_ChartScaleFactorExp;
871 track_scaled_line_width = wxMax(tsline_width, 2);
874 m_pActiveRoutePointPen = wxThePenList->FindOrCreatePen(
875 wxColour(0, 0, 255), scaled_line_width, wxPENSTYLE_SOLID);
876 m_pRoutePointPen = wxThePenList->FindOrCreatePen(
877 wxColour(0, 0, 255), scaled_line_width, wxPENSTYLE_SOLID);
881 m_pRoutePen = wxThePenList->FindOrCreatePen(
882 m_route_dlg_ctx.get_global_colour(
"UINFB"), scaled_line_width,
884 m_pSelectedRoutePen = wxThePenList->FindOrCreatePen(
885 m_route_dlg_ctx.get_global_colour(
"UINFO"), scaled_line_width,
887 m_pActiveRoutePen = wxThePenList->FindOrCreatePen(
888 m_route_dlg_ctx.get_global_colour(
"UARTE"), scaled_line_width,
890 m_pTrackPen = wxThePenList->FindOrCreatePen(
891 m_route_dlg_ctx.get_global_colour(
"CHMGD"), track_scaled_line_width,
893 m_pRouteBrush = wxTheBrushList->FindOrCreateBrush(
894 m_route_dlg_ctx.get_global_colour(
"UINFB"), wxBRUSHSTYLE_SOLID);
895 m_pSelectedRouteBrush = wxTheBrushList->FindOrCreateBrush(
896 m_route_dlg_ctx.get_global_colour(
"UINFO"), wxBRUSHSTYLE_SOLID);
897 m_pActiveRouteBrush = wxTheBrushList->FindOrCreateBrush(
898 m_route_dlg_ctx.get_global_colour(
"PLRTE"), wxBRUSHSTYLE_SOLID);
901 wxString Routeman::GetRouteReverseMessage(
void) {
903 _(
"Waypoints can be renamed to reflect the new order, the names will be "
904 "'001', '002' etc.\n\nDo you want to rename the waypoints?"));
907 wxString Routeman::GetRouteResequenceMessage(
void) {
909 _(
"Waypoints will be renamed to reflect the natural order, the names "
910 "will be '001', '002' etc.\n\nDo you want to rename the waypoints?"));
913 Route *Routeman::FindRouteByGUID(
const wxString &guid) {
914 wxRouteListNode *node1 = pRouteList->GetFirst();
916 Route *pRoute = node1->GetData();
918 if (pRoute->m_GUID == guid)
return pRoute;
919 node1 = node1->GetNext();
925 Track *Routeman::FindTrackByGUID(
const wxString &guid) {
926 for (
Track* pTrack : g_TrackList) {
927 if (pTrack->m_GUID == guid)
return pTrack;
933 void Routeman::ZeroCurrentXTEToActivePoint() {
935 if (pRouteActivatePoint)
delete pRouteActivatePoint;
936 pRouteActivatePoint =
937 new RoutePoint(gLat, gLon, wxString(_T(
"")), wxString(_T(
"")),
938 wxEmptyString,
false);
939 pRouteActivatePoint->m_bShowName =
false;
941 pActiveRouteSegmentBeginPoint = pRouteActivatePoint;
949 WayPointman::WayPointman(GlobalColourFunc color_func)
950 : m_get_global_colour(color_func) {
951 m_pWayPointList =
new RoutePointList;
953 pmarkicon_image_list = NULL;
956 m_pIconArray =
new ArrayOfMarkIcon;
957 m_pLegacyIconArray = NULL;
958 m_pExtendedIconArray = NULL;
960 m_cs = (ColorScheme)-1;
963 m_iconListScale = -999.0;
964 m_iconListHeight = -1;
967 WayPointman::~WayPointman() {
973 RoutePointList temp_list;
975 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
979 temp_list.Append(pr);
980 node = node->GetNext();
983 temp_list.DeleteContents(
true);
986 m_pWayPointList->Clear();
987 delete m_pWayPointList;
989 for (
unsigned int i = 0; i < m_pIconArray->GetCount(); i++) {
991 delete pmi->piconBitmap;
995 m_pIconArray->Clear();
998 if (pmarkicon_image_list) pmarkicon_image_list->RemoveAll();
999 delete pmarkicon_image_list;
1000 m_pLegacyIconArray->Clear();
1001 delete m_pLegacyIconArray;
1002 m_pExtendedIconArray->Clear();
1003 delete m_pExtendedIconArray;
1006 bool WayPointman::AddRoutePoint(
RoutePoint *prp) {
1007 if (!prp)
return false;
1009 wxRoutePointListNode *prpnode = m_pWayPointList->Append(prp);
1010 prp->SetManagerListNode(prpnode);
1015 bool WayPointman::RemoveRoutePoint(
RoutePoint *prp) {
1016 if (!prp)
return false;
1018 wxRoutePointListNode *prpnode =
1019 (wxRoutePointListNode *)prp->GetManagerListNode();
1024 m_pWayPointList->DeleteObject(prp);
1026 prp->SetManagerListNode(NULL);
1031 wxImageList *WayPointman::Getpmarkicon_image_list(
int nominal_height) {
1033 if (pmarkicon_image_list && (nominal_height == m_iconListHeight)) {
1034 return pmarkicon_image_list;
1038 if (NULL != pmarkicon_image_list) {
1039 pmarkicon_image_list->RemoveAll();
1040 delete pmarkicon_image_list;
1042 pmarkicon_image_list =
new wxImageList(nominal_height, nominal_height);
1044 m_iconListHeight = nominal_height;
1045 m_bitmapSizeForList = nominal_height;
1047 return pmarkicon_image_list;
1050 wxBitmap *WayPointman::CreateDimBitmap(wxBitmap *pBitmap,
double factor) {
1051 wxImage img = pBitmap->ConvertToImage();
1052 int sx = img.GetWidth();
1053 int sy = img.GetHeight();
1055 wxImage new_img(img);
1057 for (
int i = 0; i < sx; i++) {
1058 for (
int j = 0; j < sy; j++) {
1059 if (!img.IsTransparent(i, j)) {
1060 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
1061 (
unsigned char)(img.GetGreen(i, j) * factor),
1062 (
unsigned char)(img.GetBlue(i, j) * factor));
1067 wxBitmap *pret =
new wxBitmap(new_img);
1072 wxImage WayPointman::CreateDimImage(wxImage &image,
double factor) {
1073 int sx = image.GetWidth();
1074 int sy = image.GetHeight();
1076 wxImage new_img(image);
1078 for (
int i = 0; i < sx; i++) {
1079 for (
int j = 0; j < sy; j++) {
1080 if (!image.IsTransparent(i, j)) {
1081 new_img.SetRGB(i, j, (
unsigned char)(image.GetRed(i, j) * factor),
1082 (
unsigned char)(image.GetGreen(i, j) * factor),
1083 (
unsigned char)(image.GetBlue(i, j) * factor));
1088 return wxImage(new_img);
1091 bool WayPointman::DoesIconExist(
const wxString &icon_key)
const {
1095 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1096 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1097 if (pmi->icon_name.IsSameAs(icon_key))
return true;
1103 wxBitmap *WayPointman::GetIconBitmap(
const wxString &icon_key) {
1104 wxBitmap *pret = NULL;
1108 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1109 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1110 if (pmi->icon_name.IsSameAs(icon_key))
break;
1113 if (i == m_pIconArray->GetCount())
1116 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1117 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1123 if (i == m_pIconArray->GetCount())
1124 pmi = (
MarkIcon *)m_pIconArray->Item(0);
1127 if (pmi->piconBitmap)
1128 pret = pmi->piconBitmap;
1130 if (pmi->iconImage.IsOk()) {
1131 pmi->piconBitmap =
new wxBitmap(pmi->iconImage);
1132 pret = pmi->piconBitmap;
1139 bool WayPointman::GetIconPrescaled(
const wxString &icon_key) {
1143 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1144 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1145 if (pmi->icon_name.IsSameAs(icon_key))
break;
1148 if (i == m_pIconArray->GetCount())
1151 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1152 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1158 if (i == m_pIconArray->GetCount())
1159 pmi = (
MarkIcon *)m_pIconArray->Item(0);
1162 return pmi->preScaled;
1167 wxBitmap WayPointman::GetIconBitmapForList(
int index,
int height) {
1172 pmi = (
MarkIcon *)m_pIconArray->Item(index);
1174 if (pmi->iconImage.GetHeight() != height) {
1177 int w0 = pmi->iconImage.GetWidth();
1178 int h0 = pmi->iconImage.GetHeight();
1180 wxImage icon_resized = pmi->iconImage;
1181 if (h0 <= h && w0 <= w) {
1182 icon_resized = pmi->iconImage.Resize(
1183 wxSize(w, h), wxPoint(w / 2 - w0 / 2, h / 2 - h0 / 2));
1190 w1 = wxRound((
double)w0 * ((
double)h / (
double)h0));
1193 h1 = wxRound((
double)h0 * ((
double)w / (
double)w0));
1195 icon_resized = pmi->iconImage.Rescale(w1, h1);
1196 icon_resized = pmi->iconImage.Resize(
1197 wxSize(w, h), wxPoint(w / 2 - w1 / 2, h / 2 - h1 / 2));
1200 pret = wxBitmap(icon_resized);
1203 pret = wxBitmap(pmi->iconImage);
1209 wxString *WayPointman::GetIconDescription(
int index) {
1210 wxString *pret = NULL;
1214 pret = &pmi->icon_description;
1219 wxString WayPointman::GetIconDescription(wxString icon_key) {
1223 for (i = 0; i < m_pIconArray->GetCount(); i++) {
1224 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1225 if (pmi->icon_name.IsSameAs(icon_key))
1226 return wxString(pmi->icon_description);
1229 return wxEmptyString;
1232 wxString *WayPointman::GetIconKey(
int index) {
1233 wxString *pret = NULL;
1235 if ((index >= 0) && ((
unsigned int)index < m_pIconArray->GetCount())) {
1237 pret = &pmi->icon_name;
1242 int WayPointman::GetIconIndex(
const wxBitmap *pbm) {
1243 unsigned int ret = 0;
1246 wxASSERT(m_pIconArray->GetCount() >= 1);
1247 for (
unsigned int i = 0; i < m_pIconArray->GetCount(); i++) {
1248 pmi = (
MarkIcon *)m_pIconArray->Item(i);
1249 if (pmi->piconBitmap == pbm) {
1258 int WayPointman::GetIconImageListIndex(
const wxBitmap *pbm) {
1262 if (pmarkicon_image_list && !pmi->m_blistImageOK) {
1263 int h0 = pmi->iconImage.GetHeight();
1264 int w0 = pmi->iconImage.GetWidth();
1265 int h = m_bitmapSizeForList;
1266 int w = m_bitmapSizeForList;
1268 wxImage icon_larger = pmi->iconImage;
1269 if (h0 <= h && w0 <= w) {
1270 icon_larger = pmi->iconImage.Resize(
1271 wxSize(w, h), wxPoint(w / 2 - w0 / 2, h / 2 - h0 / 2));
1278 w1 = wxRound((
double)w0 * ((
double)h / (
double)h0));
1281 h1 = wxRound((
double)h0 * ((
double)w / (
double)w0));
1283 icon_larger = pmi->iconImage.Rescale(w1, h1).Resize(wxSize(w, h),
1284 wxPoint(w / 2 - w1 / 2, h / 2 - h1 / 2));
1287 int index = pmarkicon_image_list->Add(wxBitmap(icon_larger));
1292 icon_larger.ConvertAlphaToMask(128);
1294 unsigned char r, g, b;
1295 icon_larger.GetOrFindMaskColour(&r, &g, &b);
1296 wxColour unused_color(r, g, b);
1299 wxBitmap xIcon(icon_larger);
1301 wxBitmap xbmp(w, h, -1);
1302 wxMemoryDC mdc(xbmp);
1303 mdc.SetBackground(wxBrush(unused_color));
1305 mdc.DrawBitmap(xIcon, 0, 0);
1306 int xm = xbmp.GetWidth() / 2;
1307 int ym = xbmp.GetHeight() / 2;
1309 int width = wxMax(xm / 10, 2);
1310 wxPen red(m_get_global_colour(
"URED"), width);
1312 mdc.DrawLine(xm - dp, ym - dp, xm + dp, ym + dp);
1313 mdc.DrawLine(xm - dp, ym + dp, xm + dp, ym - dp);
1314 mdc.SelectObject(wxNullBitmap);
1316 wxMask *pmask =
new wxMask(xbmp, unused_color);
1317 xbmp.SetMask(pmask);
1319 pmarkicon_image_list->Add(xbmp);
1322 wxBitmap fIcon(icon_larger);
1324 wxBitmap fbmp(w, h, -1);
1325 wxMemoryDC fmdc(fbmp);
1326 fmdc.SetBackground(wxBrush(unused_color));
1328 fmdc.DrawBitmap(xIcon, 0, 0);
1329 xm = fbmp.GetWidth() / 2;
1330 ym = fbmp.GetHeight() / 2;
1332 width = wxMax(xm / 10, 2);
1333 wxPen fred(m_get_global_colour(
"UGREN"), width);
1335 fmdc.DrawLine(xm - dp, ym + dp, xm + dp, ym + dp);
1336 fmdc.SelectObject(wxNullBitmap);
1338 wxMask *pfmask =
new wxMask(fbmp, unused_color);
1339 fbmp.SetMask(pfmask);
1341 pmarkicon_image_list->Add(fbmp);
1343 pmi->m_blistImageOK =
true;
1344 pmi->listIndex = index;
1347 return pmi->listIndex;
1350 int WayPointman::GetXIconImageListIndex(
const wxBitmap *pbm) {
1351 return GetIconImageListIndex(pbm) +
1355 int WayPointman::GetFIconImageListIndex(
const wxBitmap *pbm) {
1356 return GetIconImageListIndex(pbm) +
1361 wxString WayPointman::CreateGUID(
RoutePoint *pRP) {
1372 return GpxDocument::GetUUID();
1375 RoutePoint *WayPointman::FindRoutePointByGUID(
const wxString &guid) {
1376 wxRoutePointListNode *prpnode = m_pWayPointList->GetFirst();
1380 if (prp->m_GUID == guid)
return (prp);
1382 prpnode = prpnode->GetNext();
1388 RoutePoint *WayPointman::GetNearbyWaypoint(
double lat,
double lon,
1389 double radius_meters) {
1392 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1396 double a = lat - pr->m_lat;
1397 double b = lon - pr->m_lon;
1398 double l = sqrt((a * a) + (b * b));
1400 if ((l * 60. * 1852.) < radius_meters)
return pr;
1402 node = node->GetNext();
1407 RoutePoint *WayPointman::GetOtherNearbyWaypoint(
double lat,
double lon,
1408 double radius_meters,
1409 const wxString &guid) {
1412 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1416 double a = lat - pr->m_lat;
1417 double b = lon - pr->m_lon;
1418 double l = sqrt((a * a) + (b * b));
1420 if ((l * 60. * 1852.) < radius_meters)
1421 if (pr->m_GUID != guid)
return pr;
1423 node = node->GetNext();
1428 bool WayPointman::IsReallyVisible(
RoutePoint *pWP) {
1429 if (pWP->m_bIsolatedMark)
1430 return pWP->IsVisible();
1432 wxRouteListNode *node = pRouteList->GetFirst();
1434 Route *proute = node->GetData();
1435 if (proute && proute->pRoutePointList) {
1436 if (proute->pRoutePointList->IndexOf(pWP) != wxNOT_FOUND) {
1437 if (proute->IsVisible())
return true;
1440 node = node->GetNext();
1443 if (pWP->IsShared())
1445 return pWP->IsVisible();
1450 void WayPointman::ClearRoutePointFonts(
void) {
1454 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1458 pr->m_pMarkFont = NULL;
1459 node = node->GetNext();
1463 bool WayPointman::SharedWptsExist() {
1464 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1467 if (prp->IsShared() && (prp->m_bIsInRoute || prp == pAnchorWatchPoint1 ||
1468 prp == pAnchorWatchPoint2))
1470 node = node->GetNext();
1475 void WayPointman::DeleteAllWaypoints(
bool b_delete_used) {
1477 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1481 if (!prp->m_bIsInLayer && (prp->GetIconName() != _T(
"mob")) &&
1482 ((b_delete_used && prp->IsShared()) ||
1483 ((!prp->m_bIsInRoute) && !(prp == pAnchorWatchPoint1) &&
1484 !(prp == pAnchorWatchPoint2)))) {
1485 DestroyWaypoint(prp);
1487 node = m_pWayPointList->GetFirst();
1489 node = node->GetNext();
1494 RoutePoint* WayPointman::FindWaypointByGuid(
const std::string& guid) {
1495 wxRoutePointListNode *node = m_pWayPointList->GetFirst();
1498 if (guid == rp->m_GUID)
return rp;
1499 node = node->GetNext();
1503 void WayPointman::DestroyWaypoint(
RoutePoint *pRp,
bool b_update_changeset) {
1504 if (!b_update_changeset)
1505 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
true;
1511 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(pRp);
1513 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
1520 pr->RemovePoint(pRp);
1524 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
1526 if (pr->GetnPoints() < 2) {
1528 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate;
1529 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
true;
1530 NavObjectChanges::getInstance()->DeleteConfigRoute(pr);
1531 g_pRouteMan->
DeleteRoute(pr, NavObjectChanges::getInstance());
1532 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate = prev_bskip;
1536 delete proute_array;
1540 NavObjectChanges::getInstance()->DeleteWayPoint(pRp);
1541 NavObjectChanges::getInstance()->m_bSkipChangeSetUpdate =
false;
1543 pSelect->DeleteSelectableRoutePoint(pRp);
1546 if (pRp == pAnchorWatchPoint1) pAnchorWatchPoint1 = NULL;
1547 if (pRp == pAnchorWatchPoint2) pAnchorWatchPoint2 = NULL;
1549 RemoveRoutePoint(pRp);
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.
Callbacks for RoutePropDlg.