33#include <wx/graphics.h>
34#include <wx/clipbrd.h>
35#include <wx/aui/aui.h>
39#include <wx/listimpl.cpp>
41#include "model/ais_decoder.h"
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"
50#include "model/multiplexer.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"
95#include "pluginmanager.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;
340static bool mouse_leftisdown;
342bool g_brouteCreating;
344bool g_bShowTrackPointTime;
350bool g_brightness_init;
353int g_cog_predictor_width;
354extern double g_display_size_mm;
358extern wxColour g_colourOwnshipRangeRingsColour;
362extern double g_defaultBoatSpeed;
363double g_defaultBoatSpeedUserUnit;
365extern int g_nAIS_activity_timer;
366extern bool g_bskew_comp;
367extern float g_compass_scalefactor;
368extern int g_COGAvgSec;
369extern bool g_btenhertz;
371wxGLContext *g_pGLcontext;
374extern unsigned int g_canvasConfig;
379extern float g_toolbar_scalefactor;
382wxString g_ObjQFileExt;
387extern int g_GUIScaleFactor;
390wxString g_lastS52PLIBPluginMessage;
391extern bool g_bChartBarEx;
392bool g_PrintingInProgress;
395#define MAX_BRIGHT 100
401EVT_PAINT(ChartCanvas::OnPaint)
402EVT_ACTIVATE(ChartCanvas::OnActivate)
403EVT_SIZE(ChartCanvas::OnSize)
404#ifndef HAVE_WX_GESTURE_EVENTS
405EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
407EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
408EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
409EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
410EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
411EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
412EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
413EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
414EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
415EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
416EVT_KEY_UP(ChartCanvas::OnKeyUp)
417EVT_CHAR(ChartCanvas::OnKeyChar)
418EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
419EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
420EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
421EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
422EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
423EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
424EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
425EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
431 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
432 m_nmea_log(nmea_log) {
433 parent_frame = (
MyFrame *)frame;
434 m_canvasIndex = canvasIndex;
438 SetBackgroundColour(wxColour(0, 0, 0));
439 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
443 m_bDrawingRoute =
false;
444 m_bRouteEditing =
false;
445 m_bMarkEditing =
false;
446 m_bRoutePoinDragging =
false;
447 m_bIsInRadius =
false;
448 m_bMayToggleMenuBar =
true;
451 m_bShowNavobjects =
true;
453 m_bAppendingRoute =
false;
454 pThumbDIBShow = NULL;
455 m_bShowCurrent =
false;
457 bShowingCurrent =
false;
461 m_b_paint_enable =
true;
464 pss_overlay_bmp = NULL;
465 pss_overlay_mask = NULL;
466 m_bChartDragging =
false;
467 m_bMeasure_Active =
false;
468 m_bMeasure_DistCircle =
false;
469 m_pMeasureRoute = NULL;
470 m_pTrackRolloverWin = NULL;
471 m_pRouteRolloverWin = NULL;
472 m_pAISRolloverWin = NULL;
474 m_disable_edge_pan =
false;
475 m_dragoffsetSet =
false;
479 m_singleChart = NULL;
480 m_upMode = NORTH_UP_MODE;
482 m_bShowAISScaled =
false;
483 m_timed_move_vp_active =
false;
490 m_pSelectedRoute = NULL;
491 m_pSelectedTrack = NULL;
492 m_pRoutePointEditTarget = NULL;
493 m_pFoundPoint = NULL;
494 m_pMouseRoute = NULL;
495 m_prev_pMousePoint = NULL;
496 m_pEditRouteArray = NULL;
497 m_pFoundRoutePoint = NULL;
498 m_FinishRouteOnKillFocus =
true;
500 m_pRolloverRouteSeg = NULL;
501 m_pRolloverTrackSeg = NULL;
502 m_bsectors_shown =
false;
504 m_bbrightdir =
false;
509 m_pos_image_user_day = NULL;
510 m_pos_image_user_dusk = NULL;
511 m_pos_image_user_night = NULL;
512 m_pos_image_user_grey_day = NULL;
513 m_pos_image_user_grey_dusk = NULL;
514 m_pos_image_user_grey_night = NULL;
517 m_rotation_speed = 0;
523 m_pos_image_user_yellow_day = NULL;
524 m_pos_image_user_yellow_dusk = NULL;
525 m_pos_image_user_yellow_night = NULL;
527 SetOwnShipState(SHIP_INVALID);
529 undo =
new Undo(
this);
535 m_focus_indicator_pix = 1;
537 m_pCurrentStack = NULL;
538 m_bpersistent_quilt =
false;
539 m_piano_ctx_menu = NULL;
541 m_NotificationsList = NULL;
542 m_notification_button = NULL;
544 g_ChartNotRenderScaleFactor = 2.0;
545 m_bShowScaleInStatusBar =
true;
548 m_bShowScaleInStatusBar =
false;
549 m_show_focus_bar =
true;
551 m_bShowOutlines =
false;
552 m_bDisplayGrid =
false;
553 m_bShowDepthUnits =
true;
554 m_encDisplayCategory = (int)STANDARD;
556 m_encShowLights =
true;
557 m_encShowAnchor =
true;
558 m_encShowDataQual =
false;
560 m_pQuilt =
new Quilt(
this);
562 SetAlertString(_T(
""));
565 g_PrintingInProgress =
false;
567#ifdef HAVE_WX_GESTURE_EVENTS
568 m_oldVPSScale = -1.0;
569 m_popupWanted =
false;
575 singleClickEventIsValid =
false;
584 pCursorPencil = NULL;
589 SetCursor(*pCursorArrow);
591 pPanTimer =
new wxTimer(
this, m_MouseDragging);
594 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
595 pMovementTimer->Stop();
597 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
598 pMovementStopTimer->Stop();
600 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
601 pRotDefTimer->Stop();
603 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
604 m_DoubleClickTimer->Stop();
606 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
607 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
608 m_chart_drag_inertia_active =
false;
610 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
611 m_animationActive =
false;
615 m_panx_target_final = m_pany_target_final = 0;
616 m_panx_target_now = m_pany_target_now = 0;
618 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
619 pCurTrackTimer->Stop();
620 m_curtrack_timer_msec = 10;
622 m_wheelzoom_stop_oneshot = 0;
623 m_last_wheel_dir = 0;
625 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
627 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
629 m_rollover_popup_timer_msec = 20;
631 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
633 m_b_rot_hidef =
true;
638 m_upMode = NORTH_UP_MODE;
639 m_bLookAhead =
false;
643 m_cs = GLOBAL_COLOR_SCHEME_DAY;
646 VPoint.view_scale_ppm = 1;
650 m_canvas_scale_factor = 1.;
652 m_canvas_width = 1000;
654 m_overzoomTextWidth = 0;
655 m_overzoomTextHeight = 0;
659 gShapeBasemap.Reset();
664 m_pEM_Fathoms = NULL;
666 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
668 m_pEM_OverZoom = NULL;
670 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
674 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"),
678 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
681 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
684 double factor_dusk = 0.5;
685 double factor_night = 0.25;
688 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
690 int rimg_width = m_os_image_red_day.GetWidth();
691 int rimg_height = m_os_image_red_day.GetHeight();
693 m_os_image_red_dusk = m_os_image_red_day.Copy();
694 m_os_image_red_night = m_os_image_red_day.Copy();
696 for (
int iy = 0; iy < rimg_height; iy++) {
697 for (
int ix = 0; ix < rimg_width; ix++) {
698 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
699 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
700 m_os_image_red_day.GetGreen(ix, iy),
701 m_os_image_red_day.GetBlue(ix, iy));
702 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
703 hsv.value = hsv.value * factor_dusk;
704 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
705 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
707 hsv = wxImage::RGBtoHSV(rgb);
708 hsv.value = hsv.value * factor_night;
709 nrgb = wxImage::HSVtoRGB(hsv);
710 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
716 m_os_image_grey_day =
717 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
719 int gimg_width = m_os_image_grey_day.GetWidth();
720 int gimg_height = m_os_image_grey_day.GetHeight();
722 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
723 m_os_image_grey_night = m_os_image_grey_day.Copy();
725 for (
int iy = 0; iy < gimg_height; iy++) {
726 for (
int ix = 0; ix < gimg_width; ix++) {
727 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
728 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
729 m_os_image_grey_day.GetGreen(ix, iy),
730 m_os_image_grey_day.GetBlue(ix, iy));
731 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
732 hsv.value = hsv.value * factor_dusk;
733 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
734 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
736 hsv = wxImage::RGBtoHSV(rgb);
737 hsv.value = hsv.value * factor_night;
738 nrgb = wxImage::HSVtoRGB(hsv);
739 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
745 m_os_image_yellow_day = m_os_image_red_day.Copy();
747 gimg_width = m_os_image_yellow_day.GetWidth();
748 gimg_height = m_os_image_yellow_day.GetHeight();
750 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
751 m_os_image_yellow_night = m_os_image_red_day.Copy();
753 for (
int iy = 0; iy < gimg_height; iy++) {
754 for (
int ix = 0; ix < gimg_width; ix++) {
755 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
756 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
757 m_os_image_yellow_day.GetGreen(ix, iy),
758 m_os_image_yellow_day.GetBlue(ix, iy));
759 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
760 hsv.hue += 60. / 360.;
761 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
762 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
764 hsv = wxImage::RGBtoHSV(rgb);
765 hsv.value = hsv.value * factor_dusk;
766 hsv.hue += 60. / 360.;
767 nrgb = wxImage::HSVtoRGB(hsv);
768 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
770 hsv = wxImage::RGBtoHSV(rgb);
771 hsv.hue += 60. / 360.;
772 hsv.value = hsv.value * factor_night;
773 nrgb = wxImage::HSVtoRGB(hsv);
774 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
780 m_pos_image_red = &m_os_image_red_day;
781 m_pos_image_yellow = &m_os_image_yellow_day;
782 m_pos_image_grey = &m_os_image_grey_day;
786 m_pBrightPopup = NULL;
789 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
794 m_Piano =
new Piano(
this);
796 m_bShowCompassWin =
true;
798 m_Compass->SetScaleFactor(g_compass_scalefactor);
799 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
802 m_notification_button->SetScaleFactor(g_compass_scalefactor);
803 m_notification_button->Show(
true);
805 m_pianoFrozen =
false;
807 SetMinSize(wxSize(200, 200));
809 m_displayScale = 1.0;
810#if defined(__WXOSX__) || defined(__WXGTK3__)
812 m_displayScale = GetContentScaleFactor();
814 VPoint.SetPixelScale(m_displayScale);
816#ifdef HAVE_WX_GESTURE_EVENTS
819 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
820 wxLogError(
"Failed to enable touch events");
825 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
826 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
828 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
829 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
831 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
832 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
834 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
835 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
840 auto ¬eman = NotificationManager::GetInstance();
842 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
843 evt_notificationlist_change_listener.Listen(
844 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
845 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
846 if (m_NotificationsList && m_NotificationsList->IsShown()) {
847 m_NotificationsList->ReloadNotificationList();
853ChartCanvas::~ChartCanvas() {
854 delete pThumbDIBShow;
862 delete pCursorPencil;
866 delete pMovementTimer;
867 delete pMovementStopTimer;
868 delete pCurTrackTimer;
870 delete m_DoubleClickTimer;
872 delete m_pTrackRolloverWin;
873 delete m_pRouteRolloverWin;
874 delete m_pAISRolloverWin;
875 delete m_pBrightPopup;
881 m_dc_route.SelectObject(wxNullBitmap);
884 delete pWorldBackgroundChart;
885 delete pss_overlay_bmp;
889 delete m_pEM_Fathoms;
891 delete m_pEM_OverZoom;
896 delete m_pos_image_user_day;
897 delete m_pos_image_user_dusk;
898 delete m_pos_image_user_night;
899 delete m_pos_image_user_grey_day;
900 delete m_pos_image_user_grey_dusk;
901 delete m_pos_image_user_grey_night;
902 delete m_pos_image_user_yellow_day;
903 delete m_pos_image_user_yellow_dusk;
904 delete m_pos_image_user_yellow_night;
908 if (!g_bdisable_opengl) {
911#if wxCHECK_VERSION(2, 9, 0)
912 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
919 MUIBar *muiBar = m_muiBar;
923 delete m_pCurrentStack;
928void ChartCanvas::SetupGridFont() {
929 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
931 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
933 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
934 FALSE, wxString(_T (
"Arial" )));
937void ChartCanvas::RebuildCursors() {
943 delete pCursorPencil;
947 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
951 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
952 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
953 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
954 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
955 wxImage ICursorPencil =
956 style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
957 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
959#if !defined(__WXMSW__) && !defined(__WXQT__)
960 ICursorLeft.ConvertAlphaToMask(128);
961 ICursorRight.ConvertAlphaToMask(128);
962 ICursorUp.ConvertAlphaToMask(128);
963 ICursorDown.ConvertAlphaToMask(128);
964 ICursorPencil.ConvertAlphaToMask(10);
965 ICursorCross.ConvertAlphaToMask(10);
968 if (ICursorLeft.Ok()) {
969 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
970 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
971 pCursorLeft =
new wxCursor(ICursorLeft);
973 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
975 if (ICursorRight.Ok()) {
976 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
977 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
978 pCursorRight =
new wxCursor(ICursorRight);
980 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
982 if (ICursorUp.Ok()) {
983 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
984 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
985 pCursorUp =
new wxCursor(ICursorUp);
987 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
989 if (ICursorDown.Ok()) {
990 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
991 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
992 pCursorDown =
new wxCursor(ICursorDown);
994 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
996 if (ICursorPencil.Ok()) {
997 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
998 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
999 pCursorPencil =
new wxCursor(ICursorPencil);
1001 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
1003 if (ICursorCross.Ok()) {
1004 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
1005 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
1006 pCursorCross =
new wxCursor(ICursorCross);
1008 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
1010 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
1011 pPlugIn_Cursor = NULL;
1014void ChartCanvas::CanvasApplyLocale() {
1015 CreateDepthUnitEmbossMaps(m_cs);
1016 CreateOZEmbossMapData(m_cs);
1019void ChartCanvas::SetupGlCanvas() {
1022 if (!g_bdisable_opengl) {
1024 wxLogMessage(_T(
"Creating glChartCanvas"));
1029 if (IsPrimaryCanvas()) {
1036 wxGLContext *pctx =
new wxGLContext(m_glcc);
1037 m_glcc->SetContext(pctx);
1038 g_pGLcontext = pctx;
1041 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
1043 m_glcc->SetContext(g_pGLcontext);
1053 if (!g_bdisable_opengl) {
1056 wxLogMessage(_T(
"Creating glChartCanvas"));
1060 if (IsPrimaryCanvas()) {
1061 qDebug() <<
"Creating Primary glChartCanvas";
1069 wxGLContext *pctx =
new wxGLContext(m_glcc);
1070 m_glcc->SetContext(pctx);
1071 g_pGLcontext = pctx;
1072 m_glcc->m_pParentCanvas =
this;
1075 qDebug() <<
"Creating Secondary glChartCanvas";
1081 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1084 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1085 m_glcc->SetContext(pwxctx);
1086 m_glcc->m_pParentCanvas =
this;
1094void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1095 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1110 if (m_routeState && m_FinishRouteOnKillFocus)
1111 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1113 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1117void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1118 m_routeFinishTimer.Stop();
1122 gFrame->UpdateGlobalMenuItems(
this);
1124 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1127void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1128 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1131#ifdef HAVE_WX_GESTURE_EVENTS
1132void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1138 m_popupWanted =
true;
1141void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1145void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1147void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1149void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1150 wxPoint pos =
event.GetPosition();
1154 if (!m_popupWanted) {
1155 wxMouseEvent ev(wxEVT_LEFT_UP);
1162 m_popupWanted =
false;
1164 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1171void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1174 wxPoint pos =
event.GetPosition();
1178void ChartCanvas::OnMotion(wxMouseEvent &event) {
1183 event.m_leftDown = m_leftdown;
1187void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1189 if (event.IsGestureEnd())
return;
1191 double factor =
event.GetZoomFactor();
1193 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1198 double wanted_factor = m_oldVPSScale / current_vps * factor;
1203 if (event.IsGestureStart()) {
1204 m_zoomStartPoint =
event.GetPosition();
1206 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1208 m_zoomStartPoint =
event.GetPosition();
1212void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1214void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1215 DoRotateCanvas(0.0);
1219void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1224 m_restore_dbindex = pcc->DBindex;
1226 if (pcc->GroupID < 0) pcc->GroupID = 0;
1228 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1231 m_groupIndex = pcc->GroupID;
1233 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1247 m_encDisplayCategory = pcc->nENCDisplayCategory;
1248 m_encShowDepth = pcc->bShowENCDepths;
1249 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1250 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1251 m_encShowLights = pcc->bShowENCLights;
1252 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1253 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1254 m_encShowDataQual = pcc->bShowENCDataQuality;
1258 m_upMode = NORTH_UP_MODE;
1260 m_upMode = COURSE_UP_MODE;
1262 m_upMode = HEAD_UP_MODE;
1266 m_singleChart = NULL;
1269void ChartCanvas::ApplyGlobalSettings() {
1272 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1273 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1275 m_notification_button->UpdateStatus();
1278void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1279 bool groupOK = CheckGroup(m_groupIndex);
1282 SetGroupIndex(m_groupIndex,
true);
1286void ChartCanvas::SetShowGPS(
bool bshow) {
1287 if (m_bShowGPS != bshow) {
1290 m_Compass->SetScaleFactor(g_compass_scalefactor);
1291 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1296void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1297 m_bShowCompassWin = bshow;
1299 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1300 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1304int ChartCanvas::GetPianoHeight() {
1306 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1311void ChartCanvas::ConfigureChartBar() {
1314 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1315 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1317 if (GetQuiltMode()) {
1318 m_Piano->SetRoundedRectangles(
true);
1320 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1321 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1322 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1325void ChartCanvas::ShowTides(
bool bShow) {
1326 gFrame->LoadHarmonics();
1328 if (ptcmgr->IsReady()) {
1329 SetbShowTide(bShow);
1331 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1333 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1334 SetbShowTide(
false);
1335 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1338 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1339 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1350void ChartCanvas::ShowCurrents(
bool bShow) {
1351 gFrame->LoadHarmonics();
1353 if (ptcmgr->IsReady()) {
1354 SetbShowCurrent(bShow);
1355 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1357 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1358 SetbShowCurrent(
false);
1359 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1362 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1363 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1375extern bool g_bPreserveScaleOnX;
1377extern int g_sticky_chart;
1379void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1381void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1382 SetAlertString(_T(
""));
1384 int new_index = index;
1385 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1387 bool bgroup_override =
false;
1388 int old_group_index = new_index;
1390 if (!CheckGroup(new_index)) {
1392 bgroup_override =
true;
1395 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1399 int current_chart_native_scale = GetCanvasChartNativeScale();
1402 m_groupIndex = new_index;
1405 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1408 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1412 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1416 g_sticky_chart = -1;
1420 UpdateCanvasOnGroupChange();
1423 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1425 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1428 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1429 double best_scale = GetBestStartScale(dbi_hint, vp);
1433 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1437 canvasChartsRefresh(dbi_hint);
1439 UpdateCanvasControlBar();
1441 if (!autoSwitch && bgroup_override) {
1443 wxString msg(_(
"Group \""));
1445 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1446 msg += pGroup->m_group_name;
1448 msg += _(
"\" is empty.");
1450 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1457 if (bgroup_override) {
1458 wxString msg(_(
"Group \""));
1460 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1461 msg += pGroup->m_group_name;
1463 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1465 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1469bool ChartCanvas::CheckGroup(
int igroup) {
1470 if (!ChartData)
return true;
1472 if (igroup == 0)
return true;
1477 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1479 if (pGroup->m_element_array.empty())
1483 for (
const auto &elem : pGroup->m_element_array) {
1484 for (
unsigned int ic = 0;
1485 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1487 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1489 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1494 for (
const auto &elem : pGroup->m_element_array) {
1495 const wxString &element_root = elem.m_element_name;
1496 wxString test_string = _T(
"GSHH");
1497 if (element_root.Upper().Contains(test_string))
return true;
1503void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1504 if (!ChartData)
return;
1506 AbstractPlatform::ShowBusySpinner();
1510 SetQuiltRefChart(-1);
1512 m_singleChart = NULL;
1518 if (!m_pCurrentStack) {
1520 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1523 if (-1 != dbi_hint) {
1524 if (GetQuiltMode()) {
1525 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1526 SetQuiltRefChart(dbi_hint);
1530 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1532 if (pTentative_Chart) {
1535 if (m_singleChart) m_singleChart->Deactivate();
1537 m_singleChart = pTentative_Chart;
1538 m_singleChart->Activate();
1540 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1541 GetpCurrentStack(), m_singleChart->GetFullPath());
1549 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1550 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1551 SetQuiltRefChart(selected_index);
1555 SetupCanvasQuiltMode();
1556 if (!GetQuiltMode() && m_singleChart == 0) {
1558 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1559 m_singleChart = pDummyChart;
1565 UpdateCanvasControlBar();
1566 UpdateGPSCompassStatusBox(
true);
1568 SetCursor(wxCURSOR_ARROW);
1570 AbstractPlatform::HideBusySpinner();
1573bool ChartCanvas::DoCanvasUpdate(
void) {
1575 double vpLat, vpLon;
1576 bool blong_jump =
false;
1577 meters_to_shift = 0;
1580 bool bNewChart =
false;
1581 bool bNewView =
false;
1582 bool bCanvasChartAutoOpen =
true;
1584 bool bNewPiano =
false;
1585 bool bOpenSpecified;
1591 if (bDBUpdateInProgress)
return false;
1592 if (!ChartData)
return false;
1594 if (ChartData->IsBusy())
return false;
1620 double dx = m_OSoffsetx;
1621 double dy = m_OSoffsety;
1625 if (GetUpMode() == NORTH_UP_MODE) {
1626 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1628 double offset_angle = atan2(d_north, d_east);
1629 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1630 double chart_angle = GetVPRotation();
1631 double target_angle = chart_angle + offset_angle;
1632 double d_east_mod = offset_distance * cos(target_angle);
1633 double d_north_mod = offset_distance * sin(target_angle);
1634 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1637 extern double gCog_gt;
1640 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1641 double cog_to_use = gCog;
1643 (fabs(gCog - gCog_gt) > 20)) {
1644 cog_to_use = gCog_gt;
1647 if (!g_btenhertz) cog_to_use = g_COGAvg;
1649 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1651 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1652 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1654 double pixel_delta_tent =
1655 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1657 double pixel_delta = 0;
1662 if (!std::isnan(gSog)) {
1666 pixel_delta = pixel_delta_tent;
1669 meters_to_shift = 0;
1671 if (!std::isnan(gCog)) {
1672 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1673 dir_to_shift = cog_to_use;
1674 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1680 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1694 if (GetQuiltMode()) {
1695 int current_db_index = -1;
1696 if (m_pCurrentStack)
1699 ->GetCurrentEntrydbIndex();
1707 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1709 if (m_pCurrentStack->nEntry) {
1710 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1712 SelectQuiltRefdbChart(new_dbIndex,
true);
1713 m_bautofind =
false;
1717 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1718 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1723 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1729 double proposed_scale_onscreen =
1732 int initial_db_index = m_restore_dbindex;
1733 if (initial_db_index < 0) {
1734 if (m_pCurrentStack->nEntry) {
1736 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1741 if (m_pCurrentStack->nEntry) {
1742 int initial_type = ChartData->GetDBChartType(initial_db_index);
1747 if (!IsChartQuiltableRef(initial_db_index)) {
1751 int stack_index = 0;
1753 if (stack_index >= 0) {
1754 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1755 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1756 if (IsChartQuiltableRef(test_db_index) &&
1758 ChartData->GetDBChartType(initial_db_index))) {
1759 initial_db_index = test_db_index;
1767 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1769 SetQuiltRefChart(initial_db_index);
1770 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1778 0, GetVPRotation());
1783 bool super_jump =
false;
1785 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1786 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1787 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1789 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead) {
1791 if (blong_jump) nstep = 20;
1792 StartTimedMovementVP(vpLat, vpLon, nstep);
1801 pLast_Ch = m_singleChart;
1802 ChartTypeEnum new_open_type;
1803 ChartFamilyEnum new_open_family;
1805 new_open_type = pLast_Ch->GetChartType();
1806 new_open_family = pLast_Ch->GetChartFamily();
1808 new_open_type = CHART_TYPE_KAP;
1809 new_open_family = CHART_FAMILY_RASTER;
1812 bOpenSpecified = m_bFirstAuto;
1815 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1818 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1820 if (NULL == pDummyChart) {
1826 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1828 m_singleChart = pDummyChart;
1833 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1835 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1838 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1839 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1846 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1852 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1857 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1860 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1865 if (NULL != m_singleChart)
1866 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1867 m_singleChart->GetFullPath());
1870 m_pCurrentStack->CurrentStackEntry = tEntry;
1880 if (bCanvasChartAutoOpen) {
1881 bool search_direction =
1883 int start_index = 0;
1887 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1888 (LastStack.nEntry == 0)) {
1889 search_direction =
true;
1890 start_index = m_pCurrentStack->nEntry - 1;
1894 if (bOpenSpecified) {
1895 search_direction =
false;
1897 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1900 new_open_type = CHART_TYPE_DONTCARE;
1903 pProposed = ChartData->OpenStackChartConditional(
1904 m_pCurrentStack, start_index, search_direction, new_open_type,
1908 if (NULL == pProposed)
1909 pProposed = ChartData->OpenStackChartConditional(
1910 m_pCurrentStack, start_index, search_direction,
1911 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1913 if (NULL == pProposed)
1914 pProposed = ChartData->OpenStackChartConditional(
1915 m_pCurrentStack, start_index, search_direction,
1916 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1927 if (NULL == pProposed) {
1928 if (NULL == pDummyChart) {
1934 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1936 pProposed = pDummyChart;
1940 if (m_singleChart) m_singleChart->Deactivate();
1941 m_singleChart = pProposed;
1943 if (m_singleChart) {
1944 m_singleChart->Activate();
1945 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1946 m_pCurrentStack, m_singleChart->GetFullPath());
1951 if (NULL != m_singleChart) {
1957 if (!GetVP().IsValid())
1958 set_scale = 1. / 20000.;
1960 double proposed_scale_onscreen;
1963 double new_scale_ppm =
1964 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1972 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1973 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1974 double equivalent_vp_scale =
1976 double new_scale_ppm =
1977 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1982 proposed_scale_onscreen =
1983 wxMin(proposed_scale_onscreen,
1986 proposed_scale_onscreen =
1987 wxMax(proposed_scale_onscreen,
1996 m_singleChart->GetChartSkew() * PI / 180.,
2003 if ((m_bFollow) && m_singleChart)
2005 m_singleChart->GetChartSkew() * PI / 180.,
2014 m_bFirstAuto =
false;
2018 if (bNewChart && !bNewView) Refresh(
false);
2023 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
2026 return bNewChart | bNewView;
2029void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
2030 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
2032 SetQuiltRefChart(db_index);
2034 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
2037 double best_scale_ppm = GetBestVPScale(pc);
2041 SetQuiltRefChart(-1);
2043 SetQuiltRefChart(-1);
2046void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
2047 std::vector<int> piano_chart_index_array =
2048 GetQuiltExtendedStackdbIndexArray();
2049 int current_db_index = piano_chart_index_array[selected_index];
2051 SelectQuiltRefdbChart(current_db_index);
2054double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2058 if ((g_bPreserveScaleOnX) ||
2059 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2065 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2066 double equivalent_vp_scale =
2068 double new_scale_ppm =
2069 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2076 double max_underzoom_multiplier = 2.0;
2077 if (GetVP().b_quilt) {
2078 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2079 pchart->GetChartType(),
2080 pchart->GetChartFamily());
2081 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2084 proposed_scale_onscreen = wxMin(
2085 proposed_scale_onscreen,
2087 max_underzoom_multiplier);
2090 proposed_scale_onscreen =
2091 wxMax(proposed_scale_onscreen,
2099void ChartCanvas::SetupCanvasQuiltMode(
void) {
2102 ChartData->LockCache();
2104 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2108 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2109 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2110 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2111 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2113 m_Piano->SetRoundedRectangles(
true);
2116 int target_new_dbindex = -1;
2117 if (m_pCurrentStack) {
2118 target_new_dbindex =
2119 GetQuiltReferenceChartIndex();
2121 if (-1 != target_new_dbindex) {
2122 if (!IsChartQuiltableRef(target_new_dbindex)) {
2123 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2124 int type = ChartData->GetDBChartType(target_new_dbindex);
2127 int stack_index = m_pCurrentStack->CurrentStackEntry;
2129 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2130 (stack_index >= 0)) {
2131 int proj_tent = ChartData->GetDBChartProj(
2132 m_pCurrentStack->GetDBIndex(stack_index));
2133 int type_tent = ChartData->GetDBChartType(
2134 m_pCurrentStack->GetDBIndex(stack_index));
2136 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2137 if ((proj == proj_tent) && (type_tent == type)) {
2138 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2148 if (IsChartQuiltableRef(target_new_dbindex))
2149 SelectQuiltRefdbChart(target_new_dbindex,
2152 SelectQuiltRefdbChart(-1,
false);
2154 m_singleChart = NULL;
2157 AdjustQuiltRefChart();
2165 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2169 std::vector<int> empty_array;
2170 m_Piano->SetActiveKeyArray(empty_array);
2171 m_Piano->SetNoshowIndexArray(empty_array);
2172 m_Piano->SetEclipsedIndexArray(empty_array);
2175 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2176 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2177 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2178 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2180 m_Piano->SetRoundedRectangles(
false);
2186 if (!GetQuiltMode()) {
2187 if (ChartData && ChartData->IsValid()) {
2191 if (m_bFollow ==
true) {
2199 if (!m_singleChart) {
2202 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2210 int cur_max_scale = (int)1e8;
2212 ChartBase *pChart = GetFirstQuiltChart();
2216 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2218 if (pChart->GetNativeScale() < cur_max_scale) {
2219 Candidate_Chart = pChart;
2220 cur_max_scale = pChart->GetNativeScale();
2223 pChart = GetNextQuiltChart();
2226 m_singleChart = Candidate_Chart;
2230 if (NULL == m_singleChart) {
2231 m_singleChart = ChartData->OpenStackChartConditional(
2232 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2233 CHART_FAMILY_DONTCARE);
2239 InvalidateAllQuiltPatchs();
2241 if (m_singleChart) {
2242 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2243 std::vector<int> one_array;
2244 one_array.push_back(dbi);
2245 m_Piano->SetActiveKeyArray(one_array);
2248 if (m_singleChart) {
2249 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2253 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2257bool ChartCanvas::IsTempMenuBarEnabled() {
2260 wxGetOsVersion(&major);
2268double ChartCanvas::GetCanvasRangeMeters() {
2270 GetSize(&width, &height);
2271 int minDimension = wxMin(width, height);
2274 range *= cos(GetVP().clat * PI / 180.);
2278void ChartCanvas::SetCanvasRangeMeters(
double range) {
2280 GetSize(&width, &height);
2281 int minDimension = wxMin(width, height);
2283 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2287bool ChartCanvas::SetUserOwnship() {
2291 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2292 double factor_dusk = 0.5;
2293 double factor_night = 0.25;
2295 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2296 m_pos_image_user_day =
new wxImage;
2297 *m_pos_image_user_day = pbmp->ConvertToImage();
2298 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2300 int gimg_width = m_pos_image_user_day->GetWidth();
2301 int gimg_height = m_pos_image_user_day->GetHeight();
2304 m_pos_image_user_dusk =
new wxImage;
2305 m_pos_image_user_night =
new wxImage;
2307 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2308 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2310 for (
int iy = 0; iy < gimg_height; iy++) {
2311 for (
int ix = 0; ix < gimg_width; ix++) {
2312 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2313 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2314 m_pos_image_user_day->GetGreen(ix, iy),
2315 m_pos_image_user_day->GetBlue(ix, iy));
2316 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2317 hsv.value = hsv.value * factor_dusk;
2318 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2319 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2322 hsv = wxImage::RGBtoHSV(rgb);
2323 hsv.value = hsv.value * factor_night;
2324 nrgb = wxImage::HSVtoRGB(hsv);
2325 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2332 m_pos_image_user_grey_day =
new wxImage;
2333 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2335 m_pos_image_user_grey_dusk =
new wxImage;
2336 m_pos_image_user_grey_night =
new wxImage;
2338 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2339 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2341 for (
int iy = 0; iy < gimg_height; iy++) {
2342 for (
int ix = 0; ix < gimg_width; ix++) {
2343 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2344 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2345 m_pos_image_user_grey_day->GetGreen(ix, iy),
2346 m_pos_image_user_grey_day->GetBlue(ix, iy));
2347 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2348 hsv.value = hsv.value * factor_dusk;
2349 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2350 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2353 hsv = wxImage::RGBtoHSV(rgb);
2354 hsv.value = hsv.value * factor_night;
2355 nrgb = wxImage::HSVtoRGB(hsv);
2356 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2363 m_pos_image_user_yellow_day =
new wxImage;
2364 m_pos_image_user_yellow_dusk =
new wxImage;
2365 m_pos_image_user_yellow_night =
new wxImage;
2367 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2368 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2369 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2371 for (
int iy = 0; iy < gimg_height; iy++) {
2372 for (
int ix = 0; ix < gimg_width; ix++) {
2373 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2374 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2375 m_pos_image_user_grey_day->GetGreen(ix, iy),
2376 m_pos_image_user_grey_day->GetBlue(ix, iy));
2380 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2381 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2382 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2384 hsv = wxImage::RGBtoHSV(rgb);
2385 hsv.value = hsv.value * factor_dusk;
2386 nrgb = wxImage::HSVtoRGB(hsv);
2387 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2389 hsv = wxImage::RGBtoHSV(rgb);
2390 hsv.value = hsv.value * factor_night;
2391 nrgb = wxImage::HSVtoRGB(hsv);
2392 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2404 m_display_size_mm = size;
2411 double horizontal = sd.x;
2415 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2416 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2419 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2420 ps52plib->SetPPMM(m_pix_per_mm);
2425 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2427 m_display_size_mm, sd.x, sd.y);
2431 ssx = g_monitor_info[g_current_monitor].width;
2432 ssy = g_monitor_info[g_current_monitor].height;
2433 msg.Printf(_T(
"monitor size: %d %d"), ssx, ssy);
2436 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2439void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2441 wxString msg(event.m_string.c_str(), wxConvUTF8);
2443 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2444 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2447 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2449 compress_msg_array.RemoveAt(event.thread);
2450 compress_msg_array.Insert( msg, event.thread);
2453 compress_msg_array.Add(msg);
2456 wxString combined_msg;
2457 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2458 combined_msg += compress_msg_array[i];
2459 combined_msg += _T(
"\n");
2463 pprog->Update(pprog_count, combined_msg, &skip );
2464 pprog->SetSize(pprog_size);
2469void ChartCanvas::InvalidateGL() {
2470 if (!m_glcc)
return;
2472 if (g_bopengl) m_glcc->Invalidate();
2474 if (m_Compass) m_Compass->UpdateStatus(
true);
2477int ChartCanvas::GetCanvasChartNativeScale() {
2479 if (!VPoint.b_quilt) {
2480 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2482 ret = (int)m_pQuilt->GetRefNativeScale();
2487ChartBase *ChartCanvas::GetChartAtCursor() {
2489 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2490 target_chart = m_singleChart;
2491 else if (VPoint.b_quilt)
2492 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2494 target_chart = NULL;
2495 return target_chart;
2498ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2502 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2504 target_chart = NULL;
2505 return target_chart;
2508int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2509 int new_dbIndex = -1;
2510 if (!VPoint.b_quilt) {
2511 if (m_pCurrentStack) {
2512 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2513 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2515 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2525 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2527 for (
unsigned int is = 0; is < im; is++) {
2529 m_pQuilt->GetExtendedStackIndexArray()[is]);
2532 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2542void ChartCanvas::EnablePaint(
bool b_enable) {
2543 m_b_paint_enable = b_enable;
2545 if (m_glcc) m_glcc->EnablePaint(b_enable);
2549bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2551void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2553std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2554 return m_pQuilt->GetQuiltIndexArray();
2558void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2559 VPoint.b_quilt = b_quilt;
2560 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2563bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2565int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2566 return m_pQuilt->GetRefChartdbIndex();
2569void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2570 m_pQuilt->InvalidateAllQuiltPatchs();
2573ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2574 return m_pQuilt->GetLargestScaleChart();
2577ChartBase *ChartCanvas::GetFirstQuiltChart() {
2578 return m_pQuilt->GetFirstChart();
2581ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2583int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2585void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2586 m_pQuilt->SetHiliteIndex(dbIndex);
2589void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2590 m_pQuilt->SetHiliteIndexArray(hilite_array);
2593void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2594 m_pQuilt->ClearHiliteIndexArray();
2597std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2599 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2602int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2603 return m_pQuilt->GetRefChartdbIndex();
2606std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2607 return m_pQuilt->GetExtendedStackIndexArray();
2610std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2611 return m_pQuilt->GetFullscreenIndexArray();
2614std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2615 return m_pQuilt->GetEclipsedStackIndexArray();
2618void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2620double ChartCanvas::GetQuiltMaxErrorFactor() {
2621 return m_pQuilt->GetMaxErrorFactor();
2624bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2625 return m_pQuilt->IsChartQuiltableRef(db_index);
2629 double chartMaxScale =
2631 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2634void ChartCanvas::StartMeasureRoute() {
2635 if (!m_routeState) {
2636 if (m_bMeasure_Active) {
2638 m_pMeasureRoute = NULL;
2641 m_bMeasure_Active =
true;
2642 m_nMeasureState = 1;
2643 m_bDrawingRoute =
false;
2645 SetCursor(*pCursorPencil);
2650void ChartCanvas::CancelMeasureRoute() {
2651 m_bMeasure_Active =
false;
2652 m_nMeasureState = 0;
2653 m_bDrawingRoute =
false;
2656 m_pMeasureRoute = NULL;
2658 SetCursor(*pCursorArrow);
2661ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2663void ChartCanvas::SetVP(
ViewPort &vp) {
2674void ChartCanvas::TriggerDeferredFocus() {
2677 m_deferredFocusTimer.Start(20,
true);
2679#if defined(__WXGTK__) || defined(__WXOSX__)
2690void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2695void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2696 if (SendKeyEventToPlugins(event))
2700 int key_char =
event.GetKeyCode();
2703 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2709 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2714 if (g_benable_rotate) {
2735void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2736 if (SendKeyEventToPlugins(event))
2740 bool b_handled =
false;
2742 m_modkeys =
event.GetModifiers();
2744 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2746#ifdef OCPN_ALT_MENUBAR
2752 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2754 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2755 if (!g_bTempShowMenuBar) {
2756 g_bTempShowMenuBar =
true;
2757 parent_frame->ApplyGlobalSettings(
false);
2759 m_bMayToggleMenuBar =
false;
2765 if (event.GetKeyCode() != WXK_ALT) {
2766 m_bMayToggleMenuBar =
false;
2773 switch (event.GetKeyCode()) {
2780 event.GetPosition(&x, &y);
2781 m_FinishRouteOnKillFocus =
false;
2782 CallPopupMenu(x, y);
2783 m_FinishRouteOnKillFocus =
true;
2787 m_modkeys |= wxMOD_ALT;
2791 m_modkeys |= wxMOD_CONTROL;
2796 case WXK_RAW_CONTROL:
2797 m_modkeys |= wxMOD_RAW_CONTROL;
2802 if (m_modkeys == wxMOD_CONTROL)
2803 parent_frame->DoStackDown(
this);
2804 else if (g_bsmoothpanzoom) {
2805 StartTimedMovement();
2814 if (g_bsmoothpanzoom) {
2815 StartTimedMovement();
2823 if (m_modkeys == wxMOD_CONTROL)
2824 parent_frame->DoStackUp(
this);
2825 else if (g_bsmoothpanzoom) {
2826 StartTimedMovement();
2835 if (g_bsmoothpanzoom) {
2836 StartTimedMovement();
2848 SetShowENCText(!GetShowENCText());
2854 if (!m_bMeasure_Active) {
2855 if (event.ShiftDown())
2856 m_bMeasure_DistCircle =
true;
2858 m_bMeasure_DistCircle =
false;
2860 StartMeasureRoute();
2862 CancelMeasureRoute();
2864 SetCursor(*pCursorArrow);
2874 parent_frame->ToggleColorScheme();
2876 TriggerDeferredFocus();
2880 int mod = m_modkeys & wxMOD_SHIFT;
2881 if (mod != m_brightmod) {
2883 m_bbrightdir = !m_bbrightdir;
2886 if (!m_bbrightdir) {
2887 g_nbrightness -= 10;
2888 if (g_nbrightness <= MIN_BRIGHT) {
2889 g_nbrightness = MIN_BRIGHT;
2890 m_bbrightdir =
true;
2893 g_nbrightness += 10;
2894 if (g_nbrightness >= MAX_BRIGHT) {
2895 g_nbrightness = MAX_BRIGHT;
2896 m_bbrightdir =
false;
2900 SetScreenBrightness(g_nbrightness);
2901 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2910 parent_frame->DoStackDown(
this);
2914 parent_frame->DoStackUp(
this);
2919 ToggleCanvasQuiltMode();
2925 parent_frame->ToggleFullScreen();
2930 if (m_modkeys == wxMOD_ALT) {
2933 ToggleChartOutlines();
2939 parent_frame->ActivateMOB();
2943 case WXK_NUMPAD_ADD:
2948 case WXK_NUMPAD_SUBTRACT:
2949 case WXK_PAGEDOWN: {
2950 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2955 if (m_bMeasure_Active) {
2956 if (m_nMeasureState > 2) {
2957 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2959 m_pMeasureRoute->GetnPoints();
2961 gFrame->RefreshAllCanvas();
2963 CancelMeasureRoute();
2964 StartMeasureRoute();
2972 if (event.GetKeyCode() < 128)
2974 int key_char =
event.GetKeyCode();
2978 if (!g_b_assume_azerty) {
2980 if (g_benable_rotate) {
3012 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3019 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3020 m_modkeys & wxMOD_RAW_CONTROL) {
3021 parent_frame->ToggleFullScreen();
3026 if (event.ControlDown()) key_char -= 64;
3028 if (key_char >=
'0' && key_char <=
'9')
3029 SetGroupIndex(key_char -
'0');
3034 SetShowENCAnchor(!GetShowENCAnchor());
3040 parent_frame->ToggleColorScheme();
3045 event.GetPosition(&x, &y);
3046 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3047 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3049 if (!pPopupDetailSlider) {
3050 if (VPoint.b_quilt) {
3052 if (m_pQuilt->GetChartAtPix(
3057 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3059 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3064 if (m_singleChart) {
3065 ChartType = m_singleChart->GetChartType();
3066 ChartFam = m_singleChart->GetChartFamily();
3070 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3071 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3073 this, -1, ChartType, ChartFam,
3074 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3075 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
3076 if (pPopupDetailSlider) pPopupDetailSlider->Show();
3080 if (pPopupDetailSlider) pPopupDetailSlider->Close();
3081 pPopupDetailSlider = NULL;
3088 m_nmea_log->Raise();
3092 SetShowENCLights(!GetShowENCLights());
3098 if (event.ShiftDown())
3099 m_bMeasure_DistCircle =
true;
3101 m_bMeasure_DistCircle =
false;
3103 StartMeasureRoute();
3107 if (g_bInlandEcdis && ps52plib) {
3108 SetENCDisplayCategory((_DisCat)STANDARD);
3113 ToggleChartOutlines();
3117 ToggleCanvasQuiltMode();
3121 parent_frame->ToggleTestPause();
3124 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3125 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3126 g_iNavAidRadarRingsNumberVisible = 1;
3127 else if (!g_bNavAidRadarRingsShown &&
3128 g_iNavAidRadarRingsNumberVisible == 1)
3129 g_iNavAidRadarRingsNumberVisible = 0;
3132 SetShowENCDepth(!m_encShowDepth);
3137 SetShowENCText(!GetShowENCText());
3142 SetShowENCDataQual(!GetShowENCDataQual());
3147 m_bShowNavobjects = !m_bShowNavobjects;
3162 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3167 if (event.ControlDown()) gFrame->DropMarker(
false);
3173 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3174 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3175 if ((indexActive + 1) <= r->GetnPoints()) {
3186 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3192 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3198 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3205 parent_frame->DoSettings();
3209 parent_frame->Close();
3217 if (NULL == pGoToPositionDialog)
3220 pGoToPositionDialog->SetCanvas(
this);
3221 pGoToPositionDialog->Show();
3225 if (undo->AnythingToRedo()) {
3226 undo->RedoNextAction();
3233 if (event.ShiftDown()) {
3234 if (undo->AnythingToRedo()) {
3235 undo->RedoNextAction();
3240 if (undo->AnythingToUndo()) {
3241 undo->UndoLastAction();
3250 if (m_bMeasure_Active) {
3251 CancelMeasureRoute();
3253 SetCursor(*pCursorArrow);
3256 gFrame->RefreshAllCanvas();
3270 switch (gamma_state) {
3290 SetScreenBrightness(g_nbrightness);
3295 if (event.ControlDown()) {
3296 m_bShowCompassWin = !m_bShowCompassWin;
3297 SetShowGPSCompassWindow(m_bShowCompassWin);
3314void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3315 if (SendKeyEventToPlugins(event))
3319 switch (event.GetKeyCode()) {
3321 parent_frame->SwitchKBFocus(
this);
3327 if (!m_pany) m_panspeed = 0;
3333 if (!m_panx) m_panspeed = 0;
3336 case WXK_NUMPAD_ADD:
3337 case WXK_NUMPAD_SUBTRACT:
3346 m_modkeys &= ~wxMOD_ALT;
3347#ifdef OCPN_ALT_MENUBAR
3352 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3353 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3354 parent_frame->ApplyGlobalSettings(
false);
3356 m_bMayToggleMenuBar =
true;
3362 m_modkeys &= ~wxMOD_CONTROL;
3366 if (event.GetKeyCode() < 128)
3368 int key_char =
event.GetKeyCode();
3372 if (!g_b_assume_azerty) {
3387 m_rotation_speed = 0;
3405void ChartCanvas::ToggleChartOutlines(
void) {
3406 m_bShowOutlines = !m_bShowOutlines;
3412 if (g_bopengl) InvalidateGL();
3416void ChartCanvas::ToggleLookahead() {
3417 m_bLookAhead = !m_bLookAhead;
3422void ChartCanvas::SetUpMode(
int mode) {
3425 if (mode != NORTH_UP_MODE) {
3428 if (!std::isnan(gCog)) stuff = gCog;
3430 if (g_COGAvgSec > 0) {
3431 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3434 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3436 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3437 SetVPRotation(GetVPSkew());
3442 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3443 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3445 UpdateGPSCompassStatusBox(
true);
3446 gFrame->DoChartUpdate();
3449bool ChartCanvas::DoCanvasCOGSet(
void) {
3450 if (GetUpMode() == NORTH_UP_MODE)
return false;
3451 double cog_use = g_COGAvg;
3452 if (g_btenhertz) cog_use = gCog;
3454 double rotation = 0;
3455 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3456 rotation = -gHdt * PI / 180.;
3457 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3458 rotation = -cog_use * PI / 180.;
3460 SetVPRotation(rotation);
3464double easeOutCubic(
double t) {
3466 return 1.0 - pow(1.0 - t, 3.0);
3469void ChartCanvas::StartChartDragInertia() {
3472 m_bChartDragging =
false;
3475 m_chart_drag_inertia_time = 750;
3476 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3481 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3485 size_t length = m_drag_vec_t.size();
3486 for (
size_t i = 0; i < n_vel; i++) {
3487 xacc += m_drag_vec_x.at(length - 1 - i);
3488 yacc += m_drag_vec_y.at(length - 1 - i);
3489 tacc += m_drag_vec_t.at(length - 1 - i);
3492 m_chart_drag_velocity_x = xacc / tacc;
3493 m_chart_drag_velocity_y = yacc / tacc;
3495 m_chart_drag_inertia_active =
true;
3498 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3504void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3505 if (!m_chart_drag_inertia_active)
return;
3508 wxLongLong now = wxGetLocalTimeMillis();
3509 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3510 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3511 if (t > 1.0) t = 1.0;
3512 double e = 1.0 - easeOutCubic(t);
3515 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3517 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3523 m_last_elapsed = elapsed;
3527 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3528 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3529 double inertia_lat, inertia_lon;
3536 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3537 m_chart_drag_inertia_timer.Stop();
3538 m_chart_drag_inertia_active =
false;
3541 m_target_lat = GetVP().
clat;
3542 m_target_lon = GetVP().
clon;
3543 m_pan_drag.x = m_pan_drag.y = 0;
3544 m_panx = m_pany = 0;
3547 int target_redraw_interval = 40;
3548 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3552void ChartCanvas::StopMovement() {
3553 m_panx = m_pany = 0;
3556 m_rotation_speed = 0;
3559#if !defined(__WXGTK__) && !defined(__WXQT__)
3570bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3572 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3574 if (!pMovementTimer->IsRunning()) {
3576 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3579 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3584 m_last_movement_time = wxDateTime::UNow();
3588void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3591 m_target_lat = target_lat;
3592 m_target_lon = target_lon;
3595 m_start_lat = GetVP().
clat;
3596 m_start_lon = GetVP().
clon;
3598 m_VPMovementTimer.Start(1,
true);
3599 m_timed_move_vp_active =
true;
3601 m_timedVP_step = nstep;
3604void ChartCanvas::DoTimedMovementVP() {
3605 if (!m_timed_move_vp_active)
return;
3606 if (m_stvpc++ > m_timedVP_step * 2) {
3613 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3628 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3629 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3631 m_run_lat = new_lat;
3632 m_run_lon = new_lon;
3638void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3640void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3642void ChartCanvas::StartTimedMovementTarget() {}
3644void ChartCanvas::DoTimedMovementTarget() {}
3646void ChartCanvas::StopMovementTarget() {}
3648void ChartCanvas::DoTimedMovement() {
3649 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3653 wxDateTime now = wxDateTime::UNow();
3655 if (m_last_movement_time.IsValid())
3656 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3658 m_last_movement_time = now;
3668 if (dt == 0) dt = 1;
3671 if (m_mustmove < 0) m_mustmove = 0;
3673 if (m_pan_drag.x || m_pan_drag.y) {
3675 m_pan_drag.x = m_pan_drag.y = 0;
3678 if (m_panx || m_pany) {
3679 const double slowpan = .1, maxpan = 2;
3680 if (m_modkeys == wxMOD_ALT)
3681 m_panspeed = slowpan;
3683 m_panspeed += (double)dt / 500;
3684 m_panspeed = wxMin(maxpan, m_panspeed);
3686 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3689 if (m_zoom_factor != 1) {
3690 double alpha = 400, beta = 1.5;
3691 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3693 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3695 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3700 if (zoom_factor > 1) {
3701 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3705 else if (zoom_factor < 1) {
3706 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3711 if (fabs(zoom_factor - 1) > 1e-4) {
3712 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3717 if (m_wheelzoom_stop_oneshot > 0) {
3718 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3719 m_wheelzoom_stop_oneshot = 0;
3724 if (zoom_factor > 1) {
3726 m_wheelzoom_stop_oneshot = 0;
3729 }
else if (zoom_factor < 1) {
3731 m_wheelzoom_stop_oneshot = 0;
3738 if (m_rotation_speed) {
3739 double speed = m_rotation_speed;
3740 if (m_modkeys == wxMOD_ALT) speed /= 10;
3741 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3745void ChartCanvas::SetColorScheme(ColorScheme cs) {
3746 SetAlertString(_T(
""));
3750 case GLOBAL_COLOR_SCHEME_DAY:
3751 m_pos_image_red = &m_os_image_red_day;
3752 m_pos_image_grey = &m_os_image_grey_day;
3753 m_pos_image_yellow = &m_os_image_yellow_day;
3754 m_pos_image_user = m_pos_image_user_day;
3755 m_pos_image_user_grey = m_pos_image_user_grey_day;
3756 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3757 m_cTideBitmap = m_bmTideDay;
3758 m_cCurrentBitmap = m_bmCurrentDay;
3761 case GLOBAL_COLOR_SCHEME_DUSK:
3762 m_pos_image_red = &m_os_image_red_dusk;
3763 m_pos_image_grey = &m_os_image_grey_dusk;
3764 m_pos_image_yellow = &m_os_image_yellow_dusk;
3765 m_pos_image_user = m_pos_image_user_dusk;
3766 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3767 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3768 m_cTideBitmap = m_bmTideDusk;
3769 m_cCurrentBitmap = m_bmCurrentDusk;
3771 case GLOBAL_COLOR_SCHEME_NIGHT:
3772 m_pos_image_red = &m_os_image_red_night;
3773 m_pos_image_grey = &m_os_image_grey_night;
3774 m_pos_image_yellow = &m_os_image_yellow_night;
3775 m_pos_image_user = m_pos_image_user_night;
3776 m_pos_image_user_grey = m_pos_image_user_grey_night;
3777 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3778 m_cTideBitmap = m_bmTideNight;
3779 m_cCurrentBitmap = m_bmCurrentNight;
3782 m_pos_image_red = &m_os_image_red_day;
3783 m_pos_image_grey = &m_os_image_grey_day;
3784 m_pos_image_yellow = &m_os_image_yellow_day;
3785 m_pos_image_user = m_pos_image_user_day;
3786 m_pos_image_user_grey = m_pos_image_user_grey_day;
3787 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3788 m_cTideBitmap = m_bmTideDay;
3789 m_cCurrentBitmap = m_bmCurrentDay;
3793 CreateDepthUnitEmbossMaps(cs);
3794 CreateOZEmbossMapData(cs);
3797 m_fog_color = wxColor(
3801 case GLOBAL_COLOR_SCHEME_DUSK:
3804 case GLOBAL_COLOR_SCHEME_NIGHT:
3810 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3811 m_fog_color.Blue() * dim);
3815 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3816 SetBackgroundColour( wxColour(0,0,0) );
3818 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3821 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3823 SetBackgroundColour( wxNullColour );
3830 m_Piano->SetColorScheme(cs);
3832 m_Compass->SetColorScheme(cs);
3834 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3836 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3838 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3839 if (m_notification_button) {
3840 m_notification_button->SetColorScheme(cs);
3844 if (g_bopengl && m_glcc) {
3845 m_glcc->SetColorScheme(cs);
3846 g_glTextureManager->ClearAllRasterTextures();
3851 m_brepaint_piano =
true;
3858wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3859 wxImage img = Bitmap.ConvertToImage();
3860 int sx = img.GetWidth();
3861 int sy = img.GetHeight();
3863 wxImage new_img(img);
3865 for (
int i = 0; i < sx; i++) {
3866 for (
int j = 0; j < sy; j++) {
3867 if (!img.IsTransparent(i, j)) {
3868 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3869 (
unsigned char)(img.GetGreen(i, j) * factor),
3870 (
unsigned char)(img.GetBlue(i, j) * factor));
3875 wxBitmap ret = wxBitmap(new_img);
3880void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3883 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3885 if (!m_pBrightPopup) {
3888 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3892 m_pBrightPopup->SetSize(x, y);
3893 m_pBrightPopup->Move(120, 120);
3896 int bmpsx = m_pBrightPopup->GetSize().x;
3897 int bmpsy = m_pBrightPopup->GetSize().y;
3899 wxBitmap bmp(bmpsx, bmpsx);
3900 wxMemoryDC mdc(bmp);
3902 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3903 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3904 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3905 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3908 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3910 mdc.SetFont(*pfont);
3913 if (brightness == max)
3915 else if (brightness == min)
3918 val.Printf(_T(
"%3d"), brightness);
3920 mdc.DrawText(val, 0, 0);
3922 mdc.SelectObject(wxNullBitmap);
3924 m_pBrightPopup->SetBitmap(bmp);
3925 m_pBrightPopup->Show();
3926 m_pBrightPopup->Refresh();
3929void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3930 m_b_rot_hidef =
true;
3934void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3935 if (!g_bRollover)
return;
3937 bool b_need_refresh =
false;
3939 wxSize win_size = GetSize() * m_displayScale;
3940 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3943 bool showAISRollover =
false;
3944 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3946 SelectItem *pFind = pSelectAIS->FindSelection(
3949 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3950 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3953 showAISRollover =
true;
3955 if (NULL == m_pAISRolloverWin) {
3957 m_pAISRolloverWin->IsActive(
false);
3958 b_need_refresh =
true;
3959 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3960 m_AISRollover_MMSI != FoundAIS_MMSI) {
3966 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3967 m_pAISRolloverWin->IsActive(
false);
3968 m_AISRollover_MMSI = 0;
3973 m_AISRollover_MMSI = FoundAIS_MMSI;
3975 if (!m_pAISRolloverWin->IsActive()) {
3976 wxString s = ptarget->GetRolloverString();
3977 m_pAISRolloverWin->SetString(s);
3979 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3980 AIS_ROLLOVER, win_size);
3981 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3982 m_pAISRolloverWin->IsActive(
true);
3983 b_need_refresh =
true;
3987 m_AISRollover_MMSI = 0;
3988 showAISRollover =
false;
3993 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3994 m_pAISRolloverWin->IsActive(
false);
3995 m_AISRollover_MMSI = 0;
3996 b_need_refresh =
true;
4001 bool showRouteRollover =
false;
4003 if (NULL == m_pRolloverRouteSeg) {
4008 SelectableItemList SelList = pSelect->FindSelectionList(
4010 wxSelectableItemListNode *node = SelList.GetFirst();
4016 if (pr && pr->IsVisible()) {
4017 m_pRolloverRouteSeg = pFindSel;
4018 showRouteRollover =
true;
4020 if (NULL == m_pRouteRolloverWin) {
4022 m_pRouteRolloverWin->IsActive(
false);
4025 if (!m_pRouteRolloverWin->IsActive()) {
4033 DistanceBearingMercator(
4034 segShow_point_b->m_lat, segShow_point_b->m_lon,
4035 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4037 if (!pr->m_bIsInLayer)
4038 s.Append(_(
"Route") + _T(
": "));
4040 s.Append(_(
"Layer Route: "));
4042 if (pr->m_RouteNameString.IsEmpty())
4043 s.Append(_(
"(unnamed)"));
4045 s.Append(pr->m_RouteNameString);
4047 s << _T(
"\n") << _(
"Total Length: ")
4048 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
4049 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4050 << segShow_point_b->GetName() << _T(
"\n");
4053 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4054 (
int)floor(brg + 0.5), 0x00B0);
4057 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4059 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4060 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4062 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4063 (
int)floor(varBrg + 0.5), 0x00B0);
4066 s << FormatDistanceAdaptive(dist);
4071 double shiptoEndLeg = 0.;
4072 bool validActive =
false;
4073 if (pr->IsActive() &&
4074 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
4077 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
4078 wxRoutePointListNode *node =
4079 (pr->pRoutePointList)->GetFirst()->GetNext();
4081 float dist_to_endleg = 0;
4085 prp = node->GetData();
4091 if (prp->IsSame(segShow_point_a))
break;
4092 node = node->GetNext();
4094 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
4099 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
4100 << segShow_point_b->GetName() << _T(
"\n");
4103 ->GetCurrentRngToActivePoint();
4108 s << FormatDistanceAdaptive(shiptoEndLeg);
4112 if (!std::isnan(gCog) && !std::isnan(gSog))
4114 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
4117 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
4118 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4120 << wxString(ttg_sec > SECONDS_PER_DAY
4121 ? ttg_span.Format(_(
"%Dd %H:%M"))
4122 : ttg_span.Format(_(
"%H:%M")));
4123 wxDateTime dtnow, eta;
4124 eta = dtnow.SetToCurrent().Add(ttg_span);
4125 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
4126 << eta.Format(_T(
" %d %H:%M"));
4128 s << _T(
" ---- ----");
4130 m_pRouteRolloverWin->SetString(s);
4132 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4133 LEG_ROLLOVER, win_size);
4134 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4135 m_pRouteRolloverWin->IsActive(
true);
4136 b_need_refresh =
true;
4137 showRouteRollover =
true;
4141 node = node->GetNext();
4147 m_pRolloverRouteSeg))
4148 showRouteRollover =
false;
4149 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4150 showRouteRollover =
false;
4152 showRouteRollover =
true;
4156 if (m_routeState) showRouteRollover =
false;
4159 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4160 showRouteRollover =
false;
4162 if (m_pRouteRolloverWin &&
4163 !showRouteRollover) {
4164 m_pRouteRolloverWin->IsActive(
false);
4165 m_pRolloverRouteSeg = NULL;
4166 m_pRouteRolloverWin->Destroy();
4167 m_pRouteRolloverWin = NULL;
4168 b_need_refresh =
true;
4169 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4170 m_pRouteRolloverWin->IsActive(
true);
4171 b_need_refresh =
true;
4176 bool showTrackRollover =
false;
4178 if (NULL == m_pRolloverTrackSeg) {
4183 SelectableItemList SelList = pSelect->FindSelectionList(
4185 wxSelectableItemListNode *node = SelList.GetFirst();
4191 if (pt && pt->IsVisible()) {
4192 m_pRolloverTrackSeg = pFindSel;
4193 showTrackRollover =
true;
4195 if (NULL == m_pTrackRolloverWin) {
4197 m_pTrackRolloverWin->IsActive(
false);
4200 if (!m_pTrackRolloverWin->IsActive()) {
4208 DistanceBearingMercator(
4209 segShow_point_b->m_lat, segShow_point_b->m_lon,
4210 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4212 if (!pt->m_bIsInLayer)
4213 s.Append(_(
"Track") + _T(
": "));
4215 s.Append(_(
"Layer Track: "));
4217 if (pt->GetName().IsEmpty())
4218 s.Append(_(
"(unnamed)"));
4220 s.Append(pt->GetName());
4221 double tlenght = pt->Length();
4222 s << _T(
"\n") << _(
"Total Track: ")
4223 << FormatDistanceAdaptive(tlenght);
4224 if (pt->GetLastPoint()->GetTimeString() &&
4225 pt->GetPoint(0)->GetTimeString()) {
4226 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4227 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4228 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4229 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4230 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4231 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4232 << getUsrSpeedUnit();
4233 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4234 : ttime.Format(_T(
" %H:%M")));
4238 if (g_bShowTrackPointTime &&
4239 strlen(segShow_point_b->GetTimeString())) {
4240 wxString stamp = segShow_point_b->GetTimeString();
4241 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4242 if (timestamp.IsValid()) {
4246 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4248 s << _T(
"\n") << _(
"Segment Created: ") << stamp;
4253 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4258 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4260 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4261 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4263 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4267 s << FormatDistanceAdaptive(dist);
4269 if (segShow_point_a->GetTimeString() &&
4270 segShow_point_b->GetTimeString()) {
4271 wxDateTime apoint = segShow_point_a->GetCreateTime();
4272 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4273 if (apoint.IsValid() && bpoint.IsValid()) {
4274 double segmentSpeed = toUsrSpeed(
4275 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4276 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4277 << getUsrSpeedUnit();
4281 m_pTrackRolloverWin->SetString(s);
4283 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4284 LEG_ROLLOVER, win_size);
4285 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4286 m_pTrackRolloverWin->IsActive(
true);
4287 b_need_refresh =
true;
4288 showTrackRollover =
true;
4292 node = node->GetNext();
4298 m_pRolloverTrackSeg))
4299 showTrackRollover =
false;
4300 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4301 showTrackRollover =
false;
4303 showTrackRollover =
true;
4307 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4308 showTrackRollover =
false;
4311 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4312 showTrackRollover =
false;
4318 if (m_pTrackRolloverWin &&
4319 !showTrackRollover) {
4320 m_pTrackRolloverWin->IsActive(
false);
4321 m_pRolloverTrackSeg = NULL;
4322 m_pTrackRolloverWin->Destroy();
4323 m_pTrackRolloverWin = NULL;
4324 b_need_refresh =
true;
4325 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4326 m_pTrackRolloverWin->IsActive(
true);
4327 b_need_refresh =
true;
4330 if (b_need_refresh) Refresh();
4333void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4334 if ((GetShowENCLights() || m_bsectors_shown) &&
4335 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4336 extendedSectorLegs)) {
4337 if (!m_bsectors_shown) {
4339 m_bsectors_shown =
true;
4342 if (m_bsectors_shown) {
4344 m_bsectors_shown =
false;
4352#if defined(__WXGTK__) || defined(__WXQT__)
4357 double cursor_lat, cursor_lon;
4360 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4361 while (cursor_lon < -180.) cursor_lon += 360.;
4363 while (cursor_lon > 180.) cursor_lon -= 360.;
4365 SetCursorStatus(cursor_lat, cursor_lon);
4371void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4372 if (!parent_frame->m_pStatusBar)
return;
4376 s1 += toSDMM(1, cursor_lat);
4378 s1 += toSDMM(2, cursor_lon);
4380 if (STAT_FIELD_CURSOR_LL >= 0)
4381 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4383 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4388 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4389 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4390 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4392 wxString s = st + sm;
4393 s << FormatDistanceAdaptive(dist);
4405 if (g_bShowLiveETA) {
4408 float boatSpeedDefault = g_defaultBoatSpeed;
4413 if (!std::isnan(gSog)) {
4415 if (boatSpeed < 0.5) {
4418 realTimeETA = dist / boatSpeed * 60;
4427 s << minutesToHoursDays(realTimeETA);
4432 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4433 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4435 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4440 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4448wxString minutesToHoursDays(
float timeInMinutes) {
4451 if (timeInMinutes == 0) {
4456 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4457 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4462 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4465 hours = (int)timeInMinutes / 60;
4466 min = (int)timeInMinutes % 60;
4469 s << wxString::Format(_T(
"%d"), hours);
4472 s << wxString::Format(_T(
"%d"), hours);
4474 s << wxString::Format(_T(
"%d"), min);
4481 else if (timeInMinutes > 24 * 60) {
4484 days = (int)(timeInMinutes / 60) / 24;
4485 hours = (int)(timeInMinutes / 60) % 24;
4488 s << wxString::Format(_T(
"%d"), days);
4491 s << wxString::Format(_T(
"%d"), days);
4493 s << wxString::Format(_T(
"%d"), hours);
4505void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4513 wxPoint2DDouble *r) {
4518 double rlon, wxPoint2DDouble *r) {
4529 if (!g_bopengl && m_singleChart &&
4530 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4531 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4532 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4533 (m_singleChart->GetChartProjectionType() !=
4534 PROJECTION_TRANSVERSE_MERCATOR) &&
4535 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4536 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4537 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4551 Cur_BSB_Ch->SetVPRasterParms(vp);
4552 double rpixxd, rpixyd;
4553 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4579 if (std::isnan(p.m_x)) {
4580 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4584 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4585 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4587 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4606 if (!g_bopengl && m_singleChart &&
4607 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4608 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4609 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4610 (m_singleChart->GetChartProjectionType() !=
4611 PROJECTION_TRANSVERSE_MERCATOR) &&
4612 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4613 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4614 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4625 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4628 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4633 else if (slon > 180.)
4644 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4650 DoZoomCanvas(factor,
false);
4651 extendedSectorLegs.clear();
4656 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4658 if (g_bsmoothpanzoom) {
4659 if (StartTimedMovement(stoptimer)) {
4661 m_zoom_factor = factor;
4666 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4668 DoZoomCanvas(factor, can_zoom_to_cursor);
4671 extendedSectorLegs.clear();
4674void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4676 if (!ChartData)
return;
4677 if (!m_pCurrentStack)
return;
4683 if (m_bzooming)
return;
4692 double proposed_scale_onscreen =
4695 bool b_do_zoom =
false;
4704 if (!VPoint.b_quilt) {
4707 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4708 if (new_db_index >= 0)
4709 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4713 int current_ref_stack_index = -1;
4714 if (m_pCurrentStack->nEntry) {
4716 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4717 m_pQuilt->SetReferenceChart(trial_index);
4718 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4719 if (new_db_index >= 0)
4720 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4724 if (m_pCurrentStack)
4725 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4735 double min_allowed_scale =
4738 if (proposed_scale_onscreen < min_allowed_scale) {
4743 proposed_scale_onscreen = min_allowed_scale;
4747 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4750 }
else if (factor < 1) {
4755 bool b_smallest =
false;
4757 if (!VPoint.b_quilt) {
4762 LLBBox viewbox = VPoint.GetBBox();
4764 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4765 double max_allowed_scale;
4779 if (proposed_scale_onscreen > max_allowed_scale) {
4781 proposed_scale_onscreen = max_allowed_scale;
4786 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4787 if (new_db_index >= 0)
4788 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4790 if (m_pCurrentStack)
4791 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4794 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4796 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4797 proposed_scale_onscreen =
4798 wxMin(proposed_scale_onscreen,
4804 m_absolute_min_scale_ppm)
4813 bool b_allow_ztc =
true;
4814 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4815 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4817 double brg, distance;
4818 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4821 meters_to_shift = distance * 1852;
4829 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4832 if (m_bFollow) DoCanvasUpdate();
4839void ChartCanvas::RotateCanvas(
double dir) {
4842 if (g_bsmoothpanzoom) {
4843 if (StartTimedMovement()) {
4845 m_rotation_speed = dir * 60;
4848 double speed = dir * 10;
4849 if (m_modkeys == wxMOD_ALT) speed /= 20;
4850 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4854void ChartCanvas::DoRotateCanvas(
double rotation) {
4855 while (rotation < 0) rotation += 2 * PI;
4856 while (rotation > 2 * PI) rotation -= 2 * PI;
4858 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4860 SetVPRotation(rotation);
4861 parent_frame->UpdateRotationState(VPoint.
rotation);
4864void ChartCanvas::DoTiltCanvas(
double tilt) {
4865 while (tilt < 0) tilt = 0;
4866 while (tilt > .95) tilt = .95;
4868 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4874void ChartCanvas::TogglebFollow(
void) {
4881void ChartCanvas::ClearbFollow(
void) {
4884 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4886 UpdateFollowButtonState();
4890 parent_frame->SetChartUpdatePeriod();
4893void ChartCanvas::SetbFollow(
void) {
4896 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4897 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4905 p.m_x += m_OSoffsetx;
4906 p.m_y -= m_OSoffsety;
4915 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4916 UpdateFollowButtonState();
4918 if (!g_bSmoothRecenter) {
4922 parent_frame->SetChartUpdatePeriod();
4925void ChartCanvas::UpdateFollowButtonState(
void) {
4928 m_muiBar->SetFollowButtonState(0);
4931 m_muiBar->SetFollowButtonState(2);
4933 m_muiBar->SetFollowButtonState(1);
4939 androidSetFollowTool(0);
4942 androidSetFollowTool(2);
4944 androidSetFollowTool(1);
4949void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4950 if (g_bSmoothRecenter && !m_routeState) {
4951 if (StartSmoothJump(lat, lon, scale_ppm))
4955 double gcDist, gcBearingEnd;
4956 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4958 gcBearingEnd += 180;
4959 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4962 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4963 double new_lat = lat + (lat_offset / (1852 * 60));
4964 double new_lon = lon + (lon_offset / (1852 * 60));
4967 StartSmoothJump(lat, lon, scale_ppm);
4972 if (lon > 180.0) lon -= 360.0;
4978 if (!GetQuiltMode()) {
4980 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4981 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4985 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4986 AdjustQuiltRefChart();
4993 UpdateFollowButtonState();
5001bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5006 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5007 double distance_pixels = gcDist *
GetVPScale();
5008 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5014 m_startLat = m_vLat;
5015 m_startLon = m_vLon;
5020 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5021 m_endScale = scale_ppm;
5024 m_animationDuration = 600;
5025 m_animationStart = wxGetLocalTimeMillis();
5032 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5033 m_animationActive =
true;
5038void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5040 wxLongLong now = wxGetLocalTimeMillis();
5041 double elapsed = (now - m_animationStart).ToDouble();
5042 double t = elapsed / m_animationDuration.ToDouble();
5043 if (t > 1.0) t = 1.0;
5046 double e = easeOutCubic(t);
5049 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5050 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5051 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5056 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5062 m_animationActive =
false;
5063 UpdateFollowButtonState();
5071 if (!ChartData)
return false;
5076 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
5077 UpdateFollowButtonState();
5083 extendedSectorLegs.clear();
5093 if (iters++ > 5)
return false;
5094 if (!std::isnan(dlat))
break;
5097 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5103 else if (dlat < -90)
5106 if (dlon > 360.) dlon -= 360.;
5107 if (dlon < -360.) dlon += 360.;
5122 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5126 if (VPoint.b_quilt) {
5127 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5128 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5130 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
5132 double tweak_scale_ppm =
5138 if (new_ref_dbIndex == -1) {
5139#pragma GCC diagnostic push
5140#pragma GCC diagnostic ignored "-Warray-bounds"
5147 int trial_index = -1;
5148 if (m_pCurrentStack->nEntry) {
5150 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5153 if (trial_index < 0) {
5154 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5155 if (full_screen_array.size())
5156 trial_index = full_screen_array[full_screen_array.size() - 1];
5159 if (trial_index >= 0) {
5160 m_pQuilt->SetReferenceChart(trial_index);
5165#pragma GCC diagnostic pop
5172 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5174 double offset_angle = atan2(offy, offx);
5175 double offset_distance = sqrt((offy * offy) + (offx * offx));
5176 double chart_angle = GetVPRotation();
5177 double target_angle = chart_angle - offset_angle;
5178 double d_east_mod = offset_distance * cos(target_angle);
5179 double d_north_mod = offset_distance * sin(target_angle);
5184 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5185 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5187 UpdateFollowButtonState();
5193 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5198void ChartCanvas::ReloadVP(
bool b_adjust) {
5199 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5201 LoadVP(VPoint, b_adjust);
5204void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5206 if (g_bopengl && m_glcc) {
5207 m_glcc->Invalidate();
5208 if (m_glcc->GetSize() != GetSize()) {
5209 m_glcc->SetSize(GetSize());
5214 m_cache_vp.Invalidate();
5215 m_bm_cache_vp.Invalidate();
5218 VPoint.Invalidate();
5220 if (m_pQuilt) m_pQuilt->Invalidate();
5229 vp.m_projection_type, b_adjust);
5232void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5233 m_pQuilt->SetReferenceChart(dbIndex);
5234 VPoint.Invalidate();
5235 m_pQuilt->Invalidate();
5238double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5240 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5247int ChartCanvas::AdjustQuiltRefChart() {
5250 wxASSERT(ChartData);
5252 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5254 double min_ref_scale =
5255 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5256 double max_ref_scale =
5257 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5260 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5262 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5264 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5266 int ref_family = pc->GetChartFamily();
5269 unsigned int target_stack_index = 0;
5270 int target_stack_index_check =
5271 m_pQuilt->GetExtendedStackIndexArray()
5272 [m_pQuilt->GetRefChartdbIndex()];
5274 if (wxNOT_FOUND != target_stack_index_check)
5275 target_stack_index = target_stack_index_check;
5277 int extended_array_count =
5278 m_pQuilt->GetExtendedStackIndexArray().size();
5279 while ((!brender_ok) &&
5280 ((
int)target_stack_index < (extended_array_count - 1))) {
5281 target_stack_index++;
5283 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5285 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
5286 IsChartQuiltableRef(test_db_index)) {
5289 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5291 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5298 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5299 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
5300 IsChartQuiltableRef(new_db_index)) {
5301 m_pQuilt->SetReferenceChart(new_db_index);
5304 ret = m_pQuilt->GetRefChartdbIndex();
5306 ret = m_pQuilt->GetRefChartdbIndex();
5309 ret = m_pQuilt->GetRefChartdbIndex();
5318void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5319 delete m_pCurrentStack;
5321 wxASSERT(ChartData);
5322 ChartData->BuildChartStack(m_pCurrentStack, VPoint.
clat, VPoint.
clon,
5331bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5332 double latNE,
double lonNE) {
5334 double latc = (latSW + latNE) / 2.0;
5335 double lonc = (lonSW + lonNE) / 2.0;
5338 double ne_easting, ne_northing;
5339 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5341 double sw_easting, sw_northing;
5342 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5344 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5351 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5354bool ChartCanvas::SetVPProjection(
int projection) {
5360 double prev_true_scale_ppm = m_true_scale_ppm;
5365 m_absolute_min_scale_ppm));
5373bool ChartCanvas::SetVPRotation(
double angle) {
5375 VPoint.
skew, angle);
5378 double skew,
double rotation,
int projection,
5379 bool b_adjust,
bool b_refresh) {
5384 if (VPoint.IsValid()) {
5385 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5386 (fabs(VPoint.
skew - skew) < 1e-9) &&
5387 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5388 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5389 (VPoint.m_projection_type == projection ||
5390 projection == PROJECTION_UNKNOWN))
5393 if (VPoint.m_projection_type != projection)
5394 VPoint.InvalidateTransformCache();
5404 if (projection != PROJECTION_UNKNOWN)
5405 VPoint.SetProjectionType(projection);
5406 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5407 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5410 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5411 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5412 if (VPoint.
clat > 89.5)
5414 else if (VPoint.
clat < -89.5)
5415 VPoint.
clat = -89.5;
5420 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5421 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5433 bool bwasValid = VPoint.IsValid();
5438 m_cache_vp.Invalidate();
5443 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5447 int mouseX = mouse_x;
5448 int mouseY = mouse_y;
5449 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5455 SendCursorLatLonToAllPlugIns(lat, lon);
5458 if (!VPoint.b_quilt && m_singleChart) {
5463 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5467 if ((!m_cache_vp.IsValid()) ||
5472 wxPoint cp_last, cp_this;
5476 if (cp_last != cp_this) {
5482 if (m_pCurrentStack) {
5483 assert(ChartData != 0);
5484 int current_db_index;
5486 m_pCurrentStack->GetCurrentEntrydbIndex();
5488 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5490 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5493 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5497 if (VPoint.b_quilt) {
5499 m_pQuilt->InvalidateAllQuiltPatchs();
5503 if (!m_pCurrentStack)
return false;
5505 int current_db_index;
5507 m_pCurrentStack->GetCurrentEntrydbIndex();
5509 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5510 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5513 int current_ref_stack_index = -1;
5514 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5515 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5516 current_ref_stack_index = i;
5519 if (g_bFullScreenQuilt) {
5520 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5524 bool b_needNewRef =
false;
5527 if ((-1 == current_ref_stack_index) &&
5528 (m_pQuilt->GetRefChartdbIndex() >= 0))
5529 b_needNewRef =
true;
5536 bool renderable =
true;
5538 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5539 if (referenceChart) {
5540 double chartMaxScale = referenceChart->GetNormalScaleMax(
5542 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5544 if (!renderable) b_needNewRef =
true;
5549 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5550 int target_scale = cte_ref.GetScale();
5551 int target_type = cte_ref.GetChartType();
5552 int candidate_stack_index;
5559 candidate_stack_index = 0;
5560 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5562 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5563 int candidate_scale = cte_candidate.GetScale();
5564 int candidate_type = cte_candidate.GetChartType();
5566 if ((candidate_scale >= target_scale) &&
5567 (candidate_type == target_type)) {
5568 bool renderable =
true;
5569 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5570 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5571 if (tentative_referenceChart) {
5572 double chartMaxScale =
5573 tentative_referenceChart->GetNormalScaleMax(
5575 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5578 if (renderable)
break;
5581 candidate_stack_index++;
5586 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5587 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5588 while (candidate_stack_index >= 0) {
5589 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5592 ChartData->GetChartTableEntry(idx);
5593 int candidate_scale = cte_candidate.GetScale();
5594 int candidate_type = cte_candidate.GetChartType();
5596 if ((candidate_scale <= target_scale) &&
5597 (candidate_type == target_type))
5600 candidate_stack_index--;
5605 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5606 (candidate_stack_index < 0))
5607 candidate_stack_index = 0;
5609 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5611 m_pQuilt->SetReferenceChart(new_ref_index);
5617 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5622 bool renderable =
true;
5624 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5625 if (referenceChart) {
5626 double chartMaxScale = referenceChart->GetNormalScaleMax(
5628 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5629 proj = ChartData->GetDBChartProj(ref_db_index);
5631 proj = PROJECTION_MERCATOR;
5633 VPoint.b_MercatorProjectionOverride =
5634 (m_pQuilt->GetnCharts() == 0 || !renderable);
5636 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5638 VPoint.SetProjectionType(proj);
5645 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5650 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5670 m_pQuilt->Invalidate();
5685 ChartData->PurgeCacheUnusedCharts(0.7);
5687 if (b_refresh) Refresh(
false);
5694 }
else if (!g_bopengl) {
5695 OcpnProjType projection = PROJECTION_UNKNOWN;
5698 projection = m_singleChart->GetChartProjectionType();
5699 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5700 VPoint.SetProjectionType(projection);
5704 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5705 m_cache_vp.Invalidate();
5709 UpdateCanvasControlBar();
5715 if (VPoint.GetBBox().GetValid()) {
5718 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5727 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5730 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5737 wxPoint2DDouble r, r1;
5739 double delta_check =
5743 double check_point = wxMin(89., VPoint.
clat);
5745 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5748 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5749 VPoint.
clon, 0, &rhumbDist);
5754 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5755 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5757 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5761 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5767 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5769 if (m_true_scale_ppm)
5770 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5775 double round_factor = 1000.;
5779 round_factor = 100.;
5781 round_factor = 1000.;
5784 double retina_coef = 1;
5788 retina_coef = GetContentScaleFactor();
5799 double true_scale_display =
5800 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5805 if (m_displayed_scale_factor > 10.0)
5806 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5807 m_displayed_scale_factor);
5808 else if (m_displayed_scale_factor > 1.0)
5809 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5810 m_displayed_scale_factor);
5811 else if (m_displayed_scale_factor > 0.1) {
5812 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5813 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5814 }
else if (m_displayed_scale_factor > 0.01) {
5815 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5816 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5819 _T(
"%s %4.0f (---)"), _(
"Scale"),
5820 true_scale_display);
5823 m_scaleValue = true_scale_display;
5825 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5827 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5828 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5830 bool b_noshow =
false;
5834 wxClientDC dc(parent_frame->GetStatusBar());
5836 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5837 dc.SetFont(*templateFont);
5838 dc.GetTextExtent(text, &w, &h);
5843 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5844 if (w && w > rect.width) {
5845 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5846 m_displayed_scale_factor);
5850 dc.GetTextExtent(text, &w, &h);
5852 if (w && w > rect.width) {
5858 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5863 m_vLat = VPoint.
clat;
5864 m_vLon = VPoint.
clon;
5878static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5882static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5883 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5885wxColour ChartCanvas::PredColor() {
5888 if (SHIP_NORMAL == m_ownship_state)
5889 return GetGlobalColor(_T (
"URED" ));
5891 else if (SHIP_LOWACCURACY == m_ownship_state)
5892 return GetGlobalColor(_T (
"YELO1" ));
5894 return GetGlobalColor(_T (
"NODTA" ));
5897wxColour ChartCanvas::ShipColor() {
5901 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5903 if (SHIP_LOWACCURACY == m_ownship_state)
5904 return GetGlobalColor(_T (
"YELO1" ));
5906 return GetGlobalColor(_T (
"URED" ));
5909void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5910 wxPoint2DDouble lShipMidPoint) {
5911 dc.SetPen(wxPen(PredColor(), 2));
5913 if (SHIP_NORMAL == m_ownship_state)
5914 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5916 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5918 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5919 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5921 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5923 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5924 lShipMidPoint.m_y + 12);
5927void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5928 wxPoint GPSOffsetPixels,
5929 wxPoint2DDouble lGPSPoint) {
5930 if (m_animationActive)
return;
5934 float ref_dim = m_display_size_mm / 24;
5935 ref_dim = wxMin(ref_dim, 12);
5936 ref_dim = wxMax(ref_dim, 6);
5939 cPred.Set(g_cog_predictor_color);
5940 if (cPred == wxNullColour) cPred = PredColor();
5947 double nominal_line_width_pix = wxMax(
5949 floor(m_pix_per_mm / 2));
5953 if (nominal_line_width_pix > g_cog_predictor_width)
5954 g_cog_predictor_width = nominal_line_width_pix;
5957 wxPoint lPredPoint, lHeadPoint;
5959 float pCog = std::isnan(gCog) ? 0 : gCog;
5960 float pSog = std::isnan(gSog) ? 0 : gSog;
5962 double pred_lat, pred_lon;
5963 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5964 &pred_lat, &pred_lon);
5975 float ndelta_pix = 10.;
5976 double hdg_pred_lat, hdg_pred_lon;
5977 bool b_render_hdt =
false;
5978 if (!std::isnan(gHdt)) {
5980 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5983 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5984 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5985 if (dist > ndelta_pix ) {
5986 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5987 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5992 wxPoint lShipMidPoint;
5993 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5994 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5995 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5996 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5998 if (lpp >= img_height / 2) {
5999 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
6000 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
6001 !std::isnan(gSog)) {
6003 float dash_length = ref_dim;
6004 wxDash dash_long[2];
6006 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6007 g_cog_predictor_width);
6008 dash_long[1] = dash_long[0] / 2.0;
6012 if (dash_length > 250.) {
6013 dash_long[0] = 250. / g_cog_predictor_width;
6014 dash_long[1] = dash_long[0] / 2;
6017 wxPen ppPen2(cPred, g_cog_predictor_width,
6018 (wxPenStyle)g_cog_predictor_style);
6019 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6020 ppPen2.SetDashes(2, dash_long);
6023 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6024 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6026 if (g_cog_predictor_width > 1) {
6027 float line_width = g_cog_predictor_width / 3.;
6029 wxDash dash_long3[2];
6030 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6031 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6033 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
6034 (wxPenStyle)g_cog_predictor_style);
6035 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6036 ppPen3.SetDashes(2, dash_long3);
6038 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6039 lGPSPoint.m_y + GPSOffsetPixels.y,
6040 lPredPoint.x + GPSOffsetPixels.x,
6041 lPredPoint.y + GPSOffsetPixels.y);
6044 if (g_cog_predictor_endmarker) {
6046 double png_pred_icon_scale_factor = .4;
6047 if (g_ShipScaleFactorExp > 1.0)
6048 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6049 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6053 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6054 (
float)(lPredPoint.x - lShipMidPoint.x));
6055 cog_rad += (float)PI;
6057 for (
int i = 0; i < 4; i++) {
6059 double pxa = (double)(s_png_pred_icon[j]);
6060 double pya = (double)(s_png_pred_icon[j + 1]);
6062 pya *= png_pred_icon_scale_factor;
6063 pxa *= png_pred_icon_scale_factor;
6065 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6066 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6068 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6069 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6073 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
6076 dc.SetBrush(wxBrush(cPred));
6078 dc.StrokePolygon(4, icon);
6085 float hdt_dash_length = ref_dim * 0.4;
6087 cPred.Set(g_ownship_HDTpredictor_color);
6088 if (cPred == wxNullColour) cPred = PredColor();
6090 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6091 : g_cog_predictor_width * 0.8);
6092 wxDash dash_short[2];
6094 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6097 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6100 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6101 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6102 ppPen2.SetDashes(2, dash_short);
6106 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6107 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6109 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6111 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
6113 if (g_ownship_HDTpredictor_endmarker) {
6114 double nominal_circle_size_pixels = wxMax(
6115 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6118 if (g_ShipScaleFactorExp > 1.0)
6119 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6121 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6122 lHeadPoint.y + GPSOffsetPixels.y,
6123 nominal_circle_size_pixels / 2);
6128 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6129 double factor = 1.00;
6130 if (g_pNavAidRadarRingsStepUnits == 1)
6132 else if (g_pNavAidRadarRingsStepUnits == 2) {
6133 if (std::isnan(gSog))
6138 factor *= g_fNavAidRadarRingsStep;
6142 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
6145 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6146 pow((
double)(lGPSPoint.m_y - r.y), 2));
6147 int pix_radius = (int)lpp;
6149 extern wxColor GetDimColor(wxColor c);
6150 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6152 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6155 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6157 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6158 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6162void ChartCanvas::ComputeShipScaleFactor(
6163 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6164 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6165 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6166 float screenResolution = m_pix_per_mm;
6169 double ship_bow_lat, ship_bow_lon;
6170 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6171 &ship_bow_lat, &ship_bow_lon);
6172 wxPoint lShipBowPoint;
6173 wxPoint2DDouble b_point =
6177 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6178 powf((
float)(b_point.m_y - a_point.m_y), 2));
6181 float shipLength_mm = shipLength_px / screenResolution;
6184 float ownship_min_mm = g_n_ownship_min_mm;
6185 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6188 float hdt_ant = icon_hdt + 180.;
6189 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6190 float dx = g_n_gps_antenna_offset_x / 1852.;
6191 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6199 if (shipLength_mm < ownship_min_mm) {
6200 dy /= shipLength_mm / ownship_min_mm;
6201 dx /= shipLength_mm / ownship_min_mm;
6204 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6206 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6207 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6213 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6214 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6216 float scale_factor = shipLength_px / ownShipLength;
6219 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6222 scale_factor = wxMax(scale_factor, scale_factor_min);
6224 scale_factor_y = scale_factor;
6225 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6226 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6229void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6230 if (!GetVP().IsValid())
return;
6232 wxPoint GPSOffsetPixels(0, 0);
6233 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6236 float pCog = std::isnan(gCog) ? 0 : gCog;
6237 float pSog = std::isnan(gSog) ? 0 : gSog;
6241 lShipMidPoint = lGPSPoint;
6245 float icon_hdt = pCog;
6246 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6249 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6253 double osd_head_lat, osd_head_lon;
6254 wxPoint osd_head_point;
6256 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6261 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6262 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6263 icon_rad += (float)PI;
6265 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6269 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6273 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6274 if (GetVP().chart_scale >
6277 ShipDrawLargeScale(dc, lShipMidPoint);
6283 if (m_pos_image_user)
6284 pos_image = m_pos_image_user->Copy();
6285 else if (SHIP_NORMAL == m_ownship_state)
6286 pos_image = m_pos_image_red->Copy();
6287 if (SHIP_LOWACCURACY == m_ownship_state)
6288 pos_image = m_pos_image_yellow->Copy();
6289 else if (SHIP_NORMAL != m_ownship_state)
6290 pos_image = m_pos_image_grey->Copy();
6293 if (m_pos_image_user) {
6294 pos_image = m_pos_image_user->Copy();
6296 if (SHIP_LOWACCURACY == m_ownship_state)
6297 pos_image = m_pos_image_user_yellow->Copy();
6298 else if (SHIP_NORMAL != m_ownship_state)
6299 pos_image = m_pos_image_user_grey->Copy();
6302 img_height = pos_image.GetHeight();
6304 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6305 g_OwnShipIconType > 0)
6307 int ownShipWidth = 22;
6308 int ownShipLength = 84;
6309 if (g_OwnShipIconType == 1) {
6310 ownShipWidth = pos_image.GetWidth();
6311 ownShipLength = pos_image.GetHeight();
6314 float scale_factor_x, scale_factor_y;
6315 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6316 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6317 scale_factor_x, scale_factor_y);
6319 if (g_OwnShipIconType == 1) {
6320 pos_image.Rescale(ownShipWidth * scale_factor_x,
6321 ownShipLength * scale_factor_y,
6322 wxIMAGE_QUALITY_HIGH);
6323 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6325 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6328 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6329 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6330 if (rot_image.GetAlpha(ip, jp) > 64)
6331 rot_image.SetAlpha(ip, jp, 255);
6333 wxBitmap os_bm(rot_image);
6335 int w = os_bm.GetWidth();
6336 int h = os_bm.GetHeight();
6339 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6340 lShipMidPoint.m_y - h / 2,
true);
6343 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6344 lShipMidPoint.m_y - h / 2);
6345 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6346 lShipMidPoint.m_y - h / 2 + h);
6349 else if (g_OwnShipIconType == 2) {
6350 wxPoint ownship_icon[10];
6352 for (
int i = 0; i < 10; i++) {
6354 float pxa = (float)(s_ownship_icon[j]);
6355 float pya = (float)(s_ownship_icon[j + 1]);
6356 pya *= scale_factor_y;
6357 pxa *= scale_factor_x;
6359 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6360 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6362 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6363 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6366 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6368 dc.SetBrush(wxBrush(ShipColor()));
6370 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6373 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6375 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6379 img_height = ownShipLength * scale_factor_y;
6383 if (m_pos_image_user) circle_rad = 1;
6385 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6386 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6387 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6390 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6392 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6395 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6396 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6397 if (rot_image.GetAlpha(ip, jp) > 64)
6398 rot_image.SetAlpha(ip, jp, 255);
6400 wxBitmap os_bm(rot_image);
6402 if (g_ShipScaleFactorExp > 1) {
6403 wxImage scaled_image = os_bm.ConvertToImage();
6404 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6406 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6407 scaled_image.GetHeight() * factor,
6408 wxIMAGE_QUALITY_HIGH));
6410 int w = os_bm.GetWidth();
6411 int h = os_bm.GetHeight();
6414 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6415 lShipMidPoint.m_y - h / 2,
true);
6419 if (m_pos_image_user) circle_rad = 1;
6421 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6422 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6423 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6426 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6427 lShipMidPoint.m_y - h / 2);
6428 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6429 lShipMidPoint.m_y - h / 2 + h);
6434 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6447void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6448 float &MinorSpacing) {
6453 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6454 {.000001f, 45.0f, 15.0f},
6455 {.0002f, 30.0f, 10.0f},
6456 {.0003f, 10.0f, 2.0f},
6457 {.0008f, 5.0f, 1.0f},
6458 {.001f, 2.0f, 30.0f / 60.0f},
6459 {.003f, 1.0f, 20.0f / 60.0f},
6460 {.006f, 0.5f, 10.0f / 60.0f},
6461 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6462 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6463 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6464 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6465 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6466 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6467 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6468 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6471 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6472 if (view_scale_ppm < lltab[tabi][0])
break;
6473 MajorSpacing = lltab[tabi][1];
6474 MinorSpacing = lltab[tabi][2];
6488wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6489 int deg = (int)fabs(latlon);
6490 float min = fabs((fabs(latlon) - deg) * 60.0);
6500 }
else if (latlon < 0.0) {
6512 if (spacing >= 1.0) {
6513 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6514 }
else if (spacing >= (1.0 / 60.0)) {
6515 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6517 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6534void ChartCanvas::GridDraw(
ocpnDC &dc) {
6535 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6537 double nlat, elon, slat, wlon;
6540 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6542 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6544 if (!m_pgridFont) SetupGridFont();
6545 dc.SetFont(*m_pgridFont);
6546 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6549 h = m_canvas_height;
6560 dlon = dlon + 360.0;
6563 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6566 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6569 while (lat < nlat) {
6572 CalcGridText(lat, gridlatMajor,
true);
6574 dc.
DrawLine(0, r.y, w, r.y,
false);
6575 dc.DrawText(st, 0, r.y);
6576 lat = lat + gridlatMajor;
6578 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6582 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6585 while (lat < nlat) {
6588 dc.
DrawLine(0, r.y, 10, r.y,
false);
6589 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6590 lat = lat + gridlatMinor;
6594 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6597 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6600 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6602 wxString st = CalcGridText(lon, gridlonMajor,
false);
6604 dc.
DrawLine(r.x, 0, r.x, h,
false);
6605 dc.DrawText(st, r.x, 0);
6606 lon = lon + gridlonMajor;
6611 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6615 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6617 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6620 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6621 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6622 lon = lon + gridlonMinor;
6629void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6631 double blat, blon, tlat, tlon;
6634 int x_origin = m_bDisplayGrid ? 60 : 20;
6635 int y_origin = m_canvas_height - 50;
6641 if (GetVP().chart_scale > 80000)
6645 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6646 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6651 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6652 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6656 double rotation = -VPoint.
rotation;
6658 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6660 int l1 = (y_origin - r.y) / count;
6662 for (
int i = 0; i < count; i++) {
6669 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6672 double blat, blon, tlat, tlon;
6679 int y_origin = m_canvas_height - chartbar_height - 5;
6683 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6690 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6693 int unit = g_iDistanceFormat;
6695 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6696 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6699 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6700 float places = floor(logdist), rem = logdist - places;
6701 dist = pow(10, places);
6708 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6709 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6710 double rotation = -VPoint.
rotation;
6712 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6716 int l1 = r.x - x_origin;
6718 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6723 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6724 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6725 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6727 if (!m_pgridFont) SetupGridFont();
6728 dc.SetFont(*m_pgridFont);
6729 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6731 dc.GetTextExtent(s, &w, &h);
6737 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6741void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6746 double ra_max = 40.;
6748 wxPen pen_save = dc.GetPen();
6750 wxDateTime now = wxDateTime::Now();
6756 x0 = x1 = x + radius;
6761 while (angle < 360.) {
6762 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6765 if (angle > 360.) angle = 360.;
6767 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6775 x1 = (int)(x + cos(angle * PI / 180.) * r);
6776 y1 = (int)(y + sin(angle * PI / 180.) * r);
6786 dc.
DrawLine(x + radius, y, x1, y1);
6788 dc.SetPen(pen_save);
6791static bool bAnchorSoundPlaying =
false;
6793static void onAnchorSoundFinished(
void *ptr) {
6794 g_anchorwatch_sound->UnLoad();
6795 bAnchorSoundPlaying =
false;
6798void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6800 bool play_sound =
false;
6801 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6802 if (AnchorAlertOn1) {
6803 wxPoint TargetPoint;
6806 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6807 TargetPoint.y, 100);
6811 AnchorAlertOn1 =
false;
6813 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6814 if (AnchorAlertOn2) {
6815 wxPoint TargetPoint;
6818 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6819 TargetPoint.y, 100);
6823 AnchorAlertOn2 =
false;
6826 if (!bAnchorSoundPlaying) {
6827 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6828 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6829 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6830 if (g_anchorwatch_sound->IsOk()) {
6831 bAnchorSoundPlaying =
true;
6832 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6833 g_anchorwatch_sound->Play();
6839void ChartCanvas::UpdateShips() {
6842 wxClientDC dc(
this);
6843 if (!dc.IsOk())
return;
6845 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6846 if (!test_bitmap.IsOk())
return;
6848 wxMemoryDC temp_dc(test_bitmap);
6850 temp_dc.ResetBoundingBox();
6851 temp_dc.DestroyClippingRegion();
6852 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6858 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6859 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6863 ocpndc.CalcBoundingBox(px.x, px.y);
6868 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6869 temp_dc.MaxY() - temp_dc.MinY());
6871 wxRect own_ship_update_rect = ship_draw_rect;
6873 if (!own_ship_update_rect.IsEmpty()) {
6876 own_ship_update_rect.Union(ship_draw_last_rect);
6877 own_ship_update_rect.Inflate(2);
6880 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6882 ship_draw_last_rect = ship_draw_rect;
6884 temp_dc.SelectObject(wxNullBitmap);
6887void ChartCanvas::UpdateAlerts() {
6892 wxClientDC dc(
this);
6896 dc.GetSize(&sx, &sy);
6899 wxBitmap test_bitmap(sx, sy, -1);
6903 temp_dc.SelectObject(test_bitmap);
6905 temp_dc.ResetBoundingBox();
6906 temp_dc.DestroyClippingRegion();
6907 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6914 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6915 temp_dc.MaxX() - temp_dc.MinX(),
6916 temp_dc.MaxY() - temp_dc.MinY());
6918 if (!alert_rect.IsEmpty())
6919 alert_rect.Inflate(2);
6921 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6924 wxRect alert_update_rect = alert_draw_rect;
6925 alert_update_rect.Union(alert_rect);
6928 RefreshRect(alert_update_rect,
false);
6932 alert_draw_rect = alert_rect;
6934 temp_dc.SelectObject(wxNullBitmap);
6937void ChartCanvas::UpdateAIS() {
6938 if (!g_pAIS)
return;
6943 wxClientDC dc(
this);
6947 dc.GetSize(&sx, &sy);
6955 if (g_pAIS->GetTargetList().size() > 10) {
6956 ais_rect = wxRect(0, 0, sx, sy);
6959 wxBitmap test_bitmap(sx, sy, -1);
6963 temp_dc.SelectObject(test_bitmap);
6965 temp_dc.ResetBoundingBox();
6966 temp_dc.DestroyClippingRegion();
6967 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6971 AISDraw(ocpndc, GetVP(),
this);
6972 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6976 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6977 temp_dc.MaxY() - temp_dc.MinY());
6979 if (!ais_rect.IsEmpty())
6980 ais_rect.Inflate(2);
6982 temp_dc.SelectObject(wxNullBitmap);
6985 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6988 wxRect ais_update_rect = ais_draw_rect;
6989 ais_update_rect.Union(ais_rect);
6992 RefreshRect(ais_update_rect,
false);
6996 ais_draw_rect = ais_rect;
6999void ChartCanvas::ToggleCPAWarn() {
7000 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7006 g_bTCPA_Max =
false;
7010 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
7011 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7013 if (!g_AisFirstTimeUse) {
7014 OCPNMessageBox(
this,
7015 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
7016 _(
"CPA") + _T(
" ") + mess, 4, 4);
7021void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7023void ChartCanvas::OnSize(wxSizeEvent &event) {
7024 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7026 GetClientSize(&m_canvas_width, &m_canvas_height);
7030 m_displayScale = GetContentScaleFactor();
7034 m_canvas_width *= m_displayScale;
7035 m_canvas_height *= m_displayScale;
7048 m_absolute_min_scale_ppm =
7050 (1.2 * WGS84_semimajor_axis_meters * PI);
7053 gFrame->ProcessCanvasResize();
7063 SetMUIBarPosition();
7064 UpdateFollowButtonState();
7065 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7069 xr_margin = m_canvas_width * 95 / 100;
7070 xl_margin = m_canvas_width * 5 / 100;
7071 yt_margin = m_canvas_height * 5 / 100;
7072 yb_margin = m_canvas_height * 95 / 100;
7075 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7080 m_brepaint_piano =
true;
7083 m_dc_route.SelectObject(wxNullBitmap);
7086 m_dc_route.SelectObject(*proute_bm);
7100 m_glcc->OnSize(event);
7109void ChartCanvas::ProcessNewGUIScale() {
7117void ChartCanvas::CreateMUIBar() {
7118 if (g_useMUI && !m_muiBar) {
7122 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
7124 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7125 m_muiBar->SetColorScheme(m_cs);
7126 m_muiBarHOSize = m_muiBar->m_size;
7130 SetMUIBarPosition();
7131 UpdateFollowButtonState();
7132 m_muiBar->UpdateDynamicValues();
7133 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7137void ChartCanvas::SetMUIBarPosition() {
7141 int pianoWidth = GetClientSize().x * 0.6f;
7146 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7147 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7149 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7150 m_muiBar->SetColorScheme(m_cs);
7154 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7155 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7157 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7158 m_muiBar->SetColorScheme(m_cs);
7162 m_muiBar->SetBestPosition();
7166void ChartCanvas::DestroyMuiBar() {
7173void ChartCanvas::ShowCompositeInfoWindow(
7174 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7176 if (NULL == m_pCIWin) {
7181 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7184 s = _(
"Composite of ");
7187 s1.Printf(
"%d ", n_charts);
7195 s1.Printf(_(
"Chart scale"));
7198 s2.Printf(
"1:%d\n",
scale);
7202 s1 = _(
"Zoom in for more information");
7206 int char_width = s1.Length();
7207 int char_height = 3;
7209 if (g_bChartBarEx) {
7212 for (
int i : index_vector) {
7214 wxString path = cte.GetFullSystemPath();
7218 char_width = wxMax(char_width, path.Length());
7219 if (j++ >= 9)
break;
7222 s +=
" .\n .\n .\n";
7231 m_pCIWin->SetString(s);
7233 m_pCIWin->FitToChars(char_width, char_height);
7236 p.x = x / GetContentScaleFactor();
7237 if ((p.x + m_pCIWin->GetWinSize().x) >
7238 (m_canvas_width / GetContentScaleFactor()))
7239 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7240 m_pCIWin->GetWinSize().x) /
7243 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7244 4 - m_pCIWin->GetWinSize().y;
7246 m_pCIWin->dbIndex = 0;
7247 m_pCIWin->chart_scale = 0;
7248 m_pCIWin->SetPosition(p);
7249 m_pCIWin->SetBitmap();
7250 m_pCIWin->Refresh();
7254 HideChartInfoWindow();
7258void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7260 if (NULL == m_pCIWin) {
7265 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7272 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
7273 pc = ChartData->OpenChartFromDBAndLock(
7274 dbIndex, FULL_INIT);
7276 int char_width, char_height;
7277 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7278 if (pc) ChartData->UnLockCacheChart(dbIndex);
7280 m_pCIWin->SetString(s);
7281 m_pCIWin->FitToChars(char_width, char_height);
7284 p.x = x / GetContentScaleFactor();
7285 if ((p.x + m_pCIWin->GetWinSize().x) >
7286 (m_canvas_width / GetContentScaleFactor()))
7287 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7288 m_pCIWin->GetWinSize().x) /
7291 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7292 4 - m_pCIWin->GetWinSize().y;
7294 m_pCIWin->dbIndex = dbIndex;
7295 m_pCIWin->SetPosition(p);
7296 m_pCIWin->SetBitmap();
7297 m_pCIWin->Refresh();
7301 HideChartInfoWindow();
7305void ChartCanvas::HideChartInfoWindow(
void) {
7308 m_pCIWin->Destroy();
7312 androidForceFullRepaint();
7317void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7318 wxMouseEvent ev(wxEVT_MOTION);
7321 ev.m_leftDown = mouse_leftisdown;
7323 wxEvtHandler *evthp = GetEventHandler();
7325 ::wxPostEvent(evthp, ev);
7328void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7329 if ((m_panx_target_final - m_panx_target_now) ||
7330 (m_pany_target_final - m_pany_target_now)) {
7331 DoTimedMovementTarget();
7336void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7338bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7340 if (m_disable_edge_pan)
return false;
7343 int pan_margin = m_canvas_width * margin / 100;
7344 int pan_timer_set = 200;
7345 double pan_delta = GetVP().
pix_width * delta / 100;
7349 if (x > m_canvas_width - pan_margin) {
7354 else if (x < pan_margin) {
7359 if (y < pan_margin) {
7364 else if (y > m_canvas_height - pan_margin) {
7373 wxMouseState state = ::wxGetMouseState();
7374#if wxCHECK_VERSION(3, 0, 0)
7375 if (!state.LeftIsDown())
7377 if (!state.LeftDown())
7382 if ((bft) && !pPanTimer->IsRunning()) {
7384 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7390 if ((!bft) && pPanTimer->IsRunning()) {
7400void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7401 bool setBeingEdited) {
7402 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7403 m_pRoutePointEditTarget = NULL;
7404 m_pFoundPoint = NULL;
7408 SelectableItemList SelList = pSelect->FindSelectionList(
7410 wxSelectableItemListNode *node = SelList.GetFirst();
7412 pFind = node->GetData();
7421 bool brp_viz =
false;
7422 if (m_pEditRouteArray) {
7423 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7424 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7425 if (pr->IsVisible()) {
7431 brp_viz = frp->IsVisible();
7435 if (m_pEditRouteArray)
7437 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7438 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7441 m_bRouteEditing = setBeingEdited;
7444 frp->m_bRPIsBeingEdited = setBeingEdited;
7445 m_bMarkEditing = setBeingEdited;
7448 m_pRoutePointEditTarget = frp;
7449 m_pFoundPoint = pFind;
7453 node = node->GetNext();
7457void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7458 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7459 singleClickEventIsValid =
false;
7460 m_DoubleClickTimer->Stop();
7465bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7466 if (!m_bChartDragging && !m_bDrawingRoute) {
7471 if (m_Compass && m_Compass->IsShown()) {
7473 bool isInCompass = logicalRect.Contains(event.GetPosition());
7475 if (m_Compass->MouseEvent(event)) {
7476 cursor_region = CENTER;
7477 if (!g_btouch) SetCanvasCursor(event);
7483 if (m_notification_button && m_notification_button->IsShown()) {
7485 bool isinButton = logicalRect.Contains(event.GetPosition());
7487 SetCursor(*pCursorArrow);
7488 if (event.LeftDown()) HandleNotificationMouseClick();
7493 if (MouseEventToolbar(event))
return true;
7495 if (MouseEventChartBar(event))
return true;
7497 if (MouseEventMUIBar(event))
return true;
7499 if (MouseEventIENCBar(event))
return true;
7504void ChartCanvas::HandleNotificationMouseClick() {
7505 if (!m_NotificationsList) {
7509 m_NotificationsList->RecalculateSize();
7510 m_NotificationsList->Hide();
7513 if (m_NotificationsList->IsShown()) {
7514 m_NotificationsList->Hide();
7516 m_NotificationsList->RecalculateSize();
7517 m_NotificationsList->ReloadNotificationList();
7518 m_NotificationsList->Show();
7521bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7522 if (!g_bShowChartBar)
return false;
7524 if (!m_Piano->MouseEvent(event))
return false;
7526 cursor_region = CENTER;
7527 if (!g_btouch) SetCanvasCursor(event);
7531bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7532 if (!IsPrimaryCanvas())
return false;
7534 if (g_MainToolbar) {
7535 if (!g_MainToolbar->MouseEvent(event))
7538 g_MainToolbar->RefreshToolbar();
7541 cursor_region = CENTER;
7542 if (!g_btouch) SetCanvasCursor(event);
7546bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7547 if (!IsPrimaryCanvas())
return false;
7549 if (g_iENCToolbar) {
7550 if (!g_iENCToolbar->MouseEvent(event))
7553 g_iENCToolbar->RefreshToolbar();
7560bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7562 if (!m_muiBar->MouseEvent(event))
return false;
7565 cursor_region = CENTER;
7566 if (!g_btouch) SetCanvasCursor(event);
7578 event.GetPosition(&x, &y);
7580 x *= m_displayScale;
7581 y *= m_displayScale;
7583 m_MouseDragging =
event.Dragging();
7589 if (event.Dragging()) {
7590 if ((x == mouse_x) && (y == mouse_y))
return true;
7596 mouse_leftisdown =
event.LeftDown();
7600 cursor_region = CENTER;
7604 if (m_Compass && m_Compass->IsShown() &&
7605 m_Compass->
GetRect().Contains(event.GetPosition())) {
7606 cursor_region = CENTER;
7607 }
else if (x > xr_margin) {
7608 cursor_region = MID_RIGHT;
7609 }
else if (x < xl_margin) {
7610 cursor_region = MID_LEFT;
7611 }
else if (y > yb_margin - chartbar_height &&
7612 y < m_canvas_height - chartbar_height) {
7613 cursor_region = MID_TOP;
7614 }
else if (y < yt_margin) {
7615 cursor_region = MID_BOT;
7617 cursor_region = CENTER;
7620 if (!g_btouch) SetCanvasCursor(event);
7624 leftIsDown =
event.LeftDown();
7627 if (event.LeftDown()) {
7628 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7631 g_bTempShowMenuBar =
false;
7632 parent_frame->ApplyGlobalSettings(
false);
7640 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7641 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7645 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7646 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7649 event.SetEventObject(
this);
7650 if (SendMouseEventToPlugins(event))
7657 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7658 StartChartDragInertia();
7661 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7663 if (m_DoubleClickTimer->IsRunning()) {
7664 m_DoubleClickTimer->Stop();
7669 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7670 singleClickEvent = event;
7671 singleClickEventIsValid =
true;
7680 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7681 if (g_click_stop > 0) {
7689 if (GetUpMode() == COURSE_UP_MODE) {
7690 m_b_rot_hidef =
false;
7691 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7693 pRotDefTimer->Stop();
7696 bool bRoll = !g_btouch;
7698 bRoll = g_bRollover;
7701 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7702 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7703 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7704 m_RolloverPopupTimer.Start(
7708 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7712 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7721#if !defined(__WXGTK__) && !defined(__WXQT__)
7729 if ((x >= 0) && (y >= 0))
7734 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7735 wxPoint p = ClientToScreen(wxPoint(x, y));
7741 if (m_routeState >= 2) {
7744 m_bDrawingRoute =
true;
7746 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7751 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7754 m_bDrawingRoute =
true;
7756 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7763void ChartCanvas::CallPopupMenu(
int x,
int y) {
7771 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7780#if defined(__WXMAC__) || defined(__ANDROID__)
7784 wxClientDC cdc(GetParent());
7796 if (m_pSelectedRoute) {
7798 m_pSelectedRoute->DeSelectRoute();
7800 if (g_bopengl && m_glcc) {
7805 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7808 if (m_pFoundRoutePoint) {
7816 if (g_btouch && m_pRoutePointEditTarget) {
7819 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7824 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7825 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7826 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7827 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7831 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7834 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7840 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7843 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7844 seltype |= SELTYPE_AISTARGET;
7849 m_pFoundRoutePoint = NULL;
7854 Route *pSelectedActiveRoute = NULL;
7855 Route *pSelectedVizRoute = NULL;
7859 SelectableItemList SelList =
7860 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7861 wxSelectableItemListNode *node = SelList.GetFirst();
7871 bool brp_viz =
false;
7873 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7875 if (pr->IsVisible()) {
7880 if (!brp_viz && prp->IsShared())
7882 brp_viz = prp->IsVisible();
7885 brp_viz = prp->IsVisible();
7887 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7892 m_pSelectedRoute = NULL;
7894 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7897 pSelectedActiveRoute = pr;
7898 pFoundActiveRoutePoint = prp;
7903 if (NULL == pSelectedVizRoute) {
7904 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7906 if (pr->IsVisible()) {
7907 pSelectedVizRoute = pr;
7908 pFoundVizRoutePoint = prp;
7914 delete proute_array;
7917 node = node->GetNext();
7921 if (pFoundActiveRoutePoint) {
7922 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7923 m_pSelectedRoute = pSelectedActiveRoute;
7924 }
else if (pFoundVizRoutePoint) {
7925 m_pFoundRoutePoint = pFoundVizRoutePoint;
7926 m_pSelectedRoute = pSelectedVizRoute;
7929 m_pFoundRoutePoint = pFirstVizPoint;
7931 if (m_pSelectedRoute) {
7932 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7933 }
else if (m_pFoundRoutePoint)
7934 seltype |= SELTYPE_MARKPOINT;
7938 if (m_pFoundRoutePoint) {
7942 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7943 RefreshRect(wp_rect,
true);
7952 SelectableItemList SelList =
7953 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7955 if (NULL == m_pSelectedRoute)
7958 wxSelectableItemListNode *node = SelList.GetFirst();
7963 if (pr->IsVisible()) {
7964 m_pSelectedRoute = pr;
7967 node = node->GetNext();
7971 if (m_pSelectedRoute) {
7972 if (NULL == m_pFoundRoutePoint)
7973 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7978 if (g_bopengl && m_glcc) {
7983 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7986 seltype |= SELTYPE_ROUTESEGMENT;
7990 if (pFindTrackSeg) {
7991 m_pSelectedTrack = NULL;
7993 SelectableItemList SelList =
7994 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7997 wxSelectableItemListNode *node = SelList.GetFirst();
8002 if (pt->IsVisible()) {
8003 m_pSelectedTrack = pt;
8006 node = node->GetNext();
8009 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8012 bool bseltc =
false;
8026 SelectableItemList SelList = pSelectTC->FindSelectionList(
8030 wxSelectableItemListNode *node = SelList.GetFirst();
8031 pFind = node->GetData();
8032 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8034 if (SelList.GetCount() > 1) {
8035 node = node->GetNext();
8037 pFind = node->GetData();
8039 if (pIDX_candidate->
IDX_type ==
'c') {
8040 pIDX_best_candidate = pIDX_candidate;
8044 node = node->GetNext();
8047 wxSelectableItemListNode *node = SelList.GetFirst();
8048 pFind = node->GetData();
8049 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8052 m_pIDXCandidate = pIDX_best_candidate;
8055 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
8059 seltype |= SELTYPE_CURRENTPOINT;
8062 else if (pFindTide) {
8063 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8066 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
8070 seltype |= SELTYPE_TIDEPOINT;
8074 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8077 InvokeCanvasMenu(x, y, seltype);
8080 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8084 m_pSelectedRoute = NULL;
8086 if (m_pFoundRoutePoint) {
8087 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8090 m_pFoundRoutePoint = NULL;
8098bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8106 event.GetPosition(&x, &y);
8112 SelectRadius = g_Platform->GetSelectRadiusPix() /
8113 (m_true_scale_ppm * 1852 * 60);
8120 if (event.LeftDClick() && (cursor_region == CENTER)) {
8121 m_DoubleClickTimer->Start();
8122 singleClickEventIsValid =
false;
8126 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8131 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8134 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8135 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8136 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8142 SelectableItemList rpSelList =
8143 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8144 wxSelectableItemListNode *node = rpSelList.GetFirst();
8145 bool b_onRPtarget =
false;
8149 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8150 b_onRPtarget =
true;
8153 node = node->GetNext();
8158 if (m_pRoutePointEditTarget) {
8160 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8166 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8169 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8170 m_pRoutePointEditTarget = NULL;
8171 RefreshRect(wp_rect,
true);
8175 node = rpSelList.GetFirst();
8180 wxArrayPtrVoid *proute_array =
8185 bool brp_viz =
false;
8187 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8189 if (pr->IsVisible()) {
8194 delete proute_array;
8198 brp_viz = frp->IsVisible();
8200 brp_viz = frp->IsVisible();
8203 ShowMarkPropertiesDialog(frp);
8211 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8215 if (pr->IsVisible()) {
8216 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8221 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8225 if (pt->IsVisible()) {
8226 ShowTrackPropertiesDialog(pt);
8233 ShowObjectQueryWindow(x, y, zlat, zlon);
8238 if (event.LeftDown()) {
8254 bool appending =
false;
8255 bool inserting =
false;
8258 SetCursor(*pCursorPencil);
8262 m_bRouteEditing =
true;
8264 if (m_routeState == 1) {
8265 m_pMouseRoute =
new Route();
8266 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8267 pRouteList->Append(m_pMouseRoute);
8276 double nearby_radius_meters =
8277 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8280 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8281 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8282 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8283 wxArrayPtrVoid *proute_array =
8288 bool brp_viz =
false;
8290 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8292 if (pr->IsVisible()) {
8297 delete proute_array;
8299 pNearbyPoint->IsShared())
8302 pNearbyPoint->IsVisible();
8304 brp_viz = pNearbyPoint->IsVisible();
8307 wxString msg = _(
"Use nearby waypoint?");
8309 const bool noname(pNearbyPoint->GetName() ==
"");
8312 _(
"Use nearby nameless waypoint and name it M with"
8313 " a unique number?");
8316 m_FinishRouteOnKillFocus =
false;
8318 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8319 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8320 m_FinishRouteOnKillFocus =
true;
8321 if (dlg_return == wxID_YES) {
8323 if (m_pMouseRoute) {
8324 int last_wp_num = m_pMouseRoute->GetnPoints();
8326 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8327 wxString wp_name = wxString::Format(
8328 "M%002i-%s", last_wp_num + 1, guid_short);
8329 pNearbyPoint->SetName(wp_name);
8331 pNearbyPoint->SetName(
"WPXX");
8333 pMousePoint = pNearbyPoint;
8336 if (m_routeState > 1)
8337 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8338 Undo_HasParent, NULL);
8341 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8342 bool procede =
false;
8346 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8352 m_FinishRouteOnKillFocus =
false;
8358 _(
"Insert first part of this route in the new route?");
8359 if (tail->GetIndexOf(pMousePoint) ==
8362 dmsg = _(
"Insert this route in the new route?");
8364 if (tail->GetIndexOf(pMousePoint) != 1) {
8365 dlg_return = OCPNMessageBox(
8366 this, dmsg, _(
"OpenCPN Route Create"),
8367 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8368 m_FinishRouteOnKillFocus =
true;
8370 if (dlg_return == wxID_YES) {
8377 _(
"Append last part of this route to the new route?");
8378 if (tail->GetIndexOf(pMousePoint) == 1)
8380 "Append this route to the new route?");
8385 if (tail->GetLastPoint() != pMousePoint) {
8386 dlg_return = OCPNMessageBox(
8387 this, dmsg, _(
"OpenCPN Route Create"),
8388 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8389 m_FinishRouteOnKillFocus =
true;
8391 if (dlg_return == wxID_YES) {
8402 if (!FindRouteContainingWaypoint(pMousePoint))
8403 pMousePoint->SetShared(
true);
8408 if (NULL == pMousePoint) {
8409 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8410 _T(
""), wxEmptyString);
8411 pMousePoint->SetNameShown(
false);
8415 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8417 if (m_routeState > 1)
8418 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8419 Undo_IsOrphanded, NULL);
8422 if (m_pMouseRoute) {
8423 if (m_routeState == 1) {
8425 m_pMouseRoute->AddPoint(pMousePoint);
8429 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8430 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8431 &rhumbBearing, &rhumbDist);
8432 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8433 rlat, &gcDist, &gcBearing, NULL);
8434 double gcDistNM = gcDist / 1852.0;
8437 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8438 pow(rhumbDist - gcDistNM - 1, 0.5);
8441 msg << _(
"For this leg the Great Circle route is ")
8442 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8443 << _(
" shorter than rhumbline.\n\n")
8444 << _(
"Would you like include the Great Circle routing points "
8447 m_FinishRouteOnKillFocus =
false;
8448 m_disable_edge_pan =
true;
8451 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8452 wxYES_NO | wxNO_DEFAULT);
8454 m_disable_edge_pan =
false;
8455 m_FinishRouteOnKillFocus =
true;
8457 if (answer == wxID_YES) {
8459 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8460 wxRealPoint gcCoord;
8462 for (
int i = 1; i <= segmentCount; i++) {
8463 double fraction = (double)i * (1.0 / (
double)segmentCount);
8464 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8465 gcDist * fraction, gcBearing,
8466 &gcCoord.x, &gcCoord.y, NULL);
8468 if (i < segmentCount) {
8469 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8470 _T(
""), wxEmptyString);
8471 gcPoint->SetNameShown(
false);
8473 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8475 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8478 gcPoint = pMousePoint;
8481 m_pMouseRoute->AddPoint(gcPoint);
8482 pSelect->AddSelectableRouteSegment(
8483 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8484 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8485 prevGcPoint = gcPoint;
8488 undo->CancelUndoableAction(
true);
8491 m_pMouseRoute->AddPoint(pMousePoint);
8492 pSelect->AddSelectableRouteSegment(
8493 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8494 pMousePoint, m_pMouseRoute);
8495 undo->AfterUndoableAction(m_pMouseRoute);
8499 m_pMouseRoute->AddPoint(pMousePoint);
8500 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8501 rlon, m_prev_pMousePoint,
8502 pMousePoint, m_pMouseRoute);
8503 undo->AfterUndoableAction(m_pMouseRoute);
8509 m_prev_pMousePoint = pMousePoint;
8517 int connect = tail->GetIndexOf(pMousePoint);
8522 int length = tail->GetnPoints();
8527 start = connect + 1;
8532 m_pMouseRoute->RemovePoint(
8536 for (i = start; i <= stop; i++) {
8537 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8540 m_pMouseRoute->GetnPoints();
8542 gFrame->RefreshAllCanvas();
8546 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8548 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8549 m_pMouseRoute->FinalizeForRendering();
8551 gFrame->RefreshAllCanvas();
8555 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8557 SetCursor(*pCursorPencil);
8559 if (!m_pMeasureRoute) {
8560 m_pMeasureRoute =
new Route();
8561 pRouteList->Append(m_pMeasureRoute);
8564 if (m_nMeasureState == 1) {
8570 wxString(_T (
"circle" )),
8571 wxEmptyString, wxEmptyString);
8573 pMousePoint->SetShowWaypointRangeRings(
false);
8575 m_pMeasureRoute->AddPoint(pMousePoint);
8579 m_prev_pMousePoint = pMousePoint;
8583 gFrame->RefreshAllCanvas();
8588 FindRoutePointsAtCursor(SelectRadius,
true);
8593 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8601 if (ret)
return true;
8604 if (event.Dragging()) {
8609 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8611 SelectableItemList SelList = pSelect->FindSelectionList(
8613 wxSelectableItemListNode *node = SelList.GetFirst();
8615 pFind = node->GetData();
8617 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8618 node = node->GetNext();
8623 if (m_pRoutePointEditTarget &&
8624 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8626 SelectableItemList SelList = pSelect->FindSelectionList(
8628 wxSelectableItemListNode *node = SelList.GetFirst();
8630 pFind = node->GetData();
8632 if (m_pRoutePointEditTarget == frp) {
8633 m_bIsInRadius =
true;
8636 node = node->GetNext();
8639 if (!m_dragoffsetSet) {
8641 .PresetDragOffset(
this, mouse_x, mouse_y);
8642 m_dragoffsetSet =
true;
8647 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8648 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8650 if (NULL == g_pMarkInfoDialog) {
8651 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8652 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8653 DraggingAllowed =
false;
8655 if (m_pRoutePointEditTarget &&
8656 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8657 DraggingAllowed =
false;
8659 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8661 if (DraggingAllowed) {
8662 if (!undo->InUndoableAction()) {
8663 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8664 Undo_NeedsCopy, m_pFoundPoint);
8670 if (!g_bopengl && m_pEditRouteArray) {
8671 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8672 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8677 if (g_pRouteMan->IsRouteValid(pr)) {
8679 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8680 pre_rect.Union(route_rect);
8688 if (CheckEdgePan(x, y,
true, 5, 2))
8696 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8698 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8699 m_pRoutePointEditTarget,
8700 SELTYPE_DRAGHANDLE);
8701 m_pFoundPoint->m_slat =
8702 m_pRoutePointEditTarget->m_lat;
8703 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8705 m_pRoutePointEditTarget->m_lat =
8707 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8708 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8709 m_pFoundPoint->m_slat =
8711 m_pFoundPoint->m_slon = new_cursor_lon;
8715 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8716 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8717 g_pMarkInfoDialog->UpdateProperties(
true);
8727 if (m_pEditRouteArray) {
8728 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8730 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8731 if (g_pRouteMan->IsRouteValid(pr)) {
8733 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8734 post_rect.Union(route_rect);
8740 pre_rect.Union(post_rect);
8741 RefreshRect(pre_rect,
false);
8743 gFrame->RefreshCanvasOther(
this);
8744 m_bRoutePoinDragging =
true;
8749 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8750 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8752 if (NULL == g_pMarkInfoDialog) {
8753 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8754 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8755 DraggingAllowed =
false;
8757 if (m_pRoutePointEditTarget &&
8758 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8759 DraggingAllowed =
false;
8761 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8763 if (DraggingAllowed) {
8764 if (!undo->InUndoableAction()) {
8765 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8766 Undo_NeedsCopy, m_pFoundPoint);
8774 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8775 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8777 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8778 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8780 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8786 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8787 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8788 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8789 (
int)(lppmax - (pre_rect.height / 2)));
8797 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8800 m_pRoutePointEditTarget,
8801 SELTYPE_DRAGHANDLE);
8802 m_pFoundPoint->m_slat =
8803 m_pRoutePointEditTarget->m_lat;
8804 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8806 m_pRoutePointEditTarget->m_lat =
8809 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8815 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8816 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8817 g_pMarkInfoDialog->UpdateProperties(
true);
8822 if (!g_btouch) InvalidateGL();
8828 .CalculateDCRect(m_dc_route,
this, &post_rect);
8829 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8830 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8831 (
int)(lppmax - (post_rect.height / 2)));
8834 pre_rect.Union(post_rect);
8835 RefreshRect(pre_rect,
false);
8837 gFrame->RefreshCanvasOther(
this);
8838 m_bRoutePoinDragging =
true;
8843 if (ret)
return true;
8846 if (event.LeftUp()) {
8847 bool b_startedit_route =
false;
8848 m_dragoffsetSet =
false;
8851 m_bChartDragging =
false;
8852 m_bIsInRadius =
false;
8857 m_bedge_pan =
false;
8862 bool appending =
false;
8863 bool inserting =
false;
8869 if (m_pRoutePointEditTarget) {
8875 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8876 RefreshRect(wp_rect,
true);
8878 m_pRoutePointEditTarget = NULL;
8880 m_bRouteEditing =
true;
8882 if (m_routeState == 1) {
8883 m_pMouseRoute =
new Route();
8884 m_pMouseRoute->SetHiLite(50);
8885 pRouteList->Append(m_pMouseRoute);
8888 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8895 double nearby_radius_meters =
8896 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8899 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8900 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8901 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8904 m_FinishRouteOnKillFocus =
8906 dlg_return = OCPNMessageBox(
8907 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8908 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8909 m_FinishRouteOnKillFocus =
true;
8911 dlg_return = wxID_YES;
8913 if (dlg_return == wxID_YES) {
8914 pMousePoint = pNearbyPoint;
8917 if (m_routeState > 1)
8918 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8919 Undo_HasParent, NULL);
8920 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8922 bool procede =
false;
8926 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8932 m_FinishRouteOnKillFocus =
false;
8933 if (m_routeState == 1) {
8937 _(
"Insert first part of this route in the new route?");
8938 if (tail->GetIndexOf(pMousePoint) ==
8941 dmsg = _(
"Insert this route in the new route?");
8943 if (tail->GetIndexOf(pMousePoint) != 1) {
8945 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8946 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8947 m_FinishRouteOnKillFocus =
true;
8949 if (dlg_return == wxID_YES) {
8956 _(
"Append last part of this route to the new route?");
8957 if (tail->GetIndexOf(pMousePoint) == 1)
8959 "Append this route to the new route?");
8963 if (tail->GetLastPoint() != pMousePoint) {
8965 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8966 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8967 m_FinishRouteOnKillFocus =
true;
8969 if (dlg_return == wxID_YES) {
8980 if (!FindRouteContainingWaypoint(pMousePoint))
8981 pMousePoint->SetShared(
true);
8985 if (NULL == pMousePoint) {
8986 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8987 _T(
""), wxEmptyString);
8988 pMousePoint->SetNameShown(
false);
8990 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8992 if (m_routeState > 1)
8993 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8994 Undo_IsOrphanded, NULL);
8997 if (m_routeState == 1) {
8999 m_pMouseRoute->AddPoint(pMousePoint);
9000 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9004 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9005 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9006 &rhumbBearing, &rhumbDist);
9007 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9008 &gcDist, &gcBearing, NULL);
9009 double gcDistNM = gcDist / 1852.0;
9012 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9013 pow(rhumbDist - gcDistNM - 1, 0.5);
9016 msg << _(
"For this leg the Great Circle route is ")
9017 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
9018 << _(
" shorter than rhumbline.\n\n")
9019 << _(
"Would you like include the Great Circle routing points "
9023 m_FinishRouteOnKillFocus =
false;
9024 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9025 wxYES_NO | wxNO_DEFAULT);
9026 m_FinishRouteOnKillFocus =
true;
9028 int answer = wxID_NO;
9031 if (answer == wxID_YES) {
9033 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9034 wxRealPoint gcCoord;
9036 for (
int i = 1; i <= segmentCount; i++) {
9037 double fraction = (double)i * (1.0 / (
double)segmentCount);
9038 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9039 gcDist * fraction, gcBearing,
9040 &gcCoord.x, &gcCoord.y, NULL);
9042 if (i < segmentCount) {
9043 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
9044 _T(
""), wxEmptyString);
9045 gcPoint->SetNameShown(
false);
9046 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9049 gcPoint = pMousePoint;
9052 m_pMouseRoute->AddPoint(gcPoint);
9053 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9055 pSelect->AddSelectableRouteSegment(
9056 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9057 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9058 prevGcPoint = gcPoint;
9061 undo->CancelUndoableAction(
true);
9064 m_pMouseRoute->AddPoint(pMousePoint);
9065 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9066 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9067 rlon, m_prev_pMousePoint,
9068 pMousePoint, m_pMouseRoute);
9069 undo->AfterUndoableAction(m_pMouseRoute);
9073 m_pMouseRoute->AddPoint(pMousePoint);
9074 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9076 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9077 rlon, m_prev_pMousePoint,
9078 pMousePoint, m_pMouseRoute);
9079 undo->AfterUndoableAction(m_pMouseRoute);
9085 m_prev_pMousePoint = pMousePoint;
9092 int connect = tail->GetIndexOf(pMousePoint);
9097 int length = tail->GetnPoints();
9102 start = connect + 1;
9107 m_pMouseRoute->RemovePoint(
9111 for (i = start; i <= stop; i++) {
9112 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9115 m_pMouseRoute->GetnPoints();
9117 gFrame->RefreshAllCanvas();
9121 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9123 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9124 m_pMouseRoute->FinalizeForRendering();
9129 }
else if (m_bMeasure_Active && m_nMeasureState)
9132 m_bedge_pan =
false;
9136 if (m_nMeasureState == 1) {
9137 m_pMeasureRoute =
new Route();
9138 pRouteList->Append(m_pMeasureRoute);
9143 if (m_pMeasureRoute) {
9146 wxEmptyString, wxEmptyString);
9149 m_pMeasureRoute->AddPoint(pMousePoint);
9153 m_prev_pMousePoint = pMousePoint;
9155 m_pMeasureRoute->GetnPoints();
9159 CancelMeasureRoute();
9165 bool bSelectAllowed =
true;
9166 if (NULL == g_pMarkInfoDialog) {
9167 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9168 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9169 bSelectAllowed =
false;
9176 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9178 if (bSelectAllowed) {
9179 bool b_was_editing_mark = m_bMarkEditing;
9180 bool b_was_editing_route = m_bRouteEditing;
9181 FindRoutePointsAtCursor(SelectRadius,
9187 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9188 m_pRoutePointEditTarget = NULL;
9190 if (!b_was_editing_route) {
9191 if (m_pEditRouteArray) {
9192 b_startedit_route =
true;
9196 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9197 m_pTrackRolloverWin->IsActive(
false);
9199 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9200 m_pRouteRolloverWin->IsActive(
false);
9204 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9206 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9211 if (g_pRouteMan->IsRouteValid(pr)) {
9214 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9215 pre_rect.Union(route_rect);
9218 RefreshRect(pre_rect,
true);
9221 b_startedit_route =
false;
9225 if (m_pRoutePointEditTarget) {
9226 if (b_was_editing_mark ||
9227 b_was_editing_route) {
9228 if (m_lastRoutePointEditTarget) {
9232 .EnableDragHandle(
false);
9233 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9234 SELTYPE_DRAGHANDLE);
9238 if (m_pRoutePointEditTarget) {
9241 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9242 wxPoint2DDouble dragHandlePoint =
9244 .GetDragHandlePoint(
this);
9245 pSelect->AddSelectablePoint(
9246 dragHandlePoint.m_y, dragHandlePoint.m_x,
9247 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9250 if (m_lastRoutePointEditTarget) {
9254 .EnableDragHandle(
false);
9255 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9256 SELTYPE_DRAGHANDLE);
9259 wxArrayPtrVoid *lastEditRouteArray =
9261 m_lastRoutePointEditTarget);
9262 if (lastEditRouteArray) {
9263 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9265 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9266 if (g_pRouteMan->IsRouteValid(pr)) {
9270 delete lastEditRouteArray;
9281 if (m_lastRoutePointEditTarget) {
9284 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9285 RefreshRect(wp_rect,
true);
9288 if (m_pRoutePointEditTarget) {
9291 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9292 RefreshRect(wp_rect,
true);
9301 bool b_start_rollover =
false;
9302 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9303 SelectItem *pFind = pSelectAIS->FindSelection(
9305 if (pFind) b_start_rollover =
true;
9308 if (!b_start_rollover && !b_startedit_route) {
9309 SelectableItemList SelList = pSelect->FindSelectionList(
9311 wxSelectableItemListNode *node = SelList.GetFirst();
9317 if (pr && pr->IsVisible()) {
9318 b_start_rollover =
true;
9321 node = node->GetNext();
9325 if (!b_start_rollover && !b_startedit_route) {
9326 SelectableItemList SelList = pSelect->FindSelectionList(
9328 wxSelectableItemListNode *node = SelList.GetFirst();
9334 if (tr && tr->IsVisible()) {
9335 b_start_rollover =
true;
9338 node = node->GetNext();
9342 if (b_start_rollover)
9343 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9347 bool appending =
false;
9348 bool inserting =
false;
9350 if (m_bRouteEditing ) {
9352 if (m_pRoutePointEditTarget) {
9358 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9359 double nearby_radius_meters =
9360 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9361 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9362 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9363 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9365 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9369 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9371 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9386 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9391 OCPNMessageBox(
this,
9392 _(
"Replace this RoutePoint by the nearby "
9394 _(
"OpenCPN RoutePoint change"),
9395 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9396 if (dlg_return == wxID_YES) {
9401 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9404 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9406 if (tail && current && (tail != current)) {
9408 connect = tail->GetIndexOf(pNearbyPoint);
9409 int index_current_route =
9410 current->GetIndexOf(m_pRoutePointEditTarget);
9411 index_last = current->GetIndexOf(current->GetLastPoint());
9412 dlg_return1 = wxID_NO;
9414 index_current_route) {
9416 if (connect != tail->GetnPoints()) {
9419 _(
"Last part of route to be appended to dragged "
9423 _(
"Full route to be appended to dragged route?");
9425 dlg_return1 = OCPNMessageBox(
9426 this, dmsg, _(
"OpenCPN Route Create"),
9427 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9428 if (dlg_return1 == wxID_YES) {
9432 }
else if (index_current_route ==
9437 _(
"First part of route to be inserted into dragged "
9439 if (connect == tail->GetnPoints())
9441 "Full route to be inserted into dragged route?");
9443 dlg_return1 = OCPNMessageBox(
9444 this, dmsg, _(
"OpenCPN Route Create"),
9445 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9446 if (dlg_return1 == wxID_YES) {
9453 if (m_pRoutePointEditTarget->IsShared()) {
9455 dlg_return = OCPNMessageBox(
9457 _(
"Do you really want to delete and replace this "
9459 _T(
"\n") + _(
"which has been created manually?"),
9460 (
"OpenCPN RoutePoint warning"),
9461 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9464 if (dlg_return == wxID_YES) {
9465 pMousePoint = pNearbyPoint;
9467 pMousePoint->SetShared(
true);
9477 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9479 if (m_pEditRouteArray) {
9480 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9482 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9483 if (g_pRouteMan->IsRouteValid(pr)) {
9489 pSelect->DeleteAllSelectableRoutePoints(pr);
9490 pSelect->DeleteAllSelectableRouteSegments(pr);
9495 pSelect->AddAllSelectableRouteSegments(pr);
9496 pSelect->AddAllSelectableRoutePoints(pr);
9498 pr->FinalizeForRendering();
9499 pr->UpdateSegmentDistances();
9500 if (m_bRoutePoinDragging) {
9502 NavObj_dB::GetInstance().UpdateRoute(pr);
9509 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9510 if (m_pEditRouteArray) {
9511 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9513 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9514 if (g_pRouteMan->IsRouteValid(pr)) {
9515 if (pRoutePropDialog->GetRoute() == pr) {
9516 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9532 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9535 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9536 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9537 g_pMarkInfoDialog->Hide();
9539 delete m_pRoutePointEditTarget;
9540 m_lastRoutePointEditTarget = NULL;
9541 m_pRoutePointEditTarget = NULL;
9542 undo->AfterUndoableAction(pMousePoint);
9543 undo->InvalidateUndo();
9548 else if (m_bMarkEditing) {
9549 if (m_pRoutePointEditTarget)
9550 if (m_bRoutePoinDragging) {
9552 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9556 if (m_pRoutePointEditTarget)
9557 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9559 if (!m_pRoutePointEditTarget) {
9560 delete m_pEditRouteArray;
9561 m_pEditRouteArray = NULL;
9562 m_bRouteEditing =
false;
9564 m_bRoutePoinDragging =
false;
9571 int length = tail->GetnPoints();
9572 for (
int i = connect + 1; i <= length; i++) {
9573 current->AddPointAndSegment(tail->GetPoint(i),
false);
9576 gFrame->RefreshAllCanvas();
9579 current->FinalizeForRendering();
9585 pSelect->DeleteAllSelectableRoutePoints(current);
9586 pSelect->DeleteAllSelectableRouteSegments(current);
9587 for (
int i = 1; i < connect; i++) {
9588 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9590 pSelect->AddAllSelectableRouteSegments(current);
9591 pSelect->AddAllSelectableRoutePoints(current);
9592 current->FinalizeForRendering();
9598 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9599 if (m_pEditRouteArray) {
9600 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9601 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9602 if (g_pRouteMan->IsRouteValid(pr)) {
9603 if (pRoutePropDialog->GetRoute() == pr) {
9604 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9614 if (m_bRouteEditing) {
9617 bool appending =
false;
9618 bool inserting =
false;
9621 if (m_pRoutePointEditTarget) {
9622 m_pRoutePointEditTarget->
m_bBlink =
false;
9626 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9627 double nearby_radius_meters =
9628 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9629 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9630 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9631 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9633 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9634 bool duplicate =
false;
9636 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9638 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9653 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9658 OCPNMessageBox(
this,
9659 _(
"Replace this RoutePoint by the nearby "
9661 _(
"OpenCPN RoutePoint change"),
9662 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9663 if (dlg_return == wxID_YES) {
9667 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9670 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9672 if (tail && current && (tail != current)) {
9674 connect = tail->GetIndexOf(pNearbyPoint);
9675 int index_current_route =
9676 current->GetIndexOf(m_pRoutePointEditTarget);
9677 index_last = current->GetIndexOf(current->GetLastPoint());
9678 dlg_return1 = wxID_NO;
9680 index_current_route) {
9682 if (connect != tail->GetnPoints()) {
9685 _(
"Last part of route to be appended to dragged "
9689 _(
"Full route to be appended to dragged route?");
9691 dlg_return1 = OCPNMessageBox(
9692 this, dmsg, _(
"OpenCPN Route Create"),
9693 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9694 if (dlg_return1 == wxID_YES) {
9698 }
else if (index_current_route ==
9703 _(
"First part of route to be inserted into dragged "
9705 if (connect == tail->GetnPoints())
9707 "Full route to be inserted into dragged route?");
9709 dlg_return1 = OCPNMessageBox(
9710 this, dmsg, _(
"OpenCPN Route Create"),
9711 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9712 if (dlg_return1 == wxID_YES) {
9719 if (m_pRoutePointEditTarget->IsShared()) {
9720 dlg_return = wxID_NO;
9721 dlg_return = OCPNMessageBox(
9723 _(
"Do you really want to delete and replace this "
9725 _T(
"\n") + _(
"which has been created manually?"),
9726 (
"OpenCPN RoutePoint warning"),
9727 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9730 if (dlg_return == wxID_YES) {
9731 pMousePoint = pNearbyPoint;
9733 pMousePoint->SetShared(
true);
9743 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9745 if (m_pEditRouteArray) {
9746 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9748 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9749 if (g_pRouteMan->IsRouteValid(pr)) {
9754 pSelect->DeleteAllSelectableRoutePoints(pr);
9755 pSelect->DeleteAllSelectableRouteSegments(pr);
9760 pSelect->AddAllSelectableRouteSegments(pr);
9761 pSelect->AddAllSelectableRoutePoints(pr);
9763 pr->FinalizeForRendering();
9764 pr->UpdateSegmentDistances();
9767 if (m_bRoutePoinDragging) {
9772 NavObj_dB::GetInstance().UpdateRoutePoint(
9773 m_pRoutePointEditTarget);
9775 NavObj_dB::GetInstance().UpdateRoute(pr);
9787 int length = tail->GetnPoints();
9788 for (
int i = connect + 1; i <= length; i++) {
9789 current->AddPointAndSegment(tail->GetPoint(i),
false);
9793 gFrame->RefreshAllCanvas();
9796 current->FinalizeForRendering();
9802 pSelect->DeleteAllSelectableRoutePoints(current);
9803 pSelect->DeleteAllSelectableRouteSegments(current);
9804 for (
int i = 1; i < connect; i++) {
9805 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9807 pSelect->AddAllSelectableRouteSegments(current);
9808 pSelect->AddAllSelectableRoutePoints(current);
9809 current->FinalizeForRendering();
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);
9831 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9834 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9835 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9836 g_pMarkInfoDialog->Hide();
9838 delete m_pRoutePointEditTarget;
9839 m_lastRoutePointEditTarget = NULL;
9840 undo->AfterUndoableAction(pMousePoint);
9841 undo->InvalidateUndo();
9846 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9849 delete m_pEditRouteArray;
9850 m_pEditRouteArray = NULL;
9854 m_bRouteEditing =
false;
9855 m_pRoutePointEditTarget = NULL;
9861 else if (m_bMarkEditing) {
9862 if (m_pRoutePointEditTarget) {
9863 if (m_bRoutePoinDragging) {
9865 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9867 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9872 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9874 RefreshRect(wp_rect,
true);
9877 m_pRoutePointEditTarget = NULL;
9878 m_bMarkEditing =
false;
9883 else if (leftIsDown) {
9888 if (!m_bChartDragging && !m_bMeasure_Active) {
9890 m_bChartDragging =
false;
9894 m_bRoutePoinDragging =
false;
9897 if (ret)
return true;
9900 if (event.RightDown()) {
9911 m_FinishRouteOnKillFocus =
false;
9912 CallPopupMenu(mx, my);
9913 m_FinishRouteOnKillFocus =
true;
9924 if (event.ShiftDown()) {
9928 event.GetPosition(&x, &y);
9930 x *= m_displayScale;
9931 y *= m_displayScale;
9937 int wheel_dir =
event.GetWheelRotation();
9940 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9941 wheel_dir = wheel_dir > 0 ? 1 : -1;
9943 double factor = g_mouse_zoom_sensitivity;
9944 if (wheel_dir < 0) factor = 1 / factor;
9946 if (g_bsmoothpanzoom) {
9947 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9948 if (wheel_dir == m_last_wheel_dir) {
9949 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9954 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9955 m_wheelstopwatch.Start(0);
9960 m_last_wheel_dir = wheel_dir;
9965 if (event.LeftDown()) {
9972 last_drag.x = x, last_drag.y = y;
9973 panleftIsDown =
true;
9976 if (event.LeftUp()) {
9977 if (panleftIsDown) {
9979 panleftIsDown =
false;
9982 if (!m_bChartDragging && !m_bMeasure_Active) {
9983 switch (cursor_region) {
10005 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10010 m_bChartDragging =
false;
10016 if (event.Dragging() && event.LeftIsDown()) {
10034 struct timespec now;
10035 clock_gettime(CLOCK_MONOTONIC, &now);
10036 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10038 if (
false == m_bChartDragging) {
10040 last_drag.x = x, last_drag.y = y;
10041 m_bChartDragging =
true;
10042 m_chart_drag_total_time = 0;
10043 m_chart_drag_total_x = 0;
10044 m_chart_drag_total_y = 0;
10045 m_inertia_last_drag_x = x;
10046 m_inertia_last_drag_y = y;
10047 m_drag_vec_x.clear();
10048 m_drag_vec_y.clear();
10049 m_drag_vec_t.clear();
10050 m_last_drag_time = tnow;
10054 uint64_t delta_t = tnow - m_last_drag_time;
10055 double delta_tf = delta_t / 1e9;
10057 m_chart_drag_total_time += delta_tf;
10058 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10059 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10061 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10062 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10063 m_drag_vec_t.push_back(delta_tf);
10065 m_inertia_last_drag_x = x;
10066 m_inertia_last_drag_y = y;
10067 m_last_drag_time = tnow;
10069 if ((last_drag.x != x) || (last_drag.y != y)) {
10070 if (!m_routeState) {
10073 m_bChartDragging =
true;
10074 StartTimedMovement();
10075 m_pan_drag.x += last_drag.x - x;
10076 m_pan_drag.y += last_drag.y - y;
10077 last_drag.x = x, last_drag.y = y;
10081 if ((last_drag.x != x) || (last_drag.y != y)) {
10082 if (!m_routeState) {
10085 m_bChartDragging =
true;
10086 StartTimedMovement();
10087 m_pan_drag.x += last_drag.x - x;
10088 m_pan_drag.y += last_drag.y - y;
10089 last_drag.x = x, last_drag.y = y;
10096 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10098 m_DoubleClickTimer->Start();
10099 singleClickEventIsValid =
false;
10107void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10108 if (MouseEventOverlayWindows(event))
return;
10115void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10118 wxCursor *ptarget_cursor = pCursorArrow;
10119 if (!pPlugIn_Cursor) {
10120 ptarget_cursor = pCursorArrow;
10121 if ((!m_routeState) &&
10122 (!m_bMeasure_Active) ) {
10123 if (cursor_region == MID_RIGHT) {
10124 ptarget_cursor = pCursorRight;
10125 }
else if (cursor_region == MID_LEFT) {
10126 ptarget_cursor = pCursorLeft;
10127 }
else if (cursor_region == MID_TOP) {
10128 ptarget_cursor = pCursorDown;
10129 }
else if (cursor_region == MID_BOT) {
10130 ptarget_cursor = pCursorUp;
10132 ptarget_cursor = pCursorArrow;
10134 }
else if (m_bMeasure_Active ||
10136 ptarget_cursor = pCursorPencil;
10138 ptarget_cursor = pPlugIn_Cursor;
10141 SetCursor(*ptarget_cursor);
10144void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10145 SetCursor(*pCursorArrow);
10148void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10152 wxArrayString files;
10154 ChartBase *target_chart = GetChartAtCursor();
10155 if (target_chart) {
10156 file.Assign(target_chart->GetFullPath());
10157 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10158 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10161 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10163 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10164 unsigned int im = stackIndexArray.size();
10165 int scale = 2147483647;
10166 if (VPoint.b_quilt && im > 0) {
10167 for (
unsigned int is = 0; is < im; is++) {
10168 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
10169 CHART_TYPE_MBTILES) {
10170 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10172 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10173 if (ChartData->GetChartTableEntry(stackIndexArray[is])
10175 .Contains(lat, lon)) {
10176 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10179 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10180 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
10188 std::vector<Ais8_001_22 *> area_notices;
10190 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10193 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10194 auto target_data = target.second;
10195 if (!target_data->area_notices.empty()) {
10196 for (
auto &ani : target_data->area_notices) {
10201 for (Ais8_001_22_SubAreaList::iterator sa =
10202 area_notice.sub_areas.begin();
10203 sa != area_notice.sub_areas.end(); ++sa) {
10204 switch (sa->shape) {
10205 case AIS8_001_22_SHAPE_CIRCLE: {
10206 wxPoint target_point;
10208 bbox.Expand(target_point);
10209 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10212 case AIS8_001_22_SHAPE_RECT: {
10213 wxPoint target_point;
10215 bbox.Expand(target_point);
10216 if (sa->e_dim_m > sa->n_dim_m)
10217 bbox.EnLarge(sa->e_dim_m * vp_scale);
10219 bbox.EnLarge(sa->n_dim_m * vp_scale);
10222 case AIS8_001_22_SHAPE_POLYGON:
10223 case AIS8_001_22_SHAPE_POLYLINE: {
10224 for (
int i = 0; i < 4; ++i) {
10225 double lat = sa->latitude;
10226 double lon = sa->longitude;
10227 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10229 wxPoint target_point;
10231 bbox.Expand(target_point);
10235 case AIS8_001_22_SHAPE_SECTOR: {
10236 double lat1 = sa->latitude;
10237 double lon1 = sa->longitude;
10239 wxPoint target_point;
10241 bbox.Expand(target_point);
10242 for (
int i = 0; i < 18; ++i) {
10245 sa->left_bound_deg +
10246 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10247 sa->radius_m / 1852.0, &lat, &lon);
10249 bbox.Expand(target_point);
10251 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10254 bbox.Expand(target_point);
10260 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10261 area_notices.push_back(&area_notice);
10268 if (target_chart || !area_notices.empty() || file.HasName()) {
10270 int sel_rad_pix = 5;
10271 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10276 SetCursor(wxCURSOR_WAIT);
10277 bool lightsVis = m_encShowLights;
10278 if (!lightsVis) SetShowENCLights(
true);
10281 ListOfObjRazRules *rule_list = NULL;
10282 ListOfPI_S57Obj *pi_rule_list = NULL;
10285 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10286 else if (target_plugin_chart)
10287 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10288 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10290 ListOfObjRazRules *overlay_rule_list = NULL;
10291 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10294 if (CHs57_Overlay) {
10295 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10296 zlat, zlon, SelectRadius, &GetVP());
10299 if (!lightsVis) SetShowENCLights(
false);
10302 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10303 wxString face = dFont->GetFaceName();
10305 if (NULL == g_pObjectQueryDialog) {
10306 g_pObjectQueryDialog =
10307 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10308 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10311 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10312 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10316 fg = g_pObjectQueryDialog->GetForegroundColour();
10320 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
10321 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10324 int points = dFont->GetPointSize();
10326 int points = dFont->GetPointSize() + 1;
10330 for (
int i = -2; i < 5; i++) {
10331 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10333 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10335 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
10337 if (overlay_rule_list && CHs57_Overlay) {
10338 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10339 objText << _T(
"<hr noshade>");
10342 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10343 an != area_notices.end(); ++an) {
10344 objText << _T(
"<b>AIS Area Notice:</b> " );
10345 objText << ais8_001_22_notice_names[(*an)->notice_type];
10346 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10347 (*an)->sub_areas.begin();
10348 sa != (*an)->sub_areas.end(); ++sa)
10349 if (!sa->text.empty()) objText << sa->text;
10350 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10351 objText << _T(
"<hr noshade>" );
10355 objText << Chs57->CreateObjDescriptions(rule_list);
10356 else if (target_plugin_chart)
10357 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10360 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
10363 wxString AddFiles, filenameOK;
10365 if (!target_plugin_chart) {
10368 AddFiles = wxString::Format(
10369 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
10371 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
10372 _T(
"cellpadding=3>"),
10373 file.GetFullName());
10375 file.Assign(file.GetPath(), wxT(
""));
10376 wxDir dir(file.GetFullPath());
10378 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10380 file.Assign(dir.GetNameWithSep().append(filename));
10381 wxString FormatString =
10382 _T(
"<td valign=top><font size=-2><a ")
10383 _T("href=\"%s\">%s</a></font></td>");
10384 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10385 filenameOK = file.GetFullPath();
10387 if (3 * ((
int)filecount / 3) == filecount)
10388 FormatString.Prepend(_T(
"<tr>"));
10390 FormatString.Prepend(
10391 _T(
"<td>  </td>"));
10394 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10395 file.GetFullName());
10398 cont = dir.GetNext(&filename);
10400 objText << AddFiles << _T(
"</table>");
10402 objText << _T(
"</font>");
10403 objText << _T(
"</body></html>");
10405 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10406 g_pObjectQueryDialog->SetHTMLPage(objText);
10407 g_pObjectQueryDialog->Show();
10409 if ((!Chs57 && filecount == 1)) {
10411 wxHtmlLinkInfo hli(filenameOK);
10412 wxHtmlLinkEvent hle(1, hli);
10413 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10416 if (rule_list) rule_list->Clear();
10419 if (overlay_rule_list) overlay_rule_list->Clear();
10420 delete overlay_rule_list;
10422 if (pi_rule_list) pi_rule_list->Clear();
10423 delete pi_rule_list;
10425 SetCursor(wxCURSOR_ARROW);
10429void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10431 if (!g_pMarkInfoDialog) {
10438 wxSize canvas_size = GetSize();
10441 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10443 g_pMarkInfoDialog->Layout();
10445 wxPoint canvas_pos = GetPosition();
10446 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10448 bool newFit =
false;
10449 if (canvas_size.x < fitted_size.x) {
10450 fitted_size.x = canvas_size.x - 40;
10451 if (canvas_size.y < fitted_size.y)
10452 fitted_size.y -= 40;
10454 if (canvas_size.y < fitted_size.y) {
10455 fitted_size.y = canvas_size.y - 40;
10456 if (canvas_size.x < fitted_size.x)
10457 fitted_size.x -= 40;
10461 g_pMarkInfoDialog->SetSize(fitted_size);
10462 g_pMarkInfoDialog->Centre();
10468 wxString title_base = _(
"Mark Properties");
10470 title_base = _(
"Waypoint Properties");
10472 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10473 g_pMarkInfoDialog->UpdateProperties();
10475 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title_base, _(
"Layer"),
10477 g_pMarkInfoDialog->SetDialogTitle(caption);
10479 g_pMarkInfoDialog->SetDialogTitle(title_base);
10481 g_pMarkInfoDialog->Show();
10482 g_pMarkInfoDialog->Raise();
10483 g_pMarkInfoDialog->InitialFocus();
10484 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10487void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10488 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10489 pRoutePropDialog->SetRouteAndUpdate(selected);
10491 pRoutePropDialog->Show();
10492 pRoutePropDialog->Raise();
10494 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10498 wxSize canvas_size = GetSize();
10499 wxPoint canvas_pos = GetPosition();
10500 wxSize fitted_size = pRoutePropDialog->GetSize();
10503 if (canvas_size.x < fitted_size.x) {
10504 fitted_size.x = canvas_size.x;
10505 if (canvas_size.y < fitted_size.y)
10506 fitted_size.y -= 20;
10508 if (canvas_size.y < fitted_size.y) {
10509 fitted_size.y = canvas_size.y;
10510 if (canvas_size.x < fitted_size.x)
10511 fitted_size.x -= 20;
10514 pRoutePropDialog->SetSize(fitted_size);
10515 pRoutePropDialog->Centre();
10520 wxPoint xxp = ClientToScreen(canvas_pos);
10524 pRoutePropDialog->SetRouteAndUpdate(selected);
10526 pRoutePropDialog->Show();
10531void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10532 pTrackPropDialog = TrackPropDlg::getInstance(
10535 pTrackPropDialog->SetTrackAndUpdate(selected);
10538 pTrackPropDialog->Show();
10543void pupHandler_PasteWaypoint() {
10546 int pasteBuffer = kml.ParsePasteBuffer();
10547 RoutePoint *pasted = kml.GetParsedRoutePoint();
10548 if (!pasted)
return;
10550 double nearby_radius_meters =
10551 g_Platform->GetSelectRadiusPix() /
10552 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10554 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10555 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10557 int answer = wxID_NO;
10561 "There is an existing waypoint at the same location as the one you are "
10562 "pasting. Would you like to merge the pasted data with it?\n\n");
10563 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10564 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10565 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10568 if (answer == wxID_YES) {
10569 nearPoint->SetName(pasted->GetName());
10571 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10572 pRouteManagerDialog->UpdateWptListCtrl();
10575 if (answer == wxID_NO) {
10578 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10581 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10584 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10585 pRouteManagerDialog->UpdateWptListCtrl();
10586 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10587 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10590 gFrame->InvalidateAllGL();
10591 gFrame->RefreshAllCanvas(
false);
10594void pupHandler_PasteRoute() {
10597 int pasteBuffer = kml.ParsePasteBuffer();
10598 Route *pasted = kml.GetParsedRoute();
10599 if (!pasted)
return;
10601 double nearby_radius_meters =
10602 g_Platform->GetSelectRadiusPix() /
10603 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10609 bool mergepoints =
false;
10610 bool createNewRoute =
true;
10611 int existingWaypointCounter = 0;
10613 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10614 curPoint = pasted->GetPoint(i);
10615 nearPoint = pWayPointMan->GetNearbyWaypoint(
10616 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10618 mergepoints =
true;
10619 existingWaypointCounter++;
10627 int answer = wxID_NO;
10631 "There are existing waypoints at the same location as some of the ones "
10632 "you are pasting. Would you like to just merge the pasted data into "
10634 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10635 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10636 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10638 if (answer == wxID_CANCEL) {
10645 if (mergepoints && answer == wxID_YES &&
10646 existingWaypointCounter == pasted->GetnPoints()) {
10647 wxRouteListNode *route_node = pRouteList->GetFirst();
10648 while (route_node) {
10649 Route *proute = route_node->GetData();
10652 createNewRoute =
false;
10655 route_node = route_node->GetNext();
10659 Route *newRoute = 0;
10662 if (createNewRoute) {
10663 newRoute =
new Route();
10667 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10668 curPoint = pasted->GetPoint(i);
10671 newPoint = pWayPointMan->GetNearbyWaypoint(
10672 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10673 newPoint->SetName(curPoint->GetName());
10676 if (createNewRoute) newRoute->AddPoint(newPoint);
10682 newPoint->SetIconName(_T(
"circle"));
10685 newPoint->SetShared(
false);
10687 newRoute->AddPoint(newPoint);
10688 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10691 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10694 if (i > 1 && createNewRoute)
10695 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10696 curPoint->m_lat, curPoint->m_lon,
10697 prevPoint, newPoint, newRoute);
10698 prevPoint = newPoint;
10701 if (createNewRoute) {
10702 pRouteList->Append(newRoute);
10704 NavObj_dB::GetInstance().InsertRoute(newRoute);
10706 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10707 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10710 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10711 pRouteManagerDialog->UpdateRouteListCtrl();
10712 pRouteManagerDialog->UpdateWptListCtrl();
10714 gFrame->InvalidateAllGL();
10715 gFrame->RefreshAllCanvas(
false);
10717 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10718 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10721void pupHandler_PasteTrack() {
10724 int pasteBuffer = kml.ParsePasteBuffer();
10725 Track *pasted = kml.GetParsedTrack();
10726 if (!pasted)
return;
10734 newTrack->SetName(pasted->GetName());
10736 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10737 curPoint = pasted->GetPoint(i);
10741 wxDateTime now = wxDateTime::Now();
10744 newTrack->AddPoint(newPoint);
10747 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10748 newPoint->m_lat, newPoint->m_lon,
10749 prevPoint, newPoint, newTrack);
10751 prevPoint = newPoint;
10754 g_TrackList.push_back(newTrack);
10756 NavObj_dB::GetInstance().InsertTrack(newTrack);
10758 gFrame->InvalidateAllGL();
10759 gFrame->RefreshAllCanvas(
false);
10762bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10764 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10765 m_pIDXCandidate, m_nmea_log);
10768 wxEVT_COMMAND_MENU_SELECTED,
10769 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10771 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10774 wxEVT_COMMAND_MENU_SELECTED,
10775 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10777 delete m_canvasMenu;
10778 m_canvasMenu = NULL;
10788void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10791 if (m_canvasMenu) {
10792 m_canvasMenu->PopupMenuHandler(event);
10797void ChartCanvas::StartRoute(
void) {
10799 if (g_brouteCreating)
return;
10801 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10803 g_brouteCreating =
true;
10805 m_bDrawingRoute =
false;
10806 SetCursor(*pCursorPencil);
10808 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10810 HideGlobalToolbar();
10813 androidSetRouteAnnunciator(
true);
10817void ChartCanvas::FinishRoute(
void) {
10819 m_prev_pMousePoint = NULL;
10820 m_bDrawingRoute =
false;
10823 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10825 androidSetRouteAnnunciator(
false);
10828 SetCursor(*pCursorArrow);
10830 if (m_pMouseRoute) {
10831 if (m_bAppendingRoute) {
10833 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
10835 if (m_pMouseRoute->GetnPoints() > 1) {
10837 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
10840 m_pMouseRoute = NULL;
10843 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10845 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10846 (pRoutePropDialog->IsShown())) {
10847 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10850 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10851 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10852 pRouteManagerDialog->UpdateRouteListCtrl();
10855 m_bAppendingRoute =
false;
10856 m_pMouseRoute = NULL;
10858 m_pSelectedRoute = NULL;
10860 undo->InvalidateUndo();
10861 gFrame->RefreshAllCanvas(
true);
10863 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10865 ShowGlobalToolbar();
10867 g_brouteCreating =
false;
10870void ChartCanvas::HideGlobalToolbar() {
10871 if (m_canvasIndex == 0) {
10872 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10876void ChartCanvas::ShowGlobalToolbar() {
10877 if (m_canvasIndex == 0) {
10878 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10882void ChartCanvas::ShowAISTargetList(
void) {
10883 if (NULL == g_pAISTargetList) {
10887 g_pAISTargetList->UpdateAISTargetList();
10890void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10891 if (!m_bShowOutlines)
return;
10893 if (!ChartData)
return;
10895 int nEntry = ChartData->GetChartTableEntries();
10897 for (
int i = 0; i < nEntry; i++) {
10901 bool b_group_draw =
false;
10902 if (m_groupIndex > 0) {
10903 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10904 int index = pt->GetGroupArray()[ig];
10905 if (m_groupIndex == index) {
10906 b_group_draw =
true;
10911 b_group_draw =
true;
10913 if (b_group_draw) RenderChartOutline(dc, i, vp);
10919 if (VPoint.b_quilt) {
10920 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10921 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10925 }
else if (m_singleChart &&
10926 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10930 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10933 if (zoom_factor > 8.0) {
10934 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10937 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10941 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
10945void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10947 if (g_bopengl && m_glcc) {
10949 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10954 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10955 if (!ChartData->IsChartAvailable(dbIndex))
return;
10958 float plylat, plylon;
10959 float plylat1, plylon1;
10961 int pixx, pixy, pixx1, pixy1;
10964 ChartData->GetDBBoundingBox(dbIndex, box);
10968 if (box.GetLonRange() == 360)
return;
10970 double lon_bias = 0;
10972 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10974 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10976 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10977 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10979 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10980 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10983 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10986 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10987 if (0 == nAuxPlyEntries)
10991 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10992 plylon += lon_bias;
10998 for (
int i = 0; i < nPly - 1; i++) {
10999 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11000 plylon1 += lon_bias;
11006 int pixxs1 = pixx1;
11007 int pixys1 = pixy1;
11009 bool b_skip =
false;
11013 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11014 pow((
double)(pixy1 - pixy), 2)) /
11020 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11025 if (fabs(dist - distgc) > 10000. * 1852.)
11031 ClipResult res = cohen_sutherland_line_clip_i(
11033 if (res != Invisible && !b_skip)
11034 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11042 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11043 plylon1 += lon_bias;
11049 ClipResult res = cohen_sutherland_line_clip_i(
11051 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11058 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
11059 for (
int j = 0; j < nAuxPlyEntries; j++) {
11061 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11066 for (
int i = 0; i < nAuxPly - 1; i++) {
11067 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11073 int pixxs1 = pixx1;
11074 int pixys1 = pixy1;
11076 bool b_skip =
false;
11080 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11081 ((pixy1 - pixy) * (pixy1 - pixy))) /
11086 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11091 if (fabs(dist - distgc) > 10000. * 1852.)
11097 ClipResult res = cohen_sutherland_line_clip_i(
11099 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11107 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11112 ClipResult res = cohen_sutherland_line_clip_i(
11114 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11119static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11120 const wxString &second) {
11121 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11123 int pointsize = dFont->GetPointSize();
11127 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11128 false, dFont->GetFaceName());
11130 dc.SetFont(*psRLI_font);
11138 int hilite_offset = 3;
11141 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11142 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11144 dc.GetTextExtent(first, &w1, &h1);
11145 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11151 w = wxMax(w1, w2) + (h1 / 2);
11156 xp = ref_point.x - w;
11158 yp += hilite_offset;
11160 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11162 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11163 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11165 dc.DrawText(first, xp, yp);
11166 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11169void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11170 if (!g_bAllowShipToActive)
return;
11172 Route *rt = g_pRouteMan->GetpActiveRoute();
11175 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11176 wxPoint2DDouble pa, pb;
11182 g_pRouteMan->GetRoutePen()->GetWidth();
11183 if (rt->
m_width != wxPENSTYLE_INVALID)
11185 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11186 g_shipToActiveStyle, 5)];
11187 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11189 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11191 g_pRouteMan->GetActiveRoutePen()->GetColour();
11192 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11195 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11198 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11199 (
int)pb.m_y, GetVP(),
true);
11203#ifdef USE_ANDROID_GLES2
11204 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11206 if (style != wxPENSTYLE_SOLID) {
11207 if (glChartCanvas::dash_map.find(style) !=
11208 glChartCanvas::dash_map.end()) {
11209 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11213 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11216 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11217 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11223void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11225 if (m_routeState >= 2) route = m_pMouseRoute;
11226 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11227 route = m_pMeasureRoute;
11229 if (!route)
return;
11232 if (!g_pRouteMan->IsRouteValid(route))
return;
11237 int np = route->GetnPoints();
11239 if (g_btouch && (np > 1)) np--;
11241 render_lat = rp.m_lat;
11242 render_lon = rp.m_lon;
11245 double rhumbBearing, rhumbDist;
11247 &rhumbBearing, &rhumbDist);
11248 double brg = rhumbBearing;
11249 double dist = rhumbDist;
11253 double gcBearing, gcBearing2, gcDist;
11254 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11257 double gcDistm = gcDist / 1852.0;
11260 rhumbBearing = 90.;
11262 wxPoint destPoint, lastPoint;
11265 int milesDiff = rhumbDist - gcDistm;
11266 if (milesDiff > 1) {
11277 for (
int i = 1; i <= milesDiff; i++) {
11278 double p = (double)i * (1.0 / (
double)milesDiff);
11280 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11281 &pLon, &pLat, &gcBearing2);
11283 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11285 lastPoint = destPoint;
11288 if (r_rband.x && r_rband.y) {
11289 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11291 if (m_bMeasure_DistCircle) {
11292 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11293 powf((
float)(r_rband.y - lastPoint.y), 2));
11295 dc.SetPen(*g_pRouteMan->GetRoutePen());
11296 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11297 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11303 wxString routeInfo;
11306 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11312 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11314 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11315 (
int)varBrg, 0x00B0);
11317 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
11322 routeInfo <<
"\nReverse: ";
11324 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11325 (
int)(brg + 180.) % 360, 0x00B0);
11327 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11328 (
int)(varBrg + 180.) % 360, 0x00B0);
11333 s0.Append(_(
"Route") + _T(
": "));
11335 s0.Append(_(
"Layer Route: "));
11338 if (!g_btouch) disp_length += dist;
11339 s0 += FormatDistanceAdaptive(disp_length);
11341 RouteLegInfo(dc, r_rband, routeInfo, s0);
11343 m_brepaint_piano =
true;
11346void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11347 if (!m_bShowVisibleSectors)
return;
11349 if (g_bDeferredInitDone) {
11351 double rhumbBearing, rhumbDist;
11352 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11353 &rhumbBearing, &rhumbDist);
11355 if (rhumbDist > 0.05)
11357 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11358 m_sectorlegsVisible);
11359 m_sector_glat = gLat;
11360 m_sector_glon = gLon;
11362 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11366void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11374void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11375 if (!ps52plib)
return;
11377 if (VPoint.b_quilt) {
11378 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11380 if (m_pQuilt->IsQuiltVector()) {
11381 if (ps52plib->GetStateHash() != m_s52StateHash) {
11383 m_s52StateHash = ps52plib->GetStateHash();
11387 if (ps52plib->GetStateHash() != m_s52StateHash) {
11389 m_s52StateHash = ps52plib->GetStateHash();
11394 bool bSendPlibState =
true;
11395 if (VPoint.b_quilt) {
11396 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11399 if (bSendPlibState) {
11401 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
11402 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
11403 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
11404 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
11405 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
11408 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
11409 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
11410 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
11411 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] = m_encShowAnchor;
11412 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] = GetShowENCDataQual();
11413 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
11414 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
11418 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
11419 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
11423 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
11424 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
11425 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
11426 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] =
11427 ps52plib->m_bShowS57ImportantTextOnly;
11428 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
11429 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
11430 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
11431 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
11432 v[_T(
"OpenCPN S52PLIB ColorShades")] =
11433 S52_getMarinerParam(S52_MAR_TWO_SHADES);
11436 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
11437 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
11438 v[_T(
"OpenCPN Scale Factor Exp")] =
11439 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11440 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
11446 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11447 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11448 g_lastS52PLIBPluginMessage = out;
11454void ChartCanvas::OnPaint(wxPaintEvent &event) {
11455 wxPaintDC dc(
this);
11465 if (!m_b_paint_enable) {
11470 UpdateCanvasS52PLIBConfig();
11473 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11475 if (m_glcc && g_bopengl) {
11476 if (!s_in_update) {
11486 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11488 wxRegion ru = GetUpdateRegion();
11490 int rx, ry, rwidth, rheight;
11491 ru.GetBox(rx, ry, rwidth, rheight);
11495#ifdef ocpnUSE_DIBSECTION
11498 wxMemoryDC temp_dc;
11506 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11507 height += m_Piano->GetHeight();
11509 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11513 int thumbx, thumby, thumbsx, thumbsy;
11514 pthumbwin->GetPosition(&thumbx, &thumby);
11515 pthumbwin->GetSize(&thumbsx, &thumbsy);
11516 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11518 if (pthumbwin->IsShown()) {
11519 rgn_chart.Subtract(rgn_thumbwin);
11520 ru.Subtract(rgn_thumbwin);
11526 wxRegion rgn_blit = ru;
11527 if (g_bShowChartBar) {
11528 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11529 GetClientSize().x, m_Piano->GetHeight());
11532 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11533 if (style->chartStatusWindowTransparent)
11534 m_brepaint_piano =
true;
11536 ru.Subtract(chart_bar_rect);
11540 if (m_Compass && m_Compass->IsShown()) {
11541 wxRect compassRect = m_Compass->
GetRect();
11542 if (ru.Contains(compassRect) != wxOutRegion) {
11543 ru.Subtract(compassRect);
11547 wxRect noteRect = m_notification_button->
GetRect();
11548 if (ru.Contains(noteRect) != wxOutRegion) {
11549 ru.Subtract(noteRect);
11553 bool b_newview =
true;
11558 m_cache_vp.IsValid()) {
11564 bool b_rcache_ok =
false;
11565 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11566 b_rcache_ok = !b_newview;
11569 if (VPoint.b_MercatorProjectionOverride)
11570 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11584 if (b_rcache_ok) chart_get_region.Clear();
11587 if (VPoint.b_quilt)
11589 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11591 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11596 AbstractPlatform::ShowBusySpinner();
11600 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11601 (m_working_bm.GetHeight() != svp.
pix_height))
11605 if (fabs(VPoint.
rotation) < 0.01) {
11606 bool b_save =
true;
11608 if (g_SencThreadManager) {
11609 if (g_SencThreadManager->GetJobCount()) {
11611 m_cache_vp.Invalidate();
11625 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11630 int dy = c_new.y - c_old.y;
11631 int dx = c_new.x - c_old.x;
11636 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11640 temp_dc.SelectObject(m_working_bm);
11642 wxMemoryDC cache_dc;
11643 cache_dc.SelectObject(m_cached_chart_bm);
11647 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11650 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11656 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11659 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11667 update_region.Union(
11670 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11675 update_region.Union(
11678 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11682 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11684 cache_dc.SelectObject(wxNullBitmap);
11688 temp_dc.SelectObject(m_cached_chart_bm);
11691 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11695 temp_dc.SelectObject(m_working_bm);
11696 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11701 temp_dc.SelectObject(m_cached_chart_bm);
11706 temp_dc.SelectObject(m_working_bm);
11707 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11720 wxMemoryDC scratch_dc_0;
11721 scratch_dc_0.SelectObject(m_cached_chart_bm);
11724 scratch_dc_0.SelectObject(wxNullBitmap);
11733 temp_dc.SelectObject(m_working_bm);
11736 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11737 chart_get_all_region);
11740 AbstractPlatform::HideBusySpinner();
11746 if (!m_singleChart) {
11747 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11752 if (!chart_get_region.IsEmpty()) {
11753 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11757 if (temp_dc.IsOk()) {
11762 if (!VPoint.b_quilt) {
11765 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11766 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11773 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11774 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11777 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11779 temp_dc.DestroyClippingRegion();
11784 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11786 if (!backgroundRegion.IsEmpty()) {
11792 wxColour water = pWorldBackgroundChart->water;
11793 if (water.IsOk()) {
11794 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11795 temp_dc.SetBrush(wxBrush(water));
11797 while (upd.HaveRects()) {
11798 wxRect rect = upd.GetRect();
11799 temp_dc.DrawRectangle(rect);
11804 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11805 temp_dc.SetDeviceClippingRegion(*clip_region);
11806 delete clip_region;
11810 SetVPRotation(VPoint.
skew);
11813 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11819 wxMemoryDC *pChartDC = &temp_dc;
11820 wxMemoryDC rotd_dc;
11822 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11824 if (!b_rcache_ok) {
11826 wxMemoryDC tbase_dc;
11828 tbase_dc.SelectObject(bm_base);
11830 tbase_dc.SelectObject(wxNullBitmap);
11832 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11835 wxImage base_image;
11836 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11844 bool b_rot_ok =
false;
11845 if (base_image.IsOk()) {
11848 m_b_rot_hidef =
false;
11852 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11853 m_b_rot_hidef, &m_roffset);
11858 rot_vp.IsValid() && (ri.IsOk())) {
11865 m_prot_bm =
new wxBitmap(ri);
11868 m_roffset.x += VPoint.rv_rect.x;
11869 m_roffset.y += VPoint.rv_rect.y;
11872 if (m_prot_bm && m_prot_bm->IsOk()) {
11873 rotd_dc.SelectObject(*m_prot_bm);
11874 pChartDC = &rotd_dc;
11876 pChartDC = &temp_dc;
11877 m_roffset = wxPoint(0, 0);
11880 pChartDC = &temp_dc;
11881 m_roffset = wxPoint(0, 0);
11884 wxPoint offset = m_roffset;
11887 m_cache_vp = VPoint;
11890 wxMemoryDC mscratch_dc;
11891 mscratch_dc.SelectObject(*pscratch_bm);
11893 mscratch_dc.ResetBoundingBox();
11894 mscratch_dc.DestroyClippingRegion();
11895 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11898 wxRegionIterator upd(rgn_blit);
11900 wxRect rect = upd.GetRect();
11902 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11903 rect.x - offset.x, rect.y - offset.y);
11909 if (m_show_focus_bar && (g_canvasConfig != 0)) {
11910 if (
this == wxWindow::FindFocus()) {
11911 g_focusCanvas =
this;
11913 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11914 mscratch_dc.SetPen(wxPen(colour));
11915 mscratch_dc.SetBrush(wxBrush(colour));
11917 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11918 mscratch_dc.DrawRectangle(activeRect);
11923 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11924 unsigned int im = stackIndexArray.size();
11925 if (VPoint.b_quilt && im > 0) {
11926 std::vector<int> tiles_to_show;
11927 for (
unsigned int is = 0; is < im; is++) {
11929 ChartData->GetChartTableEntry(stackIndexArray[is]);
11930 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11933 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11934 tiles_to_show.push_back(stackIndexArray[is]);
11938 if (tiles_to_show.size())
11939 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11945 ocpnDC scratch_dc(mscratch_dc);
11946 RenderAlertMessage(mscratch_dc, GetVP());
11952#ifdef ocpnUSE_DIBSECTION
11957 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11958 q_dc.SelectObject(qbm);
11961 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11964 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11965 q_dc.SetBrush(qbr);
11966 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11969 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11972 q_dc.SelectObject(wxNullBitmap);
11981 if( VPoint.b_quilt ) {
11982 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11983 ChartBase *chart = m_pQuilt->GetRefChart();
11984 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11989 ChPI->ClearPLIBTextList();
11992 ps52plib->ClearTextList();
11996 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11998 wxColor maskBackground = wxColour(1,0,0);
11999 t_dc.SelectObject( qbm );
12000 t_dc.SetBackground(wxBrush(maskBackground));
12004 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12007 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12008 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12011 wxRegionIterator upd_final( ru );
12012 while( upd_final ) {
12013 wxRect rect = upd_final.GetRect();
12014 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12018 t_dc.SelectObject( wxNullBitmap );
12024 if (VPoint.b_quilt) {
12025 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12026 ChartBase *chart = m_pQuilt->GetRefChart();
12027 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12031 ChPI->ClearPLIBTextList();
12033 if (ps52plib) ps52plib->ClearTextList();
12038 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12040 if (g_bShowChartBar && m_Piano) {
12041 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12042 GetVP().pix_width, m_Piano->GetHeight());
12045 if (!style->chartStatusWindowTransparent)
12046 chart_all_text_region.Subtract(chart_bar_rect);
12049 if (m_Compass && m_Compass->IsShown()) {
12050 wxRect compassRect = m_Compass->
GetRect();
12051 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12052 chart_all_text_region.Subtract(compassRect);
12056 mscratch_dc.DestroyClippingRegion();
12058 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12059 chart_all_text_region);
12065 ocpnDC scratch_dc(mscratch_dc);
12066 DrawOverlayObjects(scratch_dc, ru);
12069 wxRegionIterator upd_final(rgn_blit);
12070 while (upd_final) {
12071 wxRect rect = upd_final.GetRect();
12072 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12079 temp_dc.SelectObject(wxNullBitmap);
12081 mscratch_dc.SelectObject(wxNullBitmap);
12083 dc.DestroyClippingRegion();
12088void ChartCanvas::PaintCleanup() {
12100 m_bTCupdate =
false;
12104 WarpPointer(warp_x, warp_y);
12111 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12112 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12116wxColour GetErrorGraphicColor(
double val)
12135 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
12136 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
12137 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
12138 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
12139 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
12140 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
12141 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
12142 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
12143 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
12144 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
12145 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
12146 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
12147 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
12148 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
12149 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
12150 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
12151 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
12152 else if( val >= 48) c.Set(_T(
"#410000"));
12157void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12160 gr_image.InitAlpha();
12162 double maxval = -10000;
12163 double minval = 10000;
12180 maxval = wxMax(maxval, (glat - rlat));
12181 minval = wxMin(minval, (glat - rlat));
12198 double f = ((glat - rlat)-minval)/(maxval - minval);
12200 double dy = (f * 40);
12202 wxColour c = GetErrorGraphicColor(dy);
12203 unsigned char r = c.Red();
12204 unsigned char g = c.Green();
12205 unsigned char b = c.Blue();
12207 gr_image.SetRGB(j, i, r,g,b);
12208 if((glat - rlat )!= 0)
12209 gr_image.SetAlpha(j, i, 128);
12211 gr_image.SetAlpha(j, i, 255);
12218 wxBitmap *pbm =
new wxBitmap(gr_image);
12219 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12220 pbm->SetMask(gr_mask);
12222 pmdc->DrawBitmap(*pbm, 0,0);
12230void ChartCanvas::CancelMouseRoute() {
12232 m_pMouseRoute = NULL;
12233 m_bDrawingRoute =
false;
12236int ChartCanvas::GetNextContextMenuId() {
12237 return CanvasMenuHandler::GetNextContextMenuId();
12240bool ChartCanvas::SetCursor(
const wxCursor &c) {
12242 if (g_bopengl && m_glcc)
12243 return m_glcc->SetCursor(c);
12246 return wxWindow::SetCursor(c);
12249void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12250 if (g_bquiting)
return;
12260 if (!m_RolloverPopupTimer.IsRunning() &&
12261 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12262 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12263 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12264 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12267 if (m_glcc && g_bopengl) {
12270 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12272 m_glcc->Refresh(eraseBackground,
12283 if (pthumbwin && pthumbwin->IsShown()) {
12284 pthumbwin->Raise();
12285 pthumbwin->Refresh(
false);
12289 if (m_pCIWin && m_pCIWin->IsShown()) {
12291 m_pCIWin->Refresh(
false);
12299 wxWindow::Refresh(eraseBackground, rect);
12302void ChartCanvas::Update() {
12303 if (m_glcc && g_bopengl) {
12308 wxWindow::Update();
12312 if (!pemboss)
return;
12313 int x = pemboss->x, y = pemboss->y;
12314 const double factor = 200;
12316 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
12317 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12318 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
12321 wxMemoryDC snip_dc;
12322 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12323 snip_dc.SelectObject(snip_bmp);
12325 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12326 snip_dc.SelectObject(wxNullBitmap);
12328 wxImage snip_img = snip_bmp.ConvertToImage();
12331 unsigned char *pdata = snip_img.GetData();
12333 for (
int y = 0; y < pemboss->height; y++) {
12334 int map_index = (y * pemboss->width);
12335 for (
int x = 0; x < pemboss->width; x++) {
12336 double val = (pemboss->pmap[map_index] * factor) / 256.;
12338 int nred = (int)((*pdata) + val);
12339 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12340 *pdata++ = (
unsigned char)nred;
12342 int ngreen = (int)((*pdata) + val);
12343 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12344 *pdata++ = (
unsigned char)ngreen;
12346 int nblue = (int)((*pdata) + val);
12347 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12348 *pdata++ = (
unsigned char)nblue;
12356 wxBitmap emb_bmp(snip_img);
12359 wxMemoryDC result_dc;
12360 result_dc.SelectObject(emb_bmp);
12363 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12365 result_dc.SelectObject(wxNullBitmap);
12371 if (GetQuiltMode()) {
12373 int refIndex = GetQuiltRefChartdbIndex();
12374 if (refIndex >= 0) {
12375 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
12376 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12377 if (current_type == CHART_TYPE_MBTILES) {
12378 ChartBase *pChart = m_pQuilt->GetRefChart();
12381 zoom_factor = ptc->GetZoomFactor();
12386 if (zoom_factor <= 3.9)
return NULL;
12388 if (m_singleChart) {
12389 if (zoom_factor <= 3.9)
return NULL;
12394 if (m_pEM_OverZoom) {
12395 m_pEM_OverZoom->x = 4;
12396 m_pEM_OverZoom->y = 0;
12397 if (g_MainToolbar && IsPrimaryCanvas()) {
12398 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12399 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12402 return m_pEM_OverZoom;
12405void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12415 g_overlayCanvas =
this;
12417 if (g_pi_manager) {
12418 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12419 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12423 AISDrawAreaNotices(dc, GetVP(),
this);
12425 wxDC *pdc = dc.GetDC();
12427 pdc->DestroyClippingRegion();
12428 wxDCClipper(*pdc, ru);
12431 if (m_bShowNavobjects) {
12432 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12433 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12434 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12435 DrawAnchorWatchPoints(dc);
12437 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12438 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12441 AISDraw(dc, GetVP(),
this);
12445 RenderVisibleSectorLights(dc);
12447 RenderAllChartOutlines(dc, GetVP());
12448 RenderRouteLegs(dc);
12449 RenderShipToActive(dc,
false);
12451 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12452 if (g_pi_manager) {
12453 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12454 OVERLAY_OVER_SHIPS);
12457 DrawEmboss(dc, EmbossDepthScale());
12458 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12459 if (g_pi_manager) {
12460 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12461 OVERLAY_OVER_EMBOSS);
12465 RebuildTideSelectList(GetVP().GetBBox());
12466 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12469 if (m_bShowCurrent) {
12470 RebuildCurrentSelectList(GetVP().GetBBox());
12471 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12474 if (!g_PrintingInProgress) {
12475 if (IsPrimaryCanvas()) {
12476 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12479 if (IsPrimaryCanvas()) {
12480 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12483 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12485 if (m_pTrackRolloverWin) {
12486 m_pTrackRolloverWin->Draw(dc);
12487 m_brepaint_piano =
true;
12490 if (m_pRouteRolloverWin) {
12491 m_pRouteRolloverWin->Draw(dc);
12492 m_brepaint_piano =
true;
12495 if (m_pAISRolloverWin) {
12496 m_pAISRolloverWin->Draw(dc);
12497 m_brepaint_piano =
true;
12499 if (m_brepaint_piano && g_bShowChartBar) {
12500 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12503 if (m_Compass) m_Compass->Paint(dc);
12505 if (!g_CanvasHideNotificationIcon) {
12506 auto ¬eman = NotificationManager::GetInstance();
12507 if (noteman.GetNotificationCount()) {
12508 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12509 if (m_notification_button->UpdateStatus()) Refresh();
12510 m_notification_button->Show(
true);
12511 m_notification_button->Paint(dc);
12513 m_notification_button->Show(
false);
12517 if (g_pi_manager) {
12518 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12524 if (!m_bShowDepthUnits)
return NULL;
12526 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12528 if (GetQuiltMode()) {
12529 wxString s = m_pQuilt->GetQuiltDepthUnit();
12531 if (s == _T(
"FEET"))
12532 depth_unit_type = DEPTH_UNIT_FEET;
12533 else if (s.StartsWith(_T(
"FATHOMS")))
12534 depth_unit_type = DEPTH_UNIT_FATHOMS;
12535 else if (s.StartsWith(_T(
"METERS")))
12536 depth_unit_type = DEPTH_UNIT_METERS;
12537 else if (s.StartsWith(_T(
"METRES")))
12538 depth_unit_type = DEPTH_UNIT_METERS;
12539 else if (s.StartsWith(_T(
"METRIC")))
12540 depth_unit_type = DEPTH_UNIT_METERS;
12541 else if (s.StartsWith(_T(
"METER")))
12542 depth_unit_type = DEPTH_UNIT_METERS;
12545 if (m_singleChart) {
12546 depth_unit_type = m_singleChart->GetDepthUnitType();
12547 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12548 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12553 switch (depth_unit_type) {
12554 case DEPTH_UNIT_FEET:
12557 case DEPTH_UNIT_METERS:
12558 ped = m_pEM_Meters;
12560 case DEPTH_UNIT_FATHOMS:
12561 ped = m_pEM_Fathoms;
12567 ped->x = (GetVP().
pix_width - ped->width);
12569 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12570 wxRect r = m_Compass->
GetRect();
12571 ped->y = r.y + r.height;
12578void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12581 if (style->embossFont == wxEmptyString) {
12582 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12584 font.SetPointSize(60);
12585 font.SetWeight(wxFONTWEIGHT_BOLD);
12587 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12588 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12590 int emboss_width = 500;
12591 int emboss_height = 200;
12595 delete m_pEM_Meters;
12596 delete m_pEM_Fathoms;
12600 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12602 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12604 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12607#define OVERZOOM_TEXT _("OverZoom")
12609void ChartCanvas::SetOverzoomFont() {
12614 if (style->embossFont == wxEmptyString) {
12615 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12617 font.SetPointSize(40);
12618 font.SetWeight(wxFONTWEIGHT_BOLD);
12620 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12621 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12623 wxClientDC dc(
this);
12625 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12627 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12628 font.SetPointSize(font.GetPointSize() - 1);
12630 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12632 m_overzoomFont = font;
12633 m_overzoomTextWidth = w;
12634 m_overzoomTextHeight = h;
12637void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12638 delete m_pEM_OverZoom;
12640 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12642 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12643 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12646emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12647 int height,
const wxString &str,
12652 wxBitmap bmp(width, height, -1);
12655 wxMemoryDC temp_dc;
12656 temp_dc.SelectObject(bmp);
12659 temp_dc.SetBackground(*wxWHITE_BRUSH);
12660 temp_dc.SetTextBackground(*wxWHITE);
12661 temp_dc.SetTextForeground(*wxBLACK);
12665 temp_dc.SetFont(font);
12668 temp_dc.GetTextExtent(str, &str_w, &str_h);
12670 temp_dc.DrawText(str, 1, 1);
12673 temp_dc.SelectObject(wxNullBitmap);
12676 wxImage img = bmp.ConvertToImage();
12678 int image_width = str_w * 105 / 100;
12679 int image_height = str_h * 105 / 100;
12680 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12681 wxMin(image_height, img.GetHeight()));
12682 wxImage imgs = img.GetSubImage(r);
12686 case GLOBAL_COLOR_SCHEME_DAY:
12690 case GLOBAL_COLOR_SCHEME_DUSK:
12693 case GLOBAL_COLOR_SCHEME_NIGHT:
12700 const int w = imgs.GetWidth();
12701 const int h = imgs.GetHeight();
12702 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12707 for (
int y = 1; y < h - 1; y++) {
12708 for (
int x = 1; x < w - 1; x++) {
12710 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12711 val = (int)(val * val_factor);
12712 index = (y * w) + x;
12725void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12726 Track *active_track = NULL;
12727 for (
Track *pTrackDraw : g_TrackList) {
12728 if (g_pActiveTrack == pTrackDraw) {
12729 active_track = pTrackDraw;
12733 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12736 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12739void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12740 Track *active_track = NULL;
12741 for (
Track *pTrackDraw : g_TrackList) {
12742 if (g_pActiveTrack == pTrackDraw) {
12743 active_track = pTrackDraw;
12747 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12750void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12751 Route *active_route = NULL;
12753 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12754 node = node->GetNext()) {
12755 Route *pRouteDraw = node->GetData();
12756 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12757 active_route = pRouteDraw;
12762 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12767 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12770void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12771 Route *active_route = NULL;
12773 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12774 node = node->GetNext()) {
12775 Route *pRouteDraw = node->GetData();
12776 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12777 active_route = pRouteDraw;
12781 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12784void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12785 if (!pWayPointMan)
return;
12787 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12793 node = node->GetNext();
12798 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12802 if (pWP->GetShowWaypointRangeRings() &&
12803 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12804 double factor = 1.00;
12805 if (pWP->GetWaypointRangeRingsStepUnits() ==
12807 factor = 1 / 1.852;
12809 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12810 pWP->GetWaypointRangeRingsStep() / 60.;
12814 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12815 pWP->m_lat + radius, pWP->m_lon + radius);
12816 if (!BltBBox.IntersectOut(radar_box)) {
12823 node = node->GetNext();
12827void ChartCanvas::DrawBlinkObjects(
void) {
12829 wxRect update_rect;
12831 if (!pWayPointMan)
return;
12833 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12843 node = node->GetNext();
12845 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12848void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12851 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12853 wxPoint lAnchorPoint1, lAnchorPoint2;
12856 if (pAnchorWatchPoint1) {
12857 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12861 if (pAnchorWatchPoint2) {
12862 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12867 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12868 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12870 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12871 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12872 dc.SetBrush(*ppBrush);
12876 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12881 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12886 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12891 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12896double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12899 wxPoint lAnchorPoint;
12902 double tlat1, tlon1;
12904 if (pAnchorWatchPoint) {
12905 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12906 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12907 dabs = fabs(d1 / 1852.);
12908 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12913 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12914 pow((
double)(lAnchorPoint.y - r1.y), 2));
12917 if (d1 < 0) lpp = -lpp;
12925void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12926 if (!ptcmgr)
return;
12928 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12930 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12931 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12936 if ((type ==
't') || (type ==
'T')) {
12937 if (BBox.Contains(lat, lon)) {
12939 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12945extern wxDateTime gTimeSource;
12947void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12948 if (!ptcmgr)
return;
12950 wxDateTime this_now = gTimeSource;
12951 bool cur_time = !gTimeSource.IsValid();
12952 if (cur_time) this_now = wxDateTime::Now();
12953 time_t t_this_now = this_now.GetTicks();
12955 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12956 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12957 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12958 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12960 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12961 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12964 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12965 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12968 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12969 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12970 wxBRUSHSTYLE_SOLID);
12971 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12972 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12973 wxBRUSHSTYLE_SOLID);
12975 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
12976 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12977 int font_size = wxMax(10, dFont->GetPointSize());
12980 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
12981 false, dFont->GetFaceName());
12983 dc.SetPen(*pblack_pen);
12984 dc.SetBrush(*pgreen_brush);
12988 case GLOBAL_COLOR_SCHEME_DAY:
12991 case GLOBAL_COLOR_SCHEME_DUSK:
12994 case GLOBAL_COLOR_SCHEME_NIGHT:
12995 bm = m_bmTideNight;
13002 int bmw = bm.GetWidth();
13003 int bmh = bm.GetHeight();
13005 float scale_factor = 1.0;
13009 float icon_pixelRefDim = 45;
13013 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
13014 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
13015 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13029 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13031 float nominal_icon_size_pixels = 48;
13032 float pix_factor = (2 * height) / nominal_icon_size_pixels;
13042 double targetHeight0 = 16.0;
13045 double displaySize = m_display_size_mm;
13046 displaySize = wxMax(displaySize, 100);
13048 float targetHeight = wxMin(targetHeight0, displaySize / 15);
13050 double pix_factor = targetHeight / symHeight;
13053 scale_factor *= pix_factor;
13055 float user_scale_factor = g_ChartScaleFactorExp;
13056 if (g_ChartScaleFactorExp > 1.0)
13057 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13060 scale_factor *= user_scale_factor;
13061 scale_factor *= GetContentScaleFactor();
13064 double marge = 0.05;
13065 std::vector<LLBBox> drawn_boxes;
13066 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13067 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13070 if ((type ==
't') || (type ==
'T'))
13075 if (BBox.ContainsMarge(lat, lon, marge)) {
13077 if (GetVP().chart_scale < 500000) {
13078 bool bdrawn =
false;
13079 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13080 if (drawn_boxes[i].Contains(lat, lon)) {
13085 if (bdrawn)
continue;
13088 this_box.Set(lat, lon, lat, lon);
13089 this_box.EnLarge(.005);
13090 drawn_boxes.push_back(this_box);
13096 if (GetVP().chart_scale > 500000) {
13097 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13101 dc.SetFont(*plabelFont);
13113 if (ptcmgr->GetTideFlowSens(
13114 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13118 ptcmgr->GetHightOrLowTide(
13119 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13120 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13132 if (tctime > t_this_now)
13133 ptcmgr->GetHightOrLowTide(
13134 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13135 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13139 ptcmgr->GetHightOrLowTide(
13140 t_this_now, FORWARD_TEN_MINUTES_STEP,
13141 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13155 int width = (int)(12 * scale_factor + 0.5);
13156 int height = (int)(45 * scale_factor + 0.5);
13157 int linew = wxMax(1, (
int)(scale_factor));
13158 int xDraw = r.x - (width / 2);
13159 int yDraw = r.y - (height / 2);
13162 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13163 int hs = (httime > lttime) ? -4 : 4;
13164 hs *= (int)(scale_factor + 0.5);
13165 if (ts > 0.995 || ts < 0.005) hs = 0;
13166 int ht_y = (int)(height * ts);
13169 pblack_pen->SetWidth(linew);
13170 dc.SetPen(*pblack_pen);
13171 dc.SetBrush(*pyelo_brush);
13172 dc.DrawRectangle(xDraw, yDraw, width, height);
13176 dc.SetPen(*pblue_pen);
13177 dc.SetBrush(*pblue_brush);
13178 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13179 (width - (4 * linew)), height - ht_y);
13185 arrow[0].x = xDraw + 2 * linew;
13186 arrow[1].x = xDraw + width / 2;
13187 arrow[2].x = xDraw + width - 2 * linew;
13188 pyelo_pen->SetWidth(linew);
13189 pblue_pen->SetWidth(linew);
13190 if (ts > 0.35 || ts < 0.15)
13192 hl = (int)(height * 0.25) + yDraw;
13194 arrow[1].y = hl + hs;
13197 dc.SetPen(*pyelo_pen);
13199 dc.SetPen(*pblue_pen);
13200 dc.DrawLines(3, arrow);
13202 if (ts > 0.60 || ts < 0.40)
13204 hl = (int)(height * 0.5) + yDraw;
13206 arrow[1].y = hl + hs;
13209 dc.SetPen(*pyelo_pen);
13211 dc.SetPen(*pblue_pen);
13212 dc.DrawLines(3, arrow);
13214 if (ts < 0.65 || ts > 0.85)
13216 hl = (int)(height * 0.75) + yDraw;
13218 arrow[1].y = hl + hs;
13221 dc.SetPen(*pyelo_pen);
13223 dc.SetPen(*pblue_pen);
13224 dc.DrawLines(3, arrow);
13228 s.Printf(_T(
"%3.1f"), nowlev);
13230 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13232 dc.GetTextExtent(s, &wx1, NULL);
13234 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13249void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13250 if (!ptcmgr)
return;
13252 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13254 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13255 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13260 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13261 if ((BBox.Contains(lat, lon))) {
13263 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13269void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13270 if (!ptcmgr)
return;
13272 float tcvalue, dir;
13276 double lon_last = 0.;
13277 double lat_last = 0.;
13279 double marge = 0.2;
13280 bool cur_time = !gTimeSource.IsValid();
13282 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13283 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13285 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13286 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13287 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13288 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13290 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13291 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13292 wxBRUSHSTYLE_SOLID);
13293 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13294 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13295 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13296 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13298 double skew_angle = GetVPRotation();
13300 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13301 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13302 int font_size = wxMax(10, dFont->GetPointSize());
13305 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13306 false, dFont->GetFaceName());
13308 float scale_factor = 1.0;
13315 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
13316 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
13317 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13323 float nominal_icon_size_pixels = 6;
13324 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
13331 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13333 float nominal_icon_size_pixels = 15;
13334 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13341 float icon_pixelRefDim = 5;
13346 double targetHeight0 = 2.0;
13349 double displaySize = m_display_size_mm;
13350 displaySize = wxMax(displaySize, 100);
13352 float targetHeight = wxMin(targetHeight0, displaySize / 50);
13353 double pix_factor = targetHeight / symHeight;
13356 scale_factor *= pix_factor;
13358 float user_scale_factor = g_ChartScaleFactorExp;
13359 if (g_ChartScaleFactorExp > 1.0)
13360 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13363 scale_factor *= user_scale_factor;
13365 scale_factor *= GetContentScaleFactor();
13368 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13369 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13374 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13375 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13380 int dd = (int)(5.0 * scale_factor + 0.5);
13391 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13392 dc.SetPen(*pblack_pen);
13393 dc.SetBrush(*porange_brush);
13394 dc.DrawPolygon(4, d);
13397 dc.SetBrush(*pblack_brush);
13398 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13402 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13416 double a1 = fabs(tcvalue) * 10.;
13418 a1 = wxMax(1.0, a1);
13419 double a2 = log10(a1);
13421 float cscale = scale_factor * a2 * 0.4;
13423 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13424 dc.SetPen(*porange_pen);
13425 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13429 if (bDrawCurrentValues) {
13430 dc.SetFont(*pTCFont);
13431 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13432 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13453void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
13454 pCwin =
new TCWin(
this, x, y, pvIDX);
13457#define NUM_CURRENT_ARROW_POINTS 9
13458static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13459 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13460 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13461 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13463void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13465 if (
scale > 1e-2) {
13466 float sin_rot = sin(rot_angle * PI / 180.);
13467 float cos_rot = cos(rot_angle * PI / 180.);
13471 float xt = CurrentArrowArray[0].x;
13472 float yt = CurrentArrowArray[0].y;
13474 float xp = (xt * cos_rot) - (yt * sin_rot);
13475 float yp = (xt * sin_rot) + (yt * cos_rot);
13476 int x1 = (int)(xp *
scale);
13477 int y1 = (int)(yp *
scale);
13480 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13481 xt = CurrentArrowArray[ip].x;
13482 yt = CurrentArrowArray[ip].y;
13484 float xp = (xt * cos_rot) - (yt * sin_rot);
13485 float yp = (xt * sin_rot) + (yt * cos_rot);
13486 int x2 = (int)(xp *
scale);
13487 int y2 = (int)(yp *
scale);
13489 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13497wxString ChartCanvas::FindValidUploadPort() {
13500 if (!g_uploadConnection.IsEmpty() &&
13501 g_uploadConnection.StartsWith(_T(
"Serial"))) {
13502 port = g_uploadConnection;
13508 for (
auto *cp : TheConnectionParams()) {
13509 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13510 port << _T(
"Serial:") << cp->Port;
13516void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13519 if (NULL == g_pais_query_dialog_active) {
13520 int pos_x = g_ais_query_dialog_x;
13521 int pos_y = g_ais_query_dialog_y;
13523 if (g_pais_query_dialog_active) {
13524 g_pais_query_dialog_active->Destroy();
13530 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13531 wxPoint(pos_x, pos_y));
13533 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13535 g_pais_query_dialog_active->SetMMSI(mmsi);
13536 g_pais_query_dialog_active->UpdateText();
13537 wxSize sz = g_pais_query_dialog_active->GetSize();
13539 bool b_reset_pos =
false;
13544 RECT frame_title_rect;
13545 frame_title_rect.left = pos_x;
13546 frame_title_rect.top = pos_y;
13547 frame_title_rect.right = pos_x + sz.x;
13548 frame_title_rect.bottom = pos_y + 30;
13550 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13551 b_reset_pos =
true;
13556 wxRect window_title_rect;
13557 window_title_rect.x = pos_x;
13558 window_title_rect.y = pos_y;
13559 window_title_rect.width = sz.x;
13560 window_title_rect.height = 30;
13562 wxRect ClientRect = wxGetClientDisplayRect();
13563 ClientRect.Deflate(
13565 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13569 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13572 g_pais_query_dialog_active->SetMMSI(mmsi);
13573 g_pais_query_dialog_active->UpdateText();
13576 g_pais_query_dialog_active->Show();
13579void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13580 bool cur_mode = GetQuiltMode();
13582 if (!GetQuiltMode())
13583 SetQuiltMode(
true);
13584 else if (GetQuiltMode()) {
13585 SetQuiltMode(
false);
13586 g_sticky_chart = GetQuiltReferenceChartIndex();
13589 if (cur_mode != GetQuiltMode()) {
13590 SetupCanvasQuiltMode();
13599 if (ps52plib) ps52plib->GenerateStateHash();
13601 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13602 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13605void ChartCanvas::DoCanvasStackDelta(
int direction) {
13606 if (!GetQuiltMode()) {
13607 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13608 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13609 if ((current_stack_index + direction) < 0)
return;
13611 if (m_bpersistent_quilt ) {
13613 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13615 if (IsChartQuiltableRef(new_dbIndex)) {
13616 ToggleCanvasQuiltMode();
13617 SelectQuiltRefdbChart(new_dbIndex);
13618 m_bpersistent_quilt =
false;
13621 SelectChartFromStack(current_stack_index + direction);
13624 std::vector<int> piano_chart_index_array =
13625 GetQuiltExtendedStackdbIndexArray();
13626 int refdb = GetQuiltRefChartdbIndex();
13629 int current_index = -1;
13630 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13631 if (refdb == piano_chart_index_array[i]) {
13636 if (current_index == -1)
return;
13639 int target_family = ctet.GetChartFamily();
13641 int new_index = -1;
13642 int check_index = current_index + direction;
13643 bool found =
false;
13644 int check_dbIndex = -1;
13645 int new_dbIndex = -1;
13649 (
unsigned int)check_index < piano_chart_index_array.size() &&
13650 (check_index >= 0)) {
13651 check_dbIndex = piano_chart_index_array[check_index];
13652 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13653 if (target_family == cte.GetChartFamily()) {
13655 new_index = check_index;
13656 new_dbIndex = check_dbIndex;
13660 check_index += direction;
13663 if (!found)
return;
13665 if (!IsChartQuiltableRef(new_dbIndex)) {
13666 ToggleCanvasQuiltMode();
13667 SelectdbChart(new_dbIndex);
13668 m_bpersistent_quilt =
true;
13670 SelectQuiltRefChart(new_index);
13674 gFrame->UpdateGlobalMenuItems();
13676 SetQuiltChartHiLiteIndex(-1);
13687void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13690 switch (event.GetId()) {
13702 DoCanvasStackDelta(1);
13707 DoCanvasStackDelta(-1);
13717 ShowCurrents(!GetbShowCurrent());
13724 ShowTides(!GetbShowTide());
13731 if (0 == m_routeState) {
13738 androidSetRouteAnnunciator(m_routeState == 1);
13744 SetAISCanvasDisplayStyle(-1);
13756void ChartCanvas::SetShowAIS(
bool show) {
13758 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13759 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13762void ChartCanvas::SetAttenAIS(
bool show) {
13763 m_bShowAISScaled = show;
13764 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13765 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13768void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13771 bool bShowAIS_Array[3] = {
true,
true,
false};
13772 bool bShowScaled_Array[3] = {
false,
true,
true};
13773 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13774 _(
"Attenuate less critical AIS targets"),
13775 _(
"Hide AIS Targets")};
13776 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13777 _T(
"AIS_Disabled")};
13779 int AIS_Toolbar_Switch = 0;
13780 if (StyleIndx == -1) {
13782 for (
int i = 1; i < ArraySize; i++) {
13783 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13784 (bShowScaled_Array[i] == m_bShowAISScaled))
13785 AIS_Toolbar_Switch = i;
13787 AIS_Toolbar_Switch++;
13788 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13789 AIS_Toolbar_Switch++;
13792 AIS_Toolbar_Switch = StyleIndx;
13795 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13797 int AIS_Toolbar_Switch_Next =
13798 AIS_Toolbar_Switch + 1;
13799 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13800 AIS_Toolbar_Switch_Next++;
13801 if (AIS_Toolbar_Switch_Next >= ArraySize)
13802 AIS_Toolbar_Switch_Next = 0;
13805 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13806 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13809void ChartCanvas::TouchAISToolActive(
void) {}
13811void ChartCanvas::UpdateAISTBTool(
void) {}
13819void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13821 bool b_update =
false;
13822 int cc1_edge_comp = 2;
13823 wxRect rect = m_Compass->
GetRect();
13824 wxSize parent_size = GetSize();
13826 parent_size *= m_displayScale;
13830 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
13831 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13832 wxRect compass_rect(compass_pt, rect.GetSize());
13834 m_Compass->Move(compass_pt);
13836 if (m_Compass && m_Compass->IsShown())
13837 m_Compass->UpdateStatus(b_force_new | b_update);
13839 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
13840 scaler = wxMax(scaler, 1.0);
13841 wxPoint note_point = wxPoint(
13842 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
13843 m_notification_button->Move(note_point);
13844 m_notification_button->UpdateStatus();
13846 if (b_force_new | b_update) Refresh();
13849void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13850 ChartTypeEnum New_Type,
13851 ChartFamilyEnum New_Family) {
13852 if (!GetpCurrentStack())
return;
13853 if (!ChartData)
return;
13855 if (index < GetpCurrentStack()->nEntry) {
13858 pTentative_Chart = ChartData->OpenStackChartConditional(
13859 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13861 if (pTentative_Chart) {
13862 if (m_singleChart) m_singleChart->Deactivate();
13864 m_singleChart = pTentative_Chart;
13865 m_singleChart->Activate();
13867 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13868 GetpCurrentStack(), m_singleChart->GetFullPath());
13881 double best_scale_ppm = GetBestVPScale(m_singleChart);
13882 double rotation = GetVPRotation();
13883 double oldskew = GetVPSkew();
13884 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13886 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13887 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13888 if (fabs(newskew) > 0.0001) rotation = newskew;
13891 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13893 UpdateGPSCompassStatusBox(
true);
13897 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13898 if (idx < 0)
return;
13900 std::vector<int> piano_active_chart_index_array;
13901 piano_active_chart_index_array.push_back(
13902 GetpCurrentStack()->GetCurrentEntrydbIndex());
13903 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13906void ChartCanvas::SelectdbChart(
int dbindex) {
13907 if (!GetpCurrentStack())
return;
13908 if (!ChartData)
return;
13910 if (dbindex >= 0) {
13913 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13915 if (pTentative_Chart) {
13916 if (m_singleChart) m_singleChart->Deactivate();
13918 m_singleChart = pTentative_Chart;
13919 m_singleChart->Activate();
13921 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13922 GetpCurrentStack(), m_singleChart->GetFullPath());
13935 double best_scale_ppm = GetBestVPScale(m_singleChart);
13939 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13949void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13952 if (!GetQuiltMode()) {
13953 if (GetpCurrentStack()) {
13954 int stack_index = -1;
13955 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13956 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13957 if (check_dbIndex < 0)
continue;
13959 ChartData->GetChartTableEntry(check_dbIndex);
13960 if (type == cte.GetChartType()) {
13963 }
else if (family == cte.GetChartFamily()) {
13969 if (stack_index >= 0) {
13970 SelectChartFromStack(stack_index);
13974 int sel_dbIndex = -1;
13975 std::vector<int> piano_chart_index_array =
13976 GetQuiltExtendedStackdbIndexArray();
13977 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13978 int check_dbIndex = piano_chart_index_array[i];
13979 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13980 if (type == cte.GetChartType()) {
13981 if (IsChartQuiltableRef(check_dbIndex)) {
13982 sel_dbIndex = check_dbIndex;
13985 }
else if (family == cte.GetChartFamily()) {
13986 if (IsChartQuiltableRef(check_dbIndex)) {
13987 sel_dbIndex = check_dbIndex;
13993 if (sel_dbIndex >= 0) {
13994 SelectQuiltRefdbChart(sel_dbIndex,
false);
13996 AdjustQuiltRefChart();
14003 SetQuiltChartHiLiteIndex(-1);
14008bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14009 return std::find(m_tile_yesshow_index_array.begin(),
14010 m_tile_yesshow_index_array.end(),
14011 index) != m_tile_yesshow_index_array.end();
14014bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14015 return std::find(m_tile_noshow_index_array.begin(),
14016 m_tile_noshow_index_array.end(),
14017 index) != m_tile_noshow_index_array.end();
14020void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14021 if (std::find(m_tile_noshow_index_array.begin(),
14022 m_tile_noshow_index_array.end(),
14023 index) == m_tile_noshow_index_array.end()) {
14024 m_tile_noshow_index_array.push_back(index);
14034void ChartCanvas::HandlePianoClick(
14035 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14036 if (g_options && g_options->IsShown())
14038 if (!m_pCurrentStack)
return;
14039 if (!ChartData)
return;
14054 double distance = 25000;
14055 int closest_index = -1;
14056 for (
int chart_index : selected_dbIndex_array) {
14057 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
14058 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14059 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14062 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14063 if (test_distance < distance) {
14064 distance = test_distance;
14065 closest_index = chart_index;
14069 int selected_dbIndex = selected_dbIndex_array[0];
14070 if (closest_index >= 0) selected_dbIndex = closest_index;
14072 if (!GetQuiltMode()) {
14073 if (m_bpersistent_quilt ) {
14074 if (IsChartQuiltableRef(selected_dbIndex)) {
14075 ToggleCanvasQuiltMode();
14076 SelectQuiltRefdbChart(selected_dbIndex);
14077 m_bpersistent_quilt =
false;
14079 SelectChartFromStack(selected_index);
14082 SelectChartFromStack(selected_index);
14083 g_sticky_chart = selected_dbIndex;
14087 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14091 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
14092 bool bfound =
false;
14093 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14094 if (m_tile_noshow_index_array[i] ==
14095 selected_dbIndex) {
14096 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14103 m_tile_noshow_index_array.push_back(selected_dbIndex);
14107 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14108 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14112 if (IsChartQuiltableRef(selected_dbIndex)) {
14118 bool set_scale =
false;
14119 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
14120 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14126 SelectQuiltRefdbChart(selected_dbIndex,
true);
14128 SelectQuiltRefdbChart(selected_dbIndex,
false);
14133 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14135 double proposed_scale_onscreen =
14138 if (g_bPreserveScaleOnX) {
14139 proposed_scale_onscreen =
14140 wxMin(proposed_scale_onscreen,
14142 GetCanvasWidth()));
14144 proposed_scale_onscreen =
14145 wxMin(proposed_scale_onscreen,
14147 GetCanvasWidth()));
14149 proposed_scale_onscreen =
14150 wxMax(proposed_scale_onscreen,
14159 ToggleCanvasQuiltMode();
14160 SelectdbChart(selected_dbIndex);
14161 m_bpersistent_quilt =
true;
14166 SetQuiltChartHiLiteIndex(-1);
14167 gFrame->UpdateGlobalMenuItems();
14169 HideChartInfoWindow();
14174void ChartCanvas::HandlePianoRClick(
14175 int x,
int y,
int selected_index,
14176 const std::vector<int> &selected_dbIndex_array) {
14177 if (g_options && g_options->IsShown())
14179 if (!GetpCurrentStack())
return;
14181 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14182 UpdateCanvasControlBar();
14184 SetQuiltChartHiLiteIndex(-1);
14187void ChartCanvas::HandlePianoRollover(
14188 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14189 int n_charts,
int scale) {
14190 if (g_options && g_options->IsShown())
14192 if (!GetpCurrentStack())
return;
14193 if (!ChartData)
return;
14195 if (ChartData->IsBusy())
return;
14197 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14199 if (!GetQuiltMode()) {
14200 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14203 std::vector<int> piano_chart_index_array;
14204 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14205 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14206 if ((GetpCurrentStack()->nEntry > 1) ||
14207 (piano_chart_index_array.size() >= 1)) {
14208 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14210 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14212 }
else if (GetpCurrentStack()->nEntry == 1) {
14214 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14215 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14216 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14218 }
else if ((-1 == selected_index) &&
14219 (0 == selected_dbIndex_array.size())) {
14220 ShowChartInfoWindow(key_location.x, -1);
14224 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14226 if ((GetpCurrentStack()->nEntry > 1) ||
14227 (piano_chart_index_array.size() >= 1)) {
14229 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14230 selected_dbIndex_array);
14231 else if (n_charts == 1)
14232 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14234 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14241void ChartCanvas::ClearPianoRollover() {
14242 ClearQuiltChartHiLiteIndexArray();
14243 ShowChartInfoWindow(0, -1);
14244 std::vector<int> vec;
14245 ShowCompositeInfoWindow(0, 0, 0, vec);
14249void ChartCanvas::UpdateCanvasControlBar(
void) {
14250 if (m_pianoFrozen)
return;
14252 if (!GetpCurrentStack())
return;
14253 if (!ChartData)
return;
14254 if (!g_bShowChartBar)
return;
14257 int sel_family = -1;
14259 std::vector<int> piano_chart_index_array;
14260 std::vector<int> empty_piano_chart_index_array;
14262 wxString old_hash = m_Piano->GetStoredHash();
14264 if (GetQuiltMode()) {
14265 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14266 GetQuiltFullScreendbIndexArray());
14268 std::vector<int> piano_active_chart_index_array =
14269 GetQuiltCandidatedbIndexArray();
14270 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14272 std::vector<int> piano_eclipsed_chart_index_array =
14273 GetQuiltEclipsedStackdbIndexArray();
14274 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14276 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14277 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14279 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14280 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14282 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
14283 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14286 if (m_singleChart) {
14287 sel_type = m_singleChart->GetChartType();
14288 sel_family = m_singleChart->GetChartFamily();
14293 std::vector<int> piano_skew_chart_index_array;
14294 std::vector<int> piano_tmerc_chart_index_array;
14295 std::vector<int> piano_poly_chart_index_array;
14297 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14299 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14300 double skew_norm = ctei.GetChartSkew();
14301 if (skew_norm > 180.) skew_norm -= 360.;
14303 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14304 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14307 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14308 if (fabs(skew_norm) > 1.)
14309 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14311 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14312 }
else if (fabs(skew_norm) > 1.)
14313 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14315 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14316 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14317 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14319 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14320 if (new_hash != old_hash) {
14321 m_Piano->FormatKeys();
14322 HideChartInfoWindow();
14323 m_Piano->ResetRollover();
14324 SetQuiltChartHiLiteIndex(-1);
14325 m_brepaint_piano =
true;
14331 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14333 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14334 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14335 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14336 if (e == CHART_FAMILY_RASTER) mask |= 1;
14337 if (e == CHART_FAMILY_VECTOR) {
14338 if (t == CHART_TYPE_CM93COMP)
14345 wxString s_indicated;
14346 if (sel_type == CHART_TYPE_CM93COMP)
14347 s_indicated = _T(
"cm93");
14349 if (sel_family == CHART_FAMILY_RASTER)
14350 s_indicated = _T(
"raster");
14351 else if (sel_family == CHART_FAMILY_VECTOR)
14352 s_indicated = _T(
"vector");
14355 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14358void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14360void ChartCanvas::PianoPopupMenu(
14361 int x,
int y,
int selected_index,
14362 const std::vector<int> &selected_dbIndex_array) {
14363 if (!GetpCurrentStack())
return;
14366 if (!GetQuiltMode())
return;
14368 m_piano_ctx_menu =
new wxMenu();
14370 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14380 menu_selected_dbIndex = selected_dbIndex_array[0];
14381 menu_selected_index = selected_index;
14384 bool b_is_in_noshow =
false;
14385 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14386 if (m_quilt_noshow_index_array[i] ==
14387 menu_selected_dbIndex)
14389 b_is_in_noshow =
true;
14394 if (b_is_in_noshow) {
14395 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14396 _(
"Show This Chart"));
14397 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14398 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14399 }
else if (GetpCurrentStack()->nEntry > 1) {
14400 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14401 _(
"Hide This Chart"));
14402 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14403 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14407 wxPoint pos = wxPoint(x, y - 30);
14410 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14411 PopupMenu(m_piano_ctx_menu, pos);
14413 delete m_piano_ctx_menu;
14414 m_piano_ctx_menu = NULL;
14416 HideChartInfoWindow();
14417 m_Piano->ResetRollover();
14419 SetQuiltChartHiLiteIndex(-1);
14420 ClearQuiltChartHiLiteIndexArray();
14425void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14426 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14427 if (m_quilt_noshow_index_array[i] ==
14428 menu_selected_dbIndex)
14430 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14436void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14437 if (!GetpCurrentStack())
return;
14438 if (!ChartData)
return;
14440 RemoveChartFromQuilt(menu_selected_dbIndex);
14444 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14445 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
14447 int i = menu_selected_index + 1;
14448 bool b_success =
false;
14449 while (i < GetpCurrentStack()->nEntry - 1) {
14450 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14451 if (type == ChartData->GetDBChartType(dbIndex)) {
14452 SelectQuiltRefChart(i);
14462 i = menu_selected_index - 1;
14464 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14465 if (type == ChartData->GetDBChartType(dbIndex)) {
14466 SelectQuiltRefChart(i);
14476void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14478 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14479 if (m_quilt_noshow_index_array[i] ==
14482 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14487 m_quilt_noshow_index_array.push_back(dbIndex);
14490bool ChartCanvas::UpdateS52State() {
14491 bool retval =
false;
14495 ps52plib->SetShowS57Text(m_encShowText);
14496 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14497 ps52plib->m_bShowSoundg = m_encShowDepth;
14498 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14499 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14502 if (!m_encShowLights)
14503 ps52plib->AddObjNoshow(
"LIGHTS");
14505 ps52plib->RemoveObjNoshow(
"LIGHTS");
14506 ps52plib->SetLightsOff(!m_encShowLights);
14507 ps52plib->m_bExtendLightSectors =
true;
14510 ps52plib->SetAnchorOn(m_encShowAnchor);
14511 ps52plib->SetQualityOfData(m_encShowDataQual);
14517void ChartCanvas::SetShowENCDataQual(
bool show) {
14518 m_encShowDataQual = show;
14519 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14520 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14522 m_s52StateHash = 0;
14525void ChartCanvas::SetShowENCText(
bool show) {
14526 m_encShowText = show;
14527 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14528 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14530 m_s52StateHash = 0;
14533void ChartCanvas::SetENCDisplayCategory(
int category) {
14534 m_encDisplayCategory = category;
14535 m_s52StateHash = 0;
14538void ChartCanvas::SetShowENCDepth(
bool show) {
14539 m_encShowDepth = show;
14540 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14541 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14543 m_s52StateHash = 0;
14546void ChartCanvas::SetShowENCLightDesc(
bool show) {
14547 m_encShowLightDesc = show;
14548 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14549 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14551 m_s52StateHash = 0;
14554void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14555 m_encShowBuoyLabels = show;
14556 m_s52StateHash = 0;
14559void ChartCanvas::SetShowENCLights(
bool show) {
14560 m_encShowLights = show;
14561 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14562 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14564 m_s52StateHash = 0;
14567void ChartCanvas::SetShowENCAnchor(
bool show) {
14568 m_encShowAnchor = show;
14569 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14570 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14572 m_s52StateHash = 0;
14575wxRect ChartCanvas::GetMUIBarRect() {
14578 rv = m_muiBar->GetRect();
14584void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14585 if (!GetAlertString().IsEmpty()) {
14586 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14587 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14589 dc.SetFont(*pfont);
14590 dc.SetPen(*wxTRANSPARENT_PEN);
14592 dc.SetBrush(wxColour(243, 229, 47));
14594 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14598 wxRect sbr = GetScaleBarRect();
14599 int xp = sbr.x + sbr.width + 10;
14600 int yp = (sbr.y + sbr.height) - h;
14602 int wdraw = w + 10;
14603 dc.DrawRectangle(xp, yp, wdraw, h);
14604 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14605 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14615#define BRIGHT_XCALIB
14616#define __OPCPN_USEICC__
14619#ifdef __OPCPN_USEICC__
14620int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14621 double co_green,
double co_blue);
14623wxString temp_file_name;
14627class ocpnCurtain:
public wxDialog
14629 DECLARE_CLASS( ocpnCurtain )
14630 DECLARE_EVENT_TABLE()
14633 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14635 bool ProcessEvent(wxEvent& event);
14639IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14641BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14644ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14646 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14649ocpnCurtain::~ocpnCurtain()
14653bool ocpnCurtain::ProcessEvent(wxEvent& event)
14655 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14656 return GetParent()->GetEventHandler()->ProcessEvent(event);
14661#include <windows.h>
14664typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14665typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14666SetDeviceGammaRamp_ptr_type
14667 g_pSetDeviceGammaRamp;
14668GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14670WORD *g_pSavedGammaMap;
14674int InitScreenBrightness(
void) {
14677 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14681 if (NULL == hGDI32DLL) {
14682 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14684 if (NULL != hGDI32DLL) {
14686 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14687 hGDI32DLL,
"SetDeviceGammaRamp");
14688 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14689 hGDI32DLL,
"GetDeviceGammaRamp");
14692 if ((NULL == g_pSetDeviceGammaRamp) ||
14693 (NULL == g_pGetDeviceGammaRamp)) {
14694 FreeLibrary(hGDI32DLL);
14703 if (!g_pSavedGammaMap) {
14704 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14707 bbr = g_pGetDeviceGammaRamp(
14708 hDC, g_pSavedGammaMap);
14709 ReleaseDC(NULL, hDC);
14714 wxRegKey *pRegKey =
new wxRegKey(
14715 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14716 _T(
"NT\\CurrentVersion\\ICM"));
14717 if (!pRegKey->Exists()) pRegKey->Create();
14718 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14720 g_brightness_init =
true;
14726 if (NULL == g_pcurtain) {
14727 if (gFrame->CanSetTransparent()) {
14729 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14730 wxPoint(0, 0), ::wxGetDisplaySize(),
14731 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14732 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14739 g_pcurtain->Hide();
14741 HWND hWnd = GetHwndOf(g_pcurtain);
14742 SetWindowLong(hWnd, GWL_EXSTYLE,
14743 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14744 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14745 g_pcurtain->SetTransparent(0);
14747 g_pcurtain->Maximize();
14748 g_pcurtain->Show();
14751 g_pcurtain->Enable();
14752 g_pcurtain->Disable();
14759 g_brightness_init =
true;
14765 wxString cmd(_T (
"xcalib -version" ));
14767 wxArrayString output;
14768 long r = wxExecute(cmd, output);
14771 _T(
" External application \"xcalib\" not found. Screen brightness ")
14772 _T(
"not changed."));
14774 g_brightness_init =
true;
14779int RestoreScreenBrightness(
void) {
14782 if (g_pSavedGammaMap) {
14783 HDC hDC = GetDC(NULL);
14784 g_pSetDeviceGammaRamp(hDC,
14786 ReleaseDC(NULL, hDC);
14788 free(g_pSavedGammaMap);
14789 g_pSavedGammaMap = NULL;
14793 g_pcurtain->Close();
14794 g_pcurtain->Destroy();
14798 g_brightness_init =
false;
14803#ifdef BRIGHT_XCALIB
14804 if (g_brightness_init) {
14806 cmd = _T(
"xcalib -clear");
14807 wxExecute(cmd, wxEXEC_ASYNC);
14808 g_brightness_init =
false;
14818int SetScreenBrightness(
int brightness) {
14825 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14827 g_pcurtain->Close();
14828 g_pcurtain->Destroy();
14832 InitScreenBrightness();
14834 if (NULL == hGDI32DLL) {
14836 wchar_t wdll_name[80];
14837 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14838 LPCWSTR cstr = wdll_name;
14840 hGDI32DLL = LoadLibrary(cstr);
14842 if (NULL != hGDI32DLL) {
14844 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14845 hGDI32DLL,
"SetDeviceGammaRamp");
14846 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14847 hGDI32DLL,
"GetDeviceGammaRamp");
14850 if ((NULL == g_pSetDeviceGammaRamp) ||
14851 (NULL == g_pGetDeviceGammaRamp)) {
14852 FreeLibrary(hGDI32DLL);
14859 HDC hDC = GetDC(NULL);
14870 int increment = brightness * 256 / 100;
14873 WORD GammaTable[3][256];
14876 for (
int i = 0; i < 256; i++) {
14877 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14878 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14879 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14881 table_val += increment;
14883 if (table_val > 65535) table_val = 65535;
14886 g_pSetDeviceGammaRamp(hDC, GammaTable);
14887 ReleaseDC(NULL, hDC);
14894 if (g_pSavedGammaMap) {
14895 HDC hDC = GetDC(NULL);
14896 g_pSetDeviceGammaRamp(hDC,
14898 ReleaseDC(NULL, hDC);
14901 if (brightness < 100) {
14902 if (NULL == g_pcurtain) InitScreenBrightness();
14905 int sbrite = wxMax(1, brightness);
14906 sbrite = wxMin(100, sbrite);
14908 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14912 g_pcurtain->Close();
14913 g_pcurtain->Destroy();
14923#ifdef BRIGHT_XCALIB
14925 if (!g_brightness_init) {
14926 last_brightness = 100;
14927 g_brightness_init =
true;
14928 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14929 InitScreenBrightness();
14932#ifdef __OPCPN_USEICC__
14935 if (!CreateSimpleICCProfileFile(
14936 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14937 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14938 wxString cmd(_T (
"xcalib " ));
14939 cmd += temp_file_name;
14941 wxExecute(cmd, wxEXEC_ASYNC);
14950 if (brightness > last_brightness) {
14952 cmd = _T(
"xcalib -clear");
14953 wxExecute(cmd, wxEXEC_ASYNC);
14955 ::wxMilliSleep(10);
14957 int brite_adj = wxMax(1, brightness);
14958 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14959 wxExecute(cmd, wxEXEC_ASYNC);
14961 int brite_adj = wxMax(1, brightness);
14962 int factor = (brite_adj * 100) / last_brightness;
14963 factor = wxMax(1, factor);
14965 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14966 wxExecute(cmd, wxEXEC_ASYNC);
14971 last_brightness = brightness;
14978#ifdef __OPCPN_USEICC__
14980#define MLUT_TAG 0x6d4c5554L
14981#define VCGT_TAG 0x76636774L
14983int GetIntEndian(
unsigned char *s) {
14988 p = (
unsigned char *)&ret;
14991 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14993 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14998unsigned short GetShortEndian(
unsigned char *s) {
14999 unsigned short ret;
15003 p = (
unsigned char *)&ret;
15006 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15008 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15014int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15015 double co_green,
double co_blue) {
15019 fp = fopen(file_name,
"wb");
15020 if (!fp)
return -1;
15026 for (
int i = 0; i < 128; i++) header[i] = 0;
15028 fwrite(header, 128, 1, fp);
15032 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15033 fwrite(&numTags, 1, 4, fp);
15035 int tagName0 = VCGT_TAG;
15036 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15037 fwrite(&tagName, 1, 4, fp);
15039 int tagOffset0 = 128 + 4 *
sizeof(int);
15040 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15041 fwrite(&tagOffset, 1, 4, fp);
15044 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15045 fwrite(&tagSize, 1, 4, fp);
15047 fwrite(&tagName, 1, 4, fp);
15049 fwrite(&tagName, 1, 4, fp);
15054 int gammatype0 = 0;
15055 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15056 fwrite(&gammatype, 1, 4, fp);
15058 int numChannels0 = 3;
15059 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15060 fwrite(&numChannels, 1, 2, fp);
15062 int numEntries0 = 256;
15063 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15064 fwrite(&numEntries, 1, 2, fp);
15066 int entrySize0 = 1;
15067 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15068 fwrite(&entrySize, 1, 2, fp);
15070 unsigned char ramp[256];
15073 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15074 fwrite(ramp, 256, 1, fp);
15077 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15078 fwrite(ramp, 256, 1, fp);
15081 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15082 fwrite(ramp, 256, 1, fp);
bool g_bresponsive
Flag to control adaptive UI scaling.
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.
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.
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.
Primary navigation console display for route and vessel tracking.
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.
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.
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.
Class NotificationManager.
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.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Tools to send data to plugins.
Route validators for dialog validation.
Represents an entry in the chart table, containing information about a single chart.