33#include <wx/graphics.h>
34#include <wx/clipbrd.h>
35#include <wx/aui/aui.h>
39#include <wx/listimpl.cpp>
43#include "model/ais_target_data.h"
45#include "model/conn_params.h"
46#include "model/cutil.h"
47#include "model/geodesic.h"
49#include "model/idents.h"
52#include "model/nav_object_database.h"
54#include "model/navutil_base.h"
55#include "model/own_ship.h"
57#include "model/route.h"
58#include "model/routeman.h"
59#include "model/select.h"
60#include "model/select_item.h"
61#include "model/track.h"
62#include "model/wx28compat.h"
65#include "AISTargetAlertDialog.h"
66#include "CanvasConfig.h"
67#include "canvasMenu.h"
68#include "CanvasOptions.h"
77#include "hotkeys_dlg.h"
79#include "glTextureDescriptor.h"
81#include "iENCToolbar.h"
88#include "OCPN_AUIManager.h"
90#include "ocpn_frame.h"
91#include "ocpn_pixel.h"
92#include "OCPNRegion.h"
98#include "routemanagerdialog.h"
99#include "route_point_gui.h"
101#include "RoutePropDlgImpl.h"
105#include "SendToGpsDlg.h"
106#include "shapefile_basemap.h"
108#include "SystemCmdSound.h"
112#include "tide_time.h"
115#include "track_gui.h"
116#include "TrackPropDlg.h"
119#include "s57_ocpn_utils.h"
122#include "androidUTIL.h"
126#include "glChartCanvas.h"
127#include "notification_manager_gui.h"
132#include <wx/msw/msvcrt.h>
141extern float g_ShipScaleFactorExp;
142extern double g_mouse_zoom_sensitivity;
147#define printf printf2
149int __cdecl printf2(
const char *format, ...) {
153 va_start(argptr, format);
154 int ret = vsnprintf(str,
sizeof(str), format, argptr);
156 OutputDebugStringA(str);
161#if defined(__MSVC__) && (_MSC_VER < 1700)
162#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
168#define OCPN_ALT_MENUBAR 1
176extern bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
177extern void catch_signals(
int signo);
179extern void AlphaBlending(
ocpnDC &dc,
int x,
int y,
int size_x,
int size_y,
180 float radius, wxColour color,
181 unsigned char transparency);
183extern double g_ChartNotRenderScaleFactor;
185extern bool bDBUpdateInProgress;
186extern ColorScheme global_color_scheme;
187extern int g_nbrightness;
192extern RouteList *pRouteList;
193extern std::vector<Track *> g_TrackList;
204extern double AnchorPointMinDist;
205extern bool AnchorAlertOn1;
206extern bool AnchorAlertOn2;
211extern wxString GetLayerName(
int id);
212extern wxString g_uploadConnection;
213extern bool g_bsimplifiedScalebar;
215extern bool bDrawCurrentValues;
217extern s52plib *ps52plib;
219extern bool g_bTempShowMenuBar;
220extern bool g_bShowMenuBar;
221extern bool g_bShowCompassWin;
226extern int g_iNavAidRadarRingsNumberVisible;
227extern bool g_bNavAidRadarRingsShown;
228extern float g_fNavAidRadarRingsStep;
229extern int g_pNavAidRadarRingsStepUnits;
230extern bool g_bWayPointPreventDragging;
231extern bool g_bEnableZoomToCursor;
232extern bool g_bShowChartBar;
233extern int g_ENCSoundingScaleFactor;
234extern int g_ENCTextScaleFactor;
235extern int g_maxzoomin;
237bool g_bShowShipToActive;
238int g_shipToActiveStyle;
239int g_shipToActiveColor;
243extern int g_S57_dialog_sx, g_S57_dialog_sy;
246extern int g_detailslider_dialog_x, g_detailslider_dialog_y;
248extern bool g_b_overzoom_x;
249extern double g_plus_minus_zoom_factor;
251extern int g_OwnShipIconType;
252extern double g_n_ownship_length_meters;
253extern double g_n_ownship_beam_meters;
254extern double g_n_gps_antenna_offset_y;
255extern double g_n_gps_antenna_offset_x;
256extern int g_n_ownship_min_mm;
258extern double g_COGAvg;
260extern int g_click_stop;
262extern double g_ownship_predictor_minutes;
263extern int g_cog_predictor_style;
264extern wxString g_cog_predictor_color;
265extern int g_cog_predictor_endmarker;
266extern int g_ownship_HDTpredictor_style;
267extern wxString g_ownship_HDTpredictor_color;
268extern int g_ownship_HDTpredictor_endmarker;
269extern int g_ownship_HDTpredictor_width;
270extern double g_ownship_HDTpredictor_miles;
272extern bool g_bquiting;
279extern bool g_bopengl;
281extern bool g_bFullScreenQuilt;
283extern bool g_bsmoothpanzoom;
284extern bool g_bSmoothRecenter;
288extern bool g_b_assume_azerty;
290extern ChartGroupArray *g_pGroupArray;
295extern OcpnSound *g_anchorwatch_sound;
298extern int g_chart_zoom_modifier_raster;
299extern int g_chart_zoom_modifier_vector;
300extern int g_ChartScaleFactor;
305extern double g_gl_ms_per_frame;
306extern bool g_benable_rotate;
307extern bool g_bRollover;
309extern bool g_bSpaceDropMark;
310extern bool g_bAutoHideToolbar;
311extern int g_nAutoHideToolbar;
312extern bool g_bDeferredInitDone;
314extern wxString g_CmdSoundString;
316extern bool g_CanvasHideNotificationIcon;
317extern bool g_bhide_context_menus;
318extern bool g_bhide_depth_units;
319extern bool g_bhide_overzoom_flag;
343static bool mouse_leftisdown;
345bool g_brouteCreating;
347bool g_bShowTrackPointTime;
353bool g_brightness_init;
356int g_cog_predictor_width;
357extern double g_display_size_mm;
361extern wxColour g_colourOwnshipRangeRingsColour;
365extern double g_defaultBoatSpeed;
366double g_defaultBoatSpeedUserUnit;
368extern int g_nAIS_activity_timer;
369extern bool g_bskew_comp;
370extern float g_compass_scalefactor;
371extern int g_COGAvgSec;
372extern bool g_btenhertz;
374wxGLContext *g_pGLcontext;
377extern unsigned int g_canvasConfig;
382extern float g_toolbar_scalefactor;
385wxString g_ObjQFileExt;
390extern int g_GUIScaleFactor;
393wxString g_lastS52PLIBPluginMessage;
394extern bool g_bChartBarEx;
395bool g_PrintingInProgress;
398#define MAX_BRIGHT 100
404EVT_PAINT(ChartCanvas::OnPaint)
405EVT_ACTIVATE(ChartCanvas::OnActivate)
406EVT_SIZE(ChartCanvas::OnSize)
407#ifndef HAVE_WX_GESTURE_EVENTS
408EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
410EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
411EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
412EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
413EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
414EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
415EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
416EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
417EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
418EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
419EVT_KEY_UP(ChartCanvas::OnKeyUp)
420EVT_CHAR(ChartCanvas::OnKeyChar)
421EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
422EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
423EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
424EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
425EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
426EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
427EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
428EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
434 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
435 m_nmea_log(nmea_log) {
436 parent_frame = (
MyFrame *)frame;
437 m_canvasIndex = canvasIndex;
441 SetBackgroundColour(wxColour(0, 0, 0));
442 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
446 m_bDrawingRoute =
false;
447 m_bRouteEditing =
false;
448 m_bMarkEditing =
false;
449 m_bRoutePoinDragging =
false;
450 m_bIsInRadius =
false;
451 m_bMayToggleMenuBar =
true;
454 m_bShowNavobjects =
true;
456 m_bAppendingRoute =
false;
457 pThumbDIBShow = NULL;
458 m_bShowCurrent =
false;
460 bShowingCurrent =
false;
464 m_b_paint_enable =
true;
467 pss_overlay_bmp = NULL;
468 pss_overlay_mask = NULL;
469 m_bChartDragging =
false;
470 m_bMeasure_Active =
false;
471 m_bMeasure_DistCircle =
false;
472 m_pMeasureRoute = NULL;
473 m_pTrackRolloverWin = NULL;
474 m_pRouteRolloverWin = NULL;
475 m_pAISRolloverWin = NULL;
477 m_disable_edge_pan =
false;
478 m_dragoffsetSet =
false;
482 m_singleChart = NULL;
483 m_upMode = NORTH_UP_MODE;
485 m_bShowAISScaled =
false;
486 m_timed_move_vp_active =
false;
493 m_pSelectedRoute = NULL;
494 m_pSelectedTrack = NULL;
495 m_pRoutePointEditTarget = NULL;
496 m_pFoundPoint = NULL;
497 m_pMouseRoute = NULL;
498 m_prev_pMousePoint = NULL;
499 m_pEditRouteArray = NULL;
500 m_pFoundRoutePoint = NULL;
501 m_FinishRouteOnKillFocus =
true;
503 m_pRolloverRouteSeg = NULL;
504 m_pRolloverTrackSeg = NULL;
505 m_bsectors_shown =
false;
507 m_bbrightdir =
false;
512 m_pos_image_user_day = NULL;
513 m_pos_image_user_dusk = NULL;
514 m_pos_image_user_night = NULL;
515 m_pos_image_user_grey_day = NULL;
516 m_pos_image_user_grey_dusk = NULL;
517 m_pos_image_user_grey_night = NULL;
520 m_rotation_speed = 0;
526 m_pos_image_user_yellow_day = NULL;
527 m_pos_image_user_yellow_dusk = NULL;
528 m_pos_image_user_yellow_night = NULL;
530 SetOwnShipState(SHIP_INVALID);
532 undo =
new Undo(
this);
538 m_focus_indicator_pix = 1;
540 m_pCurrentStack = NULL;
541 m_bpersistent_quilt =
false;
542 m_piano_ctx_menu = NULL;
544 m_NotificationsList = NULL;
545 m_notification_button = NULL;
547 g_ChartNotRenderScaleFactor = 2.0;
548 m_bShowScaleInStatusBar =
true;
551 m_bShowScaleInStatusBar =
false;
552 m_show_focus_bar =
true;
554 m_bShowOutlines =
false;
555 m_bDisplayGrid =
false;
556 m_bShowDepthUnits =
true;
557 m_encDisplayCategory = (int)STANDARD;
559 m_encShowLights =
true;
560 m_encShowAnchor =
true;
561 m_encShowDataQual =
false;
563 m_pQuilt =
new Quilt(
this);
565 SetAlertString(_T(
""));
568 g_PrintingInProgress =
false;
570#ifdef HAVE_WX_GESTURE_EVENTS
571 m_oldVPSScale = -1.0;
572 m_popupWanted =
false;
578 singleClickEventIsValid =
false;
587 pCursorPencil = NULL;
592 SetCursor(*pCursorArrow);
594 pPanTimer =
new wxTimer(
this, m_MouseDragging);
597 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
598 pMovementTimer->Stop();
600 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
601 pMovementStopTimer->Stop();
603 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
604 pRotDefTimer->Stop();
606 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
607 m_DoubleClickTimer->Stop();
609 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
610 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
611 m_chart_drag_inertia_active =
false;
613 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
614 m_animationActive =
false;
618 m_panx_target_final = m_pany_target_final = 0;
619 m_panx_target_now = m_pany_target_now = 0;
621 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
622 pCurTrackTimer->Stop();
623 m_curtrack_timer_msec = 10;
625 m_wheelzoom_stop_oneshot = 0;
626 m_last_wheel_dir = 0;
628 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
630 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
632 m_rollover_popup_timer_msec = 20;
634 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
636 m_b_rot_hidef =
true;
641 m_upMode = NORTH_UP_MODE;
642 m_bLookAhead =
false;
646 m_cs = GLOBAL_COLOR_SCHEME_DAY;
649 VPoint.view_scale_ppm = 1;
653 m_canvas_scale_factor = 1.;
655 m_canvas_width = 1000;
657 m_overzoomTextWidth = 0;
658 m_overzoomTextHeight = 0;
662 gShapeBasemap.Reset();
667 m_pEM_Fathoms = NULL;
669 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
671 m_pEM_OverZoom = NULL;
673 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
677 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"),
681 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
684 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
687 double factor_dusk = 0.5;
688 double factor_night = 0.25;
691 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
693 int rimg_width = m_os_image_red_day.GetWidth();
694 int rimg_height = m_os_image_red_day.GetHeight();
696 m_os_image_red_dusk = m_os_image_red_day.Copy();
697 m_os_image_red_night = m_os_image_red_day.Copy();
699 for (
int iy = 0; iy < rimg_height; iy++) {
700 for (
int ix = 0; ix < rimg_width; ix++) {
701 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
702 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
703 m_os_image_red_day.GetGreen(ix, iy),
704 m_os_image_red_day.GetBlue(ix, iy));
705 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
706 hsv.value = hsv.value * factor_dusk;
707 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
708 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
710 hsv = wxImage::RGBtoHSV(rgb);
711 hsv.value = hsv.value * factor_night;
712 nrgb = wxImage::HSVtoRGB(hsv);
713 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
719 m_os_image_grey_day =
720 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
722 int gimg_width = m_os_image_grey_day.GetWidth();
723 int gimg_height = m_os_image_grey_day.GetHeight();
725 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
726 m_os_image_grey_night = m_os_image_grey_day.Copy();
728 for (
int iy = 0; iy < gimg_height; iy++) {
729 for (
int ix = 0; ix < gimg_width; ix++) {
730 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
731 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
732 m_os_image_grey_day.GetGreen(ix, iy),
733 m_os_image_grey_day.GetBlue(ix, iy));
734 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
735 hsv.value = hsv.value * factor_dusk;
736 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
737 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
739 hsv = wxImage::RGBtoHSV(rgb);
740 hsv.value = hsv.value * factor_night;
741 nrgb = wxImage::HSVtoRGB(hsv);
742 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
748 m_os_image_yellow_day = m_os_image_red_day.Copy();
750 gimg_width = m_os_image_yellow_day.GetWidth();
751 gimg_height = m_os_image_yellow_day.GetHeight();
753 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
754 m_os_image_yellow_night = m_os_image_red_day.Copy();
756 for (
int iy = 0; iy < gimg_height; iy++) {
757 for (
int ix = 0; ix < gimg_width; ix++) {
758 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
759 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
760 m_os_image_yellow_day.GetGreen(ix, iy),
761 m_os_image_yellow_day.GetBlue(ix, iy));
762 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
763 hsv.hue += 60. / 360.;
764 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
765 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
767 hsv = wxImage::RGBtoHSV(rgb);
768 hsv.value = hsv.value * factor_dusk;
769 hsv.hue += 60. / 360.;
770 nrgb = wxImage::HSVtoRGB(hsv);
771 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
773 hsv = wxImage::RGBtoHSV(rgb);
774 hsv.hue += 60. / 360.;
775 hsv.value = hsv.value * factor_night;
776 nrgb = wxImage::HSVtoRGB(hsv);
777 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
783 m_pos_image_red = &m_os_image_red_day;
784 m_pos_image_yellow = &m_os_image_yellow_day;
785 m_pos_image_grey = &m_os_image_grey_day;
789 m_pBrightPopup = NULL;
792 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
797 m_Piano =
new Piano(
this);
799 m_bShowCompassWin =
true;
801 m_Compass->SetScaleFactor(g_compass_scalefactor);
802 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
805 m_notification_button->SetScaleFactor(g_compass_scalefactor);
806 m_notification_button->Show(
true);
808 m_pianoFrozen =
false;
810 SetMinSize(wxSize(200, 200));
812 m_displayScale = 1.0;
813#if defined(__WXOSX__) || defined(__WXGTK3__)
815 m_displayScale = GetContentScaleFactor();
817 VPoint.SetPixelScale(m_displayScale);
819#ifdef HAVE_WX_GESTURE_EVENTS
822 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
823 wxLogError(
"Failed to enable touch events");
828 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
829 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
831 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
832 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
834 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
835 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
837 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
838 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
843 auto ¬eman = NotificationManager::GetInstance();
845 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
846 evt_notificationlist_change_listener.Listen(
847 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
848 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
849 if (m_NotificationsList && m_NotificationsList->IsShown()) {
850 m_NotificationsList->ReloadNotificationList();
856ChartCanvas::~ChartCanvas() {
857 delete pThumbDIBShow;
865 delete pCursorPencil;
869 delete pMovementTimer;
870 delete pMovementStopTimer;
871 delete pCurTrackTimer;
873 delete m_DoubleClickTimer;
875 delete m_pTrackRolloverWin;
876 delete m_pRouteRolloverWin;
877 delete m_pAISRolloverWin;
878 delete m_pBrightPopup;
884 m_dc_route.SelectObject(wxNullBitmap);
887 delete pWorldBackgroundChart;
888 delete pss_overlay_bmp;
892 delete m_pEM_Fathoms;
894 delete m_pEM_OverZoom;
899 delete m_pos_image_user_day;
900 delete m_pos_image_user_dusk;
901 delete m_pos_image_user_night;
902 delete m_pos_image_user_grey_day;
903 delete m_pos_image_user_grey_dusk;
904 delete m_pos_image_user_grey_night;
905 delete m_pos_image_user_yellow_day;
906 delete m_pos_image_user_yellow_dusk;
907 delete m_pos_image_user_yellow_night;
911 if (!g_bdisable_opengl) {
914#if wxCHECK_VERSION(2, 9, 0)
915 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
922 MUIBar *muiBar = m_muiBar;
926 delete m_pCurrentStack;
931void ChartCanvas::SetupGridFont() {
932 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
934 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
936 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
937 FALSE, wxString(_T (
"Arial" )));
940void ChartCanvas::RebuildCursors() {
946 delete pCursorPencil;
950 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
954 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
955 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
956 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
957 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
958 wxImage ICursorPencil =
959 style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
960 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
962#if !defined(__WXMSW__) && !defined(__WXQT__)
963 ICursorLeft.ConvertAlphaToMask(128);
964 ICursorRight.ConvertAlphaToMask(128);
965 ICursorUp.ConvertAlphaToMask(128);
966 ICursorDown.ConvertAlphaToMask(128);
967 ICursorPencil.ConvertAlphaToMask(10);
968 ICursorCross.ConvertAlphaToMask(10);
971 if (ICursorLeft.Ok()) {
972 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
973 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
974 pCursorLeft =
new wxCursor(ICursorLeft);
976 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
978 if (ICursorRight.Ok()) {
979 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
980 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
981 pCursorRight =
new wxCursor(ICursorRight);
983 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
985 if (ICursorUp.Ok()) {
986 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
987 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
988 pCursorUp =
new wxCursor(ICursorUp);
990 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
992 if (ICursorDown.Ok()) {
993 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
994 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
995 pCursorDown =
new wxCursor(ICursorDown);
997 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
999 if (ICursorPencil.Ok()) {
1000 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
1001 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
1002 pCursorPencil =
new wxCursor(ICursorPencil);
1004 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
1006 if (ICursorCross.Ok()) {
1007 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
1008 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
1009 pCursorCross =
new wxCursor(ICursorCross);
1011 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
1013 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
1014 pPlugIn_Cursor = NULL;
1017void ChartCanvas::CanvasApplyLocale() {
1018 CreateDepthUnitEmbossMaps(m_cs);
1019 CreateOZEmbossMapData(m_cs);
1022void ChartCanvas::SetupGlCanvas() {
1025 if (!g_bdisable_opengl) {
1027 wxLogMessage(_T(
"Creating glChartCanvas"));
1032 if (IsPrimaryCanvas()) {
1039 wxGLContext *pctx =
new wxGLContext(m_glcc);
1040 m_glcc->SetContext(pctx);
1041 g_pGLcontext = pctx;
1044 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
1046 m_glcc->SetContext(g_pGLcontext);
1056 if (!g_bdisable_opengl) {
1059 wxLogMessage(_T(
"Creating glChartCanvas"));
1063 if (IsPrimaryCanvas()) {
1064 qDebug() <<
"Creating Primary glChartCanvas";
1072 wxGLContext *pctx =
new wxGLContext(m_glcc);
1073 m_glcc->SetContext(pctx);
1074 g_pGLcontext = pctx;
1075 m_glcc->m_pParentCanvas =
this;
1078 qDebug() <<
"Creating Secondary glChartCanvas";
1084 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1087 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1088 m_glcc->SetContext(pwxctx);
1089 m_glcc->m_pParentCanvas =
this;
1097void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1098 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1113 if (m_routeState && m_FinishRouteOnKillFocus)
1114 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1116 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1120void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1121 m_routeFinishTimer.Stop();
1125 gFrame->UpdateGlobalMenuItems(
this);
1127 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1130void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1131 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1134#ifdef HAVE_WX_GESTURE_EVENTS
1135void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1141 m_popupWanted =
true;
1144void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1148void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1150void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1152void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1153 wxPoint pos =
event.GetPosition();
1157 if (!m_popupWanted) {
1158 wxMouseEvent ev(wxEVT_LEFT_UP);
1165 m_popupWanted =
false;
1167 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1174void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1177 wxPoint pos =
event.GetPosition();
1181void ChartCanvas::OnMotion(wxMouseEvent &event) {
1186 event.m_leftDown = m_leftdown;
1190void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1192 if (event.IsGestureEnd())
return;
1194 double factor =
event.GetZoomFactor();
1196 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1201 double wanted_factor = m_oldVPSScale / current_vps * factor;
1206 if (event.IsGestureStart()) {
1207 m_zoomStartPoint =
event.GetPosition();
1209 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1211 m_zoomStartPoint =
event.GetPosition();
1215void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1217void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1218 DoRotateCanvas(0.0);
1222void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1227 m_restore_dbindex = pcc->DBindex;
1229 if (pcc->GroupID < 0) pcc->GroupID = 0;
1231 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1234 m_groupIndex = pcc->GroupID;
1236 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1250 m_encDisplayCategory = pcc->nENCDisplayCategory;
1251 m_encShowDepth = pcc->bShowENCDepths;
1252 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1253 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1254 m_encShowLights = pcc->bShowENCLights;
1255 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1256 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1257 m_encShowDataQual = pcc->bShowENCDataQuality;
1261 m_upMode = NORTH_UP_MODE;
1263 m_upMode = COURSE_UP_MODE;
1265 m_upMode = HEAD_UP_MODE;
1269 m_singleChart = NULL;
1272void ChartCanvas::ApplyGlobalSettings() {
1275 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1276 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1278 m_notification_button->UpdateStatus();
1281void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1282 bool groupOK = CheckGroup(m_groupIndex);
1285 SetGroupIndex(m_groupIndex,
true);
1289void ChartCanvas::SetShowGPS(
bool bshow) {
1290 if (m_bShowGPS != bshow) {
1293 m_Compass->SetScaleFactor(g_compass_scalefactor);
1294 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1299void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1300 m_bShowCompassWin = bshow;
1302 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1303 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1307int ChartCanvas::GetPianoHeight() {
1309 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1314void ChartCanvas::ConfigureChartBar() {
1317 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1318 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1320 if (GetQuiltMode()) {
1321 m_Piano->SetRoundedRectangles(
true);
1323 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1324 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1325 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1328void ChartCanvas::ShowTides(
bool bShow) {
1329 gFrame->LoadHarmonics();
1331 if (ptcmgr->IsReady()) {
1332 SetbShowTide(bShow);
1334 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1336 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1337 SetbShowTide(
false);
1338 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1341 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1342 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1353void ChartCanvas::ShowCurrents(
bool bShow) {
1354 gFrame->LoadHarmonics();
1356 if (ptcmgr->IsReady()) {
1357 SetbShowCurrent(bShow);
1358 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1360 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1361 SetbShowCurrent(
false);
1362 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1365 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1366 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1378extern bool g_bPreserveScaleOnX;
1380extern int g_sticky_chart;
1382void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1384void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1385 SetAlertString(_T(
""));
1387 int new_index = index;
1388 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1390 bool bgroup_override =
false;
1391 int old_group_index = new_index;
1393 if (!CheckGroup(new_index)) {
1395 bgroup_override =
true;
1398 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1402 int current_chart_native_scale = GetCanvasChartNativeScale();
1405 m_groupIndex = new_index;
1408 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1411 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1415 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1419 g_sticky_chart = -1;
1423 UpdateCanvasOnGroupChange();
1426 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1428 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1431 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1432 double best_scale = GetBestStartScale(dbi_hint, vp);
1436 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1440 canvasChartsRefresh(dbi_hint);
1442 UpdateCanvasControlBar();
1444 if (!autoSwitch && bgroup_override) {
1446 wxString msg(_(
"Group \""));
1448 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1449 msg += pGroup->m_group_name;
1451 msg += _(
"\" is empty.");
1453 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1460 if (bgroup_override) {
1461 wxString msg(_(
"Group \""));
1463 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1464 msg += pGroup->m_group_name;
1466 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1468 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1472bool ChartCanvas::CheckGroup(
int igroup) {
1473 if (!ChartData)
return true;
1475 if (igroup == 0)
return true;
1480 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1482 if (pGroup->m_element_array.empty())
1486 for (
const auto &elem : pGroup->m_element_array) {
1487 for (
unsigned int ic = 0;
1488 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1490 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1492 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1497 for (
const auto &elem : pGroup->m_element_array) {
1498 const wxString &element_root = elem.m_element_name;
1499 wxString test_string = _T(
"GSHH");
1500 if (element_root.Upper().Contains(test_string))
return true;
1506void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1507 if (!ChartData)
return;
1509 AbstractPlatform::ShowBusySpinner();
1513 SetQuiltRefChart(-1);
1515 m_singleChart = NULL;
1521 if (!m_pCurrentStack) {
1523 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1526 if (-1 != dbi_hint) {
1527 if (GetQuiltMode()) {
1528 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1529 SetQuiltRefChart(dbi_hint);
1533 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1535 if (pTentative_Chart) {
1538 if (m_singleChart) m_singleChart->Deactivate();
1540 m_singleChart = pTentative_Chart;
1541 m_singleChart->Activate();
1543 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1544 GetpCurrentStack(), m_singleChart->GetFullPath());
1552 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1553 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1554 SetQuiltRefChart(selected_index);
1558 SetupCanvasQuiltMode();
1559 if (!GetQuiltMode() && m_singleChart == 0) {
1561 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1562 m_singleChart = pDummyChart;
1568 UpdateCanvasControlBar();
1569 UpdateGPSCompassStatusBox(
true);
1571 SetCursor(wxCURSOR_ARROW);
1573 AbstractPlatform::HideBusySpinner();
1576bool ChartCanvas::DoCanvasUpdate(
void) {
1578 double vpLat, vpLon;
1579 bool blong_jump =
false;
1580 meters_to_shift = 0;
1583 bool bNewChart =
false;
1584 bool bNewView =
false;
1585 bool bCanvasChartAutoOpen =
true;
1587 bool bNewPiano =
false;
1588 bool bOpenSpecified;
1594 if (bDBUpdateInProgress)
return false;
1595 if (!ChartData)
return false;
1597 if (ChartData->IsBusy())
return false;
1623 double dx = m_OSoffsetx;
1624 double dy = m_OSoffsety;
1628 if (GetUpMode() == NORTH_UP_MODE) {
1629 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1631 double offset_angle = atan2(d_north, d_east);
1632 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1633 double chart_angle = GetVPRotation();
1634 double target_angle = chart_angle + offset_angle;
1635 double d_east_mod = offset_distance * cos(target_angle);
1636 double d_north_mod = offset_distance * sin(target_angle);
1637 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1640 extern double gCog_gt;
1643 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1644 double cog_to_use = gCog;
1646 (fabs(gCog - gCog_gt) > 20)) {
1647 cog_to_use = gCog_gt;
1650 if (!g_btenhertz) cog_to_use = g_COGAvg;
1652 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1654 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1655 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1657 double pixel_delta_tent =
1658 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1660 double pixel_delta = 0;
1665 if (!std::isnan(gSog)) {
1669 pixel_delta = pixel_delta_tent;
1672 meters_to_shift = 0;
1674 if (!std::isnan(gCog)) {
1675 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1676 dir_to_shift = cog_to_use;
1677 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1683 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1697 if (GetQuiltMode()) {
1698 int current_db_index = -1;
1699 if (m_pCurrentStack)
1702 ->GetCurrentEntrydbIndex();
1710 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1712 if (m_pCurrentStack->nEntry) {
1713 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1715 SelectQuiltRefdbChart(new_dbIndex,
true);
1716 m_bautofind =
false;
1720 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1721 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1726 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1732 double proposed_scale_onscreen =
1735 int initial_db_index = m_restore_dbindex;
1736 if (initial_db_index < 0) {
1737 if (m_pCurrentStack->nEntry) {
1739 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1744 if (m_pCurrentStack->nEntry) {
1745 int initial_type = ChartData->GetDBChartType(initial_db_index);
1750 if (!IsChartQuiltableRef(initial_db_index)) {
1754 int stack_index = 0;
1756 if (stack_index >= 0) {
1757 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1758 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1759 if (IsChartQuiltableRef(test_db_index) &&
1761 ChartData->GetDBChartType(initial_db_index))) {
1762 initial_db_index = test_db_index;
1770 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1772 SetQuiltRefChart(initial_db_index);
1773 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1781 0, GetVPRotation());
1786 bool super_jump =
false;
1788 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1789 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1790 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1792 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead) {
1794 if (blong_jump) nstep = 20;
1795 StartTimedMovementVP(vpLat, vpLon, nstep);
1804 pLast_Ch = m_singleChart;
1805 ChartTypeEnum new_open_type;
1806 ChartFamilyEnum new_open_family;
1808 new_open_type = pLast_Ch->GetChartType();
1809 new_open_family = pLast_Ch->GetChartFamily();
1811 new_open_type = CHART_TYPE_KAP;
1812 new_open_family = CHART_FAMILY_RASTER;
1815 bOpenSpecified = m_bFirstAuto;
1818 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1821 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1823 if (NULL == pDummyChart) {
1829 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1831 m_singleChart = pDummyChart;
1836 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1838 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1841 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1842 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1849 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1855 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1860 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1863 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1868 if (NULL != m_singleChart)
1869 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1870 m_singleChart->GetFullPath());
1873 m_pCurrentStack->CurrentStackEntry = tEntry;
1883 if (bCanvasChartAutoOpen) {
1884 bool search_direction =
1886 int start_index = 0;
1890 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1891 (LastStack.nEntry == 0)) {
1892 search_direction =
true;
1893 start_index = m_pCurrentStack->nEntry - 1;
1897 if (bOpenSpecified) {
1898 search_direction =
false;
1900 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1903 new_open_type = CHART_TYPE_DONTCARE;
1906 pProposed = ChartData->OpenStackChartConditional(
1907 m_pCurrentStack, start_index, search_direction, new_open_type,
1911 if (NULL == pProposed)
1912 pProposed = ChartData->OpenStackChartConditional(
1913 m_pCurrentStack, start_index, search_direction,
1914 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1916 if (NULL == pProposed)
1917 pProposed = ChartData->OpenStackChartConditional(
1918 m_pCurrentStack, start_index, search_direction,
1919 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1930 if (NULL == pProposed) {
1931 if (NULL == pDummyChart) {
1937 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1939 pProposed = pDummyChart;
1943 if (m_singleChart) m_singleChart->Deactivate();
1944 m_singleChart = pProposed;
1946 if (m_singleChart) {
1947 m_singleChart->Activate();
1948 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1949 m_pCurrentStack, m_singleChart->GetFullPath());
1954 if (NULL != m_singleChart) {
1960 if (!GetVP().IsValid())
1961 set_scale = 1. / 20000.;
1963 double proposed_scale_onscreen;
1966 double new_scale_ppm =
1967 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1975 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1976 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1977 double equivalent_vp_scale =
1979 double new_scale_ppm =
1980 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1985 proposed_scale_onscreen =
1986 wxMin(proposed_scale_onscreen,
1989 proposed_scale_onscreen =
1990 wxMax(proposed_scale_onscreen,
1999 m_singleChart->GetChartSkew() * PI / 180.,
2006 if ((m_bFollow) && m_singleChart)
2008 m_singleChart->GetChartSkew() * PI / 180.,
2017 m_bFirstAuto =
false;
2021 if (bNewChart && !bNewView) Refresh(
false);
2026 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
2029 return bNewChart | bNewView;
2032void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
2033 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
2035 SetQuiltRefChart(db_index);
2037 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
2040 double best_scale_ppm = GetBestVPScale(pc);
2044 SetQuiltRefChart(-1);
2046 SetQuiltRefChart(-1);
2049void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
2050 std::vector<int> piano_chart_index_array =
2051 GetQuiltExtendedStackdbIndexArray();
2052 int current_db_index = piano_chart_index_array[selected_index];
2054 SelectQuiltRefdbChart(current_db_index);
2057double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2061 if ((g_bPreserveScaleOnX) ||
2062 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2068 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2069 double equivalent_vp_scale =
2071 double new_scale_ppm =
2072 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2079 double max_underzoom_multiplier = 2.0;
2080 if (GetVP().b_quilt) {
2081 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2082 pchart->GetChartType(),
2083 pchart->GetChartFamily());
2084 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2087 proposed_scale_onscreen = wxMin(
2088 proposed_scale_onscreen,
2090 max_underzoom_multiplier);
2093 proposed_scale_onscreen =
2094 wxMax(proposed_scale_onscreen,
2102void ChartCanvas::SetupCanvasQuiltMode(
void) {
2105 ChartData->LockCache();
2107 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2111 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2112 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2113 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2114 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2116 m_Piano->SetRoundedRectangles(
true);
2119 int target_new_dbindex = -1;
2120 if (m_pCurrentStack) {
2121 target_new_dbindex =
2122 GetQuiltReferenceChartIndex();
2124 if (-1 != target_new_dbindex) {
2125 if (!IsChartQuiltableRef(target_new_dbindex)) {
2126 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2127 int type = ChartData->GetDBChartType(target_new_dbindex);
2130 int stack_index = m_pCurrentStack->CurrentStackEntry;
2132 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2133 (stack_index >= 0)) {
2134 int proj_tent = ChartData->GetDBChartProj(
2135 m_pCurrentStack->GetDBIndex(stack_index));
2136 int type_tent = ChartData->GetDBChartType(
2137 m_pCurrentStack->GetDBIndex(stack_index));
2139 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2140 if ((proj == proj_tent) && (type_tent == type)) {
2141 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2151 if (IsChartQuiltableRef(target_new_dbindex))
2152 SelectQuiltRefdbChart(target_new_dbindex,
2155 SelectQuiltRefdbChart(-1,
false);
2157 m_singleChart = NULL;
2160 AdjustQuiltRefChart();
2168 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2172 std::vector<int> empty_array;
2173 m_Piano->SetActiveKeyArray(empty_array);
2174 m_Piano->SetNoshowIndexArray(empty_array);
2175 m_Piano->SetEclipsedIndexArray(empty_array);
2178 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2179 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2180 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2181 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2183 m_Piano->SetRoundedRectangles(
false);
2189 if (!GetQuiltMode()) {
2190 if (ChartData && ChartData->IsValid()) {
2194 if (m_bFollow ==
true) {
2202 if (!m_singleChart) {
2205 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2213 int cur_max_scale = (int)1e8;
2215 ChartBase *pChart = GetFirstQuiltChart();
2219 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2221 if (pChart->GetNativeScale() < cur_max_scale) {
2222 Candidate_Chart = pChart;
2223 cur_max_scale = pChart->GetNativeScale();
2226 pChart = GetNextQuiltChart();
2229 m_singleChart = Candidate_Chart;
2233 if (NULL == m_singleChart) {
2234 m_singleChart = ChartData->OpenStackChartConditional(
2235 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2236 CHART_FAMILY_DONTCARE);
2242 InvalidateAllQuiltPatchs();
2244 if (m_singleChart) {
2245 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2246 std::vector<int> one_array;
2247 one_array.push_back(dbi);
2248 m_Piano->SetActiveKeyArray(one_array);
2251 if (m_singleChart) {
2252 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2256 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2260bool ChartCanvas::IsTempMenuBarEnabled() {
2263 wxGetOsVersion(&major);
2271double ChartCanvas::GetCanvasRangeMeters() {
2273 GetSize(&width, &height);
2274 int minDimension = wxMin(width, height);
2277 range *= cos(GetVP().clat * PI / 180.);
2281void ChartCanvas::SetCanvasRangeMeters(
double range) {
2283 GetSize(&width, &height);
2284 int minDimension = wxMin(width, height);
2286 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2290bool ChartCanvas::SetUserOwnship() {
2294 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2295 double factor_dusk = 0.5;
2296 double factor_night = 0.25;
2298 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2299 m_pos_image_user_day =
new wxImage;
2300 *m_pos_image_user_day = pbmp->ConvertToImage();
2301 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2303 int gimg_width = m_pos_image_user_day->GetWidth();
2304 int gimg_height = m_pos_image_user_day->GetHeight();
2307 m_pos_image_user_dusk =
new wxImage;
2308 m_pos_image_user_night =
new wxImage;
2310 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2311 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2313 for (
int iy = 0; iy < gimg_height; iy++) {
2314 for (
int ix = 0; ix < gimg_width; ix++) {
2315 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2316 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2317 m_pos_image_user_day->GetGreen(ix, iy),
2318 m_pos_image_user_day->GetBlue(ix, iy));
2319 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2320 hsv.value = hsv.value * factor_dusk;
2321 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2322 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2325 hsv = wxImage::RGBtoHSV(rgb);
2326 hsv.value = hsv.value * factor_night;
2327 nrgb = wxImage::HSVtoRGB(hsv);
2328 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2335 m_pos_image_user_grey_day =
new wxImage;
2336 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2338 m_pos_image_user_grey_dusk =
new wxImage;
2339 m_pos_image_user_grey_night =
new wxImage;
2341 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2342 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2344 for (
int iy = 0; iy < gimg_height; iy++) {
2345 for (
int ix = 0; ix < gimg_width; ix++) {
2346 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2347 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2348 m_pos_image_user_grey_day->GetGreen(ix, iy),
2349 m_pos_image_user_grey_day->GetBlue(ix, iy));
2350 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2351 hsv.value = hsv.value * factor_dusk;
2352 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2353 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2356 hsv = wxImage::RGBtoHSV(rgb);
2357 hsv.value = hsv.value * factor_night;
2358 nrgb = wxImage::HSVtoRGB(hsv);
2359 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2366 m_pos_image_user_yellow_day =
new wxImage;
2367 m_pos_image_user_yellow_dusk =
new wxImage;
2368 m_pos_image_user_yellow_night =
new wxImage;
2370 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2371 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2372 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2374 for (
int iy = 0; iy < gimg_height; iy++) {
2375 for (
int ix = 0; ix < gimg_width; ix++) {
2376 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2377 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2378 m_pos_image_user_grey_day->GetGreen(ix, iy),
2379 m_pos_image_user_grey_day->GetBlue(ix, iy));
2383 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2384 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2385 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2387 hsv = wxImage::RGBtoHSV(rgb);
2388 hsv.value = hsv.value * factor_dusk;
2389 nrgb = wxImage::HSVtoRGB(hsv);
2390 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2392 hsv = wxImage::RGBtoHSV(rgb);
2393 hsv.value = hsv.value * factor_night;
2394 nrgb = wxImage::HSVtoRGB(hsv);
2395 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2407 m_display_size_mm = size;
2414 double horizontal = sd.x;
2418 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2419 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2422 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2423 ps52plib->SetPPMM(m_pix_per_mm);
2428 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2430 m_display_size_mm, sd.x, sd.y);
2434 ssx = g_monitor_info[g_current_monitor].width;
2435 ssy = g_monitor_info[g_current_monitor].height;
2436 msg.Printf(_T(
"monitor size: %d %d"), ssx, ssy);
2439 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2442void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2444 wxString msg(event.m_string.c_str(), wxConvUTF8);
2446 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2447 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2450 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2452 compress_msg_array.RemoveAt(event.thread);
2453 compress_msg_array.Insert( msg, event.thread);
2456 compress_msg_array.Add(msg);
2459 wxString combined_msg;
2460 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2461 combined_msg += compress_msg_array[i];
2462 combined_msg += _T(
"\n");
2466 pprog->Update(pprog_count, combined_msg, &skip );
2467 pprog->SetSize(pprog_size);
2472void ChartCanvas::InvalidateGL() {
2473 if (!m_glcc)
return;
2475 if (g_bopengl) m_glcc->Invalidate();
2477 if (m_Compass) m_Compass->UpdateStatus(
true);
2480int ChartCanvas::GetCanvasChartNativeScale() {
2482 if (!VPoint.b_quilt) {
2483 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2485 ret = (int)m_pQuilt->GetRefNativeScale();
2490ChartBase *ChartCanvas::GetChartAtCursor() {
2492 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2493 target_chart = m_singleChart;
2494 else if (VPoint.b_quilt)
2495 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2497 target_chart = NULL;
2498 return target_chart;
2501ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2505 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2507 target_chart = NULL;
2508 return target_chart;
2511int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2512 int new_dbIndex = -1;
2513 if (!VPoint.b_quilt) {
2514 if (m_pCurrentStack) {
2515 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2516 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2518 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2528 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2530 for (
unsigned int is = 0; is < im; is++) {
2532 m_pQuilt->GetExtendedStackIndexArray()[is]);
2535 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2545void ChartCanvas::EnablePaint(
bool b_enable) {
2546 m_b_paint_enable = b_enable;
2548 if (m_glcc) m_glcc->EnablePaint(b_enable);
2552bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2554void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2556std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2557 return m_pQuilt->GetQuiltIndexArray();
2561void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2562 VPoint.b_quilt = b_quilt;
2563 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2566bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2568int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2569 return m_pQuilt->GetRefChartdbIndex();
2572void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2573 m_pQuilt->InvalidateAllQuiltPatchs();
2576ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2577 return m_pQuilt->GetLargestScaleChart();
2580ChartBase *ChartCanvas::GetFirstQuiltChart() {
2581 return m_pQuilt->GetFirstChart();
2584ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2586int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2588void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2589 m_pQuilt->SetHiliteIndex(dbIndex);
2592void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2593 m_pQuilt->SetHiliteIndexArray(hilite_array);
2596void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2597 m_pQuilt->ClearHiliteIndexArray();
2600std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2602 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2605int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2606 return m_pQuilt->GetRefChartdbIndex();
2609std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2610 return m_pQuilt->GetExtendedStackIndexArray();
2613std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2614 return m_pQuilt->GetFullscreenIndexArray();
2617std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2618 return m_pQuilt->GetEclipsedStackIndexArray();
2621void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2623double ChartCanvas::GetQuiltMaxErrorFactor() {
2624 return m_pQuilt->GetMaxErrorFactor();
2627bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2628 return m_pQuilt->IsChartQuiltableRef(db_index);
2632 double chartMaxScale =
2634 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2637void ChartCanvas::StartMeasureRoute() {
2638 if (!m_routeState) {
2639 if (m_bMeasure_Active) {
2641 m_pMeasureRoute = NULL;
2644 m_bMeasure_Active =
true;
2645 m_nMeasureState = 1;
2646 m_bDrawingRoute =
false;
2648 SetCursor(*pCursorPencil);
2653void ChartCanvas::CancelMeasureRoute() {
2654 m_bMeasure_Active =
false;
2655 m_nMeasureState = 0;
2656 m_bDrawingRoute =
false;
2659 m_pMeasureRoute = NULL;
2661 SetCursor(*pCursorArrow);
2664ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2666void ChartCanvas::SetVP(
ViewPort &vp) {
2677void ChartCanvas::TriggerDeferredFocus() {
2680 m_deferredFocusTimer.Start(20,
true);
2682#if defined(__WXGTK__) || defined(__WXOSX__)
2693void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2698void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2699 if (SendKeyEventToPlugins(event))
2703 int key_char =
event.GetKeyCode();
2706 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2712 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2717 if (g_benable_rotate) {
2738void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2739 if (SendKeyEventToPlugins(event))
2743 bool b_handled =
false;
2745 m_modkeys =
event.GetModifiers();
2747 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2749#ifdef OCPN_ALT_MENUBAR
2755 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2757 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2758 if (!g_bTempShowMenuBar) {
2759 g_bTempShowMenuBar =
true;
2760 parent_frame->ApplyGlobalSettings(
false);
2762 m_bMayToggleMenuBar =
false;
2768 if (event.GetKeyCode() != WXK_ALT) {
2769 m_bMayToggleMenuBar =
false;
2776 switch (event.GetKeyCode()) {
2783 event.GetPosition(&x, &y);
2784 m_FinishRouteOnKillFocus =
false;
2785 CallPopupMenu(x, y);
2786 m_FinishRouteOnKillFocus =
true;
2790 m_modkeys |= wxMOD_ALT;
2794 m_modkeys |= wxMOD_CONTROL;
2799 case WXK_RAW_CONTROL:
2800 m_modkeys |= wxMOD_RAW_CONTROL;
2805 if (m_modkeys == wxMOD_CONTROL)
2806 parent_frame->DoStackDown(
this);
2807 else if (g_bsmoothpanzoom) {
2808 StartTimedMovement();
2817 if (g_bsmoothpanzoom) {
2818 StartTimedMovement();
2826 if (m_modkeys == wxMOD_CONTROL)
2827 parent_frame->DoStackUp(
this);
2828 else if (g_bsmoothpanzoom) {
2829 StartTimedMovement();
2838 if (g_bsmoothpanzoom) {
2839 StartTimedMovement();
2851 SetShowENCText(!GetShowENCText());
2857 if (!m_bMeasure_Active) {
2858 if (event.ShiftDown())
2859 m_bMeasure_DistCircle =
true;
2861 m_bMeasure_DistCircle =
false;
2863 StartMeasureRoute();
2865 CancelMeasureRoute();
2867 SetCursor(*pCursorArrow);
2877 parent_frame->ToggleColorScheme();
2879 TriggerDeferredFocus();
2883 int mod = m_modkeys & wxMOD_SHIFT;
2884 if (mod != m_brightmod) {
2886 m_bbrightdir = !m_bbrightdir;
2889 if (!m_bbrightdir) {
2890 g_nbrightness -= 10;
2891 if (g_nbrightness <= MIN_BRIGHT) {
2892 g_nbrightness = MIN_BRIGHT;
2893 m_bbrightdir =
true;
2896 g_nbrightness += 10;
2897 if (g_nbrightness >= MAX_BRIGHT) {
2898 g_nbrightness = MAX_BRIGHT;
2899 m_bbrightdir =
false;
2903 SetScreenBrightness(g_nbrightness);
2904 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2913 parent_frame->DoStackDown(
this);
2917 parent_frame->DoStackUp(
this);
2922 ToggleCanvasQuiltMode();
2928 parent_frame->ToggleFullScreen();
2933 if (m_modkeys == wxMOD_ALT) {
2936 ToggleChartOutlines();
2942 parent_frame->ActivateMOB();
2946 case WXK_NUMPAD_ADD:
2951 case WXK_NUMPAD_SUBTRACT:
2952 case WXK_PAGEDOWN: {
2953 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2958 if (m_bMeasure_Active) {
2959 if (m_nMeasureState > 2) {
2960 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2962 m_pMeasureRoute->GetnPoints();
2964 gFrame->RefreshAllCanvas();
2966 CancelMeasureRoute();
2967 StartMeasureRoute();
2975 if (event.GetKeyCode() < 128)
2977 int key_char =
event.GetKeyCode();
2981 if (!g_b_assume_azerty) {
2983 if (g_benable_rotate) {
3015 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3022 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3023 m_modkeys & wxMOD_RAW_CONTROL) {
3024 parent_frame->ToggleFullScreen();
3029 if (event.ControlDown()) key_char -= 64;
3031 if (key_char >=
'0' && key_char <=
'9')
3032 SetGroupIndex(key_char -
'0');
3037 SetShowENCAnchor(!GetShowENCAnchor());
3043 parent_frame->ToggleColorScheme();
3048 event.GetPosition(&x, &y);
3049 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3050 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3052 if (!pPopupDetailSlider) {
3053 if (VPoint.b_quilt) {
3055 if (m_pQuilt->GetChartAtPix(
3060 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3062 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3067 if (m_singleChart) {
3068 ChartType = m_singleChart->GetChartType();
3069 ChartFam = m_singleChart->GetChartFamily();
3073 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3074 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3076 this, -1, ChartType, ChartFam,
3077 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3078 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
3079 if (pPopupDetailSlider) pPopupDetailSlider->Show();
3083 if (pPopupDetailSlider) pPopupDetailSlider->Close();
3084 pPopupDetailSlider = NULL;
3091 m_nmea_log->Raise();
3095 SetShowENCLights(!GetShowENCLights());
3101 if (event.ShiftDown())
3102 m_bMeasure_DistCircle =
true;
3104 m_bMeasure_DistCircle =
false;
3106 StartMeasureRoute();
3110 if (g_bInlandEcdis && ps52plib) {
3111 SetENCDisplayCategory((_DisCat)STANDARD);
3116 ToggleChartOutlines();
3120 ToggleCanvasQuiltMode();
3124 parent_frame->ToggleTestPause();
3127 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3128 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3129 g_iNavAidRadarRingsNumberVisible = 1;
3130 else if (!g_bNavAidRadarRingsShown &&
3131 g_iNavAidRadarRingsNumberVisible == 1)
3132 g_iNavAidRadarRingsNumberVisible = 0;
3135 SetShowENCDepth(!m_encShowDepth);
3140 SetShowENCText(!GetShowENCText());
3145 SetShowENCDataQual(!GetShowENCDataQual());
3150 m_bShowNavobjects = !m_bShowNavobjects;
3165 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3170 if (event.ControlDown()) gFrame->DropMarker(
false);
3176 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3177 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3178 if ((indexActive + 1) <= r->GetnPoints()) {
3189 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3195 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3201 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3208 parent_frame->DoSettings();
3212 parent_frame->Close();
3220 if (NULL == pGoToPositionDialog)
3223 pGoToPositionDialog->SetCanvas(
this);
3224 pGoToPositionDialog->Show();
3228 if (undo->AnythingToRedo()) {
3229 undo->RedoNextAction();
3236 if (event.ShiftDown()) {
3237 if (undo->AnythingToRedo()) {
3238 undo->RedoNextAction();
3243 if (undo->AnythingToUndo()) {
3244 undo->UndoLastAction();
3253 if (m_bMeasure_Active) {
3254 CancelMeasureRoute();
3256 SetCursor(*pCursorArrow);
3259 gFrame->RefreshAllCanvas();
3273 switch (gamma_state) {
3293 SetScreenBrightness(g_nbrightness);
3298 if (event.ControlDown()) {
3299 m_bShowCompassWin = !m_bShowCompassWin;
3300 SetShowGPSCompassWindow(m_bShowCompassWin);
3317void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3318 if (SendKeyEventToPlugins(event))
3322 switch (event.GetKeyCode()) {
3324 parent_frame->SwitchKBFocus(
this);
3330 if (!m_pany) m_panspeed = 0;
3336 if (!m_panx) m_panspeed = 0;
3339 case WXK_NUMPAD_ADD:
3340 case WXK_NUMPAD_SUBTRACT:
3349 m_modkeys &= ~wxMOD_ALT;
3350#ifdef OCPN_ALT_MENUBAR
3355 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3356 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3357 parent_frame->ApplyGlobalSettings(
false);
3359 m_bMayToggleMenuBar =
true;
3365 m_modkeys &= ~wxMOD_CONTROL;
3369 if (event.GetKeyCode() < 128)
3371 int key_char =
event.GetKeyCode();
3375 if (!g_b_assume_azerty) {
3390 m_rotation_speed = 0;
3408void ChartCanvas::ToggleChartOutlines(
void) {
3409 m_bShowOutlines = !m_bShowOutlines;
3415 if (g_bopengl) InvalidateGL();
3419void ChartCanvas::ToggleLookahead() {
3420 m_bLookAhead = !m_bLookAhead;
3425void ChartCanvas::SetUpMode(
int mode) {
3428 if (mode != NORTH_UP_MODE) {
3431 if (!std::isnan(gCog)) stuff = gCog;
3433 if (g_COGAvgSec > 0) {
3434 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3437 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3439 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3440 SetVPRotation(GetVPSkew());
3445 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3446 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3448 UpdateGPSCompassStatusBox(
true);
3449 gFrame->DoChartUpdate();
3452bool ChartCanvas::DoCanvasCOGSet(
void) {
3453 if (GetUpMode() == NORTH_UP_MODE)
return false;
3454 double cog_use = g_COGAvg;
3455 if (g_btenhertz) cog_use = gCog;
3457 double rotation = 0;
3458 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3459 rotation = -gHdt * PI / 180.;
3460 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3461 rotation = -cog_use * PI / 180.;
3463 SetVPRotation(rotation);
3467double easeOutCubic(
double t) {
3469 return 1.0 - pow(1.0 - t, 3.0);
3472void ChartCanvas::StartChartDragInertia() {
3475 m_bChartDragging =
false;
3478 m_chart_drag_inertia_time = 750;
3479 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3484 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3488 size_t length = m_drag_vec_t.size();
3489 for (
size_t i = 0; i < n_vel; i++) {
3490 xacc += m_drag_vec_x.at(length - 1 - i);
3491 yacc += m_drag_vec_y.at(length - 1 - i);
3492 tacc += m_drag_vec_t.at(length - 1 - i);
3495 m_chart_drag_velocity_x = xacc / tacc;
3496 m_chart_drag_velocity_y = yacc / tacc;
3498 m_chart_drag_inertia_active =
true;
3501 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3507void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3508 if (!m_chart_drag_inertia_active)
return;
3511 wxLongLong now = wxGetLocalTimeMillis();
3512 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3513 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3514 if (t > 1.0) t = 1.0;
3515 double e = 1.0 - easeOutCubic(t);
3518 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3520 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3526 m_last_elapsed = elapsed;
3530 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3531 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3532 double inertia_lat, inertia_lon;
3539 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3540 m_chart_drag_inertia_timer.Stop();
3541 m_chart_drag_inertia_active =
false;
3544 m_target_lat = GetVP().
clat;
3545 m_target_lon = GetVP().
clon;
3546 m_pan_drag.x = m_pan_drag.y = 0;
3547 m_panx = m_pany = 0;
3550 int target_redraw_interval = 40;
3551 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3555void ChartCanvas::StopMovement() {
3556 m_panx = m_pany = 0;
3559 m_rotation_speed = 0;
3562#if !defined(__WXGTK__) && !defined(__WXQT__)
3573bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3575 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3577 if (!pMovementTimer->IsRunning()) {
3579 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3582 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3587 m_last_movement_time = wxDateTime::UNow();
3591void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3594 m_target_lat = target_lat;
3595 m_target_lon = target_lon;
3598 m_start_lat = GetVP().
clat;
3599 m_start_lon = GetVP().
clon;
3601 m_VPMovementTimer.Start(1,
true);
3602 m_timed_move_vp_active =
true;
3604 m_timedVP_step = nstep;
3607void ChartCanvas::DoTimedMovementVP() {
3608 if (!m_timed_move_vp_active)
return;
3609 if (m_stvpc++ > m_timedVP_step * 2) {
3616 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3631 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3632 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3634 m_run_lat = new_lat;
3635 m_run_lon = new_lon;
3641void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3643void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3645void ChartCanvas::StartTimedMovementTarget() {}
3647void ChartCanvas::DoTimedMovementTarget() {}
3649void ChartCanvas::StopMovementTarget() {}
3651void ChartCanvas::DoTimedMovement() {
3652 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3656 wxDateTime now = wxDateTime::UNow();
3658 if (m_last_movement_time.IsValid())
3659 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3661 m_last_movement_time = now;
3671 if (dt == 0) dt = 1;
3674 if (m_mustmove < 0) m_mustmove = 0;
3676 if (m_pan_drag.x || m_pan_drag.y) {
3678 m_pan_drag.x = m_pan_drag.y = 0;
3681 if (m_panx || m_pany) {
3682 const double slowpan = .1, maxpan = 2;
3683 if (m_modkeys == wxMOD_ALT)
3684 m_panspeed = slowpan;
3686 m_panspeed += (double)dt / 500;
3687 m_panspeed = wxMin(maxpan, m_panspeed);
3689 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3692 if (m_zoom_factor != 1) {
3693 double alpha = 400, beta = 1.5;
3694 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3696 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3698 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3703 if (zoom_factor > 1) {
3704 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3708 else if (zoom_factor < 1) {
3709 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3714 if (fabs(zoom_factor - 1) > 1e-4) {
3715 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3720 if (m_wheelzoom_stop_oneshot > 0) {
3721 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3722 m_wheelzoom_stop_oneshot = 0;
3727 if (zoom_factor > 1) {
3729 m_wheelzoom_stop_oneshot = 0;
3732 }
else if (zoom_factor < 1) {
3734 m_wheelzoom_stop_oneshot = 0;
3741 if (m_rotation_speed) {
3742 double speed = m_rotation_speed;
3743 if (m_modkeys == wxMOD_ALT) speed /= 10;
3744 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3748void ChartCanvas::SetColorScheme(ColorScheme cs) {
3749 SetAlertString(_T(
""));
3753 case GLOBAL_COLOR_SCHEME_DAY:
3754 m_pos_image_red = &m_os_image_red_day;
3755 m_pos_image_grey = &m_os_image_grey_day;
3756 m_pos_image_yellow = &m_os_image_yellow_day;
3757 m_pos_image_user = m_pos_image_user_day;
3758 m_pos_image_user_grey = m_pos_image_user_grey_day;
3759 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3760 m_cTideBitmap = m_bmTideDay;
3761 m_cCurrentBitmap = m_bmCurrentDay;
3764 case GLOBAL_COLOR_SCHEME_DUSK:
3765 m_pos_image_red = &m_os_image_red_dusk;
3766 m_pos_image_grey = &m_os_image_grey_dusk;
3767 m_pos_image_yellow = &m_os_image_yellow_dusk;
3768 m_pos_image_user = m_pos_image_user_dusk;
3769 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3770 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3771 m_cTideBitmap = m_bmTideDusk;
3772 m_cCurrentBitmap = m_bmCurrentDusk;
3774 case GLOBAL_COLOR_SCHEME_NIGHT:
3775 m_pos_image_red = &m_os_image_red_night;
3776 m_pos_image_grey = &m_os_image_grey_night;
3777 m_pos_image_yellow = &m_os_image_yellow_night;
3778 m_pos_image_user = m_pos_image_user_night;
3779 m_pos_image_user_grey = m_pos_image_user_grey_night;
3780 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3781 m_cTideBitmap = m_bmTideNight;
3782 m_cCurrentBitmap = m_bmCurrentNight;
3785 m_pos_image_red = &m_os_image_red_day;
3786 m_pos_image_grey = &m_os_image_grey_day;
3787 m_pos_image_yellow = &m_os_image_yellow_day;
3788 m_pos_image_user = m_pos_image_user_day;
3789 m_pos_image_user_grey = m_pos_image_user_grey_day;
3790 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3791 m_cTideBitmap = m_bmTideDay;
3792 m_cCurrentBitmap = m_bmCurrentDay;
3796 CreateDepthUnitEmbossMaps(cs);
3797 CreateOZEmbossMapData(cs);
3800 m_fog_color = wxColor(
3804 case GLOBAL_COLOR_SCHEME_DUSK:
3807 case GLOBAL_COLOR_SCHEME_NIGHT:
3813 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3814 m_fog_color.Blue() * dim);
3818 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3819 SetBackgroundColour( wxColour(0,0,0) );
3821 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3824 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3826 SetBackgroundColour( wxNullColour );
3833 m_Piano->SetColorScheme(cs);
3835 m_Compass->SetColorScheme(cs);
3837 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3839 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3841 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3842 if (m_notification_button) {
3843 m_notification_button->SetColorScheme(cs);
3847 if (g_bopengl && m_glcc) {
3848 m_glcc->SetColorScheme(cs);
3849 g_glTextureManager->ClearAllRasterTextures();
3854 m_brepaint_piano =
true;
3861wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3862 wxImage img = Bitmap.ConvertToImage();
3863 int sx = img.GetWidth();
3864 int sy = img.GetHeight();
3866 wxImage new_img(img);
3868 for (
int i = 0; i < sx; i++) {
3869 for (
int j = 0; j < sy; j++) {
3870 if (!img.IsTransparent(i, j)) {
3871 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3872 (
unsigned char)(img.GetGreen(i, j) * factor),
3873 (
unsigned char)(img.GetBlue(i, j) * factor));
3878 wxBitmap ret = wxBitmap(new_img);
3883void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3886 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3888 if (!m_pBrightPopup) {
3891 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3895 m_pBrightPopup->SetSize(x, y);
3896 m_pBrightPopup->Move(120, 120);
3899 int bmpsx = m_pBrightPopup->GetSize().x;
3900 int bmpsy = m_pBrightPopup->GetSize().y;
3902 wxBitmap bmp(bmpsx, bmpsx);
3903 wxMemoryDC mdc(bmp);
3905 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3906 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3907 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3908 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3911 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3913 mdc.SetFont(*pfont);
3916 if (brightness == max)
3918 else if (brightness == min)
3921 val.Printf(_T(
"%3d"), brightness);
3923 mdc.DrawText(val, 0, 0);
3925 mdc.SelectObject(wxNullBitmap);
3927 m_pBrightPopup->SetBitmap(bmp);
3928 m_pBrightPopup->Show();
3929 m_pBrightPopup->Refresh();
3932void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3933 m_b_rot_hidef =
true;
3937void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3938 if (!g_bRollover)
return;
3940 bool b_need_refresh =
false;
3942 wxSize win_size = GetSize() * m_displayScale;
3943 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3946 bool showAISRollover =
false;
3947 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3949 SelectItem *pFind = pSelectAIS->FindSelection(
3952 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3953 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3956 showAISRollover =
true;
3958 if (NULL == m_pAISRolloverWin) {
3960 m_pAISRolloverWin->IsActive(
false);
3961 b_need_refresh =
true;
3962 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3963 m_AISRollover_MMSI != FoundAIS_MMSI) {
3969 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3970 m_pAISRolloverWin->IsActive(
false);
3971 m_AISRollover_MMSI = 0;
3976 m_AISRollover_MMSI = FoundAIS_MMSI;
3978 if (!m_pAISRolloverWin->IsActive()) {
3979 wxString s = ptarget->GetRolloverString();
3980 m_pAISRolloverWin->SetString(s);
3982 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3983 AIS_ROLLOVER, win_size);
3984 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3985 m_pAISRolloverWin->IsActive(
true);
3986 b_need_refresh =
true;
3990 m_AISRollover_MMSI = 0;
3991 showAISRollover =
false;
3996 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3997 m_pAISRolloverWin->IsActive(
false);
3998 m_AISRollover_MMSI = 0;
3999 b_need_refresh =
true;
4004 bool showRouteRollover =
false;
4006 if (NULL == m_pRolloverRouteSeg) {
4011 SelectableItemList SelList = pSelect->FindSelectionList(
4013 wxSelectableItemListNode *node = SelList.GetFirst();
4019 if (pr && pr->IsVisible()) {
4020 m_pRolloverRouteSeg = pFindSel;
4021 showRouteRollover =
true;
4023 if (NULL == m_pRouteRolloverWin) {
4025 m_pRouteRolloverWin->IsActive(
false);
4028 if (!m_pRouteRolloverWin->IsActive()) {
4036 DistanceBearingMercator(
4037 segShow_point_b->m_lat, segShow_point_b->m_lon,
4038 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4040 if (!pr->m_bIsInLayer)
4041 s.Append(_(
"Route") + _T(
": "));
4043 s.Append(_(
"Layer Route: "));
4045 if (pr->m_RouteNameString.IsEmpty())
4046 s.Append(_(
"(unnamed)"));
4048 s.Append(pr->m_RouteNameString);
4050 s << _T(
"\n") << _(
"Total Length: ")
4051 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
4052 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4053 << segShow_point_b->GetName() << _T(
"\n");
4056 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4057 (
int)floor(brg + 0.5), 0x00B0);
4060 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4062 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4063 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4065 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4066 (
int)floor(varBrg + 0.5), 0x00B0);
4069 s << FormatDistanceAdaptive(dist);
4074 double shiptoEndLeg = 0.;
4075 bool validActive =
false;
4076 if (pr->IsActive() &&
4077 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
4080 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
4081 wxRoutePointListNode *node =
4082 (pr->pRoutePointList)->GetFirst()->GetNext();
4084 float dist_to_endleg = 0;
4088 prp = node->GetData();
4094 if (prp->IsSame(segShow_point_a))
break;
4095 node = node->GetNext();
4097 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
4102 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
4103 << segShow_point_b->GetName() << _T(
"\n");
4106 ->GetCurrentRngToActivePoint();
4111 s << FormatDistanceAdaptive(shiptoEndLeg);
4115 if (!std::isnan(gCog) && !std::isnan(gSog))
4117 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
4120 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
4121 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4123 << wxString(ttg_sec > SECONDS_PER_DAY
4124 ? ttg_span.Format(_(
"%Dd %H:%M"))
4125 : ttg_span.Format(_(
"%H:%M")));
4126 wxDateTime dtnow, eta;
4127 eta = dtnow.SetToCurrent().Add(ttg_span);
4128 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
4129 << eta.Format(_T(
" %d %H:%M"));
4131 s << _T(
" ---- ----");
4133 m_pRouteRolloverWin->SetString(s);
4135 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4136 LEG_ROLLOVER, win_size);
4137 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4138 m_pRouteRolloverWin->IsActive(
true);
4139 b_need_refresh =
true;
4140 showRouteRollover =
true;
4144 node = node->GetNext();
4150 m_pRolloverRouteSeg))
4151 showRouteRollover =
false;
4152 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4153 showRouteRollover =
false;
4155 showRouteRollover =
true;
4159 if (m_routeState) showRouteRollover =
false;
4162 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4163 showRouteRollover =
false;
4165 if (m_pRouteRolloverWin &&
4166 !showRouteRollover) {
4167 m_pRouteRolloverWin->IsActive(
false);
4168 m_pRolloverRouteSeg = NULL;
4169 m_pRouteRolloverWin->Destroy();
4170 m_pRouteRolloverWin = NULL;
4171 b_need_refresh =
true;
4172 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4173 m_pRouteRolloverWin->IsActive(
true);
4174 b_need_refresh =
true;
4179 bool showTrackRollover =
false;
4181 if (NULL == m_pRolloverTrackSeg) {
4186 SelectableItemList SelList = pSelect->FindSelectionList(
4188 wxSelectableItemListNode *node = SelList.GetFirst();
4194 if (pt && pt->IsVisible()) {
4195 m_pRolloverTrackSeg = pFindSel;
4196 showTrackRollover =
true;
4198 if (NULL == m_pTrackRolloverWin) {
4200 m_pTrackRolloverWin->IsActive(
false);
4203 if (!m_pTrackRolloverWin->IsActive()) {
4211 DistanceBearingMercator(
4212 segShow_point_b->m_lat, segShow_point_b->m_lon,
4213 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4215 if (!pt->m_bIsInLayer)
4216 s.Append(_(
"Track") + _T(
": "));
4218 s.Append(_(
"Layer Track: "));
4220 if (pt->GetName().IsEmpty())
4221 s.Append(_(
"(unnamed)"));
4223 s.Append(pt->GetName());
4224 double tlenght = pt->Length();
4225 s << _T(
"\n") << _(
"Total Track: ")
4226 << FormatDistanceAdaptive(tlenght);
4227 if (pt->GetLastPoint()->GetTimeString() &&
4228 pt->GetPoint(0)->GetTimeString()) {
4229 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4230 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4231 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4232 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4233 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4234 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4235 << getUsrSpeedUnit();
4236 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4237 : ttime.Format(_T(
" %H:%M")));
4241 if (g_bShowTrackPointTime &&
4242 strlen(segShow_point_b->GetTimeString())) {
4243 wxString stamp = segShow_point_b->GetTimeString();
4244 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4245 if (timestamp.IsValid()) {
4249 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4251 s << _T(
"\n") << _(
"Segment Created: ") << stamp;
4256 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4261 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4263 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4264 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4266 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4270 s << FormatDistanceAdaptive(dist);
4272 if (segShow_point_a->GetTimeString() &&
4273 segShow_point_b->GetTimeString()) {
4274 wxDateTime apoint = segShow_point_a->GetCreateTime();
4275 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4276 if (apoint.IsValid() && bpoint.IsValid()) {
4277 double segmentSpeed = toUsrSpeed(
4278 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4279 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4280 << getUsrSpeedUnit();
4284 m_pTrackRolloverWin->SetString(s);
4286 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4287 LEG_ROLLOVER, win_size);
4288 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4289 m_pTrackRolloverWin->IsActive(
true);
4290 b_need_refresh =
true;
4291 showTrackRollover =
true;
4295 node = node->GetNext();
4301 m_pRolloverTrackSeg))
4302 showTrackRollover =
false;
4303 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4304 showTrackRollover =
false;
4306 showTrackRollover =
true;
4310 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4311 showTrackRollover =
false;
4314 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4315 showTrackRollover =
false;
4321 if (m_pTrackRolloverWin &&
4322 !showTrackRollover) {
4323 m_pTrackRolloverWin->IsActive(
false);
4324 m_pRolloverTrackSeg = NULL;
4325 m_pTrackRolloverWin->Destroy();
4326 m_pTrackRolloverWin = NULL;
4327 b_need_refresh =
true;
4328 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4329 m_pTrackRolloverWin->IsActive(
true);
4330 b_need_refresh =
true;
4333 if (b_need_refresh) Refresh();
4336void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4337 if ((GetShowENCLights() || m_bsectors_shown) &&
4338 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4339 extendedSectorLegs)) {
4340 if (!m_bsectors_shown) {
4342 m_bsectors_shown =
true;
4345 if (m_bsectors_shown) {
4347 m_bsectors_shown =
false;
4355#if defined(__WXGTK__) || defined(__WXQT__)
4360 double cursor_lat, cursor_lon;
4363 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4364 while (cursor_lon < -180.) cursor_lon += 360.;
4366 while (cursor_lon > 180.) cursor_lon -= 360.;
4368 SetCursorStatus(cursor_lat, cursor_lon);
4374void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4375 if (!parent_frame->m_pStatusBar)
return;
4379 s1 += toSDMM(1, cursor_lat);
4381 s1 += toSDMM(2, cursor_lon);
4383 if (STAT_FIELD_CURSOR_LL >= 0)
4384 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4386 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4391 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4392 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4393 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4395 wxString s = st + sm;
4396 s << FormatDistanceAdaptive(dist);
4408 if (g_bShowLiveETA) {
4411 float boatSpeedDefault = g_defaultBoatSpeed;
4416 if (!std::isnan(gSog)) {
4418 if (boatSpeed < 0.5) {
4421 realTimeETA = dist / boatSpeed * 60;
4430 s << minutesToHoursDays(realTimeETA);
4435 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4436 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4438 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4443 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4451wxString minutesToHoursDays(
float timeInMinutes) {
4454 if (timeInMinutes == 0) {
4459 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4460 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4465 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4468 hours = (int)timeInMinutes / 60;
4469 min = (int)timeInMinutes % 60;
4472 s << wxString::Format(_T(
"%d"), hours);
4475 s << wxString::Format(_T(
"%d"), hours);
4477 s << wxString::Format(_T(
"%d"), min);
4484 else if (timeInMinutes > 24 * 60) {
4487 days = (int)(timeInMinutes / 60) / 24;
4488 hours = (int)(timeInMinutes / 60) % 24;
4491 s << wxString::Format(_T(
"%d"), days);
4494 s << wxString::Format(_T(
"%d"), days);
4496 s << wxString::Format(_T(
"%d"), hours);
4508void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4516 wxPoint2DDouble *r) {
4521 double rlon, wxPoint2DDouble *r) {
4532 if (!g_bopengl && m_singleChart &&
4533 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4534 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4535 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4536 (m_singleChart->GetChartProjectionType() !=
4537 PROJECTION_TRANSVERSE_MERCATOR) &&
4538 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4539 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4540 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4554 Cur_BSB_Ch->SetVPRasterParms(vp);
4555 double rpixxd, rpixyd;
4556 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4582 if (std::isnan(p.m_x)) {
4583 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4587 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4588 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4590 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4609 if (!g_bopengl && m_singleChart &&
4610 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4611 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4612 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4613 (m_singleChart->GetChartProjectionType() !=
4614 PROJECTION_TRANSVERSE_MERCATOR) &&
4615 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4616 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4617 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4628 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4631 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4636 else if (slon > 180.)
4647 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4653 DoZoomCanvas(factor,
false);
4654 extendedSectorLegs.clear();
4659 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4661 if (g_bsmoothpanzoom) {
4662 if (StartTimedMovement(stoptimer)) {
4664 m_zoom_factor = factor;
4669 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4671 DoZoomCanvas(factor, can_zoom_to_cursor);
4674 extendedSectorLegs.clear();
4677void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4679 if (!ChartData)
return;
4680 if (!m_pCurrentStack)
return;
4686 if (m_bzooming)
return;
4695 double proposed_scale_onscreen =
4698 bool b_do_zoom =
false;
4707 if (!VPoint.b_quilt) {
4710 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4711 if (new_db_index >= 0)
4712 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4716 int current_ref_stack_index = -1;
4717 if (m_pCurrentStack->nEntry) {
4719 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4720 m_pQuilt->SetReferenceChart(trial_index);
4721 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4722 if (new_db_index >= 0)
4723 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4727 if (m_pCurrentStack)
4728 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4738 double min_allowed_scale =
4741 if (proposed_scale_onscreen < min_allowed_scale) {
4746 proposed_scale_onscreen = min_allowed_scale;
4750 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4753 }
else if (factor < 1) {
4758 bool b_smallest =
false;
4760 if (!VPoint.b_quilt) {
4765 LLBBox viewbox = VPoint.GetBBox();
4767 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4768 double max_allowed_scale;
4782 if (proposed_scale_onscreen > max_allowed_scale) {
4784 proposed_scale_onscreen = max_allowed_scale;
4789 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4790 if (new_db_index >= 0)
4791 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4793 if (m_pCurrentStack)
4794 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4797 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4799 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4800 proposed_scale_onscreen =
4801 wxMin(proposed_scale_onscreen,
4807 m_absolute_min_scale_ppm)
4808 proposed_scale_onscreen =
4817 bool b_allow_ztc =
true;
4818 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4819 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4821 double brg, distance;
4822 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4825 meters_to_shift = distance * 1852;
4833 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4836 if (m_bFollow) DoCanvasUpdate();
4843void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4845 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4849void ChartCanvas::RotateCanvas(
double dir) {
4852 if (g_bsmoothpanzoom) {
4853 if (StartTimedMovement()) {
4855 m_rotation_speed = dir * 60;
4858 double speed = dir * 10;
4859 if (m_modkeys == wxMOD_ALT) speed /= 20;
4860 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4864void ChartCanvas::DoRotateCanvas(
double rotation) {
4865 while (rotation < 0) rotation += 2 * PI;
4866 while (rotation > 2 * PI) rotation -= 2 * PI;
4868 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4870 SetVPRotation(rotation);
4871 parent_frame->UpdateRotationState(VPoint.
rotation);
4874void ChartCanvas::DoTiltCanvas(
double tilt) {
4875 while (tilt < 0) tilt = 0;
4876 while (tilt > .95) tilt = .95;
4878 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4884void ChartCanvas::TogglebFollow(
void) {
4891void ChartCanvas::ClearbFollow(
void) {
4894 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4896 UpdateFollowButtonState();
4900 parent_frame->SetChartUpdatePeriod();
4903void ChartCanvas::SetbFollow(
void) {
4906 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4907 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4915 p.m_x += m_OSoffsetx;
4916 p.m_y -= m_OSoffsety;
4925 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4926 UpdateFollowButtonState();
4928 if (!g_bSmoothRecenter) {
4932 parent_frame->SetChartUpdatePeriod();
4935void ChartCanvas::UpdateFollowButtonState(
void) {
4938 m_muiBar->SetFollowButtonState(0);
4941 m_muiBar->SetFollowButtonState(2);
4943 m_muiBar->SetFollowButtonState(1);
4949 androidSetFollowTool(0);
4952 androidSetFollowTool(2);
4954 androidSetFollowTool(1);
4961 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4962 if (pic->m_enabled && pic->m_init_state) {
4963 switch (pic->m_api_version) {
4966 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4977void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4978 if (g_bSmoothRecenter && !m_routeState) {
4979 if (StartSmoothJump(lat, lon, scale_ppm))
4983 double gcDist, gcBearingEnd;
4984 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4986 gcBearingEnd += 180;
4987 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4990 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4991 double new_lat = lat + (lat_offset / (1852 * 60));
4992 double new_lon = lon + (lon_offset / (1852 * 60));
4995 StartSmoothJump(lat, lon, scale_ppm);
5000 if (lon > 180.0) lon -= 360.0;
5006 if (!GetQuiltMode()) {
5008 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
5009 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
5013 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5014 AdjustQuiltRefChart();
5021 UpdateFollowButtonState();
5029bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5034 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5035 double distance_pixels = gcDist *
GetVPScale();
5036 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5042 m_startLat = m_vLat;
5043 m_startLon = m_vLon;
5048 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5049 m_endScale = scale_ppm;
5052 m_animationDuration = 600;
5053 m_animationStart = wxGetLocalTimeMillis();
5060 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5061 m_animationActive =
true;
5066void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5068 wxLongLong now = wxGetLocalTimeMillis();
5069 double elapsed = (now - m_animationStart).ToDouble();
5070 double t = elapsed / m_animationDuration.ToDouble();
5071 if (t > 1.0) t = 1.0;
5074 double e = easeOutCubic(t);
5077 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5078 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5079 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5084 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5090 m_animationActive =
false;
5091 UpdateFollowButtonState();
5099 if (!ChartData)
return false;
5101 extendedSectorLegs.clear();
5110 if (iters++ > 5)
return false;
5111 if (!std::isnan(dlat))
break;
5114 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5120 else if (dlat < -90)
5123 if (dlon > 360.) dlon -= 360.;
5124 if (dlon < -360.) dlon += 360.;
5139 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5143 if (VPoint.b_quilt) {
5144 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5145 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5147 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
5149 double tweak_scale_ppm =
5155 if (new_ref_dbIndex == -1) {
5156#pragma GCC diagnostic push
5157#pragma GCC diagnostic ignored "-Warray-bounds"
5164 int trial_index = -1;
5165 if (m_pCurrentStack->nEntry) {
5167 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5170 if (trial_index < 0) {
5171 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5172 if (full_screen_array.size())
5173 trial_index = full_screen_array[full_screen_array.size() - 1];
5176 if (trial_index >= 0) {
5177 m_pQuilt->SetReferenceChart(trial_index);
5182#pragma GCC diagnostic pop
5189 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5191 double offset_angle = atan2(offy, offx);
5192 double offset_distance = sqrt((offy * offy) + (offx * offx));
5193 double chart_angle = GetVPRotation();
5194 double target_angle = chart_angle - offset_angle;
5195 double d_east_mod = offset_distance * cos(target_angle);
5196 double d_north_mod = offset_distance * sin(target_angle);
5201 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5202 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5204 UpdateFollowButtonState();
5210 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5215void ChartCanvas::ReloadVP(
bool b_adjust) {
5216 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5218 LoadVP(VPoint, b_adjust);
5221void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5223 if (g_bopengl && m_glcc) {
5224 m_glcc->Invalidate();
5225 if (m_glcc->GetSize() != GetSize()) {
5226 m_glcc->SetSize(GetSize());
5231 m_cache_vp.Invalidate();
5232 m_bm_cache_vp.Invalidate();
5235 VPoint.Invalidate();
5237 if (m_pQuilt) m_pQuilt->Invalidate();
5246 vp.m_projection_type, b_adjust);
5249void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5250 m_pQuilt->SetReferenceChart(dbIndex);
5251 VPoint.Invalidate();
5252 m_pQuilt->Invalidate();
5255double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5257 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5264int ChartCanvas::AdjustQuiltRefChart() {
5267 wxASSERT(ChartData);
5269 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5271 double min_ref_scale =
5272 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5273 double max_ref_scale =
5274 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5277 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5278 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5279 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5281 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5284 int target_stack_index = wxNOT_FOUND;
5286 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5287 if (index == m_pQuilt->GetRefChartdbIndex()) {
5288 target_stack_index = il;
5293 if (wxNOT_FOUND == target_stack_index)
5294 target_stack_index = 0;
5296 int ref_family = pc->GetChartFamily();
5297 int extended_array_count =
5298 m_pQuilt->GetExtendedStackIndexArray().size();
5299 while ((!brender_ok) &&
5300 ((
int)target_stack_index < (extended_array_count - 1))) {
5301 target_stack_index++;
5303 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5305 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
5306 IsChartQuiltableRef(test_db_index)) {
5309 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5311 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5318 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5319 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
5320 IsChartQuiltableRef(new_db_index)) {
5321 m_pQuilt->SetReferenceChart(new_db_index);
5324 ret = m_pQuilt->GetRefChartdbIndex();
5326 ret = m_pQuilt->GetRefChartdbIndex();
5329 ret = m_pQuilt->GetRefChartdbIndex();
5338void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5339 delete m_pCurrentStack;
5341 wxASSERT(ChartData);
5342 ChartData->BuildChartStack(m_pCurrentStack, VPoint.
clat, VPoint.
clon,
5351bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5352 double latNE,
double lonNE) {
5354 double latc = (latSW + latNE) / 2.0;
5355 double lonc = (lonSW + lonNE) / 2.0;
5358 double ne_easting, ne_northing;
5359 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5361 double sw_easting, sw_northing;
5362 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5364 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5371 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5374bool ChartCanvas::SetVPProjection(
int projection) {
5380 double prev_true_scale_ppm = m_true_scale_ppm;
5385 m_absolute_min_scale_ppm));
5393bool ChartCanvas::SetVPRotation(
double angle) {
5395 VPoint.
skew, angle);
5398 double skew,
double rotation,
int projection,
5399 bool b_adjust,
bool b_refresh) {
5404 if (VPoint.IsValid()) {
5405 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5406 (fabs(VPoint.
skew - skew) < 1e-9) &&
5407 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5408 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5409 (VPoint.m_projection_type == projection ||
5410 projection == PROJECTION_UNKNOWN))
5413 if (VPoint.m_projection_type != projection)
5414 VPoint.InvalidateTransformCache();
5424 if (projection != PROJECTION_UNKNOWN)
5425 VPoint.SetProjectionType(projection);
5426 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5427 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5430 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5431 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5432 if (VPoint.
clat > 89.5)
5434 else if (VPoint.
clat < -89.5)
5435 VPoint.
clat = -89.5;
5440 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5441 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5453 bool bwasValid = VPoint.IsValid();
5458 m_cache_vp.Invalidate();
5463 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5467 int mouseX = mouse_x;
5468 int mouseY = mouse_y;
5469 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5475 SendCursorLatLonToAllPlugIns(lat, lon);
5478 if (!VPoint.b_quilt && m_singleChart) {
5483 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5487 if ((!m_cache_vp.IsValid()) ||
5492 wxPoint cp_last, cp_this;
5496 if (cp_last != cp_this) {
5502 if (m_pCurrentStack) {
5503 assert(ChartData != 0);
5504 int current_db_index;
5506 m_pCurrentStack->GetCurrentEntrydbIndex();
5508 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5510 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5513 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5517 if (VPoint.b_quilt) {
5519 m_pQuilt->InvalidateAllQuiltPatchs();
5523 if (!m_pCurrentStack)
return false;
5525 int current_db_index;
5527 m_pCurrentStack->GetCurrentEntrydbIndex();
5529 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5530 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5533 int current_ref_stack_index = -1;
5534 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5535 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5536 current_ref_stack_index = i;
5539 if (g_bFullScreenQuilt) {
5540 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5544 bool b_needNewRef =
false;
5547 if ((-1 == current_ref_stack_index) &&
5548 (m_pQuilt->GetRefChartdbIndex() >= 0))
5549 b_needNewRef =
true;
5556 bool renderable =
true;
5558 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5559 if (referenceChart) {
5560 double chartMaxScale = referenceChart->GetNormalScaleMax(
5562 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5564 if (!renderable) b_needNewRef =
true;
5569 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5570 int target_scale = cte_ref.GetScale();
5571 int target_type = cte_ref.GetChartType();
5572 int candidate_stack_index;
5579 candidate_stack_index = 0;
5580 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5582 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5583 int candidate_scale = cte_candidate.GetScale();
5584 int candidate_type = cte_candidate.GetChartType();
5586 if ((candidate_scale >= target_scale) &&
5587 (candidate_type == target_type)) {
5588 bool renderable =
true;
5589 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5590 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5591 if (tentative_referenceChart) {
5592 double chartMaxScale =
5593 tentative_referenceChart->GetNormalScaleMax(
5595 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5598 if (renderable)
break;
5601 candidate_stack_index++;
5606 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5607 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5608 while (candidate_stack_index >= 0) {
5609 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5612 ChartData->GetChartTableEntry(idx);
5613 int candidate_scale = cte_candidate.GetScale();
5614 int candidate_type = cte_candidate.GetChartType();
5616 if ((candidate_scale <= target_scale) &&
5617 (candidate_type == target_type))
5620 candidate_stack_index--;
5625 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5626 (candidate_stack_index < 0))
5627 candidate_stack_index = 0;
5629 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5631 m_pQuilt->SetReferenceChart(new_ref_index);
5637 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5642 bool renderable =
true;
5644 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5645 if (referenceChart) {
5646 double chartMaxScale = referenceChart->GetNormalScaleMax(
5648 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5649 proj = ChartData->GetDBChartProj(ref_db_index);
5651 proj = PROJECTION_MERCATOR;
5653 VPoint.b_MercatorProjectionOverride =
5654 (m_pQuilt->GetnCharts() == 0 || !renderable);
5656 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5658 VPoint.SetProjectionType(proj);
5665 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5670 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5690 m_pQuilt->Invalidate();
5705 ChartData->PurgeCacheUnusedCharts(0.7);
5707 if (b_refresh) Refresh(
false);
5714 }
else if (!g_bopengl) {
5715 OcpnProjType projection = PROJECTION_UNKNOWN;
5718 projection = m_singleChart->GetChartProjectionType();
5719 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5720 VPoint.SetProjectionType(projection);
5724 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5725 m_cache_vp.Invalidate();
5729 UpdateCanvasControlBar();
5735 if (VPoint.GetBBox().GetValid()) {
5738 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5747 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5750 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5757 wxPoint2DDouble r, r1;
5759 double delta_check =
5763 double check_point = wxMin(89., VPoint.
clat);
5765 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5768 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5769 VPoint.
clon, 0, &rhumbDist);
5774 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5775 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5777 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5781 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5787 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5789 if (m_true_scale_ppm)
5790 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5795 double round_factor = 1000.;
5799 round_factor = 100.;
5801 round_factor = 1000.;
5804 double retina_coef = 1;
5808 retina_coef = GetContentScaleFactor();
5819 double true_scale_display =
5820 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5825 if (m_displayed_scale_factor > 10.0)
5826 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5827 m_displayed_scale_factor);
5828 else if (m_displayed_scale_factor > 1.0)
5829 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5830 m_displayed_scale_factor);
5831 else if (m_displayed_scale_factor > 0.1) {
5832 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5833 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5834 }
else if (m_displayed_scale_factor > 0.01) {
5835 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5836 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5839 _T(
"%s %4.0f (---)"), _(
"Scale"),
5840 true_scale_display);
5843 m_scaleValue = true_scale_display;
5845 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5847 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5848 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5850 bool b_noshow =
false;
5854 wxClientDC dc(parent_frame->GetStatusBar());
5856 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5857 dc.SetFont(*templateFont);
5858 dc.GetTextExtent(text, &w, &h);
5863 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5864 if (w && w > rect.width) {
5865 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5866 m_displayed_scale_factor);
5870 dc.GetTextExtent(text, &w, &h);
5872 if (w && w > rect.width) {
5878 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5883 m_vLat = VPoint.
clat;
5884 m_vLon = VPoint.
clon;
5898static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5902static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5903 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5905wxColour ChartCanvas::PredColor() {
5908 if (SHIP_NORMAL == m_ownship_state)
5909 return GetGlobalColor(_T (
"URED" ));
5911 else if (SHIP_LOWACCURACY == m_ownship_state)
5912 return GetGlobalColor(_T (
"YELO1" ));
5914 return GetGlobalColor(_T (
"NODTA" ));
5917wxColour ChartCanvas::ShipColor() {
5921 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5923 if (SHIP_LOWACCURACY == m_ownship_state)
5924 return GetGlobalColor(_T (
"YELO1" ));
5926 return GetGlobalColor(_T (
"URED" ));
5929void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5930 wxPoint2DDouble lShipMidPoint) {
5931 dc.SetPen(wxPen(PredColor(), 2));
5933 if (SHIP_NORMAL == m_ownship_state)
5934 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5936 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5938 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5939 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5941 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5943 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5944 lShipMidPoint.m_y + 12);
5947void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5948 wxPoint GPSOffsetPixels,
5949 wxPoint2DDouble lGPSPoint) {
5954 float ref_dim = m_display_size_mm / 24;
5955 ref_dim = wxMin(ref_dim, 12);
5956 ref_dim = wxMax(ref_dim, 6);
5959 cPred.Set(g_cog_predictor_color);
5960 if (cPred == wxNullColour) cPred = PredColor();
5967 double nominal_line_width_pix = wxMax(
5969 floor(m_pix_per_mm / 2));
5973 if (nominal_line_width_pix > g_cog_predictor_width)
5974 g_cog_predictor_width = nominal_line_width_pix;
5977 wxPoint lPredPoint, lHeadPoint;
5979 float pCog = std::isnan(gCog) ? 0 : gCog;
5980 float pSog = std::isnan(gSog) ? 0 : gSog;
5982 double pred_lat, pred_lon;
5983 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5984 &pred_lat, &pred_lon);
5995 float ndelta_pix = 10.;
5996 double hdg_pred_lat, hdg_pred_lon;
5997 bool b_render_hdt =
false;
5998 if (!std::isnan(gHdt)) {
6000 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
6003 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
6004 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
6005 if (dist > ndelta_pix ) {
6006 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
6007 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6012 wxPoint lShipMidPoint;
6013 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6014 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6015 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6016 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6018 if (lpp >= img_height / 2) {
6019 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
6020 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
6021 !std::isnan(gSog)) {
6023 float dash_length = ref_dim;
6024 wxDash dash_long[2];
6026 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6027 g_cog_predictor_width);
6028 dash_long[1] = dash_long[0] / 2.0;
6032 if (dash_length > 250.) {
6033 dash_long[0] = 250. / g_cog_predictor_width;
6034 dash_long[1] = dash_long[0] / 2;
6037 wxPen ppPen2(cPred, g_cog_predictor_width,
6038 (wxPenStyle)g_cog_predictor_style);
6039 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6040 ppPen2.SetDashes(2, dash_long);
6043 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6044 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6046 if (g_cog_predictor_width > 1) {
6047 float line_width = g_cog_predictor_width / 3.;
6049 wxDash dash_long3[2];
6050 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6051 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6053 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
6054 (wxPenStyle)g_cog_predictor_style);
6055 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6056 ppPen3.SetDashes(2, dash_long3);
6058 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6059 lGPSPoint.m_y + GPSOffsetPixels.y,
6060 lPredPoint.x + GPSOffsetPixels.x,
6061 lPredPoint.y + GPSOffsetPixels.y);
6064 if (g_cog_predictor_endmarker) {
6066 double png_pred_icon_scale_factor = .4;
6067 if (g_ShipScaleFactorExp > 1.0)
6068 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6069 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6073 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6074 (
float)(lPredPoint.x - lShipMidPoint.x));
6075 cog_rad += (float)PI;
6077 for (
int i = 0; i < 4; i++) {
6079 double pxa = (double)(s_png_pred_icon[j]);
6080 double pya = (double)(s_png_pred_icon[j + 1]);
6082 pya *= png_pred_icon_scale_factor;
6083 pxa *= png_pred_icon_scale_factor;
6085 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6086 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6088 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6089 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6093 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
6096 dc.SetBrush(wxBrush(cPred));
6098 dc.StrokePolygon(4, icon);
6105 float hdt_dash_length = ref_dim * 0.4;
6107 cPred.Set(g_ownship_HDTpredictor_color);
6108 if (cPred == wxNullColour) cPred = PredColor();
6110 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6111 : g_cog_predictor_width * 0.8);
6112 wxDash dash_short[2];
6114 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6117 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6120 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6121 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6122 ppPen2.SetDashes(2, dash_short);
6126 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6127 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6129 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6131 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
6133 if (g_ownship_HDTpredictor_endmarker) {
6134 double nominal_circle_size_pixels = wxMax(
6135 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6138 if (g_ShipScaleFactorExp > 1.0)
6139 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6141 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6142 lHeadPoint.y + GPSOffsetPixels.y,
6143 nominal_circle_size_pixels / 2);
6148 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6149 double factor = 1.00;
6150 if (g_pNavAidRadarRingsStepUnits == 1)
6152 else if (g_pNavAidRadarRingsStepUnits == 2) {
6153 if (std::isnan(gSog))
6158 factor *= g_fNavAidRadarRingsStep;
6162 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
6165 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6166 pow((
double)(lGPSPoint.m_y - r.y), 2));
6167 int pix_radius = (int)lpp;
6169 extern wxColor GetDimColor(wxColor c);
6170 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6172 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6175 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6177 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6178 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6182void ChartCanvas::ComputeShipScaleFactor(
6183 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6184 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6185 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6186 float screenResolution = m_pix_per_mm;
6189 double ship_bow_lat, ship_bow_lon;
6190 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6191 &ship_bow_lat, &ship_bow_lon);
6192 wxPoint lShipBowPoint;
6193 wxPoint2DDouble b_point =
6197 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6198 powf((
float)(b_point.m_y - a_point.m_y), 2));
6201 float shipLength_mm = shipLength_px / screenResolution;
6204 float ownship_min_mm = g_n_ownship_min_mm;
6205 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6208 float hdt_ant = icon_hdt + 180.;
6209 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6210 float dx = g_n_gps_antenna_offset_x / 1852.;
6211 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6219 if (shipLength_mm < ownship_min_mm) {
6220 dy /= shipLength_mm / ownship_min_mm;
6221 dx /= shipLength_mm / ownship_min_mm;
6224 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6226 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6227 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6233 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6234 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6236 float scale_factor = shipLength_px / ownShipLength;
6239 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6242 scale_factor = wxMax(scale_factor, scale_factor_min);
6244 scale_factor_y = scale_factor;
6245 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6246 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6249void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6250 if (!GetVP().IsValid())
return;
6252 wxPoint GPSOffsetPixels(0, 0);
6253 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6256 float pCog = std::isnan(gCog) ? 0 : gCog;
6257 float pSog = std::isnan(gSog) ? 0 : gSog;
6261 lShipMidPoint = lGPSPoint;
6265 float icon_hdt = pCog;
6266 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6269 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6273 double osd_head_lat, osd_head_lon;
6274 wxPoint osd_head_point;
6276 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6281 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6282 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6283 icon_rad += (float)PI;
6285 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6289 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6293 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6294 if (GetVP().chart_scale >
6297 ShipDrawLargeScale(dc, lShipMidPoint);
6303 if (m_pos_image_user)
6304 pos_image = m_pos_image_user->Copy();
6305 else if (SHIP_NORMAL == m_ownship_state)
6306 pos_image = m_pos_image_red->Copy();
6307 if (SHIP_LOWACCURACY == m_ownship_state)
6308 pos_image = m_pos_image_yellow->Copy();
6309 else if (SHIP_NORMAL != m_ownship_state)
6310 pos_image = m_pos_image_grey->Copy();
6313 if (m_pos_image_user) {
6314 pos_image = m_pos_image_user->Copy();
6316 if (SHIP_LOWACCURACY == m_ownship_state)
6317 pos_image = m_pos_image_user_yellow->Copy();
6318 else if (SHIP_NORMAL != m_ownship_state)
6319 pos_image = m_pos_image_user_grey->Copy();
6322 img_height = pos_image.GetHeight();
6324 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6325 g_OwnShipIconType > 0)
6327 int ownShipWidth = 22;
6328 int ownShipLength = 84;
6329 if (g_OwnShipIconType == 1) {
6330 ownShipWidth = pos_image.GetWidth();
6331 ownShipLength = pos_image.GetHeight();
6334 float scale_factor_x, scale_factor_y;
6335 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6336 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6337 scale_factor_x, scale_factor_y);
6339 if (g_OwnShipIconType == 1) {
6340 pos_image.Rescale(ownShipWidth * scale_factor_x,
6341 ownShipLength * scale_factor_y,
6342 wxIMAGE_QUALITY_HIGH);
6343 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6345 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6348 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6349 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6350 if (rot_image.GetAlpha(ip, jp) > 64)
6351 rot_image.SetAlpha(ip, jp, 255);
6353 wxBitmap os_bm(rot_image);
6355 int w = os_bm.GetWidth();
6356 int h = os_bm.GetHeight();
6359 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6360 lShipMidPoint.m_y - h / 2,
true);
6363 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6364 lShipMidPoint.m_y - h / 2);
6365 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6366 lShipMidPoint.m_y - h / 2 + h);
6369 else if (g_OwnShipIconType == 2) {
6370 wxPoint ownship_icon[10];
6372 for (
int i = 0; i < 10; i++) {
6374 float pxa = (float)(s_ownship_icon[j]);
6375 float pya = (float)(s_ownship_icon[j + 1]);
6376 pya *= scale_factor_y;
6377 pxa *= scale_factor_x;
6379 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6380 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6382 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6383 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6386 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6388 dc.SetBrush(wxBrush(ShipColor()));
6390 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6393 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6395 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6399 img_height = ownShipLength * scale_factor_y;
6403 if (m_pos_image_user) circle_rad = 1;
6405 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6406 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6407 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6410 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6412 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6415 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6416 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6417 if (rot_image.GetAlpha(ip, jp) > 64)
6418 rot_image.SetAlpha(ip, jp, 255);
6420 wxBitmap os_bm(rot_image);
6422 if (g_ShipScaleFactorExp > 1) {
6423 wxImage scaled_image = os_bm.ConvertToImage();
6424 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6426 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6427 scaled_image.GetHeight() * factor,
6428 wxIMAGE_QUALITY_HIGH));
6430 int w = os_bm.GetWidth();
6431 int h = os_bm.GetHeight();
6434 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6435 lShipMidPoint.m_y - h / 2,
true);
6439 if (m_pos_image_user) circle_rad = 1;
6441 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6442 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6443 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6446 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6447 lShipMidPoint.m_y - h / 2);
6448 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6449 lShipMidPoint.m_y - h / 2 + h);
6454 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6467void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6468 float &MinorSpacing) {
6473 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6474 {.000001f, 45.0f, 15.0f},
6475 {.0002f, 30.0f, 10.0f},
6476 {.0003f, 10.0f, 2.0f},
6477 {.0008f, 5.0f, 1.0f},
6478 {.001f, 2.0f, 30.0f / 60.0f},
6479 {.003f, 1.0f, 20.0f / 60.0f},
6480 {.006f, 0.5f, 10.0f / 60.0f},
6481 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6482 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6483 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6484 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6485 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6486 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6487 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6488 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6491 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6492 if (view_scale_ppm < lltab[tabi][0])
break;
6493 MajorSpacing = lltab[tabi][1];
6494 MinorSpacing = lltab[tabi][2];
6508wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6509 int deg = (int)fabs(latlon);
6510 float min = fabs((fabs(latlon) - deg) * 60.0);
6520 }
else if (latlon < 0.0) {
6532 if (spacing >= 1.0) {
6533 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6534 }
else if (spacing >= (1.0 / 60.0)) {
6535 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6537 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6554void ChartCanvas::GridDraw(
ocpnDC &dc) {
6555 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6557 double nlat, elon, slat, wlon;
6560 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6562 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6564 if (!m_pgridFont) SetupGridFont();
6565 dc.SetFont(*m_pgridFont);
6566 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6569 h = m_canvas_height;
6580 dlon = dlon + 360.0;
6583 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6586 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6589 while (lat < nlat) {
6592 CalcGridText(lat, gridlatMajor,
true);
6594 dc.
DrawLine(0, r.y, w, r.y,
false);
6595 dc.DrawText(st, 0, r.y);
6596 lat = lat + gridlatMajor;
6598 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6602 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6605 while (lat < nlat) {
6608 dc.
DrawLine(0, r.y, 10, r.y,
false);
6609 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6610 lat = lat + gridlatMinor;
6614 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6617 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6620 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6622 wxString st = CalcGridText(lon, gridlonMajor,
false);
6624 dc.
DrawLine(r.x, 0, r.x, h,
false);
6625 dc.DrawText(st, r.x, 0);
6626 lon = lon + gridlonMajor;
6631 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6635 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6637 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6640 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6641 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6642 lon = lon + gridlonMinor;
6649void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6651 double blat, blon, tlat, tlon;
6654 int x_origin = m_bDisplayGrid ? 60 : 20;
6655 int y_origin = m_canvas_height - 50;
6661 if (GetVP().chart_scale > 80000)
6665 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6666 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6671 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6672 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6676 double rotation = -VPoint.
rotation;
6678 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6680 int l1 = (y_origin - r.y) / count;
6682 for (
int i = 0; i < count; i++) {
6689 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6692 double blat, blon, tlat, tlon;
6699 int y_origin = m_canvas_height - chartbar_height - 5;
6703 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6710 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6713 int unit = g_iDistanceFormat;
6715 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6716 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6719 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6720 float places = floor(logdist), rem = logdist - places;
6721 dist = pow(10, places);
6728 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6729 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6730 double rotation = -VPoint.
rotation;
6732 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6736 int l1 = r.x - x_origin;
6738 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6743 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6744 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6745 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6747 if (!m_pgridFont) SetupGridFont();
6748 dc.SetFont(*m_pgridFont);
6749 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6751 dc.GetTextExtent(s, &w, &h);
6757 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6761void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6766 double ra_max = 40.;
6768 wxPen pen_save = dc.GetPen();
6770 wxDateTime now = wxDateTime::Now();
6776 x0 = x1 = x + radius;
6781 while (angle < 360.) {
6782 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6785 if (angle > 360.) angle = 360.;
6787 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6795 x1 = (int)(x + cos(angle * PI / 180.) * r);
6796 y1 = (int)(y + sin(angle * PI / 180.) * r);
6806 dc.
DrawLine(x + radius, y, x1, y1);
6808 dc.SetPen(pen_save);
6811static bool bAnchorSoundPlaying =
false;
6813static void onAnchorSoundFinished(
void *ptr) {
6814 g_anchorwatch_sound->UnLoad();
6815 bAnchorSoundPlaying =
false;
6818void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6820 bool play_sound =
false;
6821 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6822 if (AnchorAlertOn1) {
6823 wxPoint TargetPoint;
6826 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6827 TargetPoint.y, 100);
6831 AnchorAlertOn1 =
false;
6833 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6834 if (AnchorAlertOn2) {
6835 wxPoint TargetPoint;
6838 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6839 TargetPoint.y, 100);
6843 AnchorAlertOn2 =
false;
6846 if (!bAnchorSoundPlaying) {
6847 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6848 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6849 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6850 if (g_anchorwatch_sound->IsOk()) {
6851 bAnchorSoundPlaying =
true;
6852 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6853 g_anchorwatch_sound->Play();
6859void ChartCanvas::UpdateShips() {
6862 wxClientDC dc(
this);
6863 if (!dc.IsOk())
return;
6865 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6866 if (!test_bitmap.IsOk())
return;
6868 wxMemoryDC temp_dc(test_bitmap);
6870 temp_dc.ResetBoundingBox();
6871 temp_dc.DestroyClippingRegion();
6872 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6878 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6879 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6883 ocpndc.CalcBoundingBox(px.x, px.y);
6888 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6889 temp_dc.MaxY() - temp_dc.MinY());
6891 wxRect own_ship_update_rect = ship_draw_rect;
6893 if (!own_ship_update_rect.IsEmpty()) {
6896 own_ship_update_rect.Union(ship_draw_last_rect);
6897 own_ship_update_rect.Inflate(2);
6900 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6902 ship_draw_last_rect = ship_draw_rect;
6904 temp_dc.SelectObject(wxNullBitmap);
6907void ChartCanvas::UpdateAlerts() {
6912 wxClientDC dc(
this);
6916 dc.GetSize(&sx, &sy);
6919 wxBitmap test_bitmap(sx, sy, -1);
6923 temp_dc.SelectObject(test_bitmap);
6925 temp_dc.ResetBoundingBox();
6926 temp_dc.DestroyClippingRegion();
6927 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6934 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6935 temp_dc.MaxX() - temp_dc.MinX(),
6936 temp_dc.MaxY() - temp_dc.MinY());
6938 if (!alert_rect.IsEmpty())
6939 alert_rect.Inflate(2);
6941 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6944 wxRect alert_update_rect = alert_draw_rect;
6945 alert_update_rect.Union(alert_rect);
6948 RefreshRect(alert_update_rect,
false);
6952 alert_draw_rect = alert_rect;
6954 temp_dc.SelectObject(wxNullBitmap);
6957void ChartCanvas::UpdateAIS() {
6958 if (!g_pAIS)
return;
6963 wxClientDC dc(
this);
6967 dc.GetSize(&sx, &sy);
6975 if (g_pAIS->GetTargetList().size() > 10) {
6976 ais_rect = wxRect(0, 0, sx, sy);
6979 wxBitmap test_bitmap(sx, sy, -1);
6983 temp_dc.SelectObject(test_bitmap);
6985 temp_dc.ResetBoundingBox();
6986 temp_dc.DestroyClippingRegion();
6987 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6991 AISDraw(ocpndc, GetVP(),
this);
6992 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6996 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6997 temp_dc.MaxY() - temp_dc.MinY());
6999 if (!ais_rect.IsEmpty())
7000 ais_rect.Inflate(2);
7002 temp_dc.SelectObject(wxNullBitmap);
7005 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7008 wxRect ais_update_rect = ais_draw_rect;
7009 ais_update_rect.Union(ais_rect);
7012 RefreshRect(ais_update_rect,
false);
7016 ais_draw_rect = ais_rect;
7019void ChartCanvas::ToggleCPAWarn() {
7020 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7026 g_bTCPA_Max =
false;
7030 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
7031 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7033 if (!g_AisFirstTimeUse) {
7034 OCPNMessageBox(
this,
7035 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
7036 _(
"CPA") + _T(
" ") + mess, 4, 4);
7041void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7043void ChartCanvas::OnSize(wxSizeEvent &event) {
7044 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7046 GetClientSize(&m_canvas_width, &m_canvas_height);
7050 m_displayScale = GetContentScaleFactor();
7054 m_canvas_width *= m_displayScale;
7055 m_canvas_height *= m_displayScale;
7068 m_absolute_min_scale_ppm =
7070 (1.2 * WGS84_semimajor_axis_meters * PI);
7073 gFrame->ProcessCanvasResize();
7083 SetMUIBarPosition();
7084 UpdateFollowButtonState();
7085 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7089 xr_margin = m_canvas_width * 95 / 100;
7090 xl_margin = m_canvas_width * 5 / 100;
7091 yt_margin = m_canvas_height * 5 / 100;
7092 yb_margin = m_canvas_height * 95 / 100;
7095 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7100 m_brepaint_piano =
true;
7103 m_dc_route.SelectObject(wxNullBitmap);
7106 m_dc_route.SelectObject(*proute_bm);
7120 m_glcc->OnSize(event);
7129void ChartCanvas::ProcessNewGUIScale() {
7137void ChartCanvas::CreateMUIBar() {
7138 if (g_useMUI && !m_muiBar) {
7142 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
7144 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7145 m_muiBar->SetColorScheme(m_cs);
7146 m_muiBarHOSize = m_muiBar->m_size;
7150 SetMUIBarPosition();
7151 UpdateFollowButtonState();
7152 m_muiBar->UpdateDynamicValues();
7153 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7157void ChartCanvas::SetMUIBarPosition() {
7161 int pianoWidth = GetClientSize().x * 0.6f;
7166 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7167 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7169 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7170 m_muiBar->SetColorScheme(m_cs);
7174 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7175 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7177 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7178 m_muiBar->SetColorScheme(m_cs);
7182 m_muiBar->SetBestPosition();
7186void ChartCanvas::DestroyMuiBar() {
7193void ChartCanvas::ShowCompositeInfoWindow(
7194 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7196 if (NULL == m_pCIWin) {
7201 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7204 s = _(
"Composite of ");
7207 s1.Printf(
"%d ", n_charts);
7215 s1.Printf(_(
"Chart scale"));
7218 s2.Printf(
"1:%d\n",
scale);
7222 s1 = _(
"Zoom in for more information");
7226 int char_width = s1.Length();
7227 int char_height = 3;
7229 if (g_bChartBarEx) {
7232 for (
int i : index_vector) {
7234 wxString path = cte.GetFullSystemPath();
7238 char_width = wxMax(char_width, path.Length());
7239 if (j++ >= 9)
break;
7242 s +=
" .\n .\n .\n";
7251 m_pCIWin->SetString(s);
7253 m_pCIWin->FitToChars(char_width, char_height);
7256 p.x = x / GetContentScaleFactor();
7257 if ((p.x + m_pCIWin->GetWinSize().x) >
7258 (m_canvas_width / GetContentScaleFactor()))
7259 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7260 m_pCIWin->GetWinSize().x) /
7263 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7264 4 - m_pCIWin->GetWinSize().y;
7266 m_pCIWin->dbIndex = 0;
7267 m_pCIWin->chart_scale = 0;
7268 m_pCIWin->SetPosition(p);
7269 m_pCIWin->SetBitmap();
7270 m_pCIWin->Refresh();
7274 HideChartInfoWindow();
7278void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7280 if (NULL == m_pCIWin) {
7285 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7292 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
7293 pc = ChartData->OpenChartFromDBAndLock(
7294 dbIndex, FULL_INIT);
7296 int char_width, char_height;
7297 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7298 if (pc) ChartData->UnLockCacheChart(dbIndex);
7300 m_pCIWin->SetString(s);
7301 m_pCIWin->FitToChars(char_width, char_height);
7304 p.x = x / GetContentScaleFactor();
7305 if ((p.x + m_pCIWin->GetWinSize().x) >
7306 (m_canvas_width / GetContentScaleFactor()))
7307 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7308 m_pCIWin->GetWinSize().x) /
7311 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7312 4 - m_pCIWin->GetWinSize().y;
7314 m_pCIWin->dbIndex = dbIndex;
7315 m_pCIWin->SetPosition(p);
7316 m_pCIWin->SetBitmap();
7317 m_pCIWin->Refresh();
7321 HideChartInfoWindow();
7325void ChartCanvas::HideChartInfoWindow(
void) {
7328 m_pCIWin->Destroy();
7332 androidForceFullRepaint();
7337void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7338 wxMouseEvent ev(wxEVT_MOTION);
7341 ev.m_leftDown = mouse_leftisdown;
7343 wxEvtHandler *evthp = GetEventHandler();
7345 ::wxPostEvent(evthp, ev);
7348void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7349 if ((m_panx_target_final - m_panx_target_now) ||
7350 (m_pany_target_final - m_pany_target_now)) {
7351 DoTimedMovementTarget();
7356void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7358bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7360 if (m_disable_edge_pan)
return false;
7363 int pan_margin = m_canvas_width * margin / 100;
7364 int pan_timer_set = 200;
7365 double pan_delta = GetVP().
pix_width * delta / 100;
7369 if (x > m_canvas_width - pan_margin) {
7374 else if (x < pan_margin) {
7379 if (y < pan_margin) {
7384 else if (y > m_canvas_height - pan_margin) {
7393 wxMouseState state = ::wxGetMouseState();
7394#if wxCHECK_VERSION(3, 0, 0)
7395 if (!state.LeftIsDown())
7397 if (!state.LeftDown())
7402 if ((bft) && !pPanTimer->IsRunning()) {
7404 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7410 if ((!bft) && pPanTimer->IsRunning()) {
7420void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7421 bool setBeingEdited) {
7422 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7423 m_pRoutePointEditTarget = NULL;
7424 m_pFoundPoint = NULL;
7428 SelectableItemList SelList = pSelect->FindSelectionList(
7430 wxSelectableItemListNode *node = SelList.GetFirst();
7432 pFind = node->GetData();
7441 bool brp_viz =
false;
7442 if (m_pEditRouteArray) {
7443 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7444 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7445 if (pr->IsVisible()) {
7451 brp_viz = frp->IsVisible();
7455 if (m_pEditRouteArray)
7457 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7458 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7461 m_bRouteEditing = setBeingEdited;
7464 frp->m_bRPIsBeingEdited = setBeingEdited;
7465 m_bMarkEditing = setBeingEdited;
7468 m_pRoutePointEditTarget = frp;
7469 m_pFoundPoint = pFind;
7473 node = node->GetNext();
7476std::shared_ptr<PI_PointContext> ChartCanvas::GetCanvasContextAtPoint(
int x,
7492 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7493 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7494 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7495 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7499 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7502 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7507 int FoundAIS_MMSI = 0;
7509 FoundAIS_MMSI = pFindAIS->GetUserData();
7512 if (g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7513 seltype |= SELTYPE_AISTARGET;
7519 Route *SelectedRoute = NULL;
7525 Route *pSelectedActiveRoute = NULL;
7526 Route *pSelectedVizRoute = NULL;
7530 SelectableItemList SelList =
7531 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7532 wxSelectableItemListNode *node = SelList.GetFirst();
7542 bool brp_viz =
false;
7544 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7546 if (pr->IsVisible()) {
7551 if (!brp_viz && prp->IsShared())
7553 brp_viz = prp->IsVisible();
7556 brp_viz = prp->IsVisible();
7558 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7564 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7567 pSelectedActiveRoute = pr;
7568 pFoundActiveRoutePoint = prp;
7573 if (NULL == pSelectedVizRoute) {
7574 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7576 if (pr->IsVisible()) {
7577 pSelectedVizRoute = pr;
7578 pFoundVizRoutePoint = prp;
7584 delete proute_array;
7587 node = node->GetNext();
7591 if (pFoundActiveRoutePoint) {
7592 FoundRoutePoint = pFoundActiveRoutePoint;
7593 SelectedRoute = pSelectedActiveRoute;
7594 }
else if (pFoundVizRoutePoint) {
7595 FoundRoutePoint = pFoundVizRoutePoint;
7596 SelectedRoute = pSelectedVizRoute;
7599 FoundRoutePoint = pFirstVizPoint;
7601 if (SelectedRoute) {
7602 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7603 }
else if (FoundRoutePoint)
7604 seltype |= SELTYPE_MARKPOINT;
7609 if (m_pFoundRoutePoint) {
7613 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7614 RefreshRect(wp_rect,
true);
7624 SelectableItemList SelList =
7625 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7627 if (NULL == SelectedRoute)
7630 wxSelectableItemListNode *node = SelList.GetFirst();
7635 if (pr->IsVisible()) {
7639 node = node->GetNext();
7643 if (SelectedRoute) {
7644 if (NULL == FoundRoutePoint)
7645 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7648 seltype |= SELTYPE_ROUTESEGMENT;
7653 if (pFindTrackSeg) {
7654 m_pSelectedTrack = NULL;
7656 SelectableItemList SelList =
7657 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7660 wxSelectableItemListNode *node = SelList.GetFirst();
7665 if (pt->IsVisible()) {
7666 m_pSelectedTrack = pt;
7669 node = node->GetNext();
7672 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7677 bool bseltc =
false;
7691 SelectableItemList SelList = pSelectTC->FindSelectionList(
7695 wxSelectableItemListNode *node = SelList.GetFirst();
7696 pFind = node->GetData();
7697 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7699 if (SelList.GetCount() > 1) {
7700 node = node->GetNext();
7702 pFind = node->GetData();
7704 if (pIDX_candidate->
IDX_type ==
'c') {
7705 pIDX_best_candidate = pIDX_candidate;
7709 node = node->GetNext();
7712 wxSelectableItemListNode *node = SelList.GetFirst();
7713 pFind = node->GetData();
7714 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7717 m_pIDXCandidate = pIDX_best_candidate;
7720 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
7724 seltype |= SELTYPE_CURRENTPOINT;
7727 else if (pFindTide) {
7728 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7731 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
7735 seltype |= SELTYPE_TIDEPOINT;
7740 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7743 auto rstruct = std::make_shared<PI_PointContext>();
7744 rstruct->object_type = OBJECT_CHART;
7745 rstruct->object_ident =
"";
7747 if (seltype == SELTYPE_AISTARGET) {
7748 rstruct->object_type = OBJECT_AISTARGET;
7750 val.Printf(
"%d", FoundAIS_MMSI);
7751 rstruct->object_ident = val.ToStdString();
7752 }
else if (seltype & SELTYPE_MARKPOINT) {
7753 if (FoundRoutePoint) {
7754 rstruct->object_type = OBJECT_ROUTEPOINT;
7755 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7757 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7758 if (SelectedRoute) {
7759 rstruct->object_type = OBJECT_ROUTESEGMENT;
7760 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7767void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7768 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7769 singleClickEventIsValid =
false;
7770 m_DoubleClickTimer->Stop();
7775bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7776 if (!m_bChartDragging && !m_bDrawingRoute) {
7781 if (m_Compass && m_Compass->IsShown()) {
7783 bool isInCompass = logicalRect.Contains(event.GetPosition());
7785 if (m_Compass->MouseEvent(event)) {
7786 cursor_region = CENTER;
7787 if (!g_btouch) SetCanvasCursor(event);
7793 if (m_notification_button && m_notification_button->IsShown()) {
7795 bool isinButton = logicalRect.Contains(event.GetPosition());
7797 SetCursor(*pCursorArrow);
7798 if (event.LeftDown()) HandleNotificationMouseClick();
7803 if (MouseEventToolbar(event))
return true;
7805 if (MouseEventChartBar(event))
return true;
7807 if (MouseEventMUIBar(event))
return true;
7809 if (MouseEventIENCBar(event))
return true;
7814void ChartCanvas::HandleNotificationMouseClick() {
7815 if (!m_NotificationsList) {
7819 m_NotificationsList->RecalculateSize();
7820 m_NotificationsList->Hide();
7823 if (m_NotificationsList->IsShown()) {
7824 m_NotificationsList->Hide();
7826 m_NotificationsList->RecalculateSize();
7827 m_NotificationsList->ReloadNotificationList();
7828 m_NotificationsList->Show();
7831bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7832 if (!g_bShowChartBar)
return false;
7834 if (!m_Piano->MouseEvent(event))
return false;
7836 cursor_region = CENTER;
7837 if (!g_btouch) SetCanvasCursor(event);
7841bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7842 if (!IsPrimaryCanvas())
return false;
7844 if (g_MainToolbar) {
7845 if (!g_MainToolbar->MouseEvent(event))
7848 g_MainToolbar->RefreshToolbar();
7851 cursor_region = CENTER;
7852 if (!g_btouch) SetCanvasCursor(event);
7856bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7857 if (!IsPrimaryCanvas())
return false;
7859 if (g_iENCToolbar) {
7860 if (!g_iENCToolbar->MouseEvent(event))
7863 g_iENCToolbar->RefreshToolbar();
7870bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7872 if (!m_muiBar->MouseEvent(event))
return false;
7875 cursor_region = CENTER;
7876 if (!g_btouch) SetCanvasCursor(event);
7888 event.GetPosition(&x, &y);
7890 x *= m_displayScale;
7891 y *= m_displayScale;
7893 m_MouseDragging =
event.Dragging();
7899 if (event.Dragging()) {
7900 if ((x == mouse_x) && (y == mouse_y))
return true;
7906 mouse_leftisdown =
event.LeftDown();
7910 cursor_region = CENTER;
7914 if (m_Compass && m_Compass->IsShown() &&
7915 m_Compass->
GetRect().Contains(event.GetPosition())) {
7916 cursor_region = CENTER;
7917 }
else if (x > xr_margin) {
7918 cursor_region = MID_RIGHT;
7919 }
else if (x < xl_margin) {
7920 cursor_region = MID_LEFT;
7921 }
else if (y > yb_margin - chartbar_height &&
7922 y < m_canvas_height - chartbar_height) {
7923 cursor_region = MID_TOP;
7924 }
else if (y < yt_margin) {
7925 cursor_region = MID_BOT;
7927 cursor_region = CENTER;
7930 if (!g_btouch) SetCanvasCursor(event);
7934 leftIsDown =
event.LeftDown();
7937 if (event.LeftDown()) {
7938 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7941 g_bTempShowMenuBar =
false;
7942 parent_frame->ApplyGlobalSettings(
false);
7950 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7951 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7955 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7956 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7959 event.SetEventObject(
this);
7960 if (SendMouseEventToPlugins(event))
7967 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7968 StartChartDragInertia();
7971 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7973 if (m_DoubleClickTimer->IsRunning()) {
7974 m_DoubleClickTimer->Stop();
7979 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7980 singleClickEvent = event;
7981 singleClickEventIsValid =
true;
7990 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7991 if (g_click_stop > 0) {
7999 if (GetUpMode() == COURSE_UP_MODE) {
8000 m_b_rot_hidef =
false;
8001 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
8003 pRotDefTimer->Stop();
8006 bool bRoll = !g_btouch;
8008 bRoll = g_bRollover;
8011 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
8012 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
8013 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
8014 m_RolloverPopupTimer.Start(
8018 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
8022 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
8031#if !defined(__WXGTK__) && !defined(__WXQT__)
8039 if ((x >= 0) && (y >= 0))
8044 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
8045 wxPoint p = ClientToScreen(wxPoint(x, y));
8051 if (m_routeState >= 2) {
8054 m_bDrawingRoute =
true;
8056 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8061 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
8064 m_bDrawingRoute =
true;
8066 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8079#if defined(__WXMAC__) || defined(__ANDROID__)
8083 wxClientDC cdc(GetParent());
8095 if (m_pSelectedRoute) {
8097 m_pSelectedRoute->DeSelectRoute();
8099 if (g_bopengl && m_glcc) {
8104 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8107 if (m_pFoundRoutePoint) {
8115 if (g_btouch && m_pRoutePointEditTarget) {
8118 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8123 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8124 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8125 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8126 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8130 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8133 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8139 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8142 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8143 seltype |= SELTYPE_AISTARGET;
8148 m_pFoundRoutePoint = NULL;
8153 Route *pSelectedActiveRoute = NULL;
8154 Route *pSelectedVizRoute = NULL;
8158 SelectableItemList SelList =
8159 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8160 wxSelectableItemListNode *node = SelList.GetFirst();
8170 bool brp_viz =
false;
8172 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8174 if (pr->IsVisible()) {
8179 if (!brp_viz && prp->IsShared())
8181 brp_viz = prp->IsVisible();
8184 brp_viz = prp->IsVisible();
8186 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8191 m_pSelectedRoute = NULL;
8193 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8196 pSelectedActiveRoute = pr;
8197 pFoundActiveRoutePoint = prp;
8202 if (NULL == pSelectedVizRoute) {
8203 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8205 if (pr->IsVisible()) {
8206 pSelectedVizRoute = pr;
8207 pFoundVizRoutePoint = prp;
8213 delete proute_array;
8215 node = node->GetNext();
8219 if (pFoundActiveRoutePoint) {
8220 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8221 m_pSelectedRoute = pSelectedActiveRoute;
8222 }
else if (pFoundVizRoutePoint) {
8223 m_pFoundRoutePoint = pFoundVizRoutePoint;
8224 m_pSelectedRoute = pSelectedVizRoute;
8227 m_pFoundRoutePoint = pFirstVizPoint;
8229 if (m_pSelectedRoute) {
8230 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8231 }
else if (m_pFoundRoutePoint)
8232 seltype |= SELTYPE_MARKPOINT;
8236 if (m_pFoundRoutePoint) {
8240 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8241 RefreshRect(wp_rect,
true);
8250 SelectableItemList SelList =
8251 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8253 if (NULL == m_pSelectedRoute)
8256 wxSelectableItemListNode *node = SelList.GetFirst();
8261 if (pr->IsVisible()) {
8262 m_pSelectedRoute = pr;
8265 node = node->GetNext();
8269 if (m_pSelectedRoute) {
8270 if (NULL == m_pFoundRoutePoint)
8271 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8276 if (g_bopengl && m_glcc) {
8281 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8283 seltype |= SELTYPE_ROUTESEGMENT;
8287 if (pFindTrackSeg) {
8288 m_pSelectedTrack = NULL;
8290 SelectableItemList SelList =
8291 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8294 wxSelectableItemListNode *node = SelList.GetFirst();
8299 if (pt->IsVisible()) {
8300 m_pSelectedTrack = pt;
8303 node = node->GetNext();
8305 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8320 SelectableItemList SelList =
8321 pSelectTC->FindSelectionList(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8324 wxSelectableItemListNode *node = SelList.GetFirst();
8325 pFind = node->GetData();
8326 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8328 if (SelList.GetCount() > 1) {
8329 node = node->GetNext();
8331 pFind = node->GetData();
8333 if (pIDX_candidate->
IDX_type ==
'c') {
8334 pIDX_best_candidate = pIDX_candidate;
8338 node = node->GetNext();
8341 wxSelectableItemListNode *node = SelList.GetFirst();
8342 pFind = node->GetData();
8343 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8346 m_pIDXCandidate = pIDX_best_candidate;
8347 seltype |= SELTYPE_CURRENTPOINT;
8350 else if (pFindTide) {
8351 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8352 seltype |= SELTYPE_TIDEPOINT;
8356 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8361void ChartCanvas::CallPopupMenu(
int x,
int y) {
8365 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8373 if (SELTYPE_CURRENTPOINT == seltype) {
8374 DrawTCWindow(x, y, (
void *)m_pIDXCandidate);
8379 if (SELTYPE_TIDEPOINT == seltype) {
8380 DrawTCWindow(x, y, (
void *)m_pIDXCandidate);
8385 InvokeCanvasMenu(x, y, seltype);
8388 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8392 m_pSelectedRoute = NULL;
8394 if (m_pFoundRoutePoint) {
8395 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8398 m_pFoundRoutePoint = NULL;
8404bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8412 event.GetPosition(&x, &y);
8418 SelectRadius = g_Platform->GetSelectRadiusPix() /
8419 (m_true_scale_ppm * 1852 * 60);
8426 if (event.LeftDClick() && (cursor_region == CENTER)) {
8427 m_DoubleClickTimer->Start();
8428 singleClickEventIsValid =
false;
8432 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8437 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8440 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8441 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8442 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8448 SelectableItemList rpSelList =
8449 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8450 wxSelectableItemListNode *node = rpSelList.GetFirst();
8451 bool b_onRPtarget =
false;
8455 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8456 b_onRPtarget =
true;
8459 node = node->GetNext();
8464 if (m_pRoutePointEditTarget) {
8466 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8472 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8475 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8476 m_pRoutePointEditTarget = NULL;
8477 RefreshRect(wp_rect,
true);
8481 node = rpSelList.GetFirst();
8486 wxArrayPtrVoid *proute_array =
8491 bool brp_viz =
false;
8493 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8495 if (pr->IsVisible()) {
8500 delete proute_array;
8504 brp_viz = frp->IsVisible();
8506 brp_viz = frp->IsVisible();
8509 ShowMarkPropertiesDialog(frp);
8517 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8521 if (pr->IsVisible()) {
8522 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8527 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8531 if (pt->IsVisible()) {
8532 ShowTrackPropertiesDialog(pt);
8539 ShowObjectQueryWindow(x, y, zlat, zlon);
8544 if (event.LeftDown()) {
8560 bool appending =
false;
8561 bool inserting =
false;
8564 SetCursor(*pCursorPencil);
8568 m_bRouteEditing =
true;
8570 if (m_routeState == 1) {
8571 m_pMouseRoute =
new Route();
8572 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8573 pRouteList->Append(m_pMouseRoute);
8582 double nearby_radius_meters =
8583 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8586 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8587 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8588 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8589 wxArrayPtrVoid *proute_array =
8594 bool brp_viz =
false;
8596 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8598 if (pr->IsVisible()) {
8603 delete proute_array;
8605 pNearbyPoint->IsShared())
8608 pNearbyPoint->IsVisible();
8610 brp_viz = pNearbyPoint->IsVisible();
8613 wxString msg = _(
"Use nearby waypoint?");
8615 const bool noname(pNearbyPoint->GetName() ==
"");
8618 _(
"Use nearby nameless waypoint and name it M with"
8619 " a unique number?");
8622 m_FinishRouteOnKillFocus =
false;
8624 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8625 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8626 m_FinishRouteOnKillFocus =
true;
8627 if (dlg_return == wxID_YES) {
8629 if (m_pMouseRoute) {
8630 int last_wp_num = m_pMouseRoute->GetnPoints();
8632 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8633 wxString wp_name = wxString::Format(
8634 "M%002i-%s", last_wp_num + 1, guid_short);
8635 pNearbyPoint->SetName(wp_name);
8637 pNearbyPoint->SetName(
"WPXX");
8639 pMousePoint = pNearbyPoint;
8642 if (m_routeState > 1)
8643 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8644 Undo_HasParent, NULL);
8647 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8648 bool procede =
false;
8652 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8658 m_FinishRouteOnKillFocus =
false;
8664 _(
"Insert first part of this route in the new route?");
8665 if (tail->GetIndexOf(pMousePoint) ==
8668 dmsg = _(
"Insert this route in the new route?");
8670 if (tail->GetIndexOf(pMousePoint) != 1) {
8671 dlg_return = OCPNMessageBox(
8672 this, dmsg, _(
"OpenCPN Route Create"),
8673 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8674 m_FinishRouteOnKillFocus =
true;
8676 if (dlg_return == wxID_YES) {
8683 _(
"Append last part of this route to the new route?");
8684 if (tail->GetIndexOf(pMousePoint) == 1)
8686 "Append this route to the new route?");
8691 if (tail->GetLastPoint() != pMousePoint) {
8692 dlg_return = OCPNMessageBox(
8693 this, dmsg, _(
"OpenCPN Route Create"),
8694 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8695 m_FinishRouteOnKillFocus =
true;
8697 if (dlg_return == wxID_YES) {
8708 if (!FindRouteContainingWaypoint(pMousePoint))
8709 pMousePoint->SetShared(
true);
8714 if (NULL == pMousePoint) {
8715 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8716 _T(
""), wxEmptyString);
8717 pMousePoint->SetNameShown(
false);
8721 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8723 if (m_routeState > 1)
8724 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8725 Undo_IsOrphanded, NULL);
8728 if (m_pMouseRoute) {
8729 if (m_routeState == 1) {
8731 m_pMouseRoute->AddPoint(pMousePoint);
8735 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8736 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8737 &rhumbBearing, &rhumbDist);
8738 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8739 rlat, &gcDist, &gcBearing, NULL);
8740 double gcDistNM = gcDist / 1852.0;
8743 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8744 pow(rhumbDist - gcDistNM - 1, 0.5);
8747 msg << _(
"For this leg the Great Circle route is ")
8748 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8749 << _(
" shorter than rhumbline.\n\n")
8750 << _(
"Would you like include the Great Circle routing points "
8753 m_FinishRouteOnKillFocus =
false;
8754 m_disable_edge_pan =
true;
8757 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8758 wxYES_NO | wxNO_DEFAULT);
8760 m_disable_edge_pan =
false;
8761 m_FinishRouteOnKillFocus =
true;
8763 if (answer == wxID_YES) {
8765 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8766 wxRealPoint gcCoord;
8768 for (
int i = 1; i <= segmentCount; i++) {
8769 double fraction = (double)i * (1.0 / (
double)segmentCount);
8770 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8771 gcDist * fraction, gcBearing,
8772 &gcCoord.x, &gcCoord.y, NULL);
8774 if (i < segmentCount) {
8775 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8776 _T(
""), wxEmptyString);
8777 gcPoint->SetNameShown(
false);
8779 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8781 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8784 gcPoint = pMousePoint;
8787 m_pMouseRoute->AddPoint(gcPoint);
8788 pSelect->AddSelectableRouteSegment(
8789 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8790 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8791 prevGcPoint = gcPoint;
8794 undo->CancelUndoableAction(
true);
8797 m_pMouseRoute->AddPoint(pMousePoint);
8798 pSelect->AddSelectableRouteSegment(
8799 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8800 pMousePoint, m_pMouseRoute);
8801 undo->AfterUndoableAction(m_pMouseRoute);
8805 m_pMouseRoute->AddPoint(pMousePoint);
8806 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8807 rlon, m_prev_pMousePoint,
8808 pMousePoint, m_pMouseRoute);
8809 undo->AfterUndoableAction(m_pMouseRoute);
8815 m_prev_pMousePoint = pMousePoint;
8823 int connect = tail->GetIndexOf(pMousePoint);
8828 int length = tail->GetnPoints();
8833 start = connect + 1;
8838 m_pMouseRoute->RemovePoint(
8842 for (i = start; i <= stop; i++) {
8843 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8846 m_pMouseRoute->GetnPoints();
8848 gFrame->RefreshAllCanvas();
8852 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8854 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8855 m_pMouseRoute->FinalizeForRendering();
8857 gFrame->RefreshAllCanvas();
8861 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8863 SetCursor(*pCursorPencil);
8865 if (!m_pMeasureRoute) {
8866 m_pMeasureRoute =
new Route();
8867 pRouteList->Append(m_pMeasureRoute);
8870 if (m_nMeasureState == 1) {
8876 wxString(_T (
"circle" )),
8877 wxEmptyString, wxEmptyString);
8879 pMousePoint->SetShowWaypointRangeRings(
false);
8881 m_pMeasureRoute->AddPoint(pMousePoint);
8885 m_prev_pMousePoint = pMousePoint;
8889 gFrame->RefreshAllCanvas();
8894 FindRoutePointsAtCursor(SelectRadius,
true);
8899 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8907 if (ret)
return true;
8910 if (event.Dragging()) {
8915 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8917 SelectableItemList SelList = pSelect->FindSelectionList(
8919 wxSelectableItemListNode *node = SelList.GetFirst();
8921 pFind = node->GetData();
8923 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8924 node = node->GetNext();
8929 if (m_pRoutePointEditTarget &&
8930 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8932 SelectableItemList SelList = pSelect->FindSelectionList(
8934 wxSelectableItemListNode *node = SelList.GetFirst();
8936 pFind = node->GetData();
8938 if (m_pRoutePointEditTarget == frp) {
8939 m_bIsInRadius =
true;
8942 node = node->GetNext();
8945 if (!m_dragoffsetSet) {
8947 .PresetDragOffset(
this, mouse_x, mouse_y);
8948 m_dragoffsetSet =
true;
8953 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8954 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8956 if (NULL == g_pMarkInfoDialog) {
8957 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8958 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8959 DraggingAllowed =
false;
8961 if (m_pRoutePointEditTarget &&
8962 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8963 DraggingAllowed =
false;
8965 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8967 if (DraggingAllowed) {
8968 if (!undo->InUndoableAction()) {
8969 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8970 Undo_NeedsCopy, m_pFoundPoint);
8976 if (!g_bopengl && m_pEditRouteArray) {
8977 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8978 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8983 if (g_pRouteMan->IsRouteValid(pr)) {
8985 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8986 pre_rect.Union(route_rect);
8994 if (CheckEdgePan(x, y,
true, 5, 2))
9002 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9004 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9005 m_pRoutePointEditTarget,
9006 SELTYPE_DRAGHANDLE);
9007 m_pFoundPoint->m_slat =
9008 m_pRoutePointEditTarget->m_lat;
9009 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9011 m_pRoutePointEditTarget->m_lat =
9013 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9014 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9015 m_pFoundPoint->m_slat =
9017 m_pFoundPoint->m_slon = new_cursor_lon;
9021 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
9022 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9023 g_pMarkInfoDialog->UpdateProperties(
true);
9033 if (m_pEditRouteArray) {
9034 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9036 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9037 if (g_pRouteMan->IsRouteValid(pr)) {
9039 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9040 post_rect.Union(route_rect);
9046 pre_rect.Union(post_rect);
9047 RefreshRect(pre_rect,
false);
9049 gFrame->RefreshCanvasOther(
this);
9050 m_bRoutePoinDragging =
true;
9055 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9056 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9058 if (NULL == g_pMarkInfoDialog) {
9059 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9060 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9061 DraggingAllowed =
false;
9063 if (m_pRoutePointEditTarget &&
9064 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
9065 DraggingAllowed =
false;
9067 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9069 if (DraggingAllowed) {
9070 if (!undo->InUndoableAction()) {
9071 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9072 Undo_NeedsCopy, m_pFoundPoint);
9080 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
9081 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
9083 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
9084 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
9086 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9092 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9093 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9094 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9095 (
int)(lppmax - (pre_rect.height / 2)));
9103 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9106 m_pRoutePointEditTarget,
9107 SELTYPE_DRAGHANDLE);
9108 m_pFoundPoint->m_slat =
9109 m_pRoutePointEditTarget->m_lat;
9110 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9112 m_pRoutePointEditTarget->m_lat =
9115 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9121 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
9122 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9123 g_pMarkInfoDialog->UpdateProperties(
true);
9128 if (!g_btouch) InvalidateGL();
9134 .CalculateDCRect(m_dc_route,
this, &post_rect);
9135 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9136 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9137 (
int)(lppmax - (post_rect.height / 2)));
9140 pre_rect.Union(post_rect);
9141 RefreshRect(pre_rect,
false);
9143 gFrame->RefreshCanvasOther(
this);
9144 m_bRoutePoinDragging =
true;
9149 if (ret)
return true;
9152 if (event.LeftUp()) {
9153 bool b_startedit_route =
false;
9154 m_dragoffsetSet =
false;
9157 m_bChartDragging =
false;
9158 m_bIsInRadius =
false;
9163 m_bedge_pan =
false;
9168 bool appending =
false;
9169 bool inserting =
false;
9175 if (m_pRoutePointEditTarget) {
9181 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9182 RefreshRect(wp_rect,
true);
9184 m_pRoutePointEditTarget = NULL;
9186 m_bRouteEditing =
true;
9188 if (m_routeState == 1) {
9189 m_pMouseRoute =
new Route();
9190 m_pMouseRoute->SetHiLite(50);
9191 pRouteList->Append(m_pMouseRoute);
9194 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9201 double nearby_radius_meters =
9202 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9205 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9206 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9207 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9210 m_FinishRouteOnKillFocus =
9212 dlg_return = OCPNMessageBox(
9213 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9214 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9215 m_FinishRouteOnKillFocus =
true;
9217 dlg_return = wxID_YES;
9219 if (dlg_return == wxID_YES) {
9220 pMousePoint = pNearbyPoint;
9223 if (m_routeState > 1)
9224 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9225 Undo_HasParent, NULL);
9226 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9228 bool procede =
false;
9232 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9238 m_FinishRouteOnKillFocus =
false;
9239 if (m_routeState == 1) {
9243 _(
"Insert first part of this route in the new route?");
9244 if (tail->GetIndexOf(pMousePoint) ==
9247 dmsg = _(
"Insert this route in the new route?");
9249 if (tail->GetIndexOf(pMousePoint) != 1) {
9251 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9252 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9253 m_FinishRouteOnKillFocus =
true;
9255 if (dlg_return == wxID_YES) {
9262 _(
"Append last part of this route to the new route?");
9263 if (tail->GetIndexOf(pMousePoint) == 1)
9265 "Append this route to the new route?");
9269 if (tail->GetLastPoint() != pMousePoint) {
9271 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9272 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9273 m_FinishRouteOnKillFocus =
true;
9275 if (dlg_return == wxID_YES) {
9286 if (!FindRouteContainingWaypoint(pMousePoint))
9287 pMousePoint->SetShared(
true);
9291 if (NULL == pMousePoint) {
9292 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9293 _T(
""), wxEmptyString);
9294 pMousePoint->SetNameShown(
false);
9296 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9298 if (m_routeState > 1)
9299 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9300 Undo_IsOrphanded, NULL);
9303 if (m_routeState == 1) {
9305 m_pMouseRoute->AddPoint(pMousePoint);
9306 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9310 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9311 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9312 &rhumbBearing, &rhumbDist);
9313 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9314 &gcDist, &gcBearing, NULL);
9315 double gcDistNM = gcDist / 1852.0;
9318 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9319 pow(rhumbDist - gcDistNM - 1, 0.5);
9322 msg << _(
"For this leg the Great Circle route is ")
9323 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
9324 << _(
" shorter than rhumbline.\n\n")
9325 << _(
"Would you like include the Great Circle routing points "
9329 m_FinishRouteOnKillFocus =
false;
9330 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9331 wxYES_NO | wxNO_DEFAULT);
9332 m_FinishRouteOnKillFocus =
true;
9334 int answer = wxID_NO;
9337 if (answer == wxID_YES) {
9339 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9340 wxRealPoint gcCoord;
9342 for (
int i = 1; i <= segmentCount; i++) {
9343 double fraction = (double)i * (1.0 / (
double)segmentCount);
9344 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9345 gcDist * fraction, gcBearing,
9346 &gcCoord.x, &gcCoord.y, NULL);
9348 if (i < segmentCount) {
9349 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
9350 _T(
""), wxEmptyString);
9351 gcPoint->SetNameShown(
false);
9352 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9355 gcPoint = pMousePoint;
9358 m_pMouseRoute->AddPoint(gcPoint);
9359 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9361 pSelect->AddSelectableRouteSegment(
9362 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9363 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9364 prevGcPoint = gcPoint;
9367 undo->CancelUndoableAction(
true);
9370 m_pMouseRoute->AddPoint(pMousePoint);
9371 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9372 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9373 rlon, m_prev_pMousePoint,
9374 pMousePoint, m_pMouseRoute);
9375 undo->AfterUndoableAction(m_pMouseRoute);
9379 m_pMouseRoute->AddPoint(pMousePoint);
9380 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9382 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9383 rlon, m_prev_pMousePoint,
9384 pMousePoint, m_pMouseRoute);
9385 undo->AfterUndoableAction(m_pMouseRoute);
9391 m_prev_pMousePoint = pMousePoint;
9398 int connect = tail->GetIndexOf(pMousePoint);
9403 int length = tail->GetnPoints();
9408 start = connect + 1;
9413 m_pMouseRoute->RemovePoint(
9417 for (i = start; i <= stop; i++) {
9418 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9421 m_pMouseRoute->GetnPoints();
9423 gFrame->RefreshAllCanvas();
9427 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9429 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9430 m_pMouseRoute->FinalizeForRendering();
9435 }
else if (m_bMeasure_Active && m_nMeasureState)
9438 m_bedge_pan =
false;
9442 if (m_nMeasureState == 1) {
9443 m_pMeasureRoute =
new Route();
9444 pRouteList->Append(m_pMeasureRoute);
9449 if (m_pMeasureRoute) {
9452 wxEmptyString, wxEmptyString);
9455 m_pMeasureRoute->AddPoint(pMousePoint);
9459 m_prev_pMousePoint = pMousePoint;
9461 m_pMeasureRoute->GetnPoints();
9465 CancelMeasureRoute();
9471 bool bSelectAllowed =
true;
9472 if (NULL == g_pMarkInfoDialog) {
9473 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9474 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9475 bSelectAllowed =
false;
9482 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9484 if (bSelectAllowed) {
9485 bool b_was_editing_mark = m_bMarkEditing;
9486 bool b_was_editing_route = m_bRouteEditing;
9487 FindRoutePointsAtCursor(SelectRadius,
9493 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9494 m_pRoutePointEditTarget = NULL;
9496 if (!b_was_editing_route) {
9497 if (m_pEditRouteArray) {
9498 b_startedit_route =
true;
9502 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9503 m_pTrackRolloverWin->IsActive(
false);
9505 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9506 m_pRouteRolloverWin->IsActive(
false);
9510 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9512 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9517 if (g_pRouteMan->IsRouteValid(pr)) {
9520 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9521 pre_rect.Union(route_rect);
9524 RefreshRect(pre_rect,
true);
9527 b_startedit_route =
false;
9531 if (m_pRoutePointEditTarget) {
9532 if (b_was_editing_mark ||
9533 b_was_editing_route) {
9534 if (m_lastRoutePointEditTarget) {
9538 .EnableDragHandle(
false);
9539 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9540 SELTYPE_DRAGHANDLE);
9544 if (m_pRoutePointEditTarget) {
9547 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9548 wxPoint2DDouble dragHandlePoint =
9550 .GetDragHandlePoint(
this);
9551 pSelect->AddSelectablePoint(
9552 dragHandlePoint.m_y, dragHandlePoint.m_x,
9553 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9556 if (m_lastRoutePointEditTarget) {
9560 .EnableDragHandle(
false);
9561 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9562 SELTYPE_DRAGHANDLE);
9565 wxArrayPtrVoid *lastEditRouteArray =
9567 m_lastRoutePointEditTarget);
9568 if (lastEditRouteArray) {
9569 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9571 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9572 if (g_pRouteMan->IsRouteValid(pr)) {
9576 delete lastEditRouteArray;
9587 if (m_lastRoutePointEditTarget) {
9590 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9591 RefreshRect(wp_rect,
true);
9594 if (m_pRoutePointEditTarget) {
9597 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9598 RefreshRect(wp_rect,
true);
9607 bool b_start_rollover =
false;
9608 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9609 SelectItem *pFind = pSelectAIS->FindSelection(
9611 if (pFind) b_start_rollover =
true;
9614 if (!b_start_rollover && !b_startedit_route) {
9615 SelectableItemList SelList = pSelect->FindSelectionList(
9617 wxSelectableItemListNode *node = SelList.GetFirst();
9623 if (pr && pr->IsVisible()) {
9624 b_start_rollover =
true;
9627 node = node->GetNext();
9631 if (!b_start_rollover && !b_startedit_route) {
9632 SelectableItemList SelList = pSelect->FindSelectionList(
9634 wxSelectableItemListNode *node = SelList.GetFirst();
9640 if (tr && tr->IsVisible()) {
9641 b_start_rollover =
true;
9644 node = node->GetNext();
9648 if (b_start_rollover)
9649 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9653 bool appending =
false;
9654 bool inserting =
false;
9656 if (m_bRouteEditing ) {
9658 if (m_pRoutePointEditTarget) {
9664 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9665 double nearby_radius_meters =
9666 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9667 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9668 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9669 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9671 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9675 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9677 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9692 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9697 OCPNMessageBox(
this,
9698 _(
"Replace this RoutePoint by the nearby "
9700 _(
"OpenCPN RoutePoint change"),
9701 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9702 if (dlg_return == wxID_YES) {
9707 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9710 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9712 if (tail && current && (tail != current)) {
9714 connect = tail->GetIndexOf(pNearbyPoint);
9715 int index_current_route =
9716 current->GetIndexOf(m_pRoutePointEditTarget);
9717 index_last = current->GetIndexOf(current->GetLastPoint());
9718 dlg_return1 = wxID_NO;
9720 index_current_route) {
9722 if (connect != tail->GetnPoints()) {
9725 _(
"Last part of route to be appended to dragged "
9729 _(
"Full route to be appended to dragged route?");
9731 dlg_return1 = OCPNMessageBox(
9732 this, dmsg, _(
"OpenCPN Route Create"),
9733 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9734 if (dlg_return1 == wxID_YES) {
9738 }
else if (index_current_route ==
9743 _(
"First part of route to be inserted into dragged "
9745 if (connect == tail->GetnPoints())
9747 "Full route to be inserted into dragged route?");
9749 dlg_return1 = OCPNMessageBox(
9750 this, dmsg, _(
"OpenCPN Route Create"),
9751 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9752 if (dlg_return1 == wxID_YES) {
9759 if (m_pRoutePointEditTarget->IsShared()) {
9761 dlg_return = OCPNMessageBox(
9763 _(
"Do you really want to delete and replace this "
9765 _T(
"\n") + _(
"which has been created manually?"),
9766 (
"OpenCPN RoutePoint warning"),
9767 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9770 if (dlg_return == wxID_YES) {
9771 pMousePoint = pNearbyPoint;
9773 pMousePoint->SetShared(
true);
9783 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9785 if (m_pEditRouteArray) {
9786 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9788 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9789 if (g_pRouteMan->IsRouteValid(pr)) {
9795 pSelect->DeleteAllSelectableRoutePoints(pr);
9796 pSelect->DeleteAllSelectableRouteSegments(pr);
9801 pSelect->AddAllSelectableRouteSegments(pr);
9802 pSelect->AddAllSelectableRoutePoints(pr);
9804 pr->FinalizeForRendering();
9805 pr->UpdateSegmentDistances();
9806 if (m_bRoutePoinDragging) {
9808 NavObj_dB::GetInstance().UpdateRoute(pr);
9815 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9816 if (m_pEditRouteArray) {
9817 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9819 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9820 if (g_pRouteMan->IsRouteValid(pr)) {
9821 if (pRoutePropDialog->GetRoute() == pr) {
9822 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9838 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9841 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9842 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9843 g_pMarkInfoDialog->Hide();
9845 delete m_pRoutePointEditTarget;
9846 m_lastRoutePointEditTarget = NULL;
9847 m_pRoutePointEditTarget = NULL;
9848 undo->AfterUndoableAction(pMousePoint);
9849 undo->InvalidateUndo();
9854 else if (m_bMarkEditing) {
9855 if (m_pRoutePointEditTarget)
9856 if (m_bRoutePoinDragging) {
9858 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9862 if (m_pRoutePointEditTarget)
9863 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9865 if (!m_pRoutePointEditTarget) {
9866 delete m_pEditRouteArray;
9867 m_pEditRouteArray = NULL;
9868 m_bRouteEditing =
false;
9870 m_bRoutePoinDragging =
false;
9877 int length = tail->GetnPoints();
9878 for (
int i = connect + 1; i <= length; i++) {
9879 current->AddPointAndSegment(tail->GetPoint(i),
false);
9882 gFrame->RefreshAllCanvas();
9885 current->FinalizeForRendering();
9891 pSelect->DeleteAllSelectableRoutePoints(current);
9892 pSelect->DeleteAllSelectableRouteSegments(current);
9893 for (
int i = 1; i < connect; i++) {
9894 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9896 pSelect->AddAllSelectableRouteSegments(current);
9897 pSelect->AddAllSelectableRoutePoints(current);
9898 current->FinalizeForRendering();
9904 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9905 if (m_pEditRouteArray) {
9906 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9907 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9908 if (g_pRouteMan->IsRouteValid(pr)) {
9909 if (pRoutePropDialog->GetRoute() == pr) {
9910 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9920 if (m_bRouteEditing) {
9923 bool appending =
false;
9924 bool inserting =
false;
9927 if (m_pRoutePointEditTarget) {
9928 m_pRoutePointEditTarget->
m_bBlink =
false;
9932 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9933 double nearby_radius_meters =
9934 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9935 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9936 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9937 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9939 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9940 bool duplicate =
false;
9942 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9944 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9959 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9964 OCPNMessageBox(
this,
9965 _(
"Replace this RoutePoint by the nearby "
9967 _(
"OpenCPN RoutePoint change"),
9968 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9969 if (dlg_return == wxID_YES) {
9973 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9976 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9978 if (tail && current && (tail != current)) {
9980 connect = tail->GetIndexOf(pNearbyPoint);
9981 int index_current_route =
9982 current->GetIndexOf(m_pRoutePointEditTarget);
9983 index_last = current->GetIndexOf(current->GetLastPoint());
9984 dlg_return1 = wxID_NO;
9986 index_current_route) {
9988 if (connect != tail->GetnPoints()) {
9991 _(
"Last part of route to be appended to dragged "
9995 _(
"Full route to be appended to dragged route?");
9997 dlg_return1 = OCPNMessageBox(
9998 this, dmsg, _(
"OpenCPN Route Create"),
9999 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10000 if (dlg_return1 == wxID_YES) {
10004 }
else if (index_current_route ==
10006 if (connect != 1) {
10009 _(
"First part of route to be inserted into dragged "
10011 if (connect == tail->GetnPoints())
10013 "Full route to be inserted into dragged route?");
10015 dlg_return1 = OCPNMessageBox(
10016 this, dmsg, _(
"OpenCPN Route Create"),
10017 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10018 if (dlg_return1 == wxID_YES) {
10025 if (m_pRoutePointEditTarget->IsShared()) {
10026 dlg_return = wxID_NO;
10027 dlg_return = OCPNMessageBox(
10029 _(
"Do you really want to delete and replace this "
10031 _T(
"\n") + _(
"which has been created manually?"),
10032 (
"OpenCPN RoutePoint warning"),
10033 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10036 if (dlg_return == wxID_YES) {
10037 pMousePoint = pNearbyPoint;
10039 pMousePoint->SetShared(
true);
10049 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10051 if (m_pEditRouteArray) {
10052 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10054 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10055 if (g_pRouteMan->IsRouteValid(pr)) {
10060 pSelect->DeleteAllSelectableRoutePoints(pr);
10061 pSelect->DeleteAllSelectableRouteSegments(pr);
10066 pSelect->AddAllSelectableRouteSegments(pr);
10067 pSelect->AddAllSelectableRoutePoints(pr);
10069 pr->FinalizeForRendering();
10070 pr->UpdateSegmentDistances();
10073 if (m_bRoutePoinDragging) {
10078 NavObj_dB::GetInstance().UpdateRoutePoint(
10079 m_pRoutePointEditTarget);
10081 NavObj_dB::GetInstance().UpdateRoute(pr);
10093 int length = tail->GetnPoints();
10094 for (
int i = connect + 1; i <= length; i++) {
10095 current->AddPointAndSegment(tail->GetPoint(i),
false);
10099 gFrame->RefreshAllCanvas();
10102 current->FinalizeForRendering();
10108 pSelect->DeleteAllSelectableRoutePoints(current);
10109 pSelect->DeleteAllSelectableRouteSegments(current);
10110 for (
int i = 1; i < connect; i++) {
10111 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10113 pSelect->AddAllSelectableRouteSegments(current);
10114 pSelect->AddAllSelectableRoutePoints(current);
10115 current->FinalizeForRendering();
10121 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10122 if (m_pEditRouteArray) {
10123 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10125 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10126 if (g_pRouteMan->IsRouteValid(pr)) {
10127 if (pRoutePropDialog->GetRoute() == pr) {
10128 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
10137 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10140 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
10141 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
10142 g_pMarkInfoDialog->Hide();
10144 delete m_pRoutePointEditTarget;
10145 m_lastRoutePointEditTarget = NULL;
10146 undo->AfterUndoableAction(pMousePoint);
10147 undo->InvalidateUndo();
10152 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10155 delete m_pEditRouteArray;
10156 m_pEditRouteArray = NULL;
10160 m_bRouteEditing =
false;
10161 m_pRoutePointEditTarget = NULL;
10167 else if (m_bMarkEditing) {
10168 if (m_pRoutePointEditTarget) {
10169 if (m_bRoutePoinDragging) {
10171 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10173 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10178 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10180 RefreshRect(wp_rect,
true);
10183 m_pRoutePointEditTarget = NULL;
10184 m_bMarkEditing =
false;
10189 else if (leftIsDown) {
10190 leftIsDown =
false;
10194 if (!m_bChartDragging && !m_bMeasure_Active) {
10196 m_bChartDragging =
false;
10200 m_bRoutePoinDragging =
false;
10203 if (ret)
return true;
10206 if (event.RightDown()) {
10217 m_FinishRouteOnKillFocus =
false;
10218 CallPopupMenu(mx, my);
10219 m_FinishRouteOnKillFocus =
true;
10230 if (event.ShiftDown()) {
10234 event.GetPosition(&x, &y);
10236 x *= m_displayScale;
10237 y *= m_displayScale;
10243 int wheel_dir =
event.GetWheelRotation();
10246 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10247 wheel_dir = wheel_dir > 0 ? 1 : -1;
10249 double factor = g_mouse_zoom_sensitivity;
10250 if (wheel_dir < 0) factor = 1 / factor;
10252 if (g_bsmoothpanzoom) {
10253 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10254 if (wheel_dir == m_last_wheel_dir) {
10255 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10260 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10261 m_wheelstopwatch.Start(0);
10266 m_last_wheel_dir = wheel_dir;
10271 if (event.LeftDown()) {
10278 last_drag.x = x, last_drag.y = y;
10279 panleftIsDown =
true;
10282 if (event.LeftUp()) {
10283 if (panleftIsDown) {
10285 panleftIsDown =
false;
10288 if (!m_bChartDragging && !m_bMeasure_Active) {
10289 switch (cursor_region) {
10311 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10316 m_bChartDragging =
false;
10322 if (event.Dragging() && event.LeftIsDown()) {
10340 struct timespec now;
10341 clock_gettime(CLOCK_MONOTONIC, &now);
10342 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10344 if (
false == m_bChartDragging) {
10346 last_drag.x = x, last_drag.y = y;
10347 m_bChartDragging =
true;
10348 m_chart_drag_total_time = 0;
10349 m_chart_drag_total_x = 0;
10350 m_chart_drag_total_y = 0;
10351 m_inertia_last_drag_x = x;
10352 m_inertia_last_drag_y = y;
10353 m_drag_vec_x.clear();
10354 m_drag_vec_y.clear();
10355 m_drag_vec_t.clear();
10356 m_last_drag_time = tnow;
10360 uint64_t delta_t = tnow - m_last_drag_time;
10361 double delta_tf = delta_t / 1e9;
10363 m_chart_drag_total_time += delta_tf;
10364 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10365 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10367 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10368 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10369 m_drag_vec_t.push_back(delta_tf);
10371 m_inertia_last_drag_x = x;
10372 m_inertia_last_drag_y = y;
10373 m_last_drag_time = tnow;
10375 if ((last_drag.x != x) || (last_drag.y != y)) {
10376 if (!m_routeState) {
10379 m_bChartDragging =
true;
10380 StartTimedMovement();
10381 m_pan_drag.x += last_drag.x - x;
10382 m_pan_drag.y += last_drag.y - y;
10383 last_drag.x = x, last_drag.y = y;
10387 if ((last_drag.x != x) || (last_drag.y != y)) {
10388 if (!m_routeState) {
10391 m_bChartDragging =
true;
10392 StartTimedMovement();
10393 m_pan_drag.x += last_drag.x - x;
10394 m_pan_drag.y += last_drag.y - y;
10395 last_drag.x = x, last_drag.y = y;
10402 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10404 m_DoubleClickTimer->Start();
10405 singleClickEventIsValid =
false;
10413void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10414 if (MouseEventOverlayWindows(event))
return;
10421void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10424 wxCursor *ptarget_cursor = pCursorArrow;
10425 if (!pPlugIn_Cursor) {
10426 ptarget_cursor = pCursorArrow;
10427 if ((!m_routeState) &&
10428 (!m_bMeasure_Active) ) {
10429 if (cursor_region == MID_RIGHT) {
10430 ptarget_cursor = pCursorRight;
10431 }
else if (cursor_region == MID_LEFT) {
10432 ptarget_cursor = pCursorLeft;
10433 }
else if (cursor_region == MID_TOP) {
10434 ptarget_cursor = pCursorDown;
10435 }
else if (cursor_region == MID_BOT) {
10436 ptarget_cursor = pCursorUp;
10438 ptarget_cursor = pCursorArrow;
10440 }
else if (m_bMeasure_Active ||
10442 ptarget_cursor = pCursorPencil;
10444 ptarget_cursor = pPlugIn_Cursor;
10447 SetCursor(*ptarget_cursor);
10450void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10451 SetCursor(*pCursorArrow);
10454void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10458 wxArrayString files;
10460 ChartBase *target_chart = GetChartAtCursor();
10461 if (target_chart) {
10462 file.Assign(target_chart->GetFullPath());
10463 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10464 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10467 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10469 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10470 unsigned int im = stackIndexArray.size();
10471 int scale = 2147483647;
10472 if (VPoint.b_quilt && im > 0) {
10473 for (
unsigned int is = 0; is < im; is++) {
10474 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
10475 CHART_TYPE_MBTILES) {
10476 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10478 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10479 if (ChartData->GetChartTableEntry(stackIndexArray[is])
10481 .Contains(lat, lon)) {
10482 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10485 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10486 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
10494 std::vector<Ais8_001_22 *> area_notices;
10496 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10499 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10500 auto target_data = target.second;
10501 if (!target_data->area_notices.empty()) {
10502 for (
auto &ani : target_data->area_notices) {
10507 for (Ais8_001_22_SubAreaList::iterator sa =
10508 area_notice.sub_areas.begin();
10509 sa != area_notice.sub_areas.end(); ++sa) {
10510 switch (sa->shape) {
10511 case AIS8_001_22_SHAPE_CIRCLE: {
10512 wxPoint target_point;
10514 bbox.Expand(target_point);
10515 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10518 case AIS8_001_22_SHAPE_RECT: {
10519 wxPoint target_point;
10521 bbox.Expand(target_point);
10522 if (sa->e_dim_m > sa->n_dim_m)
10523 bbox.EnLarge(sa->e_dim_m * vp_scale);
10525 bbox.EnLarge(sa->n_dim_m * vp_scale);
10528 case AIS8_001_22_SHAPE_POLYGON:
10529 case AIS8_001_22_SHAPE_POLYLINE: {
10530 for (
int i = 0; i < 4; ++i) {
10531 double lat = sa->latitude;
10532 double lon = sa->longitude;
10533 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10535 wxPoint target_point;
10537 bbox.Expand(target_point);
10541 case AIS8_001_22_SHAPE_SECTOR: {
10542 double lat1 = sa->latitude;
10543 double lon1 = sa->longitude;
10545 wxPoint target_point;
10547 bbox.Expand(target_point);
10548 for (
int i = 0; i < 18; ++i) {
10551 sa->left_bound_deg +
10552 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10553 sa->radius_m / 1852.0, &lat, &lon);
10555 bbox.Expand(target_point);
10557 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10560 bbox.Expand(target_point);
10566 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10567 area_notices.push_back(&area_notice);
10574 if (target_chart || !area_notices.empty() || file.HasName()) {
10576 int sel_rad_pix = 5;
10577 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10582 SetCursor(wxCURSOR_WAIT);
10583 bool lightsVis = m_encShowLights;
10584 if (!lightsVis) SetShowENCLights(
true);
10587 ListOfObjRazRules *rule_list = NULL;
10588 ListOfPI_S57Obj *pi_rule_list = NULL;
10591 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10592 else if (target_plugin_chart)
10593 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10594 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10596 ListOfObjRazRules *overlay_rule_list = NULL;
10597 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10600 if (CHs57_Overlay) {
10601 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10602 zlat, zlon, SelectRadius, &GetVP());
10605 if (!lightsVis) SetShowENCLights(
false);
10608 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10609 wxString face = dFont->GetFaceName();
10611 if (NULL == g_pObjectQueryDialog) {
10612 g_pObjectQueryDialog =
10613 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10614 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10617 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10618 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10622 fg = g_pObjectQueryDialog->GetForegroundColour();
10626 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
10627 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10630 int points = dFont->GetPointSize();
10632 int points = dFont->GetPointSize() + 1;
10636 for (
int i = -2; i < 5; i++) {
10637 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10639 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10641 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
10643 if (overlay_rule_list && CHs57_Overlay) {
10644 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10645 objText << _T(
"<hr noshade>");
10648 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10649 an != area_notices.end(); ++an) {
10650 objText << _T(
"<b>AIS Area Notice:</b> " );
10651 objText << ais8_001_22_notice_names[(*an)->notice_type];
10652 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10653 (*an)->sub_areas.begin();
10654 sa != (*an)->sub_areas.end(); ++sa)
10655 if (!sa->text.empty()) objText << sa->text;
10656 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10657 objText << _T(
"<hr noshade>" );
10661 objText << Chs57->CreateObjDescriptions(rule_list);
10662 else if (target_plugin_chart)
10663 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10666 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
10669 wxString AddFiles, filenameOK;
10671 if (!target_plugin_chart) {
10674 AddFiles = wxString::Format(
10675 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
10677 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
10678 _T(
"cellpadding=3>"),
10679 file.GetFullName());
10681 file.Assign(file.GetPath(), wxT(
""));
10682 wxDir dir(file.GetFullPath());
10684 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10686 file.Assign(dir.GetNameWithSep().append(filename));
10687 wxString FormatString =
10688 _T(
"<td valign=top><font size=-2><a ")
10689 _T("href=\"%s\">%s</a></font></td>");
10690 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10691 filenameOK = file.GetFullPath();
10693 if (3 * ((
int)filecount / 3) == filecount)
10694 FormatString.Prepend(_T(
"<tr>"));
10696 FormatString.Prepend(
10697 _T(
"<td>  </td>"));
10700 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10701 file.GetFullName());
10704 cont = dir.GetNext(&filename);
10706 objText << AddFiles << _T(
"</table>");
10708 objText << _T(
"</font>");
10709 objText << _T(
"</body></html>");
10711 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10712 g_pObjectQueryDialog->SetHTMLPage(objText);
10713 g_pObjectQueryDialog->Show();
10715 if ((!Chs57 && filecount == 1)) {
10717 wxHtmlLinkInfo hli(filenameOK);
10718 wxHtmlLinkEvent hle(1, hli);
10719 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10722 if (rule_list) rule_list->Clear();
10725 if (overlay_rule_list) overlay_rule_list->Clear();
10726 delete overlay_rule_list;
10728 if (pi_rule_list) pi_rule_list->Clear();
10729 delete pi_rule_list;
10731 SetCursor(wxCURSOR_ARROW);
10735void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10737 if (!g_pMarkInfoDialog) {
10744 wxSize canvas_size = GetSize();
10747 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10749 g_pMarkInfoDialog->Layout();
10751 wxPoint canvas_pos = GetPosition();
10752 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10754 bool newFit =
false;
10755 if (canvas_size.x < fitted_size.x) {
10756 fitted_size.x = canvas_size.x - 40;
10757 if (canvas_size.y < fitted_size.y)
10758 fitted_size.y -= 40;
10760 if (canvas_size.y < fitted_size.y) {
10761 fitted_size.y = canvas_size.y - 40;
10762 if (canvas_size.x < fitted_size.x)
10763 fitted_size.x -= 40;
10767 g_pMarkInfoDialog->SetSize(fitted_size);
10768 g_pMarkInfoDialog->Centre();
10774 wxString title_base = _(
"Mark Properties");
10776 title_base = _(
"Waypoint Properties");
10778 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10779 g_pMarkInfoDialog->UpdateProperties();
10781 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title_base, _(
"Layer"),
10783 g_pMarkInfoDialog->SetDialogTitle(caption);
10785 g_pMarkInfoDialog->SetDialogTitle(title_base);
10787 g_pMarkInfoDialog->Show();
10788 g_pMarkInfoDialog->Raise();
10789 g_pMarkInfoDialog->InitialFocus();
10790 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10793void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10794 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10795 pRoutePropDialog->SetRouteAndUpdate(selected);
10797 pRoutePropDialog->Show();
10798 pRoutePropDialog->Raise();
10800 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10804 wxSize canvas_size = GetSize();
10805 wxPoint canvas_pos = GetPosition();
10806 wxSize fitted_size = pRoutePropDialog->GetSize();
10809 if (canvas_size.x < fitted_size.x) {
10810 fitted_size.x = canvas_size.x;
10811 if (canvas_size.y < fitted_size.y)
10812 fitted_size.y -= 20;
10814 if (canvas_size.y < fitted_size.y) {
10815 fitted_size.y = canvas_size.y;
10816 if (canvas_size.x < fitted_size.x)
10817 fitted_size.x -= 20;
10820 pRoutePropDialog->SetSize(fitted_size);
10821 pRoutePropDialog->Centre();
10826 wxPoint xxp = ClientToScreen(canvas_pos);
10830 pRoutePropDialog->SetRouteAndUpdate(selected);
10832 pRoutePropDialog->Show();
10837void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10838 pTrackPropDialog = TrackPropDlg::getInstance(
10841 pTrackPropDialog->SetTrackAndUpdate(selected);
10844 pTrackPropDialog->Show();
10849void pupHandler_PasteWaypoint() {
10852 int pasteBuffer = kml.ParsePasteBuffer();
10853 RoutePoint *pasted = kml.GetParsedRoutePoint();
10854 if (!pasted)
return;
10856 double nearby_radius_meters =
10857 g_Platform->GetSelectRadiusPix() /
10858 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10860 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10861 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10863 int answer = wxID_NO;
10867 "There is an existing waypoint at the same location as the one you are "
10868 "pasting. Would you like to merge the pasted data with it?\n\n");
10869 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10870 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10871 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10874 if (answer == wxID_YES) {
10875 nearPoint->SetName(pasted->GetName());
10877 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10878 pRouteManagerDialog->UpdateWptListCtrl();
10881 if (answer == wxID_NO) {
10884 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10887 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10890 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10891 pRouteManagerDialog->UpdateWptListCtrl();
10892 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10893 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10896 gFrame->InvalidateAllGL();
10897 gFrame->RefreshAllCanvas(
false);
10900void pupHandler_PasteRoute() {
10903 int pasteBuffer = kml.ParsePasteBuffer();
10904 Route *pasted = kml.GetParsedRoute();
10905 if (!pasted)
return;
10907 double nearby_radius_meters =
10908 g_Platform->GetSelectRadiusPix() /
10909 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10915 bool mergepoints =
false;
10916 bool createNewRoute =
true;
10917 int existingWaypointCounter = 0;
10919 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10920 curPoint = pasted->GetPoint(i);
10921 nearPoint = pWayPointMan->GetNearbyWaypoint(
10922 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10924 mergepoints =
true;
10925 existingWaypointCounter++;
10933 int answer = wxID_NO;
10937 "There are existing waypoints at the same location as some of the ones "
10938 "you are pasting. Would you like to just merge the pasted data into "
10940 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10941 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10942 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10944 if (answer == wxID_CANCEL) {
10951 if (mergepoints && answer == wxID_YES &&
10952 existingWaypointCounter == pasted->GetnPoints()) {
10953 wxRouteListNode *route_node = pRouteList->GetFirst();
10954 while (route_node) {
10955 Route *proute = route_node->GetData();
10958 createNewRoute =
false;
10961 route_node = route_node->GetNext();
10965 Route *newRoute = 0;
10968 if (createNewRoute) {
10969 newRoute =
new Route();
10973 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10974 curPoint = pasted->GetPoint(i);
10977 newPoint = pWayPointMan->GetNearbyWaypoint(
10978 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10979 newPoint->SetName(curPoint->GetName());
10982 if (createNewRoute) newRoute->AddPoint(newPoint);
10988 newPoint->SetIconName(_T(
"circle"));
10991 newPoint->SetShared(
false);
10993 newRoute->AddPoint(newPoint);
10994 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10997 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11000 if (i > 1 && createNewRoute)
11001 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11002 curPoint->m_lat, curPoint->m_lon,
11003 prevPoint, newPoint, newRoute);
11004 prevPoint = newPoint;
11007 if (createNewRoute) {
11008 pRouteList->Append(newRoute);
11010 NavObj_dB::GetInstance().InsertRoute(newRoute);
11012 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
11013 pRoutePropDialog->SetRouteAndUpdate(newRoute);
11016 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
11017 pRouteManagerDialog->UpdateRouteListCtrl();
11018 pRouteManagerDialog->UpdateWptListCtrl();
11020 gFrame->InvalidateAllGL();
11021 gFrame->RefreshAllCanvas(
false);
11023 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
11024 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
11027void pupHandler_PasteTrack() {
11030 int pasteBuffer = kml.ParsePasteBuffer();
11031 Track *pasted = kml.GetParsedTrack();
11032 if (!pasted)
return;
11040 newTrack->SetName(pasted->GetName());
11042 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11043 curPoint = pasted->GetPoint(i);
11047 wxDateTime now = wxDateTime::Now();
11050 newTrack->AddPoint(newPoint);
11053 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11054 newPoint->m_lat, newPoint->m_lon,
11055 prevPoint, newPoint, newTrack);
11057 prevPoint = newPoint;
11060 g_TrackList.push_back(newTrack);
11062 NavObj_dB::GetInstance().InsertTrack(newTrack);
11064 gFrame->InvalidateAllGL();
11065 gFrame->RefreshAllCanvas(
false);
11068bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11071 v[_T(
"CursorPosition_x")] = x;
11072 v[_T(
"CursorPosition_y")] = y;
11075 if (seltype & SELTYPE_UNKNOWN) v[_T(
"SelectionType")] = wxT(
"Canvas");
11076 if (seltype & SELTYPE_ROUTEPOINT) v[_T(
"SelectionType")] = wxT(
"RoutePoint");
11077 if (seltype & SELTYPE_AISTARGET) v[_T(
"SelectionType")] = wxT(
"AISTarget");
11082 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11084 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11087#define SELTYPE_UNKNOWN 0x0001
11088#define SELTYPE_ROUTEPOINT 0x0002
11089#define SELTYPE_ROUTESEGMENT 0x0004
11090#define SELTYPE_TIDEPOINT 0x0008
11091#define SELTYPE_CURRENTPOINT 0x0010
11092#define SELTYPE_ROUTECREATE 0x0020
11093#define SELTYPE_AISTARGET 0x0040
11094#define SELTYPE_MARKPOINT 0x0080
11095#define SELTYPE_TRACKSEGMENT 0x0100
11096#define SELTYPE_DRAGHANDLE 0x0200
11099 if (g_bhide_context_menus)
return true;
11101 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11102 m_pIDXCandidate, m_nmea_log);
11105 wxEVT_COMMAND_MENU_SELECTED,
11106 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11108 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11111 wxEVT_COMMAND_MENU_SELECTED,
11112 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11114 delete m_canvasMenu;
11115 m_canvasMenu = NULL;
11125void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11128 if (m_canvasMenu) {
11129 m_canvasMenu->PopupMenuHandler(event);
11134void ChartCanvas::StartRoute(
void) {
11136 if (g_brouteCreating)
return;
11138 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
11140 g_brouteCreating =
true;
11142 m_bDrawingRoute =
false;
11143 SetCursor(*pCursorPencil);
11145 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11147 HideGlobalToolbar();
11150 androidSetRouteAnnunciator(
true);
11154wxString ChartCanvas::FinishRoute(
void) {
11156 m_prev_pMousePoint = NULL;
11157 m_bDrawingRoute =
false;
11159 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11162 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11164 androidSetRouteAnnunciator(
false);
11167 SetCursor(*pCursorArrow);
11169 if (m_pMouseRoute) {
11170 if (m_bAppendingRoute) {
11172 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11174 if (m_pMouseRoute->GetnPoints() > 1) {
11176 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11179 m_pMouseRoute = NULL;
11182 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11184 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
11185 (pRoutePropDialog->IsShown())) {
11186 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
11189 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11190 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11191 pRouteManagerDialog->UpdateRouteListCtrl();
11194 m_bAppendingRoute =
false;
11195 m_pMouseRoute = NULL;
11197 m_pSelectedRoute = NULL;
11199 undo->InvalidateUndo();
11200 gFrame->RefreshAllCanvas(
true);
11202 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
11204 ShowGlobalToolbar();
11206 g_brouteCreating =
false;
11211void ChartCanvas::HideGlobalToolbar() {
11212 if (m_canvasIndex == 0) {
11213 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11217void ChartCanvas::ShowGlobalToolbar() {
11218 if (m_canvasIndex == 0) {
11219 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11223void ChartCanvas::ShowAISTargetList(
void) {
11224 if (NULL == g_pAISTargetList) {
11228 g_pAISTargetList->UpdateAISTargetList();
11231void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11232 if (!m_bShowOutlines)
return;
11234 if (!ChartData)
return;
11236 int nEntry = ChartData->GetChartTableEntries();
11238 for (
int i = 0; i < nEntry; i++) {
11242 bool b_group_draw =
false;
11243 if (m_groupIndex > 0) {
11244 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11245 int index = pt->GetGroupArray()[ig];
11246 if (m_groupIndex == index) {
11247 b_group_draw =
true;
11252 b_group_draw =
true;
11254 if (b_group_draw) RenderChartOutline(dc, i, vp);
11260 if (VPoint.b_quilt) {
11261 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11262 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11266 }
else if (m_singleChart &&
11267 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11271 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11274 if (zoom_factor > 8.0) {
11275 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
11278 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
11282 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11286void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11288 if (g_bopengl && m_glcc) {
11290 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11295 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11296 if (!ChartData->IsChartAvailable(dbIndex))
return;
11299 float plylat, plylon;
11300 float plylat1, plylon1;
11302 int pixx, pixy, pixx1, pixy1;
11305 ChartData->GetDBBoundingBox(dbIndex, box);
11309 if (box.GetLonRange() == 360)
return;
11311 double lon_bias = 0;
11313 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11315 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11317 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11318 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
11320 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11321 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
11324 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
11327 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
11328 if (0 == nAuxPlyEntries)
11332 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11333 plylon += lon_bias;
11339 for (
int i = 0; i < nPly - 1; i++) {
11340 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11341 plylon1 += lon_bias;
11347 int pixxs1 = pixx1;
11348 int pixys1 = pixy1;
11350 bool b_skip =
false;
11354 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11355 pow((
double)(pixy1 - pixy), 2)) /
11361 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11366 if (fabs(dist - distgc) > 10000. * 1852.)
11372 ClipResult res = cohen_sutherland_line_clip_i(
11374 if (res != Invisible && !b_skip)
11375 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11383 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11384 plylon1 += lon_bias;
11390 ClipResult res = cohen_sutherland_line_clip_i(
11392 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11399 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
11400 for (
int j = 0; j < nAuxPlyEntries; j++) {
11402 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11407 for (
int i = 0; i < nAuxPly - 1; i++) {
11408 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11414 int pixxs1 = pixx1;
11415 int pixys1 = pixy1;
11417 bool b_skip =
false;
11421 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11422 ((pixy1 - pixy) * (pixy1 - pixy))) /
11427 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11432 if (fabs(dist - distgc) > 10000. * 1852.)
11438 ClipResult res = cohen_sutherland_line_clip_i(
11440 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11448 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11453 ClipResult res = cohen_sutherland_line_clip_i(
11455 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11460static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11461 const wxString &second) {
11462 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11464 int pointsize = dFont->GetPointSize();
11468 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11469 false, dFont->GetFaceName());
11471 dc.SetFont(*psRLI_font);
11479 int hilite_offset = 3;
11482 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11483 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11485 dc.GetTextExtent(first, &w1, &h1);
11486 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11492 w = wxMax(w1, w2) + (h1 / 2);
11497 xp = ref_point.x - w;
11499 yp += hilite_offset;
11501 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11503 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11504 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11506 dc.DrawText(first, xp, yp);
11507 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11510void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11511 if (!g_bAllowShipToActive)
return;
11513 Route *rt = g_pRouteMan->GetpActiveRoute();
11516 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11517 wxPoint2DDouble pa, pb;
11523 g_pRouteMan->GetRoutePen()->GetWidth();
11524 if (rt->
m_width != wxPENSTYLE_INVALID)
11526 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11527 g_shipToActiveStyle, 5)];
11528 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11530 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11532 g_pRouteMan->GetActiveRoutePen()->GetColour();
11533 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11536 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11539 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11540 (
int)pb.m_y, GetVP(),
true);
11544#ifdef USE_ANDROID_GLES2
11545 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11547 if (style != wxPENSTYLE_SOLID) {
11548 if (glChartCanvas::dash_map.find(style) !=
11549 glChartCanvas::dash_map.end()) {
11550 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11554 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11557 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11558 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11564void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11566 if (m_routeState >= 2) route = m_pMouseRoute;
11567 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11568 route = m_pMeasureRoute;
11570 if (!route)
return;
11573 if (!g_pRouteMan->IsRouteValid(route))
return;
11578 int np = route->GetnPoints();
11580 if (g_btouch && (np > 1)) np--;
11582 render_lat = rp.m_lat;
11583 render_lon = rp.m_lon;
11586 double rhumbBearing, rhumbDist;
11588 &rhumbBearing, &rhumbDist);
11589 double brg = rhumbBearing;
11590 double dist = rhumbDist;
11594 double gcBearing, gcBearing2, gcDist;
11595 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11598 double gcDistm = gcDist / 1852.0;
11601 rhumbBearing = 90.;
11603 wxPoint destPoint, lastPoint;
11606 int milesDiff = rhumbDist - gcDistm;
11607 if (milesDiff > 1) {
11618 for (
int i = 1; i <= milesDiff; i++) {
11619 double p = (double)i * (1.0 / (
double)milesDiff);
11621 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11622 &pLon, &pLat, &gcBearing2);
11624 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11626 lastPoint = destPoint;
11629 if (r_rband.x && r_rband.y) {
11630 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11632 if (m_bMeasure_DistCircle) {
11633 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11634 powf((
float)(r_rband.y - lastPoint.y), 2));
11636 dc.SetPen(*g_pRouteMan->GetRoutePen());
11637 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11638 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11644 wxString routeInfo;
11647 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11653 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11655 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11656 (
int)varBrg, 0x00B0);
11658 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
11663 routeInfo <<
"\nReverse: ";
11665 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11666 (
int)(brg + 180.) % 360, 0x00B0);
11668 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11669 (
int)(varBrg + 180.) % 360, 0x00B0);
11674 s0.Append(_(
"Route") + _T(
": "));
11676 s0.Append(_(
"Layer Route: "));
11679 if (!g_btouch) disp_length += dist;
11680 s0 += FormatDistanceAdaptive(disp_length);
11682 RouteLegInfo(dc, r_rband, routeInfo, s0);
11684 m_brepaint_piano =
true;
11687void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11688 if (!m_bShowVisibleSectors)
return;
11690 if (g_bDeferredInitDone) {
11692 double rhumbBearing, rhumbDist;
11693 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11694 &rhumbBearing, &rhumbDist);
11696 if (rhumbDist > 0.05)
11698 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11699 m_sectorlegsVisible);
11700 m_sector_glat = gLat;
11701 m_sector_glon = gLon;
11703 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11707void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11715void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11716 if (!ps52plib)
return;
11718 if (VPoint.b_quilt) {
11719 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11721 if (m_pQuilt->IsQuiltVector()) {
11722 if (ps52plib->GetStateHash() != m_s52StateHash) {
11724 m_s52StateHash = ps52plib->GetStateHash();
11728 if (ps52plib->GetStateHash() != m_s52StateHash) {
11730 m_s52StateHash = ps52plib->GetStateHash();
11735 bool bSendPlibState =
true;
11736 if (VPoint.b_quilt) {
11737 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11740 if (bSendPlibState) {
11742 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
11743 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
11744 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
11745 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
11746 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
11749 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
11750 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
11751 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
11752 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] = m_encShowAnchor;
11753 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] = GetShowENCDataQual();
11754 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
11755 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
11759 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
11760 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
11764 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
11765 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
11766 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
11767 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] =
11768 ps52plib->m_bShowS57ImportantTextOnly;
11769 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
11770 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
11771 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
11772 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
11773 v[_T(
"OpenCPN S52PLIB ColorShades")] =
11774 S52_getMarinerParam(S52_MAR_TWO_SHADES);
11777 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
11778 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
11779 v[_T(
"OpenCPN Scale Factor Exp")] =
11780 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11781 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
11787 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11788 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11789 g_lastS52PLIBPluginMessage = out;
11795void ChartCanvas::OnPaint(wxPaintEvent &event) {
11796 wxPaintDC dc(
this);
11806 if (!m_b_paint_enable) {
11811 UpdateCanvasS52PLIBConfig();
11814 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11816 if (m_glcc && g_bopengl) {
11817 if (!s_in_update) {
11827 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11829 wxRegion ru = GetUpdateRegion();
11831 int rx, ry, rwidth, rheight;
11832 ru.GetBox(rx, ry, rwidth, rheight);
11836#ifdef ocpnUSE_DIBSECTION
11839 wxMemoryDC temp_dc;
11847 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11848 height += m_Piano->GetHeight();
11850 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11854 int thumbx, thumby, thumbsx, thumbsy;
11855 pthumbwin->GetPosition(&thumbx, &thumby);
11856 pthumbwin->GetSize(&thumbsx, &thumbsy);
11857 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11859 if (pthumbwin->IsShown()) {
11860 rgn_chart.Subtract(rgn_thumbwin);
11861 ru.Subtract(rgn_thumbwin);
11867 wxRegion rgn_blit = ru;
11868 if (g_bShowChartBar) {
11869 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11870 GetClientSize().x, m_Piano->GetHeight());
11873 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11874 if (style->chartStatusWindowTransparent)
11875 m_brepaint_piano =
true;
11877 ru.Subtract(chart_bar_rect);
11881 if (m_Compass && m_Compass->IsShown()) {
11882 wxRect compassRect = m_Compass->
GetRect();
11883 if (ru.Contains(compassRect) != wxOutRegion) {
11884 ru.Subtract(compassRect);
11888 wxRect noteRect = m_notification_button->
GetRect();
11889 if (ru.Contains(noteRect) != wxOutRegion) {
11890 ru.Subtract(noteRect);
11894 bool b_newview =
true;
11899 m_cache_vp.IsValid()) {
11905 bool b_rcache_ok =
false;
11906 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11907 b_rcache_ok = !b_newview;
11910 if (VPoint.b_MercatorProjectionOverride)
11911 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11925 if (b_rcache_ok) chart_get_region.Clear();
11928 if (VPoint.b_quilt)
11930 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11932 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11937 AbstractPlatform::ShowBusySpinner();
11941 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11942 (m_working_bm.GetHeight() != svp.
pix_height))
11946 if (fabs(VPoint.
rotation) < 0.01) {
11947 bool b_save =
true;
11949 if (g_SencThreadManager) {
11950 if (g_SencThreadManager->GetJobCount()) {
11952 m_cache_vp.Invalidate();
11966 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11971 int dy = c_new.y - c_old.y;
11972 int dx = c_new.x - c_old.x;
11977 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11981 temp_dc.SelectObject(m_working_bm);
11983 wxMemoryDC cache_dc;
11984 cache_dc.SelectObject(m_cached_chart_bm);
11988 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11991 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11997 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12000 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12008 update_region.Union(
12011 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12016 update_region.Union(
12019 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12023 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12025 cache_dc.SelectObject(wxNullBitmap);
12029 temp_dc.SelectObject(m_cached_chart_bm);
12032 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12036 temp_dc.SelectObject(m_working_bm);
12037 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12042 temp_dc.SelectObject(m_cached_chart_bm);
12047 temp_dc.SelectObject(m_working_bm);
12048 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12061 wxMemoryDC scratch_dc_0;
12062 scratch_dc_0.SelectObject(m_cached_chart_bm);
12065 scratch_dc_0.SelectObject(wxNullBitmap);
12074 temp_dc.SelectObject(m_working_bm);
12077 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12078 chart_get_all_region);
12081 AbstractPlatform::HideBusySpinner();
12087 if (!m_singleChart) {
12088 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12093 if (!chart_get_region.IsEmpty()) {
12094 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12098 if (temp_dc.IsOk()) {
12103 if (!VPoint.b_quilt) {
12106 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12107 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12114 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12115 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12118 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12120 temp_dc.DestroyClippingRegion();
12125 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12127 if (!backgroundRegion.IsEmpty()) {
12133 wxColour water = pWorldBackgroundChart->water;
12134 if (water.IsOk()) {
12135 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12136 temp_dc.SetBrush(wxBrush(water));
12138 while (upd.HaveRects()) {
12139 wxRect rect = upd.GetRect();
12140 temp_dc.DrawRectangle(rect);
12145 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12146 temp_dc.SetDeviceClippingRegion(*clip_region);
12147 delete clip_region;
12151 SetVPRotation(VPoint.
skew);
12154 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
12160 wxMemoryDC *pChartDC = &temp_dc;
12161 wxMemoryDC rotd_dc;
12163 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12165 if (!b_rcache_ok) {
12167 wxMemoryDC tbase_dc;
12169 tbase_dc.SelectObject(bm_base);
12171 tbase_dc.SelectObject(wxNullBitmap);
12173 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12176 wxImage base_image;
12177 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12185 bool b_rot_ok =
false;
12186 if (base_image.IsOk()) {
12189 m_b_rot_hidef =
false;
12193 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12194 m_b_rot_hidef, &m_roffset);
12199 rot_vp.IsValid() && (ri.IsOk())) {
12206 m_prot_bm =
new wxBitmap(ri);
12209 m_roffset.x += VPoint.rv_rect.x;
12210 m_roffset.y += VPoint.rv_rect.y;
12213 if (m_prot_bm && m_prot_bm->IsOk()) {
12214 rotd_dc.SelectObject(*m_prot_bm);
12215 pChartDC = &rotd_dc;
12217 pChartDC = &temp_dc;
12218 m_roffset = wxPoint(0, 0);
12221 pChartDC = &temp_dc;
12222 m_roffset = wxPoint(0, 0);
12225 wxPoint offset = m_roffset;
12228 m_cache_vp = VPoint;
12231 wxMemoryDC mscratch_dc;
12232 mscratch_dc.SelectObject(*pscratch_bm);
12234 mscratch_dc.ResetBoundingBox();
12235 mscratch_dc.DestroyClippingRegion();
12236 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12239 wxRegionIterator upd(rgn_blit);
12241 wxRect rect = upd.GetRect();
12243 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12244 rect.x - offset.x, rect.y - offset.y);
12250 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12251 if (
this == wxWindow::FindFocus()) {
12252 g_focusCanvas =
this;
12254 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
12255 mscratch_dc.SetPen(wxPen(colour));
12256 mscratch_dc.SetBrush(wxBrush(colour));
12258 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12259 mscratch_dc.DrawRectangle(activeRect);
12264 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12265 unsigned int im = stackIndexArray.size();
12266 if (VPoint.b_quilt && im > 0) {
12267 std::vector<int> tiles_to_show;
12268 for (
unsigned int is = 0; is < im; is++) {
12270 ChartData->GetChartTableEntry(stackIndexArray[is]);
12271 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12274 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12275 tiles_to_show.push_back(stackIndexArray[is]);
12279 if (tiles_to_show.size())
12280 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12286 ocpnDC scratch_dc(mscratch_dc);
12287 RenderAlertMessage(mscratch_dc, GetVP());
12293#ifdef ocpnUSE_DIBSECTION
12298 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12299 q_dc.SelectObject(qbm);
12302 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12305 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12306 q_dc.SetBrush(qbr);
12307 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12310 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12313 q_dc.SelectObject(wxNullBitmap);
12322 if( VPoint.b_quilt ) {
12323 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12324 ChartBase *chart = m_pQuilt->GetRefChart();
12325 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12330 ChPI->ClearPLIBTextList();
12333 ps52plib->ClearTextList();
12337 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12339 wxColor maskBackground = wxColour(1,0,0);
12340 t_dc.SelectObject( qbm );
12341 t_dc.SetBackground(wxBrush(maskBackground));
12345 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12348 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12349 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12352 wxRegionIterator upd_final( ru );
12353 while( upd_final ) {
12354 wxRect rect = upd_final.GetRect();
12355 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12359 t_dc.SelectObject( wxNullBitmap );
12365 if (VPoint.b_quilt) {
12366 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12367 ChartBase *chart = m_pQuilt->GetRefChart();
12368 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12372 ChPI->ClearPLIBTextList();
12374 if (ps52plib) ps52plib->ClearTextList();
12379 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12381 if (g_bShowChartBar && m_Piano) {
12382 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12383 GetVP().pix_width, m_Piano->GetHeight());
12386 if (!style->chartStatusWindowTransparent)
12387 chart_all_text_region.Subtract(chart_bar_rect);
12390 if (m_Compass && m_Compass->IsShown()) {
12391 wxRect compassRect = m_Compass->
GetRect();
12392 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12393 chart_all_text_region.Subtract(compassRect);
12397 mscratch_dc.DestroyClippingRegion();
12399 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12400 chart_all_text_region);
12406 ocpnDC scratch_dc(mscratch_dc);
12407 DrawOverlayObjects(scratch_dc, ru);
12410 wxRegionIterator upd_final(rgn_blit);
12411 while (upd_final) {
12412 wxRect rect = upd_final.GetRect();
12413 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12420 temp_dc.SelectObject(wxNullBitmap);
12422 mscratch_dc.SelectObject(wxNullBitmap);
12424 dc.DestroyClippingRegion();
12429void ChartCanvas::PaintCleanup() {
12441 m_bTCupdate =
false;
12445 WarpPointer(warp_x, warp_y);
12452 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12453 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12457wxColour GetErrorGraphicColor(
double val)
12476 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
12477 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
12478 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
12479 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
12480 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
12481 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
12482 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
12483 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
12484 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
12485 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
12486 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
12487 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
12488 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
12489 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
12490 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
12491 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
12492 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
12493 else if( val >= 48) c.Set(_T(
"#410000"));
12498void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12501 gr_image.InitAlpha();
12503 double maxval = -10000;
12504 double minval = 10000;
12521 maxval = wxMax(maxval, (glat - rlat));
12522 minval = wxMin(minval, (glat - rlat));
12539 double f = ((glat - rlat)-minval)/(maxval - minval);
12541 double dy = (f * 40);
12543 wxColour c = GetErrorGraphicColor(dy);
12544 unsigned char r = c.Red();
12545 unsigned char g = c.Green();
12546 unsigned char b = c.Blue();
12548 gr_image.SetRGB(j, i, r,g,b);
12549 if((glat - rlat )!= 0)
12550 gr_image.SetAlpha(j, i, 128);
12552 gr_image.SetAlpha(j, i, 255);
12559 wxBitmap *pbm =
new wxBitmap(gr_image);
12560 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12561 pbm->SetMask(gr_mask);
12563 pmdc->DrawBitmap(*pbm, 0,0);
12571void ChartCanvas::CancelMouseRoute() {
12573 m_pMouseRoute = NULL;
12574 m_bDrawingRoute =
false;
12577int ChartCanvas::GetNextContextMenuId() {
12578 return CanvasMenuHandler::GetNextContextMenuId();
12581bool ChartCanvas::SetCursor(
const wxCursor &c) {
12583 if (g_bopengl && m_glcc)
12584 return m_glcc->SetCursor(c);
12587 return wxWindow::SetCursor(c);
12590void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12591 if (g_bquiting)
return;
12601 if (!m_RolloverPopupTimer.IsRunning() &&
12602 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12603 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12604 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12605 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12608 if (m_glcc && g_bopengl) {
12611 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12613 m_glcc->Refresh(eraseBackground,
12624 if (pthumbwin && pthumbwin->IsShown()) {
12625 pthumbwin->Raise();
12626 pthumbwin->Refresh(
false);
12630 if (m_pCIWin && m_pCIWin->IsShown()) {
12632 m_pCIWin->Refresh(
false);
12640 wxWindow::Refresh(eraseBackground, rect);
12643void ChartCanvas::Update() {
12644 if (m_glcc && g_bopengl) {
12649 wxWindow::Update();
12653 if (!pemboss)
return;
12654 int x = pemboss->x, y = pemboss->y;
12655 const double factor = 200;
12657 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
12658 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12659 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
12662 wxMemoryDC snip_dc;
12663 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12664 snip_dc.SelectObject(snip_bmp);
12666 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12667 snip_dc.SelectObject(wxNullBitmap);
12669 wxImage snip_img = snip_bmp.ConvertToImage();
12672 unsigned char *pdata = snip_img.GetData();
12674 for (
int y = 0; y < pemboss->height; y++) {
12675 int map_index = (y * pemboss->width);
12676 for (
int x = 0; x < pemboss->width; x++) {
12677 double val = (pemboss->pmap[map_index] * factor) / 256.;
12679 int nred = (int)((*pdata) + val);
12680 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12681 *pdata++ = (
unsigned char)nred;
12683 int ngreen = (int)((*pdata) + val);
12684 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12685 *pdata++ = (
unsigned char)ngreen;
12687 int nblue = (int)((*pdata) + val);
12688 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12689 *pdata++ = (
unsigned char)nblue;
12697 wxBitmap emb_bmp(snip_img);
12700 wxMemoryDC result_dc;
12701 result_dc.SelectObject(emb_bmp);
12704 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12706 result_dc.SelectObject(wxNullBitmap);
12712 if (GetQuiltMode()) {
12714 int refIndex = GetQuiltRefChartdbIndex();
12715 if (refIndex >= 0) {
12716 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
12717 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12718 if (current_type == CHART_TYPE_MBTILES) {
12719 ChartBase *pChart = m_pQuilt->GetRefChart();
12722 zoom_factor = ptc->GetZoomFactor();
12727 if (zoom_factor <= 3.9)
return NULL;
12729 if (m_singleChart) {
12730 if (zoom_factor <= 3.9)
return NULL;
12735 if (m_pEM_OverZoom) {
12736 m_pEM_OverZoom->x = 4;
12737 m_pEM_OverZoom->y = 0;
12738 if (g_MainToolbar && IsPrimaryCanvas()) {
12739 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12740 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12743 return m_pEM_OverZoom;
12746void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12756 g_overlayCanvas =
this;
12758 if (g_pi_manager) {
12759 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12760 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12764 AISDrawAreaNotices(dc, GetVP(),
this);
12766 wxDC *pdc = dc.GetDC();
12768 pdc->DestroyClippingRegion();
12769 wxDCClipper(*pdc, ru);
12772 if (m_bShowNavobjects) {
12773 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12774 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12775 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12776 DrawAnchorWatchPoints(dc);
12778 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12779 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12782 AISDraw(dc, GetVP(),
this);
12786 RenderVisibleSectorLights(dc);
12788 RenderAllChartOutlines(dc, GetVP());
12789 RenderRouteLegs(dc);
12790 RenderShipToActive(dc,
false);
12792 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12793 if (g_pi_manager) {
12794 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12798 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12799 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12801 if (g_pi_manager) {
12802 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12807 RebuildTideSelectList(GetVP().GetBBox());
12808 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12811 if (m_bShowCurrent) {
12812 RebuildCurrentSelectList(GetVP().GetBBox());
12813 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12816 if (!g_PrintingInProgress) {
12817 if (IsPrimaryCanvas()) {
12818 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12821 if (IsPrimaryCanvas()) {
12822 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12825 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12827 if (m_pTrackRolloverWin) {
12828 m_pTrackRolloverWin->Draw(dc);
12829 m_brepaint_piano =
true;
12832 if (m_pRouteRolloverWin) {
12833 m_pRouteRolloverWin->Draw(dc);
12834 m_brepaint_piano =
true;
12837 if (m_pAISRolloverWin) {
12838 m_pAISRolloverWin->Draw(dc);
12839 m_brepaint_piano =
true;
12841 if (m_brepaint_piano && g_bShowChartBar) {
12842 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12845 if (m_Compass) m_Compass->Paint(dc);
12847 if (!g_CanvasHideNotificationIcon) {
12848 auto ¬eman = NotificationManager::GetInstance();
12849 if (noteman.GetNotificationCount()) {
12850 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12851 if (m_notification_button->UpdateStatus()) Refresh();
12852 m_notification_button->Show(
true);
12853 m_notification_button->Paint(dc);
12855 m_notification_button->Show(
false);
12859 if (g_pi_manager) {
12860 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12866 if (!m_bShowDepthUnits)
return NULL;
12868 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12870 if (GetQuiltMode()) {
12871 wxString s = m_pQuilt->GetQuiltDepthUnit();
12873 if (s == _T(
"FEET"))
12874 depth_unit_type = DEPTH_UNIT_FEET;
12875 else if (s.StartsWith(_T(
"FATHOMS")))
12876 depth_unit_type = DEPTH_UNIT_FATHOMS;
12877 else if (s.StartsWith(_T(
"METERS")))
12878 depth_unit_type = DEPTH_UNIT_METERS;
12879 else if (s.StartsWith(_T(
"METRES")))
12880 depth_unit_type = DEPTH_UNIT_METERS;
12881 else if (s.StartsWith(_T(
"METRIC")))
12882 depth_unit_type = DEPTH_UNIT_METERS;
12883 else if (s.StartsWith(_T(
"METER")))
12884 depth_unit_type = DEPTH_UNIT_METERS;
12887 if (m_singleChart) {
12888 depth_unit_type = m_singleChart->GetDepthUnitType();
12889 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12890 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12895 switch (depth_unit_type) {
12896 case DEPTH_UNIT_FEET:
12899 case DEPTH_UNIT_METERS:
12900 ped = m_pEM_Meters;
12902 case DEPTH_UNIT_FATHOMS:
12903 ped = m_pEM_Fathoms;
12909 ped->x = (GetVP().
pix_width - ped->width);
12911 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12912 wxRect r = m_Compass->
GetRect();
12913 ped->y = r.y + r.height;
12920void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12923 if (style->embossFont == wxEmptyString) {
12924 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12926 font.SetPointSize(60);
12927 font.SetWeight(wxFONTWEIGHT_BOLD);
12929 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12930 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12932 int emboss_width = 500;
12933 int emboss_height = 200;
12937 delete m_pEM_Meters;
12938 delete m_pEM_Fathoms;
12942 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12944 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12946 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12949#define OVERZOOM_TEXT _("OverZoom")
12951void ChartCanvas::SetOverzoomFont() {
12956 if (style->embossFont == wxEmptyString) {
12957 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12959 font.SetPointSize(40);
12960 font.SetWeight(wxFONTWEIGHT_BOLD);
12962 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12963 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12965 wxClientDC dc(
this);
12967 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12969 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12970 font.SetPointSize(font.GetPointSize() - 1);
12972 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12974 m_overzoomFont = font;
12975 m_overzoomTextWidth = w;
12976 m_overzoomTextHeight = h;
12979void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12980 delete m_pEM_OverZoom;
12982 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12984 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12985 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12988emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12989 int height,
const wxString &str,
12994 wxBitmap bmp(width, height, -1);
12997 wxMemoryDC temp_dc;
12998 temp_dc.SelectObject(bmp);
13001 temp_dc.SetBackground(*wxWHITE_BRUSH);
13002 temp_dc.SetTextBackground(*wxWHITE);
13003 temp_dc.SetTextForeground(*wxBLACK);
13007 temp_dc.SetFont(font);
13010 temp_dc.GetTextExtent(str, &str_w, &str_h);
13012 temp_dc.DrawText(str, 1, 1);
13015 temp_dc.SelectObject(wxNullBitmap);
13018 wxImage img = bmp.ConvertToImage();
13020 int image_width = str_w * 105 / 100;
13021 int image_height = str_h * 105 / 100;
13022 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13023 wxMin(image_height, img.GetHeight()));
13024 wxImage imgs = img.GetSubImage(r);
13028 case GLOBAL_COLOR_SCHEME_DAY:
13032 case GLOBAL_COLOR_SCHEME_DUSK:
13035 case GLOBAL_COLOR_SCHEME_NIGHT:
13042 const int w = imgs.GetWidth();
13043 const int h = imgs.GetHeight();
13044 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13049 for (
int y = 1; y < h - 1; y++) {
13050 for (
int x = 1; x < w - 1; x++) {
13052 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13053 val = (int)(val * val_factor);
13054 index = (y * w) + x;
13067void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13068 Track *active_track = NULL;
13069 for (
Track *pTrackDraw : g_TrackList) {
13070 if (g_pActiveTrack == pTrackDraw) {
13071 active_track = pTrackDraw;
13075 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13078 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13081void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13082 Track *active_track = NULL;
13083 for (
Track *pTrackDraw : g_TrackList) {
13084 if (g_pActiveTrack == pTrackDraw) {
13085 active_track = pTrackDraw;
13089 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13092void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13093 Route *active_route = NULL;
13095 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
13096 node = node->GetNext()) {
13097 Route *pRouteDraw = node->GetData();
13098 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13099 active_route = pRouteDraw;
13104 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13109 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13112void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13113 Route *active_route = NULL;
13115 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
13116 node = node->GetNext()) {
13117 Route *pRouteDraw = node->GetData();
13118 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13119 active_route = pRouteDraw;
13123 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13126void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13127 if (!pWayPointMan)
return;
13129 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
13135 node = node->GetNext();
13140 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13144 if (pWP->GetShowWaypointRangeRings() &&
13145 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13146 double factor = 1.00;
13147 if (pWP->GetWaypointRangeRingsStepUnits() ==
13149 factor = 1 / 1.852;
13151 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13152 pWP->GetWaypointRangeRingsStep() / 60.;
13156 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13157 pWP->m_lat + radius, pWP->m_lon + radius);
13158 if (!BltBBox.IntersectOut(radar_box)) {
13165 node = node->GetNext();
13169void ChartCanvas::DrawBlinkObjects(
void) {
13171 wxRect update_rect;
13173 if (!pWayPointMan)
return;
13175 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
13185 node = node->GetNext();
13187 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13190void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13193 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
13195 wxPoint lAnchorPoint1, lAnchorPoint2;
13198 if (pAnchorWatchPoint1) {
13199 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
13203 if (pAnchorWatchPoint2) {
13204 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
13209 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
13210 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
13212 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13213 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13214 dc.SetBrush(*ppBrush);
13218 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13223 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13228 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13233 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13238double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13241 wxPoint lAnchorPoint;
13244 double tlat1, tlon1;
13246 if (pAnchorWatchPoint) {
13247 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13248 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13249 dabs = fabs(d1 / 1852.);
13250 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13255 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13256 pow((
double)(lAnchorPoint.y - r1.y), 2));
13259 if (d1 < 0) lpp = -lpp;
13267void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13268 if (!ptcmgr)
return;
13270 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13272 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13273 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13278 if ((type ==
't') || (type ==
'T')) {
13279 if (BBox.Contains(lat, lon)) {
13281 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13287extern wxDateTime gTimeSource;
13289void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13290 if (!ptcmgr)
return;
13292 wxDateTime this_now = gTimeSource;
13293 bool cur_time = !gTimeSource.IsValid();
13294 if (cur_time) this_now = wxDateTime::Now();
13295 time_t t_this_now = this_now.GetTicks();
13297 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13298 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13299 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13300 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
13302 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13303 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
13306 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13307 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
13308 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13309 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
13310 wxBRUSHSTYLE_SOLID);
13311 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13312 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
13313 wxBRUSHSTYLE_SOLID);
13315 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13316 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13317 int font_size = wxMax(10, dFont->GetPointSize());
13320 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13321 false, dFont->GetFaceName());
13323 dc.SetPen(*pblack_pen);
13324 dc.SetBrush(*pgreen_brush);
13328 case GLOBAL_COLOR_SCHEME_DAY:
13331 case GLOBAL_COLOR_SCHEME_DUSK:
13334 case GLOBAL_COLOR_SCHEME_NIGHT:
13335 bm = m_bmTideNight;
13342 int bmw = bm.GetWidth();
13343 int bmh = bm.GetHeight();
13345 float scale_factor = 1.0;
13349 float icon_pixelRefDim = 45;
13354 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13356 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13358 scale_factor *= pix_factor;
13360 float user_scale_factor = g_ChartScaleFactorExp;
13361 if (g_ChartScaleFactorExp > 1.0)
13362 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13365 scale_factor *= user_scale_factor;
13366 scale_factor *= GetContentScaleFactor();
13369 double marge = 0.05;
13370 std::vector<LLBBox> drawn_boxes;
13371 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13372 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13375 if ((type ==
't') || (type ==
'T'))
13380 if (BBox.ContainsMarge(lat, lon, marge)) {
13382 if (GetVP().chart_scale < 500000) {
13383 bool bdrawn =
false;
13384 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13385 if (drawn_boxes[i].Contains(lat, lon)) {
13390 if (bdrawn)
continue;
13393 this_box.Set(lat, lon, lat, lon);
13394 this_box.EnLarge(.005);
13395 drawn_boxes.push_back(this_box);
13401 if (GetVP().chart_scale > 500000) {
13402 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13406 dc.SetFont(*plabelFont);
13418 if (ptcmgr->GetTideFlowSens(
13419 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13423 ptcmgr->GetHightOrLowTide(
13424 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13425 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13437 if (tctime > t_this_now)
13438 ptcmgr->GetHightOrLowTide(
13439 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13440 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13444 ptcmgr->GetHightOrLowTide(
13445 t_this_now, FORWARD_TEN_MINUTES_STEP,
13446 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13460 int width = (int)(12 * scale_factor + 0.5);
13461 int height = (int)(45 * scale_factor + 0.5);
13462 int linew = wxMax(1, (
int)(scale_factor));
13463 int xDraw = r.x - (width / 2);
13464 int yDraw = r.y - (height / 2);
13467 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13468 int hs = (httime > lttime) ? -4 : 4;
13469 hs *= (int)(scale_factor + 0.5);
13470 if (ts > 0.995 || ts < 0.005) hs = 0;
13471 int ht_y = (int)(height * ts);
13474 pblack_pen->SetWidth(linew);
13475 dc.SetPen(*pblack_pen);
13476 dc.SetBrush(*pyelo_brush);
13477 dc.DrawRectangle(xDraw, yDraw, width, height);
13481 dc.SetPen(*pblue_pen);
13482 dc.SetBrush(*pblue_brush);
13483 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13484 (width - (4 * linew)), height - ht_y);
13490 arrow[0].x = xDraw + 2 * linew;
13491 arrow[1].x = xDraw + width / 2;
13492 arrow[2].x = xDraw + width - 2 * linew;
13493 pyelo_pen->SetWidth(linew);
13494 pblue_pen->SetWidth(linew);
13495 if (ts > 0.35 || ts < 0.15)
13497 hl = (int)(height * 0.25) + yDraw;
13499 arrow[1].y = hl + hs;
13502 dc.SetPen(*pyelo_pen);
13504 dc.SetPen(*pblue_pen);
13505 dc.DrawLines(3, arrow);
13507 if (ts > 0.60 || ts < 0.40)
13509 hl = (int)(height * 0.5) + yDraw;
13511 arrow[1].y = hl + hs;
13514 dc.SetPen(*pyelo_pen);
13516 dc.SetPen(*pblue_pen);
13517 dc.DrawLines(3, arrow);
13519 if (ts < 0.65 || ts > 0.85)
13521 hl = (int)(height * 0.75) + yDraw;
13523 arrow[1].y = hl + hs;
13526 dc.SetPen(*pyelo_pen);
13528 dc.SetPen(*pblue_pen);
13529 dc.DrawLines(3, arrow);
13533 s.Printf(_T(
"%3.1f"), nowlev);
13535 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13537 dc.GetTextExtent(s, &wx1, NULL);
13539 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13554void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13555 if (!ptcmgr)
return;
13557 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13559 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13560 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13565 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13566 if ((BBox.Contains(lat, lon))) {
13568 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13574void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13575 if (!ptcmgr)
return;
13577 float tcvalue, dir;
13581 double lon_last = 0.;
13582 double lat_last = 0.;
13584 double marge = 0.2;
13585 bool cur_time = !gTimeSource.IsValid();
13587 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13588 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13590 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13591 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13592 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13593 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13595 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13596 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13597 wxBRUSHSTYLE_SOLID);
13598 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13599 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13600 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13601 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13603 double skew_angle = GetVPRotation();
13605 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13606 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13607 int font_size = wxMax(10, dFont->GetPointSize());
13610 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13611 false, dFont->GetFaceName());
13613 float scale_factor = 1.0;
13619 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13621 float nominal_icon_size_pixels = 15;
13622 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13624 scale_factor *= pix_factor;
13626 float user_scale_factor = g_ChartScaleFactorExp;
13627 if (g_ChartScaleFactorExp > 1.0)
13628 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13631 scale_factor *= user_scale_factor;
13633 scale_factor *= GetContentScaleFactor();
13636 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13637 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13642 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13643 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13648 int dd = (int)(5.0 * scale_factor + 0.5);
13659 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13660 dc.SetPen(*pblack_pen);
13661 dc.SetBrush(*porange_brush);
13662 dc.DrawPolygon(4, d);
13665 dc.SetBrush(*pblack_brush);
13666 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13670 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13684 double a1 = fabs(tcvalue) * 10.;
13686 a1 = wxMax(1.0, a1);
13687 double a2 = log10(a1);
13689 float cscale = scale_factor * a2 * 0.3;
13691 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13692 dc.SetPen(*porange_pen);
13693 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13697 if (bDrawCurrentValues) {
13698 dc.SetFont(*pTCFont);
13699 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13700 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13721void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
13722 pCwin =
new TCWin(
this, x, y, pvIDX);
13725#define NUM_CURRENT_ARROW_POINTS 9
13726static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13727 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13728 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13729 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13731void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13733 if (
scale > 1e-2) {
13734 float sin_rot = sin(rot_angle * PI / 180.);
13735 float cos_rot = cos(rot_angle * PI / 180.);
13739 float xt = CurrentArrowArray[0].x;
13740 float yt = CurrentArrowArray[0].y;
13742 float xp = (xt * cos_rot) - (yt * sin_rot);
13743 float yp = (xt * sin_rot) + (yt * cos_rot);
13744 int x1 = (int)(xp *
scale);
13745 int y1 = (int)(yp *
scale);
13748 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13749 xt = CurrentArrowArray[ip].x;
13750 yt = CurrentArrowArray[ip].y;
13752 float xp = (xt * cos_rot) - (yt * sin_rot);
13753 float yp = (xt * sin_rot) + (yt * cos_rot);
13754 int x2 = (int)(xp *
scale);
13755 int y2 = (int)(yp *
scale);
13757 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13765wxString ChartCanvas::FindValidUploadPort() {
13768 if (!g_uploadConnection.IsEmpty() &&
13769 g_uploadConnection.StartsWith(_T(
"Serial"))) {
13770 port = g_uploadConnection;
13776 for (
auto *cp : TheConnectionParams()) {
13777 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13778 port << _T(
"Serial:") << cp->Port;
13784void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13787 if (NULL == g_pais_query_dialog_active) {
13788 int pos_x = g_ais_query_dialog_x;
13789 int pos_y = g_ais_query_dialog_y;
13791 if (g_pais_query_dialog_active) {
13792 g_pais_query_dialog_active->Destroy();
13798 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13799 wxPoint(pos_x, pos_y));
13801 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13803 g_pais_query_dialog_active->SetMMSI(mmsi);
13804 g_pais_query_dialog_active->UpdateText();
13805 wxSize sz = g_pais_query_dialog_active->GetSize();
13807 bool b_reset_pos =
false;
13812 RECT frame_title_rect;
13813 frame_title_rect.left = pos_x;
13814 frame_title_rect.top = pos_y;
13815 frame_title_rect.right = pos_x + sz.x;
13816 frame_title_rect.bottom = pos_y + 30;
13818 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13819 b_reset_pos =
true;
13824 wxRect window_title_rect;
13825 window_title_rect.x = pos_x;
13826 window_title_rect.y = pos_y;
13827 window_title_rect.width = sz.x;
13828 window_title_rect.height = 30;
13830 wxRect ClientRect = wxGetClientDisplayRect();
13831 ClientRect.Deflate(
13833 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13837 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13840 g_pais_query_dialog_active->SetMMSI(mmsi);
13841 g_pais_query_dialog_active->UpdateText();
13844 g_pais_query_dialog_active->Show();
13847void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13848 bool cur_mode = GetQuiltMode();
13850 if (!GetQuiltMode())
13851 SetQuiltMode(
true);
13852 else if (GetQuiltMode()) {
13853 SetQuiltMode(
false);
13854 g_sticky_chart = GetQuiltReferenceChartIndex();
13857 if (cur_mode != GetQuiltMode()) {
13858 SetupCanvasQuiltMode();
13867 if (ps52plib) ps52plib->GenerateStateHash();
13869 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13870 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13873void ChartCanvas::DoCanvasStackDelta(
int direction) {
13874 if (!GetQuiltMode()) {
13875 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13876 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13877 if ((current_stack_index + direction) < 0)
return;
13879 if (m_bpersistent_quilt ) {
13881 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13883 if (IsChartQuiltableRef(new_dbIndex)) {
13884 ToggleCanvasQuiltMode();
13885 SelectQuiltRefdbChart(new_dbIndex);
13886 m_bpersistent_quilt =
false;
13889 SelectChartFromStack(current_stack_index + direction);
13892 std::vector<int> piano_chart_index_array =
13893 GetQuiltExtendedStackdbIndexArray();
13894 int refdb = GetQuiltRefChartdbIndex();
13897 int current_index = -1;
13898 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13899 if (refdb == piano_chart_index_array[i]) {
13904 if (current_index == -1)
return;
13907 int target_family = ctet.GetChartFamily();
13909 int new_index = -1;
13910 int check_index = current_index + direction;
13911 bool found =
false;
13912 int check_dbIndex = -1;
13913 int new_dbIndex = -1;
13917 (
unsigned int)check_index < piano_chart_index_array.size() &&
13918 (check_index >= 0)) {
13919 check_dbIndex = piano_chart_index_array[check_index];
13920 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13921 if (target_family == cte.GetChartFamily()) {
13923 new_index = check_index;
13924 new_dbIndex = check_dbIndex;
13928 check_index += direction;
13931 if (!found)
return;
13933 if (!IsChartQuiltableRef(new_dbIndex)) {
13934 ToggleCanvasQuiltMode();
13935 SelectdbChart(new_dbIndex);
13936 m_bpersistent_quilt =
true;
13938 SelectQuiltRefChart(new_index);
13942 gFrame->UpdateGlobalMenuItems();
13944 SetQuiltChartHiLiteIndex(-1);
13955void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13958 switch (event.GetId()) {
13970 DoCanvasStackDelta(1);
13975 DoCanvasStackDelta(-1);
13985 ShowCurrents(!GetbShowCurrent());
13992 ShowTides(!GetbShowTide());
13999 if (0 == m_routeState) {
14006 androidSetRouteAnnunciator(m_routeState == 1);
14012 SetAISCanvasDisplayStyle(-1);
14024void ChartCanvas::SetShowAIS(
bool show) {
14026 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14027 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14030void ChartCanvas::SetAttenAIS(
bool show) {
14031 m_bShowAISScaled = show;
14032 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14033 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14036void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14039 bool bShowAIS_Array[3] = {
true,
true,
false};
14040 bool bShowScaled_Array[3] = {
false,
true,
true};
14041 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14042 _(
"Attenuate less critical AIS targets"),
14043 _(
"Hide AIS Targets")};
14044 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
14045 _T(
"AIS_Disabled")};
14047 int AIS_Toolbar_Switch = 0;
14048 if (StyleIndx == -1) {
14050 for (
int i = 1; i < ArraySize; i++) {
14051 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14052 (bShowScaled_Array[i] == m_bShowAISScaled))
14053 AIS_Toolbar_Switch = i;
14055 AIS_Toolbar_Switch++;
14056 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14057 AIS_Toolbar_Switch++;
14060 AIS_Toolbar_Switch = StyleIndx;
14063 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14065 int AIS_Toolbar_Switch_Next =
14066 AIS_Toolbar_Switch + 1;
14067 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14068 AIS_Toolbar_Switch_Next++;
14069 if (AIS_Toolbar_Switch_Next >= ArraySize)
14070 AIS_Toolbar_Switch_Next = 0;
14073 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14074 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14077void ChartCanvas::TouchAISToolActive(
void) {}
14079void ChartCanvas::UpdateAISTBTool(
void) {}
14087void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14089 bool b_update =
false;
14090 int cc1_edge_comp = 2;
14091 wxRect rect = m_Compass->
GetRect();
14092 wxSize parent_size = GetSize();
14094 parent_size *= m_displayScale;
14098 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14099 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14100 wxRect compass_rect(compass_pt, rect.GetSize());
14102 m_Compass->Move(compass_pt);
14104 if (m_Compass && m_Compass->IsShown())
14105 m_Compass->UpdateStatus(b_force_new | b_update);
14107 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14108 scaler = wxMax(scaler, 1.0);
14109 wxPoint note_point = wxPoint(
14110 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14111 m_notification_button->Move(note_point);
14112 m_notification_button->UpdateStatus();
14114 if (b_force_new | b_update) Refresh();
14117void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14118 ChartTypeEnum New_Type,
14119 ChartFamilyEnum New_Family) {
14120 if (!GetpCurrentStack())
return;
14121 if (!ChartData)
return;
14123 if (index < GetpCurrentStack()->nEntry) {
14126 pTentative_Chart = ChartData->OpenStackChartConditional(
14127 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14129 if (pTentative_Chart) {
14130 if (m_singleChart) m_singleChart->Deactivate();
14132 m_singleChart = pTentative_Chart;
14133 m_singleChart->Activate();
14135 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
14136 GetpCurrentStack(), m_singleChart->GetFullPath());
14149 double best_scale_ppm = GetBestVPScale(m_singleChart);
14150 double rotation = GetVPRotation();
14151 double oldskew = GetVPSkew();
14152 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14154 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14155 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14156 if (fabs(newskew) > 0.0001) rotation = newskew;
14159 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14161 UpdateGPSCompassStatusBox(
true);
14165 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14166 if (idx < 0)
return;
14168 std::vector<int> piano_active_chart_index_array;
14169 piano_active_chart_index_array.push_back(
14170 GetpCurrentStack()->GetCurrentEntrydbIndex());
14171 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14174void ChartCanvas::SelectdbChart(
int dbindex) {
14175 if (!GetpCurrentStack())
return;
14176 if (!ChartData)
return;
14178 if (dbindex >= 0) {
14181 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14183 if (pTentative_Chart) {
14184 if (m_singleChart) m_singleChart->Deactivate();
14186 m_singleChart = pTentative_Chart;
14187 m_singleChart->Activate();
14189 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
14190 GetpCurrentStack(), m_singleChart->GetFullPath());
14203 double best_scale_ppm = GetBestVPScale(m_singleChart);
14207 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14217void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14220 if (!GetQuiltMode()) {
14221 if (GetpCurrentStack()) {
14222 int stack_index = -1;
14223 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14224 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14225 if (check_dbIndex < 0)
continue;
14227 ChartData->GetChartTableEntry(check_dbIndex);
14228 if (type == cte.GetChartType()) {
14231 }
else if (family == cte.GetChartFamily()) {
14237 if (stack_index >= 0) {
14238 SelectChartFromStack(stack_index);
14242 int sel_dbIndex = -1;
14243 std::vector<int> piano_chart_index_array =
14244 GetQuiltExtendedStackdbIndexArray();
14245 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14246 int check_dbIndex = piano_chart_index_array[i];
14247 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
14248 if (type == cte.GetChartType()) {
14249 if (IsChartQuiltableRef(check_dbIndex)) {
14250 sel_dbIndex = check_dbIndex;
14253 }
else if (family == cte.GetChartFamily()) {
14254 if (IsChartQuiltableRef(check_dbIndex)) {
14255 sel_dbIndex = check_dbIndex;
14261 if (sel_dbIndex >= 0) {
14262 SelectQuiltRefdbChart(sel_dbIndex,
false);
14264 AdjustQuiltRefChart();
14271 SetQuiltChartHiLiteIndex(-1);
14276bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14277 return std::find(m_tile_yesshow_index_array.begin(),
14278 m_tile_yesshow_index_array.end(),
14279 index) != m_tile_yesshow_index_array.end();
14282bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14283 return std::find(m_tile_noshow_index_array.begin(),
14284 m_tile_noshow_index_array.end(),
14285 index) != m_tile_noshow_index_array.end();
14288void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14289 if (std::find(m_tile_noshow_index_array.begin(),
14290 m_tile_noshow_index_array.end(),
14291 index) == m_tile_noshow_index_array.end()) {
14292 m_tile_noshow_index_array.push_back(index);
14302void ChartCanvas::HandlePianoClick(
14303 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14304 if (g_options && g_options->IsShown())
14306 if (!m_pCurrentStack)
return;
14307 if (!ChartData)
return;
14322 double distance = 25000;
14323 int closest_index = -1;
14324 for (
int chart_index : selected_dbIndex_array) {
14325 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
14326 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14327 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14330 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14331 if (test_distance < distance) {
14332 distance = test_distance;
14333 closest_index = chart_index;
14337 int selected_dbIndex = selected_dbIndex_array[0];
14338 if (closest_index >= 0) selected_dbIndex = closest_index;
14340 if (!GetQuiltMode()) {
14341 if (m_bpersistent_quilt ) {
14342 if (IsChartQuiltableRef(selected_dbIndex)) {
14343 ToggleCanvasQuiltMode();
14344 SelectQuiltRefdbChart(selected_dbIndex);
14345 m_bpersistent_quilt =
false;
14347 SelectChartFromStack(selected_index);
14350 SelectChartFromStack(selected_index);
14351 g_sticky_chart = selected_dbIndex;
14355 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14359 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
14360 bool bfound =
false;
14361 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14362 if (m_tile_noshow_index_array[i] ==
14363 selected_dbIndex) {
14364 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14371 m_tile_noshow_index_array.push_back(selected_dbIndex);
14375 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14376 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14380 if (IsChartQuiltableRef(selected_dbIndex)) {
14386 bool set_scale =
false;
14387 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
14388 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14394 SelectQuiltRefdbChart(selected_dbIndex,
true);
14396 SelectQuiltRefdbChart(selected_dbIndex,
false);
14401 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14403 double proposed_scale_onscreen =
14406 if (g_bPreserveScaleOnX) {
14407 proposed_scale_onscreen =
14408 wxMin(proposed_scale_onscreen,
14410 GetCanvasWidth()));
14412 proposed_scale_onscreen =
14413 wxMin(proposed_scale_onscreen,
14415 GetCanvasWidth()));
14417 proposed_scale_onscreen =
14418 wxMax(proposed_scale_onscreen,
14427 ToggleCanvasQuiltMode();
14428 SelectdbChart(selected_dbIndex);
14429 m_bpersistent_quilt =
true;
14434 SetQuiltChartHiLiteIndex(-1);
14435 gFrame->UpdateGlobalMenuItems();
14437 HideChartInfoWindow();
14442void ChartCanvas::HandlePianoRClick(
14443 int x,
int y,
int selected_index,
14444 const std::vector<int> &selected_dbIndex_array) {
14445 if (g_options && g_options->IsShown())
14447 if (!GetpCurrentStack())
return;
14449 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14450 UpdateCanvasControlBar();
14452 SetQuiltChartHiLiteIndex(-1);
14455void ChartCanvas::HandlePianoRollover(
14456 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14457 int n_charts,
int scale) {
14458 if (g_options && g_options->IsShown())
14460 if (!GetpCurrentStack())
return;
14461 if (!ChartData)
return;
14463 if (ChartData->IsBusy())
return;
14465 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14467 if (!GetQuiltMode()) {
14468 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14471 std::vector<int> piano_chart_index_array;
14472 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14473 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14474 if ((GetpCurrentStack()->nEntry > 1) ||
14475 (piano_chart_index_array.size() >= 1)) {
14476 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14478 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14480 }
else if (GetpCurrentStack()->nEntry == 1) {
14482 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14483 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14484 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14486 }
else if ((-1 == selected_index) &&
14487 (0 == selected_dbIndex_array.size())) {
14488 ShowChartInfoWindow(key_location.x, -1);
14492 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14494 if ((GetpCurrentStack()->nEntry > 1) ||
14495 (piano_chart_index_array.size() >= 1)) {
14497 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14498 selected_dbIndex_array);
14499 else if (n_charts == 1)
14500 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14502 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14509void ChartCanvas::ClearPianoRollover() {
14510 ClearQuiltChartHiLiteIndexArray();
14511 ShowChartInfoWindow(0, -1);
14512 std::vector<int> vec;
14513 ShowCompositeInfoWindow(0, 0, 0, vec);
14517void ChartCanvas::UpdateCanvasControlBar(
void) {
14518 if (m_pianoFrozen)
return;
14520 if (!GetpCurrentStack())
return;
14521 if (!ChartData)
return;
14522 if (!g_bShowChartBar)
return;
14525 int sel_family = -1;
14527 std::vector<int> piano_chart_index_array;
14528 std::vector<int> empty_piano_chart_index_array;
14530 wxString old_hash = m_Piano->GetStoredHash();
14532 if (GetQuiltMode()) {
14533 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14534 GetQuiltFullScreendbIndexArray());
14536 std::vector<int> piano_active_chart_index_array =
14537 GetQuiltCandidatedbIndexArray();
14538 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14540 std::vector<int> piano_eclipsed_chart_index_array =
14541 GetQuiltEclipsedStackdbIndexArray();
14542 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14544 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14545 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14547 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14548 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14550 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
14551 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14554 if (m_singleChart) {
14555 sel_type = m_singleChart->GetChartType();
14556 sel_family = m_singleChart->GetChartFamily();
14561 std::vector<int> piano_skew_chart_index_array;
14562 std::vector<int> piano_tmerc_chart_index_array;
14563 std::vector<int> piano_poly_chart_index_array;
14565 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14567 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14568 double skew_norm = ctei.GetChartSkew();
14569 if (skew_norm > 180.) skew_norm -= 360.;
14571 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14572 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14575 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14576 if (fabs(skew_norm) > 1.)
14577 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14579 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14580 }
else if (fabs(skew_norm) > 1.)
14581 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14583 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14584 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14585 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14587 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14588 if (new_hash != old_hash) {
14589 m_Piano->FormatKeys();
14590 HideChartInfoWindow();
14591 m_Piano->ResetRollover();
14592 SetQuiltChartHiLiteIndex(-1);
14593 m_brepaint_piano =
true;
14599 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14601 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14602 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14603 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14604 if (e == CHART_FAMILY_RASTER) mask |= 1;
14605 if (e == CHART_FAMILY_VECTOR) {
14606 if (t == CHART_TYPE_CM93COMP)
14613 wxString s_indicated;
14614 if (sel_type == CHART_TYPE_CM93COMP)
14615 s_indicated = _T(
"cm93");
14617 if (sel_family == CHART_FAMILY_RASTER)
14618 s_indicated = _T(
"raster");
14619 else if (sel_family == CHART_FAMILY_VECTOR)
14620 s_indicated = _T(
"vector");
14623 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14626void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14628void ChartCanvas::PianoPopupMenu(
14629 int x,
int y,
int selected_index,
14630 const std::vector<int> &selected_dbIndex_array) {
14631 if (!GetpCurrentStack())
return;
14634 if (!GetQuiltMode())
return;
14636 m_piano_ctx_menu =
new wxMenu();
14638 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14648 menu_selected_dbIndex = selected_dbIndex_array[0];
14649 menu_selected_index = selected_index;
14652 bool b_is_in_noshow =
false;
14653 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14654 if (m_quilt_noshow_index_array[i] ==
14655 menu_selected_dbIndex)
14657 b_is_in_noshow =
true;
14662 if (b_is_in_noshow) {
14663 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14664 _(
"Show This Chart"));
14665 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14666 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14667 }
else if (GetpCurrentStack()->nEntry > 1) {
14668 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14669 _(
"Hide This Chart"));
14670 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14671 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14675 wxPoint pos = wxPoint(x, y - 30);
14678 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14679 PopupMenu(m_piano_ctx_menu, pos);
14681 delete m_piano_ctx_menu;
14682 m_piano_ctx_menu = NULL;
14684 HideChartInfoWindow();
14685 m_Piano->ResetRollover();
14687 SetQuiltChartHiLiteIndex(-1);
14688 ClearQuiltChartHiLiteIndexArray();
14693void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14694 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14695 if (m_quilt_noshow_index_array[i] ==
14696 menu_selected_dbIndex)
14698 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14704void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14705 if (!GetpCurrentStack())
return;
14706 if (!ChartData)
return;
14708 RemoveChartFromQuilt(menu_selected_dbIndex);
14712 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14713 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
14715 int i = menu_selected_index + 1;
14716 bool b_success =
false;
14717 while (i < GetpCurrentStack()->nEntry - 1) {
14718 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14719 if (type == ChartData->GetDBChartType(dbIndex)) {
14720 SelectQuiltRefChart(i);
14730 i = menu_selected_index - 1;
14732 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14733 if (type == ChartData->GetDBChartType(dbIndex)) {
14734 SelectQuiltRefChart(i);
14744void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14746 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14747 if (m_quilt_noshow_index_array[i] ==
14750 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14755 m_quilt_noshow_index_array.push_back(dbIndex);
14758bool ChartCanvas::UpdateS52State() {
14759 bool retval =
false;
14763 ps52plib->SetShowS57Text(m_encShowText);
14764 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14765 ps52plib->m_bShowSoundg = m_encShowDepth;
14766 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14767 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14770 if (!m_encShowLights)
14771 ps52plib->AddObjNoshow(
"LIGHTS");
14773 ps52plib->RemoveObjNoshow(
"LIGHTS");
14774 ps52plib->SetLightsOff(!m_encShowLights);
14775 ps52plib->m_bExtendLightSectors =
true;
14778 ps52plib->SetAnchorOn(m_encShowAnchor);
14779 ps52plib->SetQualityOfData(m_encShowDataQual);
14785void ChartCanvas::SetShowENCDataQual(
bool show) {
14786 m_encShowDataQual = show;
14787 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14788 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14790 m_s52StateHash = 0;
14793void ChartCanvas::SetShowENCText(
bool show) {
14794 m_encShowText = show;
14795 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14796 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14798 m_s52StateHash = 0;
14801void ChartCanvas::SetENCDisplayCategory(
int category) {
14802 m_encDisplayCategory = category;
14803 m_s52StateHash = 0;
14806void ChartCanvas::SetShowENCDepth(
bool show) {
14807 m_encShowDepth = show;
14808 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14809 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14811 m_s52StateHash = 0;
14814void ChartCanvas::SetShowENCLightDesc(
bool show) {
14815 m_encShowLightDesc = show;
14816 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14817 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14819 m_s52StateHash = 0;
14822void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14823 m_encShowBuoyLabels = show;
14824 m_s52StateHash = 0;
14827void ChartCanvas::SetShowENCLights(
bool show) {
14828 m_encShowLights = show;
14829 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14830 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14832 m_s52StateHash = 0;
14835void ChartCanvas::SetShowENCAnchor(
bool show) {
14836 m_encShowAnchor = show;
14837 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14838 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14840 m_s52StateHash = 0;
14843wxRect ChartCanvas::GetMUIBarRect() {
14846 rv = m_muiBar->GetRect();
14852void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14853 if (!GetAlertString().IsEmpty()) {
14854 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14855 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14857 dc.SetFont(*pfont);
14858 dc.SetPen(*wxTRANSPARENT_PEN);
14860 dc.SetBrush(wxColour(243, 229, 47));
14862 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14866 wxRect sbr = GetScaleBarRect();
14867 int xp = sbr.x + sbr.width + 10;
14868 int yp = (sbr.y + sbr.height) - h;
14870 int wdraw = w + 10;
14871 dc.DrawRectangle(xp, yp, wdraw, h);
14872 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14873 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14883#define BRIGHT_XCALIB
14884#define __OPCPN_USEICC__
14887#ifdef __OPCPN_USEICC__
14888int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14889 double co_green,
double co_blue);
14891wxString temp_file_name;
14895class ocpnCurtain:
public wxDialog
14897 DECLARE_CLASS( ocpnCurtain )
14898 DECLARE_EVENT_TABLE()
14901 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14903 bool ProcessEvent(wxEvent& event);
14907IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14909BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14912ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14914 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14917ocpnCurtain::~ocpnCurtain()
14921bool ocpnCurtain::ProcessEvent(wxEvent& event)
14923 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14924 return GetParent()->GetEventHandler()->ProcessEvent(event);
14929#include <windows.h>
14932typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14933typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14934SetDeviceGammaRamp_ptr_type
14935 g_pSetDeviceGammaRamp;
14936GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14938WORD *g_pSavedGammaMap;
14942int InitScreenBrightness(
void) {
14945 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14949 if (NULL == hGDI32DLL) {
14950 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14952 if (NULL != hGDI32DLL) {
14954 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14955 hGDI32DLL,
"SetDeviceGammaRamp");
14956 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14957 hGDI32DLL,
"GetDeviceGammaRamp");
14960 if ((NULL == g_pSetDeviceGammaRamp) ||
14961 (NULL == g_pGetDeviceGammaRamp)) {
14962 FreeLibrary(hGDI32DLL);
14971 if (!g_pSavedGammaMap) {
14972 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14975 bbr = g_pGetDeviceGammaRamp(
14976 hDC, g_pSavedGammaMap);
14977 ReleaseDC(NULL, hDC);
14982 wxRegKey *pRegKey =
new wxRegKey(
14983 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14984 _T(
"NT\\CurrentVersion\\ICM"));
14985 if (!pRegKey->Exists()) pRegKey->Create();
14986 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14988 g_brightness_init =
true;
14994 if (NULL == g_pcurtain) {
14995 if (gFrame->CanSetTransparent()) {
14997 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14998 wxPoint(0, 0), ::wxGetDisplaySize(),
14999 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15000 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15007 g_pcurtain->Hide();
15009 HWND hWnd = GetHwndOf(g_pcurtain);
15010 SetWindowLong(hWnd, GWL_EXSTYLE,
15011 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15012 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15013 g_pcurtain->SetTransparent(0);
15015 g_pcurtain->Maximize();
15016 g_pcurtain->Show();
15019 g_pcurtain->Enable();
15020 g_pcurtain->Disable();
15027 g_brightness_init =
true;
15033 wxString cmd(_T (
"xcalib -version" ));
15035 wxArrayString output;
15036 long r = wxExecute(cmd, output);
15039 _T(
" External application \"xcalib\" not found. Screen brightness ")
15040 _T(
"not changed."));
15042 g_brightness_init =
true;
15047int RestoreScreenBrightness(
void) {
15050 if (g_pSavedGammaMap) {
15051 HDC hDC = GetDC(NULL);
15052 g_pSetDeviceGammaRamp(hDC,
15054 ReleaseDC(NULL, hDC);
15056 free(g_pSavedGammaMap);
15057 g_pSavedGammaMap = NULL;
15061 g_pcurtain->Close();
15062 g_pcurtain->Destroy();
15066 g_brightness_init =
false;
15071#ifdef BRIGHT_XCALIB
15072 if (g_brightness_init) {
15074 cmd = _T(
"xcalib -clear");
15075 wxExecute(cmd, wxEXEC_ASYNC);
15076 g_brightness_init =
false;
15086int SetScreenBrightness(
int brightness) {
15093 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15095 g_pcurtain->Close();
15096 g_pcurtain->Destroy();
15100 InitScreenBrightness();
15102 if (NULL == hGDI32DLL) {
15104 wchar_t wdll_name[80];
15105 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15106 LPCWSTR cstr = wdll_name;
15108 hGDI32DLL = LoadLibrary(cstr);
15110 if (NULL != hGDI32DLL) {
15112 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15113 hGDI32DLL,
"SetDeviceGammaRamp");
15114 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15115 hGDI32DLL,
"GetDeviceGammaRamp");
15118 if ((NULL == g_pSetDeviceGammaRamp) ||
15119 (NULL == g_pGetDeviceGammaRamp)) {
15120 FreeLibrary(hGDI32DLL);
15127 HDC hDC = GetDC(NULL);
15138 int increment = brightness * 256 / 100;
15141 WORD GammaTable[3][256];
15144 for (
int i = 0; i < 256; i++) {
15145 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15146 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15147 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15149 table_val += increment;
15151 if (table_val > 65535) table_val = 65535;
15154 g_pSetDeviceGammaRamp(hDC, GammaTable);
15155 ReleaseDC(NULL, hDC);
15162 if (g_pSavedGammaMap) {
15163 HDC hDC = GetDC(NULL);
15164 g_pSetDeviceGammaRamp(hDC,
15166 ReleaseDC(NULL, hDC);
15169 if (brightness < 100) {
15170 if (NULL == g_pcurtain) InitScreenBrightness();
15173 int sbrite = wxMax(1, brightness);
15174 sbrite = wxMin(100, sbrite);
15176 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15180 g_pcurtain->Close();
15181 g_pcurtain->Destroy();
15191#ifdef BRIGHT_XCALIB
15193 if (!g_brightness_init) {
15194 last_brightness = 100;
15195 g_brightness_init =
true;
15196 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
15197 InitScreenBrightness();
15200#ifdef __OPCPN_USEICC__
15203 if (!CreateSimpleICCProfileFile(
15204 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15205 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15206 wxString cmd(_T (
"xcalib " ));
15207 cmd += temp_file_name;
15209 wxExecute(cmd, wxEXEC_ASYNC);
15218 if (brightness > last_brightness) {
15220 cmd = _T(
"xcalib -clear");
15221 wxExecute(cmd, wxEXEC_ASYNC);
15223 ::wxMilliSleep(10);
15225 int brite_adj = wxMax(1, brightness);
15226 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
15227 wxExecute(cmd, wxEXEC_ASYNC);
15229 int brite_adj = wxMax(1, brightness);
15230 int factor = (brite_adj * 100) / last_brightness;
15231 factor = wxMax(1, factor);
15233 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
15234 wxExecute(cmd, wxEXEC_ASYNC);
15239 last_brightness = brightness;
15246#ifdef __OPCPN_USEICC__
15248#define MLUT_TAG 0x6d4c5554L
15249#define VCGT_TAG 0x76636774L
15251int GetIntEndian(
unsigned char *s) {
15256 p = (
unsigned char *)&ret;
15259 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15261 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15266unsigned short GetShortEndian(
unsigned char *s) {
15267 unsigned short ret;
15271 p = (
unsigned char *)&ret;
15274 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15276 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15282int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15283 double co_green,
double co_blue) {
15287 fp = fopen(file_name,
"wb");
15288 if (!fp)
return -1;
15294 for (
int i = 0; i < 128; i++) header[i] = 0;
15296 fwrite(header, 128, 1, fp);
15300 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15301 fwrite(&numTags, 1, 4, fp);
15303 int tagName0 = VCGT_TAG;
15304 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15305 fwrite(&tagName, 1, 4, fp);
15307 int tagOffset0 = 128 + 4 *
sizeof(int);
15308 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15309 fwrite(&tagOffset, 1, 4, fp);
15312 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15313 fwrite(&tagSize, 1, 4, fp);
15315 fwrite(&tagName, 1, 4, fp);
15317 fwrite(&tagName, 1, 4, fp);
15322 int gammatype0 = 0;
15323 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15324 fwrite(&gammatype, 1, 4, fp);
15326 int numChannels0 = 3;
15327 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15328 fwrite(&numChannels, 1, 2, fp);
15330 int numEntries0 = 256;
15331 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15332 fwrite(&numEntries, 1, 2, fp);
15334 int entrySize0 = 1;
15335 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15336 fwrite(&entrySize, 1, 2, fp);
15338 unsigned char ramp[256];
15341 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15342 fwrite(ramp, 256, 1, fp);
15345 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15346 fwrite(ramp, 256, 1, fp);
15349 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15350 fwrite(ramp, 256, 1, fp);
bool g_bresponsive
Flag to control adaptive UI scaling.
Class AisDecoder and helpers.
Global state for AIS decoder.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Represents an active track that is currently being recorded.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void DoMovement(long dt)
Performs a step of smooth movement animation on the chart canvas.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
int PrepareContextSelections(double lat, double lon)
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
EventVar json_msg
Notified with message targeting all plugins.
double GetCanvasTrueScale()
Return the physical pixels per meter at chart center, accounting for latitude distortion.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Set the viewport center point.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Manages the chart database and provides access to chart data.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
PluginLoader is a backend module without any direct GUI functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
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)
Dialog for displaying query results of S57 objects.
Manager for S57 chart SENC creation threads.
Manages a set of ShapeBaseChart objects at different resolutions.
Window for displaying chart thumbnails.
Represents a single point in a track.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
void SetBoxes(void)
Computes the bounding box coordinates for the current viewport.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
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.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Global variables reflecting command line options and arguments.
Hooks into gui available in model.
Multiplexer class and helpers.
Class NotificationManager.
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
int GetCanvasIndexUnderMouse(void)
Gets index of chart canvas under mouse cursor.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Tools to send data to plugins.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Route validators for dialog validation.
Represents an entry in the chart table, containing information about a single chart.