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);
792 int gridFontSize = 8;
793#if defined(__WXOSX__) || defined(__WXGTK3__)
795 gridFontSize *= GetContentScaleFactor();
799 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
800 FALSE, wxString(_T (
"Arial" )));
802 m_Piano =
new Piano(
this);
804 m_bShowCompassWin =
true;
807 m_Compass->SetScaleFactor(g_compass_scalefactor);
808 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
811 m_notification_button->SetScaleFactor(g_compass_scalefactor);
812 m_notification_button->Show(
true);
814 m_pianoFrozen =
false;
816 SetMinSize(wxSize(200, 200));
818 m_displayScale = 1.0;
819#if defined(__WXOSX__) || defined(__WXGTK3__)
821 m_displayScale = GetContentScaleFactor();
823 VPoint.SetPixelScale(m_displayScale);
825#ifdef HAVE_WX_GESTURE_EVENTS
828 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
829 wxLogError(
"Failed to enable touch events");
834 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
835 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
837 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
838 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
840 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
841 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
843 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
844 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
849 auto ¬eman = NotificationManager::GetInstance();
851 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
852 evt_notificationlist_change_listener.Listen(
853 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
854 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
855 if (m_NotificationsList && m_NotificationsList->IsShown()) {
856 m_NotificationsList->ReloadNotificationList();
862ChartCanvas::~ChartCanvas() {
863 delete pThumbDIBShow;
871 delete pCursorPencil;
875 delete pMovementTimer;
876 delete pMovementStopTimer;
877 delete pCurTrackTimer;
879 delete m_DoubleClickTimer;
881 delete m_pTrackRolloverWin;
882 delete m_pRouteRolloverWin;
883 delete m_pAISRolloverWin;
884 delete m_pBrightPopup;
890 m_dc_route.SelectObject(wxNullBitmap);
893 delete pWorldBackgroundChart;
894 delete pss_overlay_bmp;
898 delete m_pEM_Fathoms;
900 delete m_pEM_OverZoom;
905 delete m_pos_image_user_day;
906 delete m_pos_image_user_dusk;
907 delete m_pos_image_user_night;
908 delete m_pos_image_user_grey_day;
909 delete m_pos_image_user_grey_dusk;
910 delete m_pos_image_user_grey_night;
911 delete m_pos_image_user_yellow_day;
912 delete m_pos_image_user_yellow_dusk;
913 delete m_pos_image_user_yellow_night;
917 if (!g_bdisable_opengl) {
920#if wxCHECK_VERSION(2, 9, 0)
921 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
928 MUIBar *muiBar = m_muiBar;
932 delete m_pCurrentStack;
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();
3841 if (g_bopengl && m_glcc) {
3842 m_glcc->SetColorScheme(cs);
3843 g_glTextureManager->ClearAllRasterTextures();
3848 m_brepaint_piano =
true;
3855wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3856 wxImage img = Bitmap.ConvertToImage();
3857 int sx = img.GetWidth();
3858 int sy = img.GetHeight();
3860 wxImage new_img(img);
3862 for (
int i = 0; i < sx; i++) {
3863 for (
int j = 0; j < sy; j++) {
3864 if (!img.IsTransparent(i, j)) {
3865 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3866 (
unsigned char)(img.GetGreen(i, j) * factor),
3867 (
unsigned char)(img.GetBlue(i, j) * factor));
3872 wxBitmap ret = wxBitmap(new_img);
3877void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3880 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3882 if (!m_pBrightPopup) {
3885 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3889 m_pBrightPopup->SetSize(x, y);
3890 m_pBrightPopup->Move(120, 120);
3893 int bmpsx = m_pBrightPopup->GetSize().x;
3894 int bmpsy = m_pBrightPopup->GetSize().y;
3896 wxBitmap bmp(bmpsx, bmpsx);
3897 wxMemoryDC mdc(bmp);
3899 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3900 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3901 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3902 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3905 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3907 mdc.SetFont(*pfont);
3910 if (brightness == max)
3912 else if (brightness == min)
3915 val.Printf(_T(
"%3d"), brightness);
3917 mdc.DrawText(val, 0, 0);
3919 mdc.SelectObject(wxNullBitmap);
3921 m_pBrightPopup->SetBitmap(bmp);
3922 m_pBrightPopup->Show();
3923 m_pBrightPopup->Refresh();
3926void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3927 m_b_rot_hidef =
true;
3931void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3932 if (!g_bRollover)
return;
3934 bool b_need_refresh =
false;
3936 wxSize win_size = GetSize() * m_displayScale;
3937 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3940 bool showAISRollover =
false;
3941 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3943 SelectItem *pFind = pSelectAIS->FindSelection(
3946 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3947 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3950 showAISRollover =
true;
3952 if (NULL == m_pAISRolloverWin) {
3954 m_pAISRolloverWin->IsActive(
false);
3955 b_need_refresh =
true;
3956 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3957 m_AISRollover_MMSI != FoundAIS_MMSI) {
3963 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3964 m_pAISRolloverWin->IsActive(
false);
3965 m_AISRollover_MMSI = 0;
3970 m_AISRollover_MMSI = FoundAIS_MMSI;
3972 if (!m_pAISRolloverWin->IsActive()) {
3973 wxString s = ptarget->GetRolloverString();
3974 m_pAISRolloverWin->SetString(s);
3976 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3977 AIS_ROLLOVER, win_size);
3978 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3979 m_pAISRolloverWin->IsActive(
true);
3980 b_need_refresh =
true;
3984 m_AISRollover_MMSI = 0;
3985 showAISRollover =
false;
3990 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3991 m_pAISRolloverWin->IsActive(
false);
3992 m_AISRollover_MMSI = 0;
3993 b_need_refresh =
true;
3998 bool showRouteRollover =
false;
4000 if (NULL == m_pRolloverRouteSeg) {
4005 SelectableItemList SelList = pSelect->FindSelectionList(
4007 wxSelectableItemListNode *node = SelList.GetFirst();
4013 if (pr && pr->IsVisible()) {
4014 m_pRolloverRouteSeg = pFindSel;
4015 showRouteRollover =
true;
4017 if (NULL == m_pRouteRolloverWin) {
4019 m_pRouteRolloverWin->IsActive(
false);
4022 if (!m_pRouteRolloverWin->IsActive()) {
4030 DistanceBearingMercator(
4031 segShow_point_b->m_lat, segShow_point_b->m_lon,
4032 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4034 if (!pr->m_bIsInLayer)
4035 s.Append(_(
"Route") + _T(
": "));
4037 s.Append(_(
"Layer Route: "));
4039 if (pr->m_RouteNameString.IsEmpty())
4040 s.Append(_(
"(unnamed)"));
4042 s.Append(pr->m_RouteNameString);
4044 s << _T(
"\n") << _(
"Total Length: ")
4045 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
4046 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4047 << segShow_point_b->GetName() << _T(
"\n");
4050 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4051 (
int)floor(brg + 0.5), 0x00B0);
4054 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4056 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4057 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4059 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4060 (
int)floor(varBrg + 0.5), 0x00B0);
4063 s << FormatDistanceAdaptive(dist);
4068 double shiptoEndLeg = 0.;
4069 bool validActive =
false;
4070 if (pr->IsActive() &&
4071 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
4074 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
4075 wxRoutePointListNode *node =
4076 (pr->pRoutePointList)->GetFirst()->GetNext();
4078 float dist_to_endleg = 0;
4082 prp = node->GetData();
4088 if (prp->IsSame(segShow_point_a))
break;
4089 node = node->GetNext();
4091 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
4096 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
4097 << segShow_point_b->GetName() << _T(
"\n");
4100 ->GetCurrentRngToActivePoint();
4105 s << FormatDistanceAdaptive(shiptoEndLeg);
4109 if (!std::isnan(gCog) && !std::isnan(gSog))
4111 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
4114 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
4115 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4117 << wxString(ttg_sec > SECONDS_PER_DAY
4118 ? ttg_span.Format(_(
"%Dd %H:%M"))
4119 : ttg_span.Format(_(
"%H:%M")));
4120 wxDateTime dtnow, eta;
4121 eta = dtnow.SetToCurrent().Add(ttg_span);
4122 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
4123 << eta.Format(_T(
" %d %H:%M"));
4125 s << _T(
" ---- ----");
4127 m_pRouteRolloverWin->SetString(s);
4129 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4130 LEG_ROLLOVER, win_size);
4131 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4132 m_pRouteRolloverWin->IsActive(
true);
4133 b_need_refresh =
true;
4134 showRouteRollover =
true;
4138 node = node->GetNext();
4144 m_pRolloverRouteSeg))
4145 showRouteRollover =
false;
4146 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4147 showRouteRollover =
false;
4149 showRouteRollover =
true;
4153 if (m_routeState) showRouteRollover =
false;
4156 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4157 showRouteRollover =
false;
4159 if (m_pRouteRolloverWin &&
4160 !showRouteRollover) {
4161 m_pRouteRolloverWin->IsActive(
false);
4162 m_pRolloverRouteSeg = NULL;
4163 m_pRouteRolloverWin->Destroy();
4164 m_pRouteRolloverWin = NULL;
4165 b_need_refresh =
true;
4166 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4167 m_pRouteRolloverWin->IsActive(
true);
4168 b_need_refresh =
true;
4173 bool showTrackRollover =
false;
4175 if (NULL == m_pRolloverTrackSeg) {
4180 SelectableItemList SelList = pSelect->FindSelectionList(
4182 wxSelectableItemListNode *node = SelList.GetFirst();
4188 if (pt && pt->IsVisible()) {
4189 m_pRolloverTrackSeg = pFindSel;
4190 showTrackRollover =
true;
4192 if (NULL == m_pTrackRolloverWin) {
4194 m_pTrackRolloverWin->IsActive(
false);
4197 if (!m_pTrackRolloverWin->IsActive()) {
4205 DistanceBearingMercator(
4206 segShow_point_b->m_lat, segShow_point_b->m_lon,
4207 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4209 if (!pt->m_bIsInLayer)
4210 s.Append(_(
"Track") + _T(
": "));
4212 s.Append(_(
"Layer Track: "));
4214 if (pt->GetName().IsEmpty())
4215 s.Append(_(
"(unnamed)"));
4217 s.Append(pt->GetName());
4218 double tlenght = pt->Length();
4219 s << _T(
"\n") << _(
"Total Track: ")
4220 << FormatDistanceAdaptive(tlenght);
4221 if (pt->GetLastPoint()->GetTimeString() &&
4222 pt->GetPoint(0)->GetTimeString()) {
4223 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4224 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4225 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4226 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4227 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4228 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4229 << getUsrSpeedUnit();
4230 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4231 : ttime.Format(_T(
" %H:%M")));
4235 if (g_bShowTrackPointTime && strlen(segShow_point_b->GetTimeString()))
4236 s << _T(
"\n") << _(
"Segment Created: ")
4237 << segShow_point_b->GetTimeString();
4241 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4246 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4248 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4249 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4251 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4255 s << FormatDistanceAdaptive(dist);
4257 if (segShow_point_a->GetTimeString() &&
4258 segShow_point_b->GetTimeString()) {
4259 wxDateTime apoint = segShow_point_a->GetCreateTime();
4260 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4261 if (apoint.IsValid() && bpoint.IsValid()) {
4262 double segmentSpeed = toUsrSpeed(
4263 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4264 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4265 << getUsrSpeedUnit();
4269 m_pTrackRolloverWin->SetString(s);
4271 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4272 LEG_ROLLOVER, win_size);
4273 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4274 m_pTrackRolloverWin->IsActive(
true);
4275 b_need_refresh =
true;
4276 showTrackRollover =
true;
4280 node = node->GetNext();
4286 m_pRolloverTrackSeg))
4287 showTrackRollover =
false;
4288 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4289 showTrackRollover =
false;
4291 showTrackRollover =
true;
4295 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4296 showTrackRollover =
false;
4299 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4300 showTrackRollover =
false;
4306 if (m_pTrackRolloverWin &&
4307 !showTrackRollover) {
4308 m_pTrackRolloverWin->IsActive(
false);
4309 m_pRolloverTrackSeg = NULL;
4310 m_pTrackRolloverWin->Destroy();
4311 m_pTrackRolloverWin = NULL;
4312 b_need_refresh =
true;
4313 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4314 m_pTrackRolloverWin->IsActive(
true);
4315 b_need_refresh =
true;
4318 if (b_need_refresh) Refresh();
4321void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4322 if ((GetShowENCLights() || m_bsectors_shown) &&
4323 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4324 extendedSectorLegs)) {
4325 if (!m_bsectors_shown) {
4327 m_bsectors_shown =
true;
4330 if (m_bsectors_shown) {
4332 m_bsectors_shown =
false;
4340#if defined(__WXGTK__) || defined(__WXQT__)
4345 double cursor_lat, cursor_lon;
4348 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4349 while (cursor_lon < -180.) cursor_lon += 360.;
4351 while (cursor_lon > 180.) cursor_lon -= 360.;
4353 SetCursorStatus(cursor_lat, cursor_lon);
4359void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4360 if (!parent_frame->m_pStatusBar)
return;
4364 s1 += toSDMM(1, cursor_lat);
4366 s1 += toSDMM(2, cursor_lon);
4368 if (STAT_FIELD_CURSOR_LL >= 0)
4369 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4371 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4376 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4377 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4378 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4380 wxString s = st + sm;
4381 s << FormatDistanceAdaptive(dist);
4393 if (g_bShowLiveETA) {
4396 float boatSpeedDefault = g_defaultBoatSpeed;
4401 if (!std::isnan(gSog)) {
4403 if (boatSpeed < 0.5) {
4406 realTimeETA = dist / boatSpeed * 60;
4415 s << minutesToHoursDays(realTimeETA);
4420 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4421 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4423 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4428 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4436wxString minutesToHoursDays(
float timeInMinutes) {
4439 if (timeInMinutes == 0) {
4444 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4445 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4450 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4453 hours = (int)timeInMinutes / 60;
4454 min = (int)timeInMinutes % 60;
4457 s << wxString::Format(_T(
"%d"), hours);
4460 s << wxString::Format(_T(
"%d"), hours);
4462 s << wxString::Format(_T(
"%d"), min);
4469 else if (timeInMinutes > 24 * 60) {
4472 days = (int)(timeInMinutes / 60) / 24;
4473 hours = (int)(timeInMinutes / 60) % 24;
4476 s << wxString::Format(_T(
"%d"), days);
4479 s << wxString::Format(_T(
"%d"), days);
4481 s << wxString::Format(_T(
"%d"), hours);
4493void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4501 wxPoint2DDouble *r) {
4506 double rlon, wxPoint2DDouble *r) {
4517 if (!g_bopengl && m_singleChart &&
4518 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4519 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4520 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4521 (m_singleChart->GetChartProjectionType() !=
4522 PROJECTION_TRANSVERSE_MERCATOR) &&
4523 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4524 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4525 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4539 Cur_BSB_Ch->SetVPRasterParms(vp);
4540 double rpixxd, rpixyd;
4541 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4567 if (std::isnan(p.m_x)) {
4568 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4572 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4573 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4575 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4594 if (!g_bopengl && m_singleChart &&
4595 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4596 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4597 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4598 (m_singleChart->GetChartProjectionType() !=
4599 PROJECTION_TRANSVERSE_MERCATOR) &&
4600 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4601 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4602 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4613 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4616 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4621 else if (slon > 180.)
4632 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4638 DoZoomCanvas(factor,
false);
4639 extendedSectorLegs.clear();
4644 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4646 if (g_bsmoothpanzoom) {
4647 if (StartTimedMovement(stoptimer)) {
4649 m_zoom_factor = factor;
4654 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4656 DoZoomCanvas(factor, can_zoom_to_cursor);
4659 extendedSectorLegs.clear();
4662void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4664 if (!ChartData)
return;
4665 if (!m_pCurrentStack)
return;
4671 if (m_bzooming)
return;
4680 double proposed_scale_onscreen =
4683 bool b_do_zoom =
false;
4692 if (!VPoint.b_quilt) {
4695 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4696 if (new_db_index >= 0)
4697 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4701 int current_ref_stack_index = -1;
4702 if (m_pCurrentStack->nEntry) {
4704 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4705 m_pQuilt->SetReferenceChart(trial_index);
4706 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4707 if (new_db_index >= 0)
4708 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4712 if (m_pCurrentStack)
4713 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4723 double min_allowed_scale =
4726 if (proposed_scale_onscreen < min_allowed_scale) {
4731 proposed_scale_onscreen = min_allowed_scale;
4735 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4738 }
else if (factor < 1) {
4743 bool b_smallest =
false;
4745 if (!VPoint.b_quilt) {
4750 LLBBox viewbox = VPoint.GetBBox();
4752 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4753 double max_allowed_scale;
4767 if (proposed_scale_onscreen > max_allowed_scale) {
4769 proposed_scale_onscreen = max_allowed_scale;
4774 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4775 if (new_db_index >= 0)
4776 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4778 if (m_pCurrentStack)
4779 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4782 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4784 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4785 proposed_scale_onscreen =
4786 wxMin(proposed_scale_onscreen,
4792 m_absolute_min_scale_ppm)
4801 bool b_allow_ztc =
true;
4802 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4803 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4805 double brg, distance;
4806 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4809 meters_to_shift = distance * 1852;
4817 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4820 if (m_bFollow) DoCanvasUpdate();
4827void ChartCanvas::RotateCanvas(
double dir) {
4830 if (g_bsmoothpanzoom) {
4831 if (StartTimedMovement()) {
4833 m_rotation_speed = dir * 60;
4836 double speed = dir * 10;
4837 if (m_modkeys == wxMOD_ALT) speed /= 20;
4838 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4842void ChartCanvas::DoRotateCanvas(
double rotation) {
4843 while (rotation < 0) rotation += 2 * PI;
4844 while (rotation > 2 * PI) rotation -= 2 * PI;
4846 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4848 SetVPRotation(rotation);
4849 parent_frame->UpdateRotationState(VPoint.
rotation);
4852void ChartCanvas::DoTiltCanvas(
double tilt) {
4853 while (tilt < 0) tilt = 0;
4854 while (tilt > .95) tilt = .95;
4856 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4862void ChartCanvas::TogglebFollow(
void) {
4869void ChartCanvas::ClearbFollow(
void) {
4872 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4874 UpdateFollowButtonState();
4878 parent_frame->SetChartUpdatePeriod();
4881void ChartCanvas::SetbFollow(
void) {
4884 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4885 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4893 p.m_x += m_OSoffsetx;
4894 p.m_y -= m_OSoffsety;
4903 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4904 UpdateFollowButtonState();
4906 if (!g_bSmoothRecenter) {
4910 parent_frame->SetChartUpdatePeriod();
4913void ChartCanvas::UpdateFollowButtonState(
void) {
4916 m_muiBar->SetFollowButtonState(0);
4919 m_muiBar->SetFollowButtonState(2);
4921 m_muiBar->SetFollowButtonState(1);
4927 androidSetFollowTool(0);
4930 androidSetFollowTool(2);
4932 androidSetFollowTool(1);
4937void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4938 if (g_bSmoothRecenter && !m_routeState) {
4939 if (StartSmoothJump(lat, lon, scale_ppm))
4943 double gcDist, gcBearingEnd;
4944 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4946 gcBearingEnd += 180;
4947 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4950 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4951 double new_lat = lat + (lat_offset / (1852 * 60));
4952 double new_lon = lon + (lon_offset / (1852 * 60));
4955 StartSmoothJump(lat, lon, scale_ppm);
4960 if (lon > 180.0) lon -= 360.0;
4966 if (!GetQuiltMode()) {
4968 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4969 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4973 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4974 AdjustQuiltRefChart();
4981 UpdateFollowButtonState();
4989bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4994 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4995 double distance_pixels = gcDist *
GetVPScale();
4996 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5002 m_startLat = m_vLat;
5003 m_startLon = m_vLon;
5008 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5009 m_endScale = scale_ppm;
5012 m_animationDuration = 600;
5013 m_animationStart = wxGetLocalTimeMillis();
5020 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5021 m_animationActive =
true;
5026void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5028 wxLongLong now = wxGetLocalTimeMillis();
5029 double elapsed = (now - m_animationStart).ToDouble();
5030 double t = elapsed / m_animationDuration.ToDouble();
5031 if (t > 1.0) t = 1.0;
5034 double e = easeOutCubic(t);
5037 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5038 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5039 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5044 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5050 m_animationActive =
false;
5051 UpdateFollowButtonState();
5059 if (!ChartData)
return false;
5064 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
5065 UpdateFollowButtonState();
5071 extendedSectorLegs.clear();
5081 if (iters++ > 5)
return false;
5082 if (!std::isnan(dlat))
break;
5085 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5091 else if (dlat < -90)
5094 if (dlon > 360.) dlon -= 360.;
5095 if (dlon < -360.) dlon += 360.;
5110 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5114 if (VPoint.b_quilt) {
5115 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5116 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5118 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
5120 double tweak_scale_ppm =
5126 if (new_ref_dbIndex == -1) {
5127#pragma GCC diagnostic push
5128#pragma GCC diagnostic ignored "-Warray-bounds"
5135 int trial_index = -1;
5136 if (m_pCurrentStack->nEntry) {
5138 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5141 if (trial_index < 0) {
5142 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5143 if (full_screen_array.size())
5144 trial_index = full_screen_array[full_screen_array.size() - 1];
5147 if (trial_index >= 0) {
5148 m_pQuilt->SetReferenceChart(trial_index);
5153#pragma GCC diagnostic pop
5160 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5162 double offset_angle = atan2(offy, offx);
5163 double offset_distance = sqrt((offy * offy) + (offx * offx));
5164 double chart_angle = GetVPRotation();
5165 double target_angle = chart_angle - offset_angle;
5166 double d_east_mod = offset_distance * cos(target_angle);
5167 double d_north_mod = offset_distance * sin(target_angle);
5172 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5173 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5175 UpdateFollowButtonState();
5181 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5186void ChartCanvas::ReloadVP(
bool b_adjust) {
5187 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5189 LoadVP(VPoint, b_adjust);
5192void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5194 if (g_bopengl && m_glcc) {
5195 m_glcc->Invalidate();
5196 if (m_glcc->GetSize() != GetSize()) {
5197 m_glcc->SetSize(GetSize());
5202 m_cache_vp.Invalidate();
5203 m_bm_cache_vp.Invalidate();
5206 VPoint.Invalidate();
5208 if (m_pQuilt) m_pQuilt->Invalidate();
5217 vp.m_projection_type, b_adjust);
5220void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5221 m_pQuilt->SetReferenceChart(dbIndex);
5222 VPoint.Invalidate();
5223 m_pQuilt->Invalidate();
5226double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5228 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5235int ChartCanvas::AdjustQuiltRefChart() {
5238 wxASSERT(ChartData);
5240 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5242 double min_ref_scale =
5243 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5244 double max_ref_scale =
5245 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5248 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5250 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5252 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5254 int ref_family = pc->GetChartFamily();
5257 unsigned int target_stack_index = 0;
5258 int target_stack_index_check =
5259 m_pQuilt->GetExtendedStackIndexArray()
5260 [m_pQuilt->GetRefChartdbIndex()];
5262 if (wxNOT_FOUND != target_stack_index_check)
5263 target_stack_index = target_stack_index_check;
5265 int extended_array_count =
5266 m_pQuilt->GetExtendedStackIndexArray().size();
5267 while ((!brender_ok) &&
5268 ((
int)target_stack_index < (extended_array_count - 1))) {
5269 target_stack_index++;
5271 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5273 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
5274 IsChartQuiltableRef(test_db_index)) {
5277 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5279 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5286 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5287 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
5288 IsChartQuiltableRef(new_db_index)) {
5289 m_pQuilt->SetReferenceChart(new_db_index);
5292 ret = m_pQuilt->GetRefChartdbIndex();
5294 ret = m_pQuilt->GetRefChartdbIndex();
5297 ret = m_pQuilt->GetRefChartdbIndex();
5306void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5307 delete m_pCurrentStack;
5309 wxASSERT(ChartData);
5310 ChartData->BuildChartStack(m_pCurrentStack, VPoint.
clat, VPoint.
clon,
5319bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5320 double latNE,
double lonNE) {
5322 double latc = (latSW + latNE) / 2.0;
5323 double lonc = (lonSW + lonNE) / 2.0;
5326 double ne_easting, ne_northing;
5327 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5329 double sw_easting, sw_northing;
5330 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5332 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5339 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5342bool ChartCanvas::SetVPProjection(
int projection) {
5348 double prev_true_scale_ppm = m_true_scale_ppm;
5353 m_absolute_min_scale_ppm));
5361bool ChartCanvas::SetVPRotation(
double angle) {
5363 VPoint.
skew, angle);
5366 double skew,
double rotation,
int projection,
5367 bool b_adjust,
bool b_refresh) {
5372 if (VPoint.IsValid()) {
5373 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5374 (fabs(VPoint.
skew - skew) < 1e-9) &&
5375 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5376 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5377 (VPoint.m_projection_type == projection ||
5378 projection == PROJECTION_UNKNOWN))
5381 if (VPoint.m_projection_type != projection)
5382 VPoint.InvalidateTransformCache();
5392 if (projection != PROJECTION_UNKNOWN)
5393 VPoint.SetProjectionType(projection);
5394 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5395 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5398 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5399 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5400 if (VPoint.
clat > 89.5)
5402 else if (VPoint.
clat < -89.5)
5403 VPoint.
clat = -89.5;
5408 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5409 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5421 bool bwasValid = VPoint.IsValid();
5426 m_cache_vp.Invalidate();
5431 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5435 int mouseX = mouse_x;
5436 int mouseY = mouse_y;
5437 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5443 SendCursorLatLonToAllPlugIns(lat, lon);
5446 if (!VPoint.b_quilt && m_singleChart) {
5451 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5455 if ((!m_cache_vp.IsValid()) ||
5460 wxPoint cp_last, cp_this;
5464 if (cp_last != cp_this) {
5470 if (m_pCurrentStack) {
5471 assert(ChartData != 0);
5472 int current_db_index;
5474 m_pCurrentStack->GetCurrentEntrydbIndex();
5476 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5478 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5481 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5485 if (VPoint.b_quilt) {
5487 m_pQuilt->InvalidateAllQuiltPatchs();
5491 if (!m_pCurrentStack)
return false;
5493 int current_db_index;
5495 m_pCurrentStack->GetCurrentEntrydbIndex();
5497 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5498 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5501 int current_ref_stack_index = -1;
5502 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5503 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5504 current_ref_stack_index = i;
5507 if (g_bFullScreenQuilt) {
5508 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5512 bool b_needNewRef =
false;
5515 if ((-1 == current_ref_stack_index) &&
5516 (m_pQuilt->GetRefChartdbIndex() >= 0))
5517 b_needNewRef =
true;
5524 bool renderable =
true;
5526 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5527 if (referenceChart) {
5528 double chartMaxScale = referenceChart->GetNormalScaleMax(
5530 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5532 if (!renderable) b_needNewRef =
true;
5537 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5538 int target_scale = cte_ref.GetScale();
5539 int target_type = cte_ref.GetChartType();
5540 int candidate_stack_index;
5547 candidate_stack_index = 0;
5548 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5550 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5551 int candidate_scale = cte_candidate.GetScale();
5552 int candidate_type = cte_candidate.GetChartType();
5554 if ((candidate_scale >= target_scale) &&
5555 (candidate_type == target_type)) {
5556 bool renderable =
true;
5557 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5558 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5559 if (tentative_referenceChart) {
5560 double chartMaxScale =
5561 tentative_referenceChart->GetNormalScaleMax(
5563 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5566 if (renderable)
break;
5569 candidate_stack_index++;
5574 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5575 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5576 while (candidate_stack_index >= 0) {
5577 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5580 ChartData->GetChartTableEntry(idx);
5581 int candidate_scale = cte_candidate.GetScale();
5582 int candidate_type = cte_candidate.GetChartType();
5584 if ((candidate_scale <= target_scale) &&
5585 (candidate_type == target_type))
5588 candidate_stack_index--;
5593 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5594 (candidate_stack_index < 0))
5595 candidate_stack_index = 0;
5597 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5599 m_pQuilt->SetReferenceChart(new_ref_index);
5605 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5610 bool renderable =
true;
5612 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5613 if (referenceChart) {
5614 double chartMaxScale = referenceChart->GetNormalScaleMax(
5616 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5617 proj = ChartData->GetDBChartProj(ref_db_index);
5619 proj = PROJECTION_MERCATOR;
5621 VPoint.b_MercatorProjectionOverride =
5622 (m_pQuilt->GetnCharts() == 0 || !renderable);
5624 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5626 VPoint.SetProjectionType(proj);
5633 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5638 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5658 m_pQuilt->Invalidate();
5673 ChartData->PurgeCacheUnusedCharts(0.7);
5675 if (b_refresh) Refresh(
false);
5682 }
else if (!g_bopengl) {
5683 OcpnProjType projection = PROJECTION_UNKNOWN;
5686 projection = m_singleChart->GetChartProjectionType();
5687 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5688 VPoint.SetProjectionType(projection);
5692 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5693 m_cache_vp.Invalidate();
5697 UpdateCanvasControlBar();
5703 if (VPoint.GetBBox().GetValid()) {
5706 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5715 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5718 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5725 wxPoint2DDouble r, r1;
5727 double delta_check =
5731 double check_point = wxMin(89., VPoint.
clat);
5733 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5736 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5737 VPoint.
clon, 0, &rhumbDist);
5742 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5743 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5745 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5749 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5755 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5757 if (m_true_scale_ppm)
5758 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5763 double round_factor = 1000.;
5767 round_factor = 100.;
5769 round_factor = 1000.;
5772 double retina_coef = 1;
5776 retina_coef = GetContentScaleFactor();
5787 double true_scale_display =
5788 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5793 if (m_displayed_scale_factor > 10.0)
5794 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5795 m_displayed_scale_factor);
5796 else if (m_displayed_scale_factor > 1.0)
5797 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5798 m_displayed_scale_factor);
5799 else if (m_displayed_scale_factor > 0.1) {
5800 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5801 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5802 }
else if (m_displayed_scale_factor > 0.01) {
5803 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5804 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5807 _T(
"%s %4.0f (---)"), _(
"Scale"),
5808 true_scale_display);
5811 m_scaleValue = true_scale_display;
5813 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5815 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5816 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5818 bool b_noshow =
false;
5822 wxClientDC dc(parent_frame->GetStatusBar());
5824 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5825 dc.SetFont(*templateFont);
5826 dc.GetTextExtent(text, &w, &h);
5831 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5832 if (w && w > rect.width) {
5833 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5834 m_displayed_scale_factor);
5838 dc.GetTextExtent(text, &w, &h);
5840 if (w && w > rect.width) {
5846 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5851 m_vLat = VPoint.
clat;
5852 m_vLon = VPoint.
clon;
5866static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5870static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5871 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5873wxColour ChartCanvas::PredColor() {
5876 if (SHIP_NORMAL == m_ownship_state)
5877 return GetGlobalColor(_T (
"URED" ));
5879 else if (SHIP_LOWACCURACY == m_ownship_state)
5880 return GetGlobalColor(_T (
"YELO1" ));
5882 return GetGlobalColor(_T (
"NODTA" ));
5885wxColour ChartCanvas::ShipColor() {
5889 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5891 if (SHIP_LOWACCURACY == m_ownship_state)
5892 return GetGlobalColor(_T (
"YELO1" ));
5894 return GetGlobalColor(_T (
"URED" ));
5897void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5898 wxPoint2DDouble lShipMidPoint) {
5899 dc.SetPen(wxPen(PredColor(), 2));
5901 if (SHIP_NORMAL == m_ownship_state)
5902 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5904 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5906 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5907 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5909 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5911 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5912 lShipMidPoint.m_y + 12);
5915void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5916 wxPoint GPSOffsetPixels,
5917 wxPoint2DDouble lGPSPoint) {
5918 if (m_animationActive)
return;
5922 float ref_dim = m_display_size_mm / 24;
5923 ref_dim = wxMin(ref_dim, 12);
5924 ref_dim = wxMax(ref_dim, 6);
5927 cPred.Set(g_cog_predictor_color);
5928 if (cPred == wxNullColour) cPred = PredColor();
5935 double nominal_line_width_pix = wxMax(
5937 floor(m_pix_per_mm / 2));
5941 if (nominal_line_width_pix > g_cog_predictor_width)
5942 g_cog_predictor_width = nominal_line_width_pix;
5945 wxPoint lPredPoint, lHeadPoint;
5947 float pCog = std::isnan(gCog) ? 0 : gCog;
5948 float pSog = std::isnan(gSog) ? 0 : gSog;
5950 double pred_lat, pred_lon;
5951 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5952 &pred_lat, &pred_lon);
5963 float ndelta_pix = 10.;
5964 double hdg_pred_lat, hdg_pred_lon;
5965 bool b_render_hdt =
false;
5966 if (!std::isnan(gHdt)) {
5968 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5971 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5972 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5973 if (dist > ndelta_pix ) {
5974 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5975 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5980 wxPoint lShipMidPoint;
5981 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5982 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5983 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5984 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5986 if (lpp >= img_height / 2) {
5987 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5988 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5989 !std::isnan(gSog)) {
5991 float dash_length = ref_dim;
5992 wxDash dash_long[2];
5994 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5995 g_cog_predictor_width);
5996 dash_long[1] = dash_long[0] / 2.0;
6000 if (dash_length > 250.) {
6001 dash_long[0] = 250. / g_cog_predictor_width;
6002 dash_long[1] = dash_long[0] / 2;
6005 wxPen ppPen2(cPred, g_cog_predictor_width,
6006 (wxPenStyle)g_cog_predictor_style);
6007 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6008 ppPen2.SetDashes(2, dash_long);
6011 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6012 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6014 if (g_cog_predictor_width > 1) {
6015 float line_width = g_cog_predictor_width / 3.;
6017 wxDash dash_long3[2];
6018 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6019 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6021 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
6022 (wxPenStyle)g_cog_predictor_style);
6023 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6024 ppPen3.SetDashes(2, dash_long3);
6026 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6027 lGPSPoint.m_y + GPSOffsetPixels.y,
6028 lPredPoint.x + GPSOffsetPixels.x,
6029 lPredPoint.y + GPSOffsetPixels.y);
6032 if (g_cog_predictor_endmarker) {
6034 double png_pred_icon_scale_factor = .4;
6035 if (g_ShipScaleFactorExp > 1.0)
6036 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6037 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6041 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6042 (
float)(lPredPoint.x - lShipMidPoint.x));
6043 cog_rad += (float)PI;
6045 for (
int i = 0; i < 4; i++) {
6047 double pxa = (double)(s_png_pred_icon[j]);
6048 double pya = (double)(s_png_pred_icon[j + 1]);
6050 pya *= png_pred_icon_scale_factor;
6051 pxa *= png_pred_icon_scale_factor;
6053 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6054 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6056 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6057 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6061 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
6064 dc.SetBrush(wxBrush(cPred));
6066 dc.StrokePolygon(4, icon);
6073 float hdt_dash_length = ref_dim * 0.4;
6075 cPred.Set(g_ownship_HDTpredictor_color);
6076 if (cPred == wxNullColour) cPred = PredColor();
6078 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6079 : g_cog_predictor_width * 0.8);
6080 wxDash dash_short[2];
6082 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6085 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6088 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6089 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6090 ppPen2.SetDashes(2, dash_short);
6094 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6095 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6097 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6099 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
6101 if (g_ownship_HDTpredictor_endmarker) {
6102 double nominal_circle_size_pixels = wxMax(
6103 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6106 if (g_ShipScaleFactorExp > 1.0)
6107 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6109 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6110 lHeadPoint.y + GPSOffsetPixels.y,
6111 nominal_circle_size_pixels / 2);
6116 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6117 double factor = 1.00;
6118 if (g_pNavAidRadarRingsStepUnits == 1)
6120 else if (g_pNavAidRadarRingsStepUnits == 2) {
6121 if (std::isnan(gSog))
6126 factor *= g_fNavAidRadarRingsStep;
6130 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
6133 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6134 pow((
double)(lGPSPoint.m_y - r.y), 2));
6135 int pix_radius = (int)lpp;
6137 extern wxColor GetDimColor(wxColor c);
6138 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6140 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6143 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6145 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6146 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6150void ChartCanvas::ComputeShipScaleFactor(
6151 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6152 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6153 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6154 float screenResolution = m_pix_per_mm;
6157 double ship_bow_lat, ship_bow_lon;
6158 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6159 &ship_bow_lat, &ship_bow_lon);
6160 wxPoint lShipBowPoint;
6161 wxPoint2DDouble b_point =
6165 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6166 powf((
float)(b_point.m_y - a_point.m_y), 2));
6169 float shipLength_mm = shipLength_px / screenResolution;
6172 float ownship_min_mm = g_n_ownship_min_mm;
6173 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6176 float hdt_ant = icon_hdt + 180.;
6177 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6178 float dx = g_n_gps_antenna_offset_x / 1852.;
6179 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6187 if (shipLength_mm < ownship_min_mm) {
6188 dy /= shipLength_mm / ownship_min_mm;
6189 dx /= shipLength_mm / ownship_min_mm;
6192 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6194 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6195 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6201 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6202 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6204 float scale_factor = shipLength_px / ownShipLength;
6207 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6210 scale_factor = wxMax(scale_factor, scale_factor_min);
6212 scale_factor_y = scale_factor;
6213 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6214 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6217void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6218 if (!GetVP().IsValid())
return;
6220 wxPoint GPSOffsetPixels(0, 0);
6221 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6224 float pCog = std::isnan(gCog) ? 0 : gCog;
6225 float pSog = std::isnan(gSog) ? 0 : gSog;
6229 lShipMidPoint = lGPSPoint;
6233 float icon_hdt = pCog;
6234 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6237 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6241 double osd_head_lat, osd_head_lon;
6242 wxPoint osd_head_point;
6244 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6249 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6250 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6251 icon_rad += (float)PI;
6253 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6257 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6261 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6262 if (GetVP().chart_scale >
6265 ShipDrawLargeScale(dc, lShipMidPoint);
6271 if (m_pos_image_user)
6272 pos_image = m_pos_image_user->Copy();
6273 else if (SHIP_NORMAL == m_ownship_state)
6274 pos_image = m_pos_image_red->Copy();
6275 if (SHIP_LOWACCURACY == m_ownship_state)
6276 pos_image = m_pos_image_yellow->Copy();
6277 else if (SHIP_NORMAL != m_ownship_state)
6278 pos_image = m_pos_image_grey->Copy();
6281 if (m_pos_image_user) {
6282 pos_image = m_pos_image_user->Copy();
6284 if (SHIP_LOWACCURACY == m_ownship_state)
6285 pos_image = m_pos_image_user_yellow->Copy();
6286 else if (SHIP_NORMAL != m_ownship_state)
6287 pos_image = m_pos_image_user_grey->Copy();
6290 img_height = pos_image.GetHeight();
6292 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6293 g_OwnShipIconType > 0)
6295 int ownShipWidth = 22;
6296 int ownShipLength = 84;
6297 if (g_OwnShipIconType == 1) {
6298 ownShipWidth = pos_image.GetWidth();
6299 ownShipLength = pos_image.GetHeight();
6302 float scale_factor_x, scale_factor_y;
6303 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6304 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6305 scale_factor_x, scale_factor_y);
6307 if (g_OwnShipIconType == 1) {
6308 pos_image.Rescale(ownShipWidth * scale_factor_x,
6309 ownShipLength * scale_factor_y,
6310 wxIMAGE_QUALITY_HIGH);
6311 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6313 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6316 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6317 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6318 if (rot_image.GetAlpha(ip, jp) > 64)
6319 rot_image.SetAlpha(ip, jp, 255);
6321 wxBitmap os_bm(rot_image);
6323 int w = os_bm.GetWidth();
6324 int h = os_bm.GetHeight();
6327 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6328 lShipMidPoint.m_y - h / 2,
true);
6331 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6332 lShipMidPoint.m_y - h / 2);
6333 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6334 lShipMidPoint.m_y - h / 2 + h);
6337 else if (g_OwnShipIconType == 2) {
6338 wxPoint ownship_icon[10];
6340 for (
int i = 0; i < 10; i++) {
6342 float pxa = (float)(s_ownship_icon[j]);
6343 float pya = (float)(s_ownship_icon[j + 1]);
6344 pya *= scale_factor_y;
6345 pxa *= scale_factor_x;
6347 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6348 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6350 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6351 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6354 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6356 dc.SetBrush(wxBrush(ShipColor()));
6358 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6361 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6363 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6367 img_height = ownShipLength * scale_factor_y;
6371 if (m_pos_image_user) circle_rad = 1;
6373 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6374 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6375 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6378 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6380 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6383 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6384 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6385 if (rot_image.GetAlpha(ip, jp) > 64)
6386 rot_image.SetAlpha(ip, jp, 255);
6388 wxBitmap os_bm(rot_image);
6390 if (g_ShipScaleFactorExp > 1) {
6391 wxImage scaled_image = os_bm.ConvertToImage();
6392 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6394 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6395 scaled_image.GetHeight() * factor,
6396 wxIMAGE_QUALITY_HIGH));
6398 int w = os_bm.GetWidth();
6399 int h = os_bm.GetHeight();
6402 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6403 lShipMidPoint.m_y - h / 2,
true);
6407 if (m_pos_image_user) circle_rad = 1;
6409 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6410 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6411 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6414 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6415 lShipMidPoint.m_y - h / 2);
6416 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6417 lShipMidPoint.m_y - h / 2 + h);
6422 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6435void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6436 float &MinorSpacing) {
6441 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6442 {.000001f, 45.0f, 15.0f},
6443 {.0002f, 30.0f, 10.0f},
6444 {.0003f, 10.0f, 2.0f},
6445 {.0008f, 5.0f, 1.0f},
6446 {.001f, 2.0f, 30.0f / 60.0f},
6447 {.003f, 1.0f, 20.0f / 60.0f},
6448 {.006f, 0.5f, 10.0f / 60.0f},
6449 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6450 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6451 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6452 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6453 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6454 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6455 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6456 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6459 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6460 if (view_scale_ppm < lltab[tabi][0])
break;
6461 MajorSpacing = lltab[tabi][1];
6462 MinorSpacing = lltab[tabi][2];
6476wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6477 int deg = (int)fabs(latlon);
6478 float min = fabs((fabs(latlon) - deg) * 60.0);
6488 }
else if (latlon < 0.0) {
6500 if (spacing >= 1.0) {
6501 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6502 }
else if (spacing >= (1.0 / 60.0)) {
6503 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6505 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6522void ChartCanvas::GridDraw(
ocpnDC &dc) {
6523 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6525 double nlat, elon, slat, wlon;
6528 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6530 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6532 dc.SetFont(*m_pgridFont);
6533 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6536 h = m_canvas_height;
6547 dlon = dlon + 360.0;
6550 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6553 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6556 while (lat < nlat) {
6559 CalcGridText(lat, gridlatMajor,
true);
6561 dc.
DrawLine(0, r.y, w, r.y,
false);
6562 dc.DrawText(st, 0, r.y);
6563 lat = lat + gridlatMajor;
6565 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6569 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6572 while (lat < nlat) {
6575 dc.
DrawLine(0, r.y, 10, r.y,
false);
6576 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6577 lat = lat + gridlatMinor;
6581 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6584 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6587 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6589 wxString st = CalcGridText(lon, gridlonMajor,
false);
6591 dc.
DrawLine(r.x, 0, r.x, h,
false);
6592 dc.DrawText(st, r.x, 0);
6593 lon = lon + gridlonMajor;
6598 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6602 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6604 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6607 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6608 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6609 lon = lon + gridlonMinor;
6616void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6618 double blat, blon, tlat, tlon;
6621 int x_origin = m_bDisplayGrid ? 60 : 20;
6622 int y_origin = m_canvas_height - 50;
6628 if (GetVP().chart_scale > 80000)
6632 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6633 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6638 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6639 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6643 double rotation = -VPoint.
rotation;
6645 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6647 int l1 = (y_origin - r.y) / count;
6649 for (
int i = 0; i < count; i++) {
6656 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6659 double blat, blon, tlat, tlon;
6666 int y_origin = m_canvas_height - chartbar_height - 5;
6670 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6677 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6680 int unit = g_iDistanceFormat;
6682 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6683 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6686 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6687 float places = floor(logdist), rem = logdist - places;
6688 dist = pow(10, places);
6695 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6696 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6697 double rotation = -VPoint.
rotation;
6699 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6703 int l1 = r.x - x_origin;
6705 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6710 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6711 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6712 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6714 dc.SetFont(*m_pgridFont);
6715 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6717 dc.GetTextExtent(s, &w, &h);
6718 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6722void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6727 double ra_max = 40.;
6729 wxPen pen_save = dc.GetPen();
6731 wxDateTime now = wxDateTime::Now();
6737 x0 = x1 = x + radius;
6742 while (angle < 360.) {
6743 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6746 if (angle > 360.) angle = 360.;
6748 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6756 x1 = (int)(x + cos(angle * PI / 180.) * r);
6757 y1 = (int)(y + sin(angle * PI / 180.) * r);
6767 dc.
DrawLine(x + radius, y, x1, y1);
6769 dc.SetPen(pen_save);
6772static bool bAnchorSoundPlaying =
false;
6774static void onAnchorSoundFinished(
void *ptr) {
6775 g_anchorwatch_sound->UnLoad();
6776 bAnchorSoundPlaying =
false;
6779void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6781 bool play_sound =
false;
6782 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6783 if (AnchorAlertOn1) {
6784 wxPoint TargetPoint;
6787 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6788 TargetPoint.y, 100);
6792 AnchorAlertOn1 =
false;
6794 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6795 if (AnchorAlertOn2) {
6796 wxPoint TargetPoint;
6799 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6800 TargetPoint.y, 100);
6804 AnchorAlertOn2 =
false;
6807 if (!bAnchorSoundPlaying) {
6808 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6809 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6810 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6811 if (g_anchorwatch_sound->IsOk()) {
6812 bAnchorSoundPlaying =
true;
6813 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6814 g_anchorwatch_sound->Play();
6820void ChartCanvas::UpdateShips() {
6823 wxClientDC dc(
this);
6824 if (!dc.IsOk())
return;
6826 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6827 if (!test_bitmap.IsOk())
return;
6829 wxMemoryDC temp_dc(test_bitmap);
6831 temp_dc.ResetBoundingBox();
6832 temp_dc.DestroyClippingRegion();
6833 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6839 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6840 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6844 ocpndc.CalcBoundingBox(px.x, px.y);
6849 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6850 temp_dc.MaxY() - temp_dc.MinY());
6852 wxRect own_ship_update_rect = ship_draw_rect;
6854 if (!own_ship_update_rect.IsEmpty()) {
6857 own_ship_update_rect.Union(ship_draw_last_rect);
6858 own_ship_update_rect.Inflate(2);
6861 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6863 ship_draw_last_rect = ship_draw_rect;
6865 temp_dc.SelectObject(wxNullBitmap);
6868void ChartCanvas::UpdateAlerts() {
6873 wxClientDC dc(
this);
6877 dc.GetSize(&sx, &sy);
6880 wxBitmap test_bitmap(sx, sy, -1);
6884 temp_dc.SelectObject(test_bitmap);
6886 temp_dc.ResetBoundingBox();
6887 temp_dc.DestroyClippingRegion();
6888 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6895 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6896 temp_dc.MaxX() - temp_dc.MinX(),
6897 temp_dc.MaxY() - temp_dc.MinY());
6899 if (!alert_rect.IsEmpty())
6900 alert_rect.Inflate(2);
6902 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6905 wxRect alert_update_rect = alert_draw_rect;
6906 alert_update_rect.Union(alert_rect);
6909 RefreshRect(alert_update_rect,
false);
6913 alert_draw_rect = alert_rect;
6915 temp_dc.SelectObject(wxNullBitmap);
6918void ChartCanvas::UpdateAIS() {
6919 if (!g_pAIS)
return;
6924 wxClientDC dc(
this);
6928 dc.GetSize(&sx, &sy);
6936 if (g_pAIS->GetTargetList().size() > 10) {
6937 ais_rect = wxRect(0, 0, sx, sy);
6940 wxBitmap test_bitmap(sx, sy, -1);
6944 temp_dc.SelectObject(test_bitmap);
6946 temp_dc.ResetBoundingBox();
6947 temp_dc.DestroyClippingRegion();
6948 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6952 AISDraw(ocpndc, GetVP(),
this);
6953 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6957 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6958 temp_dc.MaxY() - temp_dc.MinY());
6960 if (!ais_rect.IsEmpty())
6961 ais_rect.Inflate(2);
6963 temp_dc.SelectObject(wxNullBitmap);
6966 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6969 wxRect ais_update_rect = ais_draw_rect;
6970 ais_update_rect.Union(ais_rect);
6973 RefreshRect(ais_update_rect,
false);
6977 ais_draw_rect = ais_rect;
6980void ChartCanvas::ToggleCPAWarn() {
6981 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6987 g_bTCPA_Max =
false;
6991 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6992 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6994 if (!g_AisFirstTimeUse) {
6995 OCPNMessageBox(
this,
6996 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
6997 _(
"CPA") + _T(
" ") + mess, 4, 4);
7002void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7004void ChartCanvas::OnSize(wxSizeEvent &event) {
7005 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7007 GetClientSize(&m_canvas_width, &m_canvas_height);
7011 m_displayScale = GetContentScaleFactor();
7015 m_canvas_width *= m_displayScale;
7016 m_canvas_height *= m_displayScale;
7029 m_absolute_min_scale_ppm =
7031 (1.2 * WGS84_semimajor_axis_meters * PI);
7034 gFrame->ProcessCanvasResize();
7044 SetMUIBarPosition();
7045 UpdateFollowButtonState();
7046 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7050 xr_margin = m_canvas_width * 95 / 100;
7051 xl_margin = m_canvas_width * 5 / 100;
7052 yt_margin = m_canvas_height * 5 / 100;
7053 yb_margin = m_canvas_height * 95 / 100;
7056 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7061 m_brepaint_piano =
true;
7064 m_dc_route.SelectObject(wxNullBitmap);
7067 m_dc_route.SelectObject(*proute_bm);
7081 m_glcc->OnSize(event);
7090void ChartCanvas::ProcessNewGUIScale() {
7098void ChartCanvas::CreateMUIBar() {
7099 if (g_useMUI && !m_muiBar) {
7103 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
7105 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7106 m_muiBar->SetColorScheme(m_cs);
7107 m_muiBarHOSize = m_muiBar->m_size;
7111 SetMUIBarPosition();
7112 UpdateFollowButtonState();
7113 m_muiBar->UpdateDynamicValues();
7114 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7118void ChartCanvas::SetMUIBarPosition() {
7122 int pianoWidth = GetClientSize().x * 0.6f;
7127 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7128 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7130 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7131 m_muiBar->SetColorScheme(m_cs);
7135 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7136 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7138 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7139 m_muiBar->SetColorScheme(m_cs);
7143 m_muiBar->SetBestPosition();
7147void ChartCanvas::DestroyMuiBar() {
7154void ChartCanvas::ShowCompositeInfoWindow(
7155 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7157 if (NULL == m_pCIWin) {
7162 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7165 s = _(
"Composite of ");
7168 s1.Printf(
"%d ", n_charts);
7176 s1.Printf(_(
"Chart scale"));
7179 s2.Printf(
"1:%d\n",
scale);
7183 s1 = _(
"Zoom in for more information");
7187 int char_width = s1.Length();
7188 int char_height = 3;
7190 if (g_bChartBarEx) {
7193 for (
int i : index_vector) {
7195 wxString path = cte.GetFullSystemPath();
7199 char_width = wxMax(char_width, path.Length());
7200 if (j++ >= 9)
break;
7203 s +=
" .\n .\n .\n";
7212 m_pCIWin->SetString(s);
7214 m_pCIWin->FitToChars(char_width, char_height);
7217 p.x = x / GetContentScaleFactor();
7218 if ((p.x + m_pCIWin->GetWinSize().x) >
7219 (m_canvas_width / GetContentScaleFactor()))
7220 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7221 m_pCIWin->GetWinSize().x) /
7224 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7225 4 - m_pCIWin->GetWinSize().y;
7227 m_pCIWin->dbIndex = 0;
7228 m_pCIWin->chart_scale = 0;
7229 m_pCIWin->SetPosition(p);
7230 m_pCIWin->SetBitmap();
7231 m_pCIWin->Refresh();
7235 HideChartInfoWindow();
7239void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7241 if (NULL == m_pCIWin) {
7246 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7253 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
7254 pc = ChartData->OpenChartFromDBAndLock(
7255 dbIndex, FULL_INIT);
7257 int char_width, char_height;
7258 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7259 if (pc) ChartData->UnLockCacheChart(dbIndex);
7261 m_pCIWin->SetString(s);
7262 m_pCIWin->FitToChars(char_width, char_height);
7265 p.x = x / GetContentScaleFactor();
7266 if ((p.x + m_pCIWin->GetWinSize().x) >
7267 (m_canvas_width / GetContentScaleFactor()))
7268 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7269 m_pCIWin->GetWinSize().x) /
7272 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7273 4 - m_pCIWin->GetWinSize().y;
7275 m_pCIWin->dbIndex = dbIndex;
7276 m_pCIWin->SetPosition(p);
7277 m_pCIWin->SetBitmap();
7278 m_pCIWin->Refresh();
7282 HideChartInfoWindow();
7286void ChartCanvas::HideChartInfoWindow(
void) {
7289 m_pCIWin->Destroy();
7293 androidForceFullRepaint();
7298void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7299 wxMouseEvent ev(wxEVT_MOTION);
7302 ev.m_leftDown = mouse_leftisdown;
7304 wxEvtHandler *evthp = GetEventHandler();
7306 ::wxPostEvent(evthp, ev);
7309void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7310 if ((m_panx_target_final - m_panx_target_now) ||
7311 (m_pany_target_final - m_pany_target_now)) {
7312 DoTimedMovementTarget();
7317void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7319bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7321 if (m_disable_edge_pan)
return false;
7324 int pan_margin = m_canvas_width * margin / 100;
7325 int pan_timer_set = 200;
7326 double pan_delta = GetVP().
pix_width * delta / 100;
7330 if (x > m_canvas_width - pan_margin) {
7335 else if (x < pan_margin) {
7340 if (y < pan_margin) {
7345 else if (y > m_canvas_height - pan_margin) {
7354 wxMouseState state = ::wxGetMouseState();
7355#if wxCHECK_VERSION(3, 0, 0)
7356 if (!state.LeftIsDown())
7358 if (!state.LeftDown())
7363 if ((bft) && !pPanTimer->IsRunning()) {
7365 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7371 if ((!bft) && pPanTimer->IsRunning()) {
7381void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7382 bool setBeingEdited) {
7383 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7384 m_pRoutePointEditTarget = NULL;
7385 m_pFoundPoint = NULL;
7389 SelectableItemList SelList = pSelect->FindSelectionList(
7391 wxSelectableItemListNode *node = SelList.GetFirst();
7393 pFind = node->GetData();
7402 bool brp_viz =
false;
7403 if (m_pEditRouteArray) {
7404 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7405 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7406 if (pr->IsVisible()) {
7412 brp_viz = frp->IsVisible();
7416 if (m_pEditRouteArray)
7418 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7419 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7422 m_bRouteEditing = setBeingEdited;
7425 frp->m_bRPIsBeingEdited = setBeingEdited;
7426 m_bMarkEditing = setBeingEdited;
7429 m_pRoutePointEditTarget = frp;
7430 m_pFoundPoint = pFind;
7434 node = node->GetNext();
7438void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7439 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7440 singleClickEventIsValid =
false;
7441 m_DoubleClickTimer->Stop();
7446bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7447 if (!m_bChartDragging && !m_bDrawingRoute) {
7452 if (m_Compass && m_Compass->IsShown()) {
7454 bool isInCompass = logicalRect.Contains(event.GetPosition());
7456 if (m_Compass->MouseEvent(event)) {
7457 cursor_region = CENTER;
7458 if (!g_btouch) SetCanvasCursor(event);
7464 if (m_notification_button && m_notification_button->IsShown()) {
7466 bool isinButton = logicalRect.Contains(event.GetPosition());
7468 SetCursor(*pCursorArrow);
7469 if (event.LeftDown()) HandleNotificationMouseClick();
7474 if (MouseEventToolbar(event))
return true;
7476 if (MouseEventChartBar(event))
return true;
7478 if (MouseEventMUIBar(event))
return true;
7480 if (MouseEventIENCBar(event))
return true;
7485void ChartCanvas::HandleNotificationMouseClick() {
7486 if (!m_NotificationsList) {
7491 wxPoint ClientUpperRight = ClientToScreen(wxPoint(GetSize().x, 0));
7492 wxPoint list_bottom = ClientToScreen(wxPoint(0, GetSize().y / 2));
7493 int size_y = list_bottom.y - (ClientUpperRight.y + 5);
7494 size_y -= GetCharHeight();
7495 size_y = wxMax(size_y, 200);
7497 m_NotificationsList->SetSize(wxSize(GetCharWidth() * 80, size_y));
7499 wxPoint m_currentNLPos = ClientToScreen(wxPoint(
7500 GetSize().x / 2, m_notification_button->
GetRect().y +
7501 m_notification_button->
GetRect().height + 5));
7503 m_NotificationsList->Move(m_currentNLPos);
7504 m_NotificationsList->Hide();
7507 if (m_NotificationsList->IsShown()) {
7508 m_NotificationsList->Hide();
7510 m_NotificationsList->ReloadNotificationList();
7511 m_NotificationsList->Show();
7514bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7515 if (!g_bShowChartBar)
return false;
7517 if (!m_Piano->MouseEvent(event))
return false;
7519 cursor_region = CENTER;
7520 if (!g_btouch) SetCanvasCursor(event);
7524bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7525 if (!IsPrimaryCanvas())
return false;
7527 if (g_MainToolbar) {
7528 if (!g_MainToolbar->MouseEvent(event))
7531 g_MainToolbar->RefreshToolbar();
7534 cursor_region = CENTER;
7535 if (!g_btouch) SetCanvasCursor(event);
7539bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7540 if (!IsPrimaryCanvas())
return false;
7542 if (g_iENCToolbar) {
7543 if (!g_iENCToolbar->MouseEvent(event))
7546 g_iENCToolbar->RefreshToolbar();
7553bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7555 if (!m_muiBar->MouseEvent(event))
return false;
7558 cursor_region = CENTER;
7559 if (!g_btouch) SetCanvasCursor(event);
7571 event.GetPosition(&x, &y);
7573 x *= m_displayScale;
7574 y *= m_displayScale;
7576 m_MouseDragging =
event.Dragging();
7582 if (event.Dragging()) {
7583 if ((x == mouse_x) && (y == mouse_y))
return true;
7589 mouse_leftisdown =
event.LeftDown();
7593 cursor_region = CENTER;
7597 if (m_Compass && m_Compass->IsShown() &&
7598 m_Compass->
GetRect().Contains(event.GetPosition())) {
7599 cursor_region = CENTER;
7600 }
else if (x > xr_margin) {
7601 cursor_region = MID_RIGHT;
7602 }
else if (x < xl_margin) {
7603 cursor_region = MID_LEFT;
7604 }
else if (y > yb_margin - chartbar_height &&
7605 y < m_canvas_height - chartbar_height) {
7606 cursor_region = MID_TOP;
7607 }
else if (y < yt_margin) {
7608 cursor_region = MID_BOT;
7610 cursor_region = CENTER;
7613 if (!g_btouch) SetCanvasCursor(event);
7617 leftIsDown =
event.LeftDown();
7620 if (event.LeftDown()) {
7621 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7624 g_bTempShowMenuBar =
false;
7625 parent_frame->ApplyGlobalSettings(
false);
7633 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7634 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7638 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7639 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7642 event.SetEventObject(
this);
7643 if (SendMouseEventToPlugins(event))
7650 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7651 StartChartDragInertia();
7654 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7656 if (m_DoubleClickTimer->IsRunning()) {
7657 m_DoubleClickTimer->Stop();
7662 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7663 singleClickEvent = event;
7664 singleClickEventIsValid =
true;
7673 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7674 if (g_click_stop > 0) {
7682 if (GetUpMode() == COURSE_UP_MODE) {
7683 m_b_rot_hidef =
false;
7684 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7686 pRotDefTimer->Stop();
7689 bool bRoll = !g_btouch;
7691 bRoll = g_bRollover;
7694 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7695 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7696 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7697 m_RolloverPopupTimer.Start(
7701 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7705 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7714#if !defined(__WXGTK__) && !defined(__WXQT__)
7722 if ((x >= 0) && (y >= 0))
7727 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7728 wxPoint p = ClientToScreen(wxPoint(x, y));
7734 if (m_routeState >= 2) {
7737 m_bDrawingRoute =
true;
7739 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7744 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7747 m_bDrawingRoute =
true;
7749 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7756void ChartCanvas::CallPopupMenu(
int x,
int y) {
7764 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7773#if defined(__WXMAC__) || defined(__ANDROID__)
7777 wxClientDC cdc(GetParent());
7789 if (m_pSelectedRoute) {
7791 m_pSelectedRoute->DeSelectRoute();
7793 if (g_bopengl && m_glcc) {
7798 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7801 if (m_pFoundRoutePoint) {
7809 if (g_btouch && m_pRoutePointEditTarget) {
7812 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7817 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7818 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7819 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7820 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7824 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7827 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7833 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7836 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7837 seltype |= SELTYPE_AISTARGET;
7842 m_pFoundRoutePoint = NULL;
7847 Route *pSelectedActiveRoute = NULL;
7848 Route *pSelectedVizRoute = NULL;
7852 SelectableItemList SelList =
7853 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7854 wxSelectableItemListNode *node = SelList.GetFirst();
7864 bool brp_viz =
false;
7866 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7868 if (pr->IsVisible()) {
7873 if (!brp_viz && prp->IsShared())
7875 brp_viz = prp->IsVisible();
7878 brp_viz = prp->IsVisible();
7880 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7885 m_pSelectedRoute = NULL;
7887 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7890 pSelectedActiveRoute = pr;
7891 pFoundActiveRoutePoint = prp;
7896 if (NULL == pSelectedVizRoute) {
7897 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7899 if (pr->IsVisible()) {
7900 pSelectedVizRoute = pr;
7901 pFoundVizRoutePoint = prp;
7907 delete proute_array;
7910 node = node->GetNext();
7914 if (pFoundActiveRoutePoint) {
7915 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7916 m_pSelectedRoute = pSelectedActiveRoute;
7917 }
else if (pFoundVizRoutePoint) {
7918 m_pFoundRoutePoint = pFoundVizRoutePoint;
7919 m_pSelectedRoute = pSelectedVizRoute;
7922 m_pFoundRoutePoint = pFirstVizPoint;
7924 if (m_pSelectedRoute) {
7925 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7926 }
else if (m_pFoundRoutePoint)
7927 seltype |= SELTYPE_MARKPOINT;
7931 if (m_pFoundRoutePoint) {
7935 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7936 RefreshRect(wp_rect,
true);
7945 SelectableItemList SelList =
7946 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7948 if (NULL == m_pSelectedRoute)
7951 wxSelectableItemListNode *node = SelList.GetFirst();
7956 if (pr->IsVisible()) {
7957 m_pSelectedRoute = pr;
7960 node = node->GetNext();
7964 if (m_pSelectedRoute) {
7965 if (NULL == m_pFoundRoutePoint)
7966 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7971 if (g_bopengl && m_glcc) {
7976 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7979 seltype |= SELTYPE_ROUTESEGMENT;
7983 if (pFindTrackSeg) {
7984 m_pSelectedTrack = NULL;
7986 SelectableItemList SelList =
7987 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7990 wxSelectableItemListNode *node = SelList.GetFirst();
7995 if (pt->IsVisible()) {
7996 m_pSelectedTrack = pt;
7999 node = node->GetNext();
8002 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8005 bool bseltc =
false;
8019 SelectableItemList SelList = pSelectTC->FindSelectionList(
8023 wxSelectableItemListNode *node = SelList.GetFirst();
8024 pFind = node->GetData();
8025 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8027 if (SelList.GetCount() > 1) {
8028 node = node->GetNext();
8030 pFind = node->GetData();
8032 if (pIDX_candidate->
IDX_type ==
'c') {
8033 pIDX_best_candidate = pIDX_candidate;
8037 node = node->GetNext();
8040 wxSelectableItemListNode *node = SelList.GetFirst();
8041 pFind = node->GetData();
8042 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8045 m_pIDXCandidate = pIDX_best_candidate;
8048 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
8052 seltype |= SELTYPE_CURRENTPOINT;
8055 else if (pFindTide) {
8056 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8059 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
8063 seltype |= SELTYPE_TIDEPOINT;
8067 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8070 InvokeCanvasMenu(x, y, seltype);
8073 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8077 m_pSelectedRoute = NULL;
8079 if (m_pFoundRoutePoint) {
8080 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8083 m_pFoundRoutePoint = NULL;
8091bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8099 event.GetPosition(&x, &y);
8105 SelectRadius = g_Platform->GetSelectRadiusPix() /
8106 (m_true_scale_ppm * 1852 * 60);
8113 if (event.LeftDClick() && (cursor_region == CENTER)) {
8114 m_DoubleClickTimer->Start();
8115 singleClickEventIsValid =
false;
8119 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8124 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8127 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8128 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8129 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8135 SelectableItemList rpSelList =
8136 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8137 wxSelectableItemListNode *node = rpSelList.GetFirst();
8138 bool b_onRPtarget =
false;
8142 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8143 b_onRPtarget =
true;
8146 node = node->GetNext();
8151 if (m_pRoutePointEditTarget) {
8153 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8159 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8162 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8163 m_pRoutePointEditTarget = NULL;
8164 RefreshRect(wp_rect,
true);
8168 node = rpSelList.GetFirst();
8173 wxArrayPtrVoid *proute_array =
8178 bool brp_viz =
false;
8180 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8182 if (pr->IsVisible()) {
8187 delete proute_array;
8191 brp_viz = frp->IsVisible();
8193 brp_viz = frp->IsVisible();
8196 ShowMarkPropertiesDialog(frp);
8204 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8208 if (pr->IsVisible()) {
8209 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8214 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8218 if (pt->IsVisible()) {
8219 ShowTrackPropertiesDialog(pt);
8226 ShowObjectQueryWindow(x, y, zlat, zlon);
8231 if (event.LeftDown()) {
8247 bool appending =
false;
8248 bool inserting =
false;
8251 SetCursor(*pCursorPencil);
8255 m_bRouteEditing =
true;
8257 if (m_routeState == 1) {
8258 m_pMouseRoute =
new Route();
8259 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8260 pRouteList->Append(m_pMouseRoute);
8269 double nearby_radius_meters =
8270 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8273 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8274 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8275 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8276 wxArrayPtrVoid *proute_array =
8281 bool brp_viz =
false;
8283 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8285 if (pr->IsVisible()) {
8290 delete proute_array;
8292 pNearbyPoint->IsShared())
8295 pNearbyPoint->IsVisible();
8297 brp_viz = pNearbyPoint->IsVisible();
8300 wxString msg = _(
"Use nearby waypoint?");
8302 const bool noname(pNearbyPoint->GetName() ==
"");
8305 _(
"Use nearby nameless waypoint and name it M with"
8306 " a unique number?");
8309 m_FinishRouteOnKillFocus =
false;
8311 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8312 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8313 m_FinishRouteOnKillFocus =
true;
8314 if (dlg_return == wxID_YES) {
8316 if (m_pMouseRoute) {
8317 int last_wp_num = m_pMouseRoute->GetnPoints();
8319 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8320 wxString wp_name = wxString::Format(
8321 "M%002i-%s", last_wp_num + 1, guid_short);
8322 pNearbyPoint->SetName(wp_name);
8324 pNearbyPoint->SetName(
"WPXX");
8326 pMousePoint = pNearbyPoint;
8329 if (m_routeState > 1)
8330 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8331 Undo_HasParent, NULL);
8334 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8335 bool procede =
false;
8339 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8345 m_FinishRouteOnKillFocus =
false;
8351 _(
"Insert first part of this route in the new route?");
8352 if (tail->GetIndexOf(pMousePoint) ==
8355 dmsg = _(
"Insert this route in the new route?");
8357 if (tail->GetIndexOf(pMousePoint) != 1) {
8358 dlg_return = OCPNMessageBox(
8359 this, dmsg, _(
"OpenCPN Route Create"),
8360 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8361 m_FinishRouteOnKillFocus =
true;
8363 if (dlg_return == wxID_YES) {
8370 _(
"Append last part of this route to the new route?");
8371 if (tail->GetIndexOf(pMousePoint) == 1)
8373 "Append this route to the new route?");
8378 if (tail->GetLastPoint() != pMousePoint) {
8379 dlg_return = OCPNMessageBox(
8380 this, dmsg, _(
"OpenCPN Route Create"),
8381 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8382 m_FinishRouteOnKillFocus =
true;
8384 if (dlg_return == wxID_YES) {
8395 if (!FindRouteContainingWaypoint(pMousePoint))
8396 pMousePoint->SetShared(
true);
8401 if (NULL == pMousePoint) {
8402 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8403 _T(
""), wxEmptyString);
8404 pMousePoint->SetNameShown(
false);
8408 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8410 if (m_routeState > 1)
8411 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8412 Undo_IsOrphanded, NULL);
8415 if (m_pMouseRoute) {
8416 if (m_routeState == 1) {
8418 m_pMouseRoute->AddPoint(pMousePoint);
8422 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8423 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8424 &rhumbBearing, &rhumbDist);
8425 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8426 rlat, &gcDist, &gcBearing, NULL);
8427 double gcDistNM = gcDist / 1852.0;
8430 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8431 pow(rhumbDist - gcDistNM - 1, 0.5);
8434 msg << _(
"For this leg the Great Circle route is ")
8435 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8436 << _(
" shorter than rhumbline.\n\n")
8437 << _(
"Would you like include the Great Circle routing points "
8440 m_FinishRouteOnKillFocus =
false;
8441 m_disable_edge_pan =
true;
8444 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8445 wxYES_NO | wxNO_DEFAULT);
8447 m_disable_edge_pan =
false;
8448 m_FinishRouteOnKillFocus =
true;
8450 if (answer == wxID_YES) {
8452 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8453 wxRealPoint gcCoord;
8455 for (
int i = 1; i <= segmentCount; i++) {
8456 double fraction = (double)i * (1.0 / (
double)segmentCount);
8457 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8458 gcDist * fraction, gcBearing,
8459 &gcCoord.x, &gcCoord.y, NULL);
8461 if (i < segmentCount) {
8462 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8463 _T(
""), wxEmptyString);
8464 gcPoint->SetNameShown(
false);
8466 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8468 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8471 gcPoint = pMousePoint;
8474 m_pMouseRoute->AddPoint(gcPoint);
8475 pSelect->AddSelectableRouteSegment(
8476 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8477 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8478 prevGcPoint = gcPoint;
8481 undo->CancelUndoableAction(
true);
8484 m_pMouseRoute->AddPoint(pMousePoint);
8485 pSelect->AddSelectableRouteSegment(
8486 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8487 pMousePoint, m_pMouseRoute);
8488 undo->AfterUndoableAction(m_pMouseRoute);
8492 m_pMouseRoute->AddPoint(pMousePoint);
8493 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8494 rlon, m_prev_pMousePoint,
8495 pMousePoint, m_pMouseRoute);
8496 undo->AfterUndoableAction(m_pMouseRoute);
8502 m_prev_pMousePoint = pMousePoint;
8510 int connect = tail->GetIndexOf(pMousePoint);
8515 int length = tail->GetnPoints();
8520 start = connect + 1;
8525 m_pMouseRoute->RemovePoint(
8529 for (i = start; i <= stop; i++) {
8530 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8533 m_pMouseRoute->GetnPoints();
8535 gFrame->RefreshAllCanvas();
8539 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8541 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8542 m_pMouseRoute->FinalizeForRendering();
8544 gFrame->RefreshAllCanvas();
8548 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8550 SetCursor(*pCursorPencil);
8552 if (!m_pMeasureRoute) {
8553 m_pMeasureRoute =
new Route();
8554 pRouteList->Append(m_pMeasureRoute);
8557 if (m_nMeasureState == 1) {
8563 wxString(_T (
"circle" )),
8564 wxEmptyString, wxEmptyString);
8566 pMousePoint->SetShowWaypointRangeRings(
false);
8568 m_pMeasureRoute->AddPoint(pMousePoint);
8572 m_prev_pMousePoint = pMousePoint;
8576 gFrame->RefreshAllCanvas();
8581 FindRoutePointsAtCursor(SelectRadius,
true);
8586 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8594 if (ret)
return true;
8597 if (event.Dragging()) {
8602 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8604 SelectableItemList SelList = pSelect->FindSelectionList(
8606 wxSelectableItemListNode *node = SelList.GetFirst();
8608 pFind = node->GetData();
8610 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8611 node = node->GetNext();
8616 if (m_pRoutePointEditTarget &&
8617 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8619 SelectableItemList SelList = pSelect->FindSelectionList(
8621 wxSelectableItemListNode *node = SelList.GetFirst();
8623 pFind = node->GetData();
8625 if (m_pRoutePointEditTarget == frp) {
8626 m_bIsInRadius =
true;
8629 node = node->GetNext();
8632 if (!m_dragoffsetSet) {
8634 .PresetDragOffset(
this, mouse_x, mouse_y);
8635 m_dragoffsetSet =
true;
8640 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8641 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8643 if (NULL == g_pMarkInfoDialog) {
8644 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8645 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8646 DraggingAllowed =
false;
8648 if (m_pRoutePointEditTarget &&
8649 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8650 DraggingAllowed =
false;
8652 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8654 if (DraggingAllowed) {
8655 if (!undo->InUndoableAction()) {
8656 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8657 Undo_NeedsCopy, m_pFoundPoint);
8663 if (!g_bopengl && m_pEditRouteArray) {
8664 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8665 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8670 if (g_pRouteMan->IsRouteValid(pr)) {
8672 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8673 pre_rect.Union(route_rect);
8681 if (CheckEdgePan(x, y,
true, 5, 2))
8689 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8691 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8692 m_pRoutePointEditTarget,
8693 SELTYPE_DRAGHANDLE);
8694 m_pFoundPoint->m_slat =
8695 m_pRoutePointEditTarget->m_lat;
8696 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8698 m_pRoutePointEditTarget->m_lat =
8700 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8701 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8702 m_pFoundPoint->m_slat =
8704 m_pFoundPoint->m_slon = new_cursor_lon;
8708 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8709 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8710 g_pMarkInfoDialog->UpdateProperties(
true);
8720 if (m_pEditRouteArray) {
8721 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8723 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8724 if (g_pRouteMan->IsRouteValid(pr)) {
8726 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8727 post_rect.Union(route_rect);
8733 pre_rect.Union(post_rect);
8734 RefreshRect(pre_rect,
false);
8736 gFrame->RefreshCanvasOther(
this);
8737 m_bRoutePoinDragging =
true;
8742 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8743 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8745 if (NULL == g_pMarkInfoDialog) {
8746 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8747 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8748 DraggingAllowed =
false;
8750 if (m_pRoutePointEditTarget &&
8751 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8752 DraggingAllowed =
false;
8754 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8756 if (DraggingAllowed) {
8757 if (!undo->InUndoableAction()) {
8758 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8759 Undo_NeedsCopy, m_pFoundPoint);
8767 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8768 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8770 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8771 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8773 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8779 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8780 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8781 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8782 (
int)(lppmax - (pre_rect.height / 2)));
8790 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8793 m_pRoutePointEditTarget,
8794 SELTYPE_DRAGHANDLE);
8795 m_pFoundPoint->m_slat =
8796 m_pRoutePointEditTarget->m_lat;
8797 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8799 m_pRoutePointEditTarget->m_lat =
8802 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8808 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8809 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8810 g_pMarkInfoDialog->UpdateProperties(
true);
8815 if (!g_btouch) InvalidateGL();
8821 .CalculateDCRect(m_dc_route,
this, &post_rect);
8822 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8823 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8824 (
int)(lppmax - (post_rect.height / 2)));
8827 pre_rect.Union(post_rect);
8828 RefreshRect(pre_rect,
false);
8830 gFrame->RefreshCanvasOther(
this);
8831 m_bRoutePoinDragging =
true;
8836 if (ret)
return true;
8839 if (event.LeftUp()) {
8840 bool b_startedit_route =
false;
8841 m_dragoffsetSet =
false;
8844 m_bChartDragging =
false;
8845 m_bIsInRadius =
false;
8850 m_bedge_pan =
false;
8855 bool appending =
false;
8856 bool inserting =
false;
8862 if (m_pRoutePointEditTarget) {
8868 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8869 RefreshRect(wp_rect,
true);
8871 m_pRoutePointEditTarget = NULL;
8873 m_bRouteEditing =
true;
8875 if (m_routeState == 1) {
8876 m_pMouseRoute =
new Route();
8877 m_pMouseRoute->SetHiLite(50);
8878 pRouteList->Append(m_pMouseRoute);
8887 double nearby_radius_meters =
8888 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8891 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8892 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8893 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8896 m_FinishRouteOnKillFocus =
8898 dlg_return = OCPNMessageBox(
8899 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8900 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8901 m_FinishRouteOnKillFocus =
true;
8903 dlg_return = wxID_YES;
8905 if (dlg_return == wxID_YES) {
8906 pMousePoint = pNearbyPoint;
8909 if (m_routeState > 1)
8910 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8911 Undo_HasParent, NULL);
8912 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8914 bool procede =
false;
8918 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8924 m_FinishRouteOnKillFocus =
false;
8925 if (m_routeState == 1) {
8929 _(
"Insert first part of this route in the new route?");
8930 if (tail->GetIndexOf(pMousePoint) ==
8933 dmsg = _(
"Insert this route in the new route?");
8935 if (tail->GetIndexOf(pMousePoint) != 1) {
8937 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8938 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8939 m_FinishRouteOnKillFocus =
true;
8941 if (dlg_return == wxID_YES) {
8948 _(
"Append last part of this route to the new route?");
8949 if (tail->GetIndexOf(pMousePoint) == 1)
8951 "Append this route to the new route?");
8955 if (tail->GetLastPoint() != pMousePoint) {
8957 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8958 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8959 m_FinishRouteOnKillFocus =
true;
8961 if (dlg_return == wxID_YES) {
8972 if (!FindRouteContainingWaypoint(pMousePoint))
8973 pMousePoint->SetShared(
true);
8977 if (NULL == pMousePoint) {
8978 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8979 _T(
""), wxEmptyString);
8980 pMousePoint->SetNameShown(
false);
8983 NavObj_dB::GetInstance().InsertRoutePoint(pMousePoint);
8985 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8987 if (m_routeState > 1)
8988 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8989 Undo_IsOrphanded, NULL);
8992 if (m_routeState == 1) {
8994 m_pMouseRoute->AddPoint(pMousePoint);
8997 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8998 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8999 &rhumbBearing, &rhumbDist);
9000 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9001 &gcDist, &gcBearing, NULL);
9002 double gcDistNM = gcDist / 1852.0;
9005 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9006 pow(rhumbDist - gcDistNM - 1, 0.5);
9009 msg << _(
"For this leg the Great Circle route is ")
9010 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
9011 << _(
" shorter than rhumbline.\n\n")
9012 << _(
"Would you like include the Great Circle routing points "
9016 m_FinishRouteOnKillFocus =
false;
9017 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9018 wxYES_NO | wxNO_DEFAULT);
9019 m_FinishRouteOnKillFocus =
true;
9021 int answer = wxID_NO;
9024 if (answer == wxID_YES) {
9026 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9027 wxRealPoint gcCoord;
9029 for (
int i = 1; i <= segmentCount; i++) {
9030 double fraction = (double)i * (1.0 / (
double)segmentCount);
9031 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9032 gcDist * fraction, gcBearing,
9033 &gcCoord.x, &gcCoord.y, NULL);
9035 if (i < segmentCount) {
9036 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
9037 _T(
""), wxEmptyString);
9038 gcPoint->SetNameShown(
false);
9040 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
9042 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9045 gcPoint = pMousePoint;
9048 m_pMouseRoute->AddPoint(gcPoint);
9049 pSelect->AddSelectableRouteSegment(
9050 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9051 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9052 prevGcPoint = gcPoint;
9055 undo->CancelUndoableAction(
true);
9058 m_pMouseRoute->AddPoint(pMousePoint);
9059 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9060 rlon, m_prev_pMousePoint,
9061 pMousePoint, m_pMouseRoute);
9062 undo->AfterUndoableAction(m_pMouseRoute);
9066 m_pMouseRoute->AddPoint(pMousePoint);
9067 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9068 rlon, m_prev_pMousePoint,
9069 pMousePoint, m_pMouseRoute);
9070 undo->AfterUndoableAction(m_pMouseRoute);
9076 m_prev_pMousePoint = pMousePoint;
9083 int connect = tail->GetIndexOf(pMousePoint);
9088 int length = tail->GetnPoints();
9093 start = connect + 1;
9098 m_pMouseRoute->RemovePoint(
9102 for (i = start; i <= stop; i++) {
9103 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9106 m_pMouseRoute->GetnPoints();
9108 gFrame->RefreshAllCanvas();
9112 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9114 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9115 m_pMouseRoute->FinalizeForRendering();
9120 }
else if (m_bMeasure_Active && m_nMeasureState)
9123 m_bedge_pan =
false;
9127 if (m_nMeasureState == 1) {
9128 m_pMeasureRoute =
new Route();
9129 pRouteList->Append(m_pMeasureRoute);
9134 if (m_pMeasureRoute) {
9137 wxEmptyString, wxEmptyString);
9140 m_pMeasureRoute->AddPoint(pMousePoint);
9144 m_prev_pMousePoint = pMousePoint;
9146 m_pMeasureRoute->GetnPoints();
9150 CancelMeasureRoute();
9156 bool bSelectAllowed =
true;
9157 if (NULL == g_pMarkInfoDialog) {
9158 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9159 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9160 bSelectAllowed =
false;
9167 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9169 if (bSelectAllowed) {
9170 bool b_was_editing_mark = m_bMarkEditing;
9171 bool b_was_editing_route = m_bRouteEditing;
9172 FindRoutePointsAtCursor(SelectRadius,
9178 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9179 m_pRoutePointEditTarget = NULL;
9181 if (!b_was_editing_route) {
9182 if (m_pEditRouteArray) {
9183 b_startedit_route =
true;
9187 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9188 m_pTrackRolloverWin->IsActive(
false);
9190 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9191 m_pRouteRolloverWin->IsActive(
false);
9195 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9197 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9202 if (g_pRouteMan->IsRouteValid(pr)) {
9205 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9206 pre_rect.Union(route_rect);
9209 RefreshRect(pre_rect,
true);
9212 b_startedit_route =
false;
9216 if (m_pRoutePointEditTarget) {
9217 if (b_was_editing_mark ||
9218 b_was_editing_route) {
9219 if (m_lastRoutePointEditTarget) {
9223 .EnableDragHandle(
false);
9224 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9225 SELTYPE_DRAGHANDLE);
9229 if (m_pRoutePointEditTarget) {
9232 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9233 wxPoint2DDouble dragHandlePoint =
9235 .GetDragHandlePoint(
this);
9236 pSelect->AddSelectablePoint(
9237 dragHandlePoint.m_y, dragHandlePoint.m_x,
9238 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9241 if (m_lastRoutePointEditTarget) {
9245 .EnableDragHandle(
false);
9246 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9247 SELTYPE_DRAGHANDLE);
9250 wxArrayPtrVoid *lastEditRouteArray =
9252 m_lastRoutePointEditTarget);
9253 if (lastEditRouteArray) {
9254 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9256 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9257 if (g_pRouteMan->IsRouteValid(pr)) {
9261 delete lastEditRouteArray;
9272 if (m_lastRoutePointEditTarget) {
9275 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9276 RefreshRect(wp_rect,
true);
9279 if (m_pRoutePointEditTarget) {
9282 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9283 RefreshRect(wp_rect,
true);
9292 bool b_start_rollover =
false;
9293 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9294 SelectItem *pFind = pSelectAIS->FindSelection(
9296 if (pFind) b_start_rollover =
true;
9299 if (!b_start_rollover && !b_startedit_route) {
9300 SelectableItemList SelList = pSelect->FindSelectionList(
9302 wxSelectableItemListNode *node = SelList.GetFirst();
9308 if (pr && pr->IsVisible()) {
9309 b_start_rollover =
true;
9312 node = node->GetNext();
9316 if (!b_start_rollover && !b_startedit_route) {
9317 SelectableItemList SelList = pSelect->FindSelectionList(
9319 wxSelectableItemListNode *node = SelList.GetFirst();
9325 if (tr && tr->IsVisible()) {
9326 b_start_rollover =
true;
9329 node = node->GetNext();
9333 if (b_start_rollover)
9334 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9338 bool appending =
false;
9339 bool inserting =
false;
9341 if (m_bRouteEditing ) {
9343 if (m_pRoutePointEditTarget) {
9349 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9350 double nearby_radius_meters =
9351 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9352 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9353 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9354 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9356 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9360 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9362 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9377 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9382 OCPNMessageBox(
this,
9383 _(
"Replace this RoutePoint by the nearby "
9385 _(
"OpenCPN RoutePoint change"),
9386 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9387 if (dlg_return == wxID_YES) {
9392 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9395 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9397 if (tail && current && (tail != current)) {
9399 connect = tail->GetIndexOf(pNearbyPoint);
9400 int index_current_route =
9401 current->GetIndexOf(m_pRoutePointEditTarget);
9402 index_last = current->GetIndexOf(current->GetLastPoint());
9403 dlg_return1 = wxID_NO;
9405 index_current_route) {
9407 if (connect != tail->GetnPoints()) {
9410 _(
"Last part of route to be appended to dragged "
9414 _(
"Full route to be appended to dragged route?");
9416 dlg_return1 = OCPNMessageBox(
9417 this, dmsg, _(
"OpenCPN Route Create"),
9418 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9419 if (dlg_return1 == wxID_YES) {
9423 }
else if (index_current_route ==
9428 _(
"First part of route to be inserted into dragged "
9430 if (connect == tail->GetnPoints())
9432 "Full route to be inserted into dragged route?");
9434 dlg_return1 = OCPNMessageBox(
9435 this, dmsg, _(
"OpenCPN Route Create"),
9436 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9437 if (dlg_return1 == wxID_YES) {
9444 if (m_pRoutePointEditTarget->IsShared()) {
9446 dlg_return = OCPNMessageBox(
9448 _(
"Do you really want to delete and replace this "
9450 _T(
"\n") + _(
"which has been created manually?"),
9451 (
"OpenCPN RoutePoint warning"),
9452 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9455 if (dlg_return == wxID_YES) {
9456 pMousePoint = pNearbyPoint;
9458 pMousePoint->SetShared(
true);
9468 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9470 if (m_pEditRouteArray) {
9471 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9473 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9474 if (g_pRouteMan->IsRouteValid(pr)) {
9480 pSelect->DeleteAllSelectableRoutePoints(pr);
9481 pSelect->DeleteAllSelectableRouteSegments(pr);
9486 pSelect->AddAllSelectableRouteSegments(pr);
9487 pSelect->AddAllSelectableRoutePoints(pr);
9489 pr->FinalizeForRendering();
9490 pr->UpdateSegmentDistances();
9491 if (m_bRoutePoinDragging) {
9493 NavObj_dB::GetInstance().UpdateRoute(pr);
9500 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9501 if (m_pEditRouteArray) {
9502 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9504 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9505 if (g_pRouteMan->IsRouteValid(pr)) {
9506 if (pRoutePropDialog->GetRoute() == pr) {
9507 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9523 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9526 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9527 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9528 g_pMarkInfoDialog->Hide();
9530 delete m_pRoutePointEditTarget;
9531 m_lastRoutePointEditTarget = NULL;
9532 m_pRoutePointEditTarget = NULL;
9533 undo->AfterUndoableAction(pMousePoint);
9534 undo->InvalidateUndo();
9539 else if (m_bMarkEditing) {
9540 if (m_pRoutePointEditTarget)
9541 if (m_bRoutePoinDragging) {
9543 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9547 if (m_pRoutePointEditTarget)
9548 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9550 if (!m_pRoutePointEditTarget) {
9551 delete m_pEditRouteArray;
9552 m_pEditRouteArray = NULL;
9553 m_bRouteEditing =
false;
9555 m_bRoutePoinDragging =
false;
9562 int length = tail->GetnPoints();
9563 for (
int i = connect + 1; i <= length; i++) {
9564 current->AddPointAndSegment(tail->GetPoint(i),
false);
9567 gFrame->RefreshAllCanvas();
9570 current->FinalizeForRendering();
9576 pSelect->DeleteAllSelectableRoutePoints(current);
9577 pSelect->DeleteAllSelectableRouteSegments(current);
9578 for (
int i = 1; i < connect; i++) {
9579 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9581 pSelect->AddAllSelectableRouteSegments(current);
9582 pSelect->AddAllSelectableRoutePoints(current);
9583 current->FinalizeForRendering();
9589 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9590 if (m_pEditRouteArray) {
9591 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9592 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9593 if (g_pRouteMan->IsRouteValid(pr)) {
9594 if (pRoutePropDialog->GetRoute() == pr) {
9595 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9605 if (m_bRouteEditing) {
9608 bool appending =
false;
9609 bool inserting =
false;
9612 if (m_pRoutePointEditTarget) {
9613 m_pRoutePointEditTarget->
m_bBlink =
false;
9617 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9618 double nearby_radius_meters =
9619 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9620 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9621 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9622 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9624 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9625 bool duplicate =
false;
9627 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9629 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9644 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9649 OCPNMessageBox(
this,
9650 _(
"Replace this RoutePoint by the nearby "
9652 _(
"OpenCPN RoutePoint change"),
9653 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9654 if (dlg_return == wxID_YES) {
9658 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9661 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9663 if (tail && current && (tail != current)) {
9665 connect = tail->GetIndexOf(pNearbyPoint);
9666 int index_current_route =
9667 current->GetIndexOf(m_pRoutePointEditTarget);
9668 index_last = current->GetIndexOf(current->GetLastPoint());
9669 dlg_return1 = wxID_NO;
9671 index_current_route) {
9673 if (connect != tail->GetnPoints()) {
9676 _(
"Last part of route to be appended to dragged "
9680 _(
"Full route to be appended to dragged route?");
9682 dlg_return1 = OCPNMessageBox(
9683 this, dmsg, _(
"OpenCPN Route Create"),
9684 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9685 if (dlg_return1 == wxID_YES) {
9689 }
else if (index_current_route ==
9694 _(
"First part of route to be inserted into dragged "
9696 if (connect == tail->GetnPoints())
9698 "Full route to be inserted into dragged route?");
9700 dlg_return1 = OCPNMessageBox(
9701 this, dmsg, _(
"OpenCPN Route Create"),
9702 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9703 if (dlg_return1 == wxID_YES) {
9710 if (m_pRoutePointEditTarget->IsShared()) {
9711 dlg_return = wxID_NO;
9712 dlg_return = OCPNMessageBox(
9714 _(
"Do you really want to delete and replace this "
9716 _T(
"\n") + _(
"which has been created manually?"),
9717 (
"OpenCPN RoutePoint warning"),
9718 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9721 if (dlg_return == wxID_YES) {
9722 pMousePoint = pNearbyPoint;
9724 pMousePoint->SetShared(
true);
9734 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9736 if (m_pEditRouteArray) {
9737 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9739 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9740 if (g_pRouteMan->IsRouteValid(pr)) {
9745 pSelect->DeleteAllSelectableRoutePoints(pr);
9746 pSelect->DeleteAllSelectableRouteSegments(pr);
9751 pSelect->AddAllSelectableRouteSegments(pr);
9752 pSelect->AddAllSelectableRoutePoints(pr);
9754 pr->FinalizeForRendering();
9755 pr->UpdateSegmentDistances();
9758 if (m_bRoutePoinDragging) {
9760 NavObj_dB::GetInstance().UpdateRoute(pr);
9772 int length = tail->GetnPoints();
9773 for (
int i = connect + 1; i <= length; i++) {
9774 current->AddPointAndSegment(tail->GetPoint(i),
false);
9778 gFrame->RefreshAllCanvas();
9781 current->FinalizeForRendering();
9787 pSelect->DeleteAllSelectableRoutePoints(current);
9788 pSelect->DeleteAllSelectableRouteSegments(current);
9789 for (
int i = 1; i < connect; i++) {
9790 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9792 pSelect->AddAllSelectableRouteSegments(current);
9793 pSelect->AddAllSelectableRoutePoints(current);
9794 current->FinalizeForRendering();
9800 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9801 if (m_pEditRouteArray) {
9802 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9804 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9805 if (g_pRouteMan->IsRouteValid(pr)) {
9806 if (pRoutePropDialog->GetRoute() == pr) {
9807 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9816 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9819 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9820 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9821 g_pMarkInfoDialog->Hide();
9823 delete m_pRoutePointEditTarget;
9824 m_lastRoutePointEditTarget = NULL;
9825 undo->AfterUndoableAction(pMousePoint);
9826 undo->InvalidateUndo();
9831 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9834 delete m_pEditRouteArray;
9835 m_pEditRouteArray = NULL;
9839 m_bRouteEditing =
false;
9840 m_pRoutePointEditTarget = NULL;
9846 else if (m_bMarkEditing) {
9847 if (m_pRoutePointEditTarget) {
9848 if (m_bRoutePoinDragging) {
9850 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9852 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9857 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9859 RefreshRect(wp_rect,
true);
9862 m_pRoutePointEditTarget = NULL;
9863 m_bMarkEditing =
false;
9868 else if (leftIsDown) {
9873 if (!m_bChartDragging && !m_bMeasure_Active) {
9875 m_bChartDragging =
false;
9879 m_bRoutePoinDragging =
false;
9882 if (ret)
return true;
9885 if (event.RightDown()) {
9896 m_FinishRouteOnKillFocus =
false;
9897 CallPopupMenu(mx, my);
9898 m_FinishRouteOnKillFocus =
true;
9909 if (event.ShiftDown()) {
9913 event.GetPosition(&x, &y);
9915 x *= m_displayScale;
9916 y *= m_displayScale;
9922 int wheel_dir =
event.GetWheelRotation();
9925 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9926 wheel_dir = wheel_dir > 0 ? 1 : -1;
9928 double factor = g_mouse_zoom_sensitivity;
9929 if (wheel_dir < 0) factor = 1 / factor;
9931 if (g_bsmoothpanzoom) {
9932 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9933 if (wheel_dir == m_last_wheel_dir) {
9934 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9939 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9940 m_wheelstopwatch.Start(0);
9945 m_last_wheel_dir = wheel_dir;
9950 if (event.LeftDown()) {
9957 last_drag.x = x, last_drag.y = y;
9958 panleftIsDown =
true;
9961 if (event.LeftUp()) {
9962 if (panleftIsDown) {
9964 panleftIsDown =
false;
9967 if (!m_bChartDragging && !m_bMeasure_Active) {
9968 switch (cursor_region) {
9990 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
9995 m_bChartDragging =
false;
10001 if (event.Dragging() && event.LeftIsDown()) {
10019 struct timespec now;
10020 clock_gettime(CLOCK_MONOTONIC, &now);
10021 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10023 if (
false == m_bChartDragging) {
10025 last_drag.x = x, last_drag.y = y;
10026 m_bChartDragging =
true;
10027 m_chart_drag_total_time = 0;
10028 m_chart_drag_total_x = 0;
10029 m_chart_drag_total_y = 0;
10030 m_inertia_last_drag_x = x;
10031 m_inertia_last_drag_y = y;
10032 m_drag_vec_x.clear();
10033 m_drag_vec_y.clear();
10034 m_drag_vec_t.clear();
10035 m_last_drag_time = tnow;
10039 uint64_t delta_t = tnow - m_last_drag_time;
10040 double delta_tf = delta_t / 1e9;
10042 m_chart_drag_total_time += delta_tf;
10043 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10044 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10046 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10047 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10048 m_drag_vec_t.push_back(delta_tf);
10050 m_inertia_last_drag_x = x;
10051 m_inertia_last_drag_y = y;
10052 m_last_drag_time = tnow;
10054 if ((last_drag.x != x) || (last_drag.y != y)) {
10055 if (!m_routeState) {
10058 m_bChartDragging =
true;
10059 StartTimedMovement();
10060 m_pan_drag.x += last_drag.x - x;
10061 m_pan_drag.y += last_drag.y - y;
10062 last_drag.x = x, last_drag.y = y;
10066 if ((last_drag.x != x) || (last_drag.y != y)) {
10067 if (!m_routeState) {
10070 m_bChartDragging =
true;
10071 StartTimedMovement();
10072 m_pan_drag.x += last_drag.x - x;
10073 m_pan_drag.y += last_drag.y - y;
10074 last_drag.x = x, last_drag.y = y;
10081 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10083 m_DoubleClickTimer->Start();
10084 singleClickEventIsValid =
false;
10092void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10093 if (MouseEventOverlayWindows(event))
return;
10100void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10103 wxCursor *ptarget_cursor = pCursorArrow;
10104 if (!pPlugIn_Cursor) {
10105 ptarget_cursor = pCursorArrow;
10106 if ((!m_routeState) &&
10107 (!m_bMeasure_Active) ) {
10108 if (cursor_region == MID_RIGHT) {
10109 ptarget_cursor = pCursorRight;
10110 }
else if (cursor_region == MID_LEFT) {
10111 ptarget_cursor = pCursorLeft;
10112 }
else if (cursor_region == MID_TOP) {
10113 ptarget_cursor = pCursorDown;
10114 }
else if (cursor_region == MID_BOT) {
10115 ptarget_cursor = pCursorUp;
10117 ptarget_cursor = pCursorArrow;
10119 }
else if (m_bMeasure_Active ||
10121 ptarget_cursor = pCursorPencil;
10123 ptarget_cursor = pPlugIn_Cursor;
10126 SetCursor(*ptarget_cursor);
10129void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10130 SetCursor(*pCursorArrow);
10133void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10137 wxArrayString files;
10139 ChartBase *target_chart = GetChartAtCursor();
10140 if (target_chart) {
10141 file.Assign(target_chart->GetFullPath());
10142 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10143 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10146 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10148 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10149 unsigned int im = stackIndexArray.size();
10150 int scale = 2147483647;
10151 if (VPoint.b_quilt && im > 0) {
10152 for (
unsigned int is = 0; is < im; is++) {
10153 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
10154 CHART_TYPE_MBTILES) {
10155 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10157 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10158 if (ChartData->GetChartTableEntry(stackIndexArray[is])
10160 .Contains(lat, lon)) {
10161 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10164 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10165 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
10173 std::vector<Ais8_001_22 *> area_notices;
10175 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10178 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10179 auto target_data = target.second;
10180 if (!target_data->area_notices.empty()) {
10181 for (
auto &ani : target_data->area_notices) {
10186 for (Ais8_001_22_SubAreaList::iterator sa =
10187 area_notice.sub_areas.begin();
10188 sa != area_notice.sub_areas.end(); ++sa) {
10189 switch (sa->shape) {
10190 case AIS8_001_22_SHAPE_CIRCLE: {
10191 wxPoint target_point;
10193 bbox.Expand(target_point);
10194 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10197 case AIS8_001_22_SHAPE_RECT: {
10198 wxPoint target_point;
10200 bbox.Expand(target_point);
10201 if (sa->e_dim_m > sa->n_dim_m)
10202 bbox.EnLarge(sa->e_dim_m * vp_scale);
10204 bbox.EnLarge(sa->n_dim_m * vp_scale);
10207 case AIS8_001_22_SHAPE_POLYGON:
10208 case AIS8_001_22_SHAPE_POLYLINE: {
10209 for (
int i = 0; i < 4; ++i) {
10210 double lat = sa->latitude;
10211 double lon = sa->longitude;
10212 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10214 wxPoint target_point;
10216 bbox.Expand(target_point);
10220 case AIS8_001_22_SHAPE_SECTOR: {
10221 double lat1 = sa->latitude;
10222 double lon1 = sa->longitude;
10224 wxPoint target_point;
10226 bbox.Expand(target_point);
10227 for (
int i = 0; i < 18; ++i) {
10230 sa->left_bound_deg +
10231 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10232 sa->radius_m / 1852.0, &lat, &lon);
10234 bbox.Expand(target_point);
10236 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10239 bbox.Expand(target_point);
10245 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10246 area_notices.push_back(&area_notice);
10253 if (target_chart || !area_notices.empty() || file.HasName()) {
10255 int sel_rad_pix = 5;
10256 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10261 SetCursor(wxCURSOR_WAIT);
10262 bool lightsVis = m_encShowLights;
10263 if (!lightsVis) SetShowENCLights(
true);
10266 ListOfObjRazRules *rule_list = NULL;
10267 ListOfPI_S57Obj *pi_rule_list = NULL;
10270 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10271 else if (target_plugin_chart)
10272 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10273 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10275 ListOfObjRazRules *overlay_rule_list = NULL;
10276 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10279 if (CHs57_Overlay) {
10280 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10281 zlat, zlon, SelectRadius, &GetVP());
10284 if (!lightsVis) SetShowENCLights(
false);
10287 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10288 wxString face = dFont->GetFaceName();
10290 if (NULL == g_pObjectQueryDialog) {
10291 g_pObjectQueryDialog =
10292 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10293 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10296 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10297 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10301 fg = g_pObjectQueryDialog->GetForegroundColour();
10305 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
10306 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10309 int points = dFont->GetPointSize();
10311 int points = dFont->GetPointSize() + 1;
10315 for (
int i = -2; i < 5; i++) {
10316 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10318 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10320 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
10322 if (overlay_rule_list && CHs57_Overlay) {
10323 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10324 objText << _T(
"<hr noshade>");
10327 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10328 an != area_notices.end(); ++an) {
10329 objText << _T(
"<b>AIS Area Notice:</b> " );
10330 objText << ais8_001_22_notice_names[(*an)->notice_type];
10331 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10332 (*an)->sub_areas.begin();
10333 sa != (*an)->sub_areas.end(); ++sa)
10334 if (!sa->text.empty()) objText << sa->text;
10335 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10336 objText << _T(
"<hr noshade>" );
10340 objText << Chs57->CreateObjDescriptions(rule_list);
10341 else if (target_plugin_chart)
10342 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10345 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
10348 wxString AddFiles, filenameOK;
10350 if (!target_plugin_chart) {
10353 AddFiles = wxString::Format(
10354 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
10356 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
10357 _T(
"cellpadding=3>"),
10358 file.GetFullName());
10360 file.Assign(file.GetPath(), wxT(
""));
10361 wxDir dir(file.GetFullPath());
10363 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10365 file.Assign(dir.GetNameWithSep().append(filename));
10366 wxString FormatString =
10367 _T(
"<td valign=top><font size=-2><a ")
10368 _T("href=\"%s\">%s</a></font></td>");
10369 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10370 filenameOK = file.GetFullPath();
10372 if (3 * ((
int)filecount / 3) == filecount)
10373 FormatString.Prepend(_T(
"<tr>"));
10375 FormatString.Prepend(
10376 _T(
"<td>  </td>"));
10379 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10380 file.GetFullName());
10383 cont = dir.GetNext(&filename);
10385 objText << AddFiles << _T(
"</table>");
10387 objText << _T(
"</font>");
10388 objText << _T(
"</body></html>");
10390 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10391 g_pObjectQueryDialog->SetHTMLPage(objText);
10392 g_pObjectQueryDialog->Show();
10394 if ((!Chs57 && filecount == 1)) {
10396 wxHtmlLinkInfo hli(filenameOK);
10397 wxHtmlLinkEvent hle(1, hli);
10398 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10401 if (rule_list) rule_list->Clear();
10404 if (overlay_rule_list) overlay_rule_list->Clear();
10405 delete overlay_rule_list;
10407 if (pi_rule_list) pi_rule_list->Clear();
10408 delete pi_rule_list;
10410 SetCursor(wxCURSOR_ARROW);
10414void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10416 if (!g_pMarkInfoDialog) {
10423 wxSize canvas_size = GetSize();
10426 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10428 g_pMarkInfoDialog->Layout();
10430 wxPoint canvas_pos = GetPosition();
10431 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10433 bool newFit =
false;
10434 if (canvas_size.x < fitted_size.x) {
10435 fitted_size.x = canvas_size.x - 40;
10436 if (canvas_size.y < fitted_size.y)
10437 fitted_size.y -= 40;
10439 if (canvas_size.y < fitted_size.y) {
10440 fitted_size.y = canvas_size.y - 40;
10441 if (canvas_size.x < fitted_size.x)
10442 fitted_size.x -= 40;
10446 g_pMarkInfoDialog->SetSize(fitted_size);
10447 g_pMarkInfoDialog->Centre();
10453 wxString title_base = _(
"Mark Properties");
10455 title_base = _(
"Waypoint Properties");
10457 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10458 g_pMarkInfoDialog->UpdateProperties();
10460 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title_base, _(
"Layer"),
10462 g_pMarkInfoDialog->SetDialogTitle(caption);
10464 g_pMarkInfoDialog->SetDialogTitle(title_base);
10466 g_pMarkInfoDialog->Show();
10467 g_pMarkInfoDialog->Raise();
10468 g_pMarkInfoDialog->InitialFocus();
10469 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10472void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10473 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10474 pRoutePropDialog->SetRouteAndUpdate(selected);
10476 pRoutePropDialog->Show();
10477 pRoutePropDialog->Raise();
10479 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10483 wxSize canvas_size = GetSize();
10484 wxPoint canvas_pos = GetPosition();
10485 wxSize fitted_size = pRoutePropDialog->GetSize();
10488 if (canvas_size.x < fitted_size.x) {
10489 fitted_size.x = canvas_size.x;
10490 if (canvas_size.y < fitted_size.y)
10491 fitted_size.y -= 20;
10493 if (canvas_size.y < fitted_size.y) {
10494 fitted_size.y = canvas_size.y;
10495 if (canvas_size.x < fitted_size.x)
10496 fitted_size.x -= 20;
10499 pRoutePropDialog->SetSize(fitted_size);
10500 pRoutePropDialog->Centre();
10505 wxPoint xxp = ClientToScreen(canvas_pos);
10509 pRoutePropDialog->SetRouteAndUpdate(selected);
10511 pRoutePropDialog->Show();
10516void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10517 pTrackPropDialog = TrackPropDlg::getInstance(
10520 pTrackPropDialog->SetTrackAndUpdate(selected);
10523 pTrackPropDialog->Show();
10528void pupHandler_PasteWaypoint() {
10531 int pasteBuffer = kml.ParsePasteBuffer();
10532 RoutePoint *pasted = kml.GetParsedRoutePoint();
10533 if (!pasted)
return;
10535 double nearby_radius_meters =
10536 g_Platform->GetSelectRadiusPix() /
10537 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10539 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10540 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10542 int answer = wxID_NO;
10546 "There is an existing waypoint at the same location as the one you are "
10547 "pasting. Would you like to merge the pasted data with it?\n\n");
10548 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10549 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10550 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10553 if (answer == wxID_YES) {
10554 nearPoint->SetName(pasted->GetName());
10556 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10557 pRouteManagerDialog->UpdateWptListCtrl();
10560 if (answer == wxID_NO) {
10563 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10566 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10569 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10570 pRouteManagerDialog->UpdateWptListCtrl();
10571 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10572 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10575 gFrame->InvalidateAllGL();
10576 gFrame->RefreshAllCanvas(
false);
10579void pupHandler_PasteRoute() {
10582 int pasteBuffer = kml.ParsePasteBuffer();
10583 Route *pasted = kml.GetParsedRoute();
10584 if (!pasted)
return;
10586 double nearby_radius_meters =
10587 g_Platform->GetSelectRadiusPix() /
10588 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10594 bool mergepoints =
false;
10595 bool createNewRoute =
true;
10596 int existingWaypointCounter = 0;
10598 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10599 curPoint = pasted->GetPoint(i);
10600 nearPoint = pWayPointMan->GetNearbyWaypoint(
10601 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10603 mergepoints =
true;
10604 existingWaypointCounter++;
10612 int answer = wxID_NO;
10616 "There are existing waypoints at the same location as some of the ones "
10617 "you are pasting. Would you like to just merge the pasted data into "
10619 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10620 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10621 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10623 if (answer == wxID_CANCEL) {
10630 if (mergepoints && answer == wxID_YES &&
10631 existingWaypointCounter == pasted->GetnPoints()) {
10632 wxRouteListNode *route_node = pRouteList->GetFirst();
10633 while (route_node) {
10634 Route *proute = route_node->GetData();
10637 createNewRoute =
false;
10640 route_node = route_node->GetNext();
10644 Route *newRoute = 0;
10647 if (createNewRoute) {
10648 newRoute =
new Route();
10652 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10653 curPoint = pasted->GetPoint(i);
10656 newPoint = pWayPointMan->GetNearbyWaypoint(
10657 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10658 newPoint->SetName(curPoint->GetName());
10661 if (createNewRoute) newRoute->AddPoint(newPoint);
10667 newPoint->SetIconName(_T(
"circle"));
10670 newPoint->SetShared(
false);
10672 newRoute->AddPoint(newPoint);
10673 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10676 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10679 if (i > 1 && createNewRoute)
10680 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10681 curPoint->m_lat, curPoint->m_lon,
10682 prevPoint, newPoint, newRoute);
10683 prevPoint = newPoint;
10686 if (createNewRoute) {
10687 pRouteList->Append(newRoute);
10689 NavObj_dB::GetInstance().InsertRoute(newRoute);
10691 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10692 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10695 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10696 pRouteManagerDialog->UpdateRouteListCtrl();
10697 pRouteManagerDialog->UpdateWptListCtrl();
10699 gFrame->InvalidateAllGL();
10700 gFrame->RefreshAllCanvas(
false);
10702 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10703 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10706void pupHandler_PasteTrack() {
10709 int pasteBuffer = kml.ParsePasteBuffer();
10710 Track *pasted = kml.GetParsedTrack();
10711 if (!pasted)
return;
10719 newTrack->SetName(pasted->GetName());
10721 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10722 curPoint = pasted->GetPoint(i);
10726 wxDateTime now = wxDateTime::Now();
10729 newTrack->AddPoint(newPoint);
10732 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10733 newPoint->m_lat, newPoint->m_lon,
10734 prevPoint, newPoint, newTrack);
10736 prevPoint = newPoint;
10739 g_TrackList.push_back(newTrack);
10741 NavObj_dB::GetInstance().InsertTrack(newTrack);
10743 gFrame->InvalidateAllGL();
10744 gFrame->RefreshAllCanvas(
false);
10747bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10749 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10750 m_pIDXCandidate, m_nmea_log);
10753 wxEVT_COMMAND_MENU_SELECTED,
10754 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10756 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10759 wxEVT_COMMAND_MENU_SELECTED,
10760 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10762 delete m_canvasMenu;
10763 m_canvasMenu = NULL;
10773void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10776 if (m_canvasMenu) {
10777 m_canvasMenu->PopupMenuHandler(event);
10782void ChartCanvas::StartRoute(
void) {
10784 if (g_brouteCreating)
return;
10786 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10788 g_brouteCreating =
true;
10790 m_bDrawingRoute =
false;
10791 SetCursor(*pCursorPencil);
10793 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10795 HideGlobalToolbar();
10798 androidSetRouteAnnunciator(
true);
10802void ChartCanvas::FinishRoute(
void) {
10804 m_prev_pMousePoint = NULL;
10805 m_bDrawingRoute =
false;
10808 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10810 androidSetRouteAnnunciator(
false);
10813 SetCursor(*pCursorArrow);
10815 if (m_pMouseRoute) {
10816 if (m_bAppendingRoute) {
10818 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
10820 if (m_pMouseRoute->GetnPoints() > 1) {
10822 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
10825 m_pMouseRoute = NULL;
10828 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10830 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10831 (pRoutePropDialog->IsShown())) {
10832 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10835 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10836 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10837 pRouteManagerDialog->UpdateRouteListCtrl();
10840 m_bAppendingRoute =
false;
10841 m_pMouseRoute = NULL;
10843 m_pSelectedRoute = NULL;
10845 undo->InvalidateUndo();
10846 gFrame->RefreshAllCanvas(
true);
10848 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10850 ShowGlobalToolbar();
10852 g_brouteCreating =
false;
10855void ChartCanvas::HideGlobalToolbar() {
10856 if (m_canvasIndex == 0) {
10857 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10861void ChartCanvas::ShowGlobalToolbar() {
10862 if (m_canvasIndex == 0) {
10863 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10867void ChartCanvas::ShowAISTargetList(
void) {
10868 if (NULL == g_pAISTargetList) {
10872 g_pAISTargetList->UpdateAISTargetList();
10875void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10876 if (!m_bShowOutlines)
return;
10878 if (!ChartData)
return;
10880 int nEntry = ChartData->GetChartTableEntries();
10882 for (
int i = 0; i < nEntry; i++) {
10886 bool b_group_draw =
false;
10887 if (m_groupIndex > 0) {
10888 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10889 int index = pt->GetGroupArray()[ig];
10890 if (m_groupIndex == index) {
10891 b_group_draw =
true;
10896 b_group_draw =
true;
10898 if (b_group_draw) RenderChartOutline(dc, i, vp);
10904 if (VPoint.b_quilt) {
10905 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10906 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10910 }
else if (m_singleChart &&
10911 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10915 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10918 if (zoom_factor > 8.0) {
10919 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10922 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10926 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
10930void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10932 if (g_bopengl && m_glcc) {
10934 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10939 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10940 if (!ChartData->IsChartAvailable(dbIndex))
return;
10943 float plylat, plylon;
10944 float plylat1, plylon1;
10946 int pixx, pixy, pixx1, pixy1;
10949 ChartData->GetDBBoundingBox(dbIndex, box);
10953 if (box.GetLonRange() == 360)
return;
10955 double lon_bias = 0;
10957 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10959 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10961 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10962 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10964 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10965 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10968 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10971 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10972 if (0 == nAuxPlyEntries)
10976 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10977 plylon += lon_bias;
10983 for (
int i = 0; i < nPly - 1; i++) {
10984 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
10985 plylon1 += lon_bias;
10991 int pixxs1 = pixx1;
10992 int pixys1 = pixy1;
10994 bool b_skip =
false;
10998 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
10999 pow((
double)(pixy1 - pixy), 2)) /
11005 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11010 if (fabs(dist - distgc) > 10000. * 1852.)
11016 ClipResult res = cohen_sutherland_line_clip_i(
11018 if (res != Invisible && !b_skip)
11019 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11027 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11028 plylon1 += lon_bias;
11034 ClipResult res = cohen_sutherland_line_clip_i(
11036 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11043 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
11044 for (
int j = 0; j < nAuxPlyEntries; j++) {
11046 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11051 for (
int i = 0; i < nAuxPly - 1; i++) {
11052 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11058 int pixxs1 = pixx1;
11059 int pixys1 = pixy1;
11061 bool b_skip =
false;
11065 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11066 ((pixy1 - pixy) * (pixy1 - pixy))) /
11071 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11076 if (fabs(dist - distgc) > 10000. * 1852.)
11082 ClipResult res = cohen_sutherland_line_clip_i(
11084 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11092 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11097 ClipResult res = cohen_sutherland_line_clip_i(
11099 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11104static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11105 const wxString &second) {
11106 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11108 int pointsize = dFont->GetPointSize();
11112 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11113 false, dFont->GetFaceName());
11115 dc.SetFont(*psRLI_font);
11123 int hilite_offset = 3;
11126 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11127 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11129 dc.GetTextExtent(first, &w1, &h1);
11130 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11136 w = wxMax(w1, w2) + (h1 / 2);
11141 xp = ref_point.x - w;
11143 yp += hilite_offset;
11145 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11147 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11148 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11150 dc.DrawText(first, xp, yp);
11151 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11154void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11155 if (!g_bAllowShipToActive)
return;
11157 Route *rt = g_pRouteMan->GetpActiveRoute();
11160 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11161 wxPoint2DDouble pa, pb;
11167 g_pRouteMan->GetRoutePen()->GetWidth();
11168 if (rt->
m_width != wxPENSTYLE_INVALID)
11170 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11171 g_shipToActiveStyle, 5)];
11172 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11174 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11176 g_pRouteMan->GetActiveRoutePen()->GetColour();
11177 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11180 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11183 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11184 (
int)pb.m_y, GetVP(),
true);
11188#ifdef USE_ANDROID_GLES2
11189 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11191 if (style != wxPENSTYLE_SOLID) {
11192 if (glChartCanvas::dash_map.find(style) !=
11193 glChartCanvas::dash_map.end()) {
11194 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11198 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11201 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11202 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11208void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11210 if (m_routeState >= 2) route = m_pMouseRoute;
11211 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11212 route = m_pMeasureRoute;
11214 if (!route)
return;
11217 if (!g_pRouteMan->IsRouteValid(route))
return;
11222 int np = route->GetnPoints();
11224 if (g_btouch && (np > 1)) np--;
11226 render_lat = rp.m_lat;
11227 render_lon = rp.m_lon;
11230 double rhumbBearing, rhumbDist;
11232 &rhumbBearing, &rhumbDist);
11233 double brg = rhumbBearing;
11234 double dist = rhumbDist;
11238 double gcBearing, gcBearing2, gcDist;
11239 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11242 double gcDistm = gcDist / 1852.0;
11245 rhumbBearing = 90.;
11247 wxPoint destPoint, lastPoint;
11250 int milesDiff = rhumbDist - gcDistm;
11251 if (milesDiff > 1) {
11262 for (
int i = 1; i <= milesDiff; i++) {
11263 double p = (double)i * (1.0 / (
double)milesDiff);
11265 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11266 &pLon, &pLat, &gcBearing2);
11268 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11270 lastPoint = destPoint;
11273 if (r_rband.x && r_rband.y) {
11274 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11276 if (m_bMeasure_DistCircle) {
11277 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11278 powf((
float)(r_rband.y - lastPoint.y), 2));
11280 dc.SetPen(*g_pRouteMan->GetRoutePen());
11281 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11282 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11288 wxString routeInfo;
11291 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11297 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11299 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11300 (
int)varBrg, 0x00B0);
11302 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
11307 routeInfo <<
"\nReverse: ";
11309 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11310 (
int)(brg + 180.) % 360, 0x00B0);
11312 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11313 (
int)(varBrg + 180.) % 360, 0x00B0);
11318 s0.Append(_(
"Route") + _T(
": "));
11320 s0.Append(_(
"Layer Route: "));
11323 if (!g_btouch) disp_length += dist;
11324 s0 += FormatDistanceAdaptive(disp_length);
11326 RouteLegInfo(dc, r_rband, routeInfo, s0);
11328 m_brepaint_piano =
true;
11331void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11332 if (!m_bShowVisibleSectors)
return;
11334 if (g_bDeferredInitDone) {
11336 double rhumbBearing, rhumbDist;
11337 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11338 &rhumbBearing, &rhumbDist);
11340 if (rhumbDist > 0.05)
11342 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11343 m_sectorlegsVisible);
11344 m_sector_glat = gLat;
11345 m_sector_glon = gLon;
11347 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11351void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11359void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11360 if (!ps52plib)
return;
11362 if (VPoint.b_quilt) {
11363 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11365 if (m_pQuilt->IsQuiltVector()) {
11366 if (ps52plib->GetStateHash() != m_s52StateHash) {
11368 m_s52StateHash = ps52plib->GetStateHash();
11372 if (ps52plib->GetStateHash() != m_s52StateHash) {
11374 m_s52StateHash = ps52plib->GetStateHash();
11379 bool bSendPlibState =
true;
11380 if (VPoint.b_quilt) {
11381 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11384 if (bSendPlibState) {
11386 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
11387 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
11388 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
11389 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
11390 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
11393 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
11394 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
11395 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
11396 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] = m_encShowAnchor;
11397 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] = GetShowENCDataQual();
11398 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
11399 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
11403 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
11404 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
11408 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
11409 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
11410 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
11411 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] =
11412 ps52plib->m_bShowS57ImportantTextOnly;
11413 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
11414 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
11415 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
11416 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
11417 v[_T(
"OpenCPN S52PLIB ColorShades")] =
11418 S52_getMarinerParam(S52_MAR_TWO_SHADES);
11421 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
11422 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
11423 v[_T(
"OpenCPN Scale Factor Exp")] =
11424 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11425 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
11431 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11432 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11433 g_lastS52PLIBPluginMessage = out;
11439void ChartCanvas::OnPaint(wxPaintEvent &event) {
11440 wxPaintDC dc(
this);
11450 if (!m_b_paint_enable) {
11455 UpdateCanvasS52PLIBConfig();
11458 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11460 if (m_glcc && g_bopengl) {
11461 if (!s_in_update) {
11471 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11473 wxRegion ru = GetUpdateRegion();
11475 int rx, ry, rwidth, rheight;
11476 ru.GetBox(rx, ry, rwidth, rheight);
11480#ifdef ocpnUSE_DIBSECTION
11483 wxMemoryDC temp_dc;
11491 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11492 height += m_Piano->GetHeight();
11494 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11498 int thumbx, thumby, thumbsx, thumbsy;
11499 pthumbwin->GetPosition(&thumbx, &thumby);
11500 pthumbwin->GetSize(&thumbsx, &thumbsy);
11501 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11503 if (pthumbwin->IsShown()) {
11504 rgn_chart.Subtract(rgn_thumbwin);
11505 ru.Subtract(rgn_thumbwin);
11511 wxRegion rgn_blit = ru;
11512 if (g_bShowChartBar) {
11513 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11514 GetClientSize().x, m_Piano->GetHeight());
11517 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11518 if (style->chartStatusWindowTransparent)
11519 m_brepaint_piano =
true;
11521 ru.Subtract(chart_bar_rect);
11525 if (m_Compass && m_Compass->IsShown()) {
11526 wxRect compassRect = m_Compass->
GetRect();
11527 if (ru.Contains(compassRect) != wxOutRegion) {
11528 ru.Subtract(compassRect);
11532 wxRect noteRect = m_notification_button->
GetRect();
11533 if (ru.Contains(noteRect) != wxOutRegion) {
11534 ru.Subtract(noteRect);
11538 bool b_newview =
true;
11543 m_cache_vp.IsValid()) {
11549 bool b_rcache_ok =
false;
11550 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11551 b_rcache_ok = !b_newview;
11554 if (VPoint.b_MercatorProjectionOverride)
11555 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11569 if (b_rcache_ok) chart_get_region.Clear();
11572 if (VPoint.b_quilt)
11574 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11576 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11581 AbstractPlatform::ShowBusySpinner();
11585 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11586 (m_working_bm.GetHeight() != svp.
pix_height))
11590 if (fabs(VPoint.
rotation) < 0.01) {
11591 bool b_save =
true;
11593 if (g_SencThreadManager) {
11594 if (g_SencThreadManager->GetJobCount()) {
11596 m_cache_vp.Invalidate();
11610 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11615 int dy = c_new.y - c_old.y;
11616 int dx = c_new.x - c_old.x;
11621 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11625 temp_dc.SelectObject(m_working_bm);
11627 wxMemoryDC cache_dc;
11628 cache_dc.SelectObject(m_cached_chart_bm);
11632 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11635 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11641 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11644 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11652 update_region.Union(
11655 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11660 update_region.Union(
11663 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11667 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11669 cache_dc.SelectObject(wxNullBitmap);
11673 temp_dc.SelectObject(m_cached_chart_bm);
11676 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11680 temp_dc.SelectObject(m_working_bm);
11681 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11686 temp_dc.SelectObject(m_cached_chart_bm);
11691 temp_dc.SelectObject(m_working_bm);
11692 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11705 wxMemoryDC scratch_dc_0;
11706 scratch_dc_0.SelectObject(m_cached_chart_bm);
11709 scratch_dc_0.SelectObject(wxNullBitmap);
11718 temp_dc.SelectObject(m_working_bm);
11721 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11722 chart_get_all_region);
11725 AbstractPlatform::HideBusySpinner();
11731 if (!m_singleChart) {
11732 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11737 if (!chart_get_region.IsEmpty()) {
11738 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11742 if (temp_dc.IsOk()) {
11747 if (!VPoint.b_quilt) {
11750 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11751 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11758 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11759 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11762 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11764 temp_dc.DestroyClippingRegion();
11769 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11771 if (!backgroundRegion.IsEmpty()) {
11777 wxColour water = pWorldBackgroundChart->water;
11778 if (water.IsOk()) {
11779 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11780 temp_dc.SetBrush(wxBrush(water));
11782 while (upd.HaveRects()) {
11783 wxRect rect = upd.GetRect();
11784 temp_dc.DrawRectangle(rect);
11789 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11790 temp_dc.SetDeviceClippingRegion(*clip_region);
11791 delete clip_region;
11795 SetVPRotation(VPoint.
skew);
11798 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11804 wxMemoryDC *pChartDC = &temp_dc;
11805 wxMemoryDC rotd_dc;
11807 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11809 if (!b_rcache_ok) {
11811 wxMemoryDC tbase_dc;
11813 tbase_dc.SelectObject(bm_base);
11815 tbase_dc.SelectObject(wxNullBitmap);
11817 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11820 wxImage base_image;
11821 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11829 bool b_rot_ok =
false;
11830 if (base_image.IsOk()) {
11833 m_b_rot_hidef =
false;
11837 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11838 m_b_rot_hidef, &m_roffset);
11843 rot_vp.IsValid() && (ri.IsOk())) {
11850 m_prot_bm =
new wxBitmap(ri);
11853 m_roffset.x += VPoint.rv_rect.x;
11854 m_roffset.y += VPoint.rv_rect.y;
11857 if (m_prot_bm && m_prot_bm->IsOk()) {
11858 rotd_dc.SelectObject(*m_prot_bm);
11859 pChartDC = &rotd_dc;
11861 pChartDC = &temp_dc;
11862 m_roffset = wxPoint(0, 0);
11865 pChartDC = &temp_dc;
11866 m_roffset = wxPoint(0, 0);
11869 wxPoint offset = m_roffset;
11872 m_cache_vp = VPoint;
11875 wxMemoryDC mscratch_dc;
11876 mscratch_dc.SelectObject(*pscratch_bm);
11878 mscratch_dc.ResetBoundingBox();
11879 mscratch_dc.DestroyClippingRegion();
11880 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11883 wxRegionIterator upd(rgn_blit);
11885 wxRect rect = upd.GetRect();
11887 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11888 rect.x - offset.x, rect.y - offset.y);
11894 if (m_show_focus_bar && (g_canvasConfig != 0)) {
11895 if (
this == wxWindow::FindFocus()) {
11896 g_focusCanvas =
this;
11898 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11899 mscratch_dc.SetPen(wxPen(colour));
11900 mscratch_dc.SetBrush(wxBrush(colour));
11902 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11903 mscratch_dc.DrawRectangle(activeRect);
11908 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11909 unsigned int im = stackIndexArray.size();
11910 if (VPoint.b_quilt && im > 0) {
11911 std::vector<int> tiles_to_show;
11912 for (
unsigned int is = 0; is < im; is++) {
11914 ChartData->GetChartTableEntry(stackIndexArray[is]);
11915 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11918 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11919 tiles_to_show.push_back(stackIndexArray[is]);
11923 if (tiles_to_show.size())
11924 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11930 ocpnDC scratch_dc(mscratch_dc);
11931 RenderAlertMessage(mscratch_dc, GetVP());
11937#ifdef ocpnUSE_DIBSECTION
11942 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11943 q_dc.SelectObject(qbm);
11946 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11949 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11950 q_dc.SetBrush(qbr);
11951 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11954 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11957 q_dc.SelectObject(wxNullBitmap);
11966 if( VPoint.b_quilt ) {
11967 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11968 ChartBase *chart = m_pQuilt->GetRefChart();
11969 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11974 ChPI->ClearPLIBTextList();
11977 ps52plib->ClearTextList();
11981 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11983 wxColor maskBackground = wxColour(1,0,0);
11984 t_dc.SelectObject( qbm );
11985 t_dc.SetBackground(wxBrush(maskBackground));
11989 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
11992 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
11993 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
11996 wxRegionIterator upd_final( ru );
11997 while( upd_final ) {
11998 wxRect rect = upd_final.GetRect();
11999 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12003 t_dc.SelectObject( wxNullBitmap );
12009 if (VPoint.b_quilt) {
12010 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12011 ChartBase *chart = m_pQuilt->GetRefChart();
12012 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12016 ChPI->ClearPLIBTextList();
12018 if (ps52plib) ps52plib->ClearTextList();
12023 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12025 if (g_bShowChartBar && m_Piano) {
12026 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12027 GetVP().pix_width, m_Piano->GetHeight());
12030 if (!style->chartStatusWindowTransparent)
12031 chart_all_text_region.Subtract(chart_bar_rect);
12034 if (m_Compass && m_Compass->IsShown()) {
12035 wxRect compassRect = m_Compass->
GetRect();
12036 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12037 chart_all_text_region.Subtract(compassRect);
12041 mscratch_dc.DestroyClippingRegion();
12043 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12044 chart_all_text_region);
12050 ocpnDC scratch_dc(mscratch_dc);
12051 DrawOverlayObjects(scratch_dc, ru);
12054 wxRegionIterator upd_final(rgn_blit);
12055 while (upd_final) {
12056 wxRect rect = upd_final.GetRect();
12057 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12064 temp_dc.SelectObject(wxNullBitmap);
12066 mscratch_dc.SelectObject(wxNullBitmap);
12068 dc.DestroyClippingRegion();
12073void ChartCanvas::PaintCleanup() {
12085 m_bTCupdate =
false;
12089 WarpPointer(warp_x, warp_y);
12096 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12097 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12101wxColour GetErrorGraphicColor(
double val)
12120 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
12121 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
12122 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
12123 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
12124 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
12125 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
12126 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
12127 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
12128 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
12129 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
12130 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
12131 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
12132 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
12133 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
12134 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
12135 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
12136 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
12137 else if( val >= 48) c.Set(_T(
"#410000"));
12142void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12145 gr_image.InitAlpha();
12147 double maxval = -10000;
12148 double minval = 10000;
12165 maxval = wxMax(maxval, (glat - rlat));
12166 minval = wxMin(minval, (glat - rlat));
12183 double f = ((glat - rlat)-minval)/(maxval - minval);
12185 double dy = (f * 40);
12187 wxColour c = GetErrorGraphicColor(dy);
12188 unsigned char r = c.Red();
12189 unsigned char g = c.Green();
12190 unsigned char b = c.Blue();
12192 gr_image.SetRGB(j, i, r,g,b);
12193 if((glat - rlat )!= 0)
12194 gr_image.SetAlpha(j, i, 128);
12196 gr_image.SetAlpha(j, i, 255);
12203 wxBitmap *pbm =
new wxBitmap(gr_image);
12204 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12205 pbm->SetMask(gr_mask);
12207 pmdc->DrawBitmap(*pbm, 0,0);
12215void ChartCanvas::CancelMouseRoute() {
12217 m_pMouseRoute = NULL;
12218 m_bDrawingRoute =
false;
12221int ChartCanvas::GetNextContextMenuId() {
12222 return CanvasMenuHandler::GetNextContextMenuId();
12225bool ChartCanvas::SetCursor(
const wxCursor &c) {
12227 if (g_bopengl && m_glcc)
12228 return m_glcc->SetCursor(c);
12231 return wxWindow::SetCursor(c);
12234void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12235 if (g_bquiting)
return;
12245 if (!m_RolloverPopupTimer.IsRunning() &&
12246 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12247 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12248 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12249 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12252 if (m_glcc && g_bopengl) {
12255 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12257 m_glcc->Refresh(eraseBackground,
12268 if (pthumbwin && pthumbwin->IsShown()) {
12269 pthumbwin->Raise();
12270 pthumbwin->Refresh(
false);
12274 if (m_pCIWin && m_pCIWin->IsShown()) {
12276 m_pCIWin->Refresh(
false);
12284 wxWindow::Refresh(eraseBackground, rect);
12287void ChartCanvas::Update() {
12288 if (m_glcc && g_bopengl) {
12293 wxWindow::Update();
12297 if (!pemboss)
return;
12298 int x = pemboss->x, y = pemboss->y;
12299 const double factor = 200;
12301 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
12302 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12303 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
12306 wxMemoryDC snip_dc;
12307 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12308 snip_dc.SelectObject(snip_bmp);
12310 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12311 snip_dc.SelectObject(wxNullBitmap);
12313 wxImage snip_img = snip_bmp.ConvertToImage();
12316 unsigned char *pdata = snip_img.GetData();
12318 for (
int y = 0; y < pemboss->height; y++) {
12319 int map_index = (y * pemboss->width);
12320 for (
int x = 0; x < pemboss->width; x++) {
12321 double val = (pemboss->pmap[map_index] * factor) / 256.;
12323 int nred = (int)((*pdata) + val);
12324 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12325 *pdata++ = (
unsigned char)nred;
12327 int ngreen = (int)((*pdata) + val);
12328 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12329 *pdata++ = (
unsigned char)ngreen;
12331 int nblue = (int)((*pdata) + val);
12332 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12333 *pdata++ = (
unsigned char)nblue;
12341 wxBitmap emb_bmp(snip_img);
12344 wxMemoryDC result_dc;
12345 result_dc.SelectObject(emb_bmp);
12348 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12350 result_dc.SelectObject(wxNullBitmap);
12356 if (GetQuiltMode()) {
12358 int refIndex = GetQuiltRefChartdbIndex();
12359 if (refIndex >= 0) {
12360 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
12361 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12362 if (current_type == CHART_TYPE_MBTILES) {
12363 ChartBase *pChart = m_pQuilt->GetRefChart();
12366 zoom_factor = ptc->GetZoomFactor();
12371 if (zoom_factor <= 3.9)
return NULL;
12373 if (m_singleChart) {
12374 if (zoom_factor <= 3.9)
return NULL;
12379 if (m_pEM_OverZoom) {
12380 m_pEM_OverZoom->x = 4;
12381 m_pEM_OverZoom->y = 0;
12382 if (g_MainToolbar && IsPrimaryCanvas()) {
12383 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12384 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12387 return m_pEM_OverZoom;
12390void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12400 g_overlayCanvas =
this;
12402 if (g_pi_manager) {
12403 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12404 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12408 AISDrawAreaNotices(dc, GetVP(),
this);
12410 wxDC *pdc = dc.GetDC();
12412 pdc->DestroyClippingRegion();
12413 wxDCClipper(*pdc, ru);
12416 if (m_bShowNavobjects) {
12417 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12418 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12419 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12420 DrawAnchorWatchPoints(dc);
12422 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12423 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12426 AISDraw(dc, GetVP(),
this);
12430 RenderVisibleSectorLights(dc);
12432 RenderAllChartOutlines(dc, GetVP());
12433 RenderRouteLegs(dc);
12434 RenderShipToActive(dc,
false);
12436 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12437 if (g_pi_manager) {
12438 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12439 OVERLAY_OVER_SHIPS);
12442 DrawEmboss(dc, EmbossDepthScale());
12443 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12444 if (g_pi_manager) {
12445 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12446 OVERLAY_OVER_EMBOSS);
12450 RebuildTideSelectList(GetVP().GetBBox());
12451 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12454 if (m_bShowCurrent) {
12455 RebuildCurrentSelectList(GetVP().GetBBox());
12456 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12459 if (!g_PrintingInProgress) {
12460 if (IsPrimaryCanvas()) {
12461 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12464 if (IsPrimaryCanvas()) {
12465 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12468 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12470 if (m_pTrackRolloverWin) {
12471 m_pTrackRolloverWin->Draw(dc);
12472 m_brepaint_piano =
true;
12475 if (m_pRouteRolloverWin) {
12476 m_pRouteRolloverWin->Draw(dc);
12477 m_brepaint_piano =
true;
12480 if (m_pAISRolloverWin) {
12481 m_pAISRolloverWin->Draw(dc);
12482 m_brepaint_piano =
true;
12484 if (m_brepaint_piano && g_bShowChartBar) {
12485 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12488 if (m_Compass) m_Compass->Paint(dc);
12490 if (!g_CanvasHideNotificationIcon) {
12491 auto ¬eman = NotificationManager::GetInstance();
12492 if (noteman.GetNotificationCount()) {
12493 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12494 if (m_notification_button->UpdateStatus()) Refresh();
12495 m_notification_button->Show(
true);
12496 m_notification_button->Paint(dc);
12498 m_notification_button->Show(
false);
12502 if (g_pi_manager) {
12503 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12509 if (!m_bShowDepthUnits)
return NULL;
12511 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12513 if (GetQuiltMode()) {
12514 wxString s = m_pQuilt->GetQuiltDepthUnit();
12516 if (s == _T(
"FEET"))
12517 depth_unit_type = DEPTH_UNIT_FEET;
12518 else if (s.StartsWith(_T(
"FATHOMS")))
12519 depth_unit_type = DEPTH_UNIT_FATHOMS;
12520 else if (s.StartsWith(_T(
"METERS")))
12521 depth_unit_type = DEPTH_UNIT_METERS;
12522 else if (s.StartsWith(_T(
"METRES")))
12523 depth_unit_type = DEPTH_UNIT_METERS;
12524 else if (s.StartsWith(_T(
"METRIC")))
12525 depth_unit_type = DEPTH_UNIT_METERS;
12526 else if (s.StartsWith(_T(
"METER")))
12527 depth_unit_type = DEPTH_UNIT_METERS;
12530 if (m_singleChart) {
12531 depth_unit_type = m_singleChart->GetDepthUnitType();
12532 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12533 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12538 switch (depth_unit_type) {
12539 case DEPTH_UNIT_FEET:
12542 case DEPTH_UNIT_METERS:
12543 ped = m_pEM_Meters;
12545 case DEPTH_UNIT_FATHOMS:
12546 ped = m_pEM_Fathoms;
12552 ped->x = (GetVP().
pix_width - ped->width);
12554 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12555 wxRect r = m_Compass->
GetRect();
12556 ped->y = r.y + r.height;
12563void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12566 if (style->embossFont == wxEmptyString) {
12567 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12569 font.SetPointSize(60);
12570 font.SetWeight(wxFONTWEIGHT_BOLD);
12572 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12573 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12575 int emboss_width = 500;
12576 int emboss_height = 200;
12580 delete m_pEM_Meters;
12581 delete m_pEM_Fathoms;
12585 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12587 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12589 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12592#define OVERZOOM_TEXT _("OverZoom")
12594void ChartCanvas::SetOverzoomFont() {
12599 if (style->embossFont == wxEmptyString) {
12600 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12602 font.SetPointSize(40);
12603 font.SetWeight(wxFONTWEIGHT_BOLD);
12605 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12606 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12608 wxClientDC dc(
this);
12610 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12612 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12613 font.SetPointSize(font.GetPointSize() - 1);
12615 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12617 m_overzoomFont = font;
12618 m_overzoomTextWidth = w;
12619 m_overzoomTextHeight = h;
12622void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12623 delete m_pEM_OverZoom;
12625 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12627 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12628 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12631emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12632 int height,
const wxString &str,
12637 wxBitmap bmp(width, height, -1);
12640 wxMemoryDC temp_dc;
12641 temp_dc.SelectObject(bmp);
12644 temp_dc.SetBackground(*wxWHITE_BRUSH);
12645 temp_dc.SetTextBackground(*wxWHITE);
12646 temp_dc.SetTextForeground(*wxBLACK);
12650 temp_dc.SetFont(font);
12653 temp_dc.GetTextExtent(str, &str_w, &str_h);
12655 temp_dc.DrawText(str, 1, 1);
12658 temp_dc.SelectObject(wxNullBitmap);
12661 wxImage img = bmp.ConvertToImage();
12663 int image_width = str_w * 105 / 100;
12664 int image_height = str_h * 105 / 100;
12665 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12666 wxMin(image_height, img.GetHeight()));
12667 wxImage imgs = img.GetSubImage(r);
12671 case GLOBAL_COLOR_SCHEME_DAY:
12675 case GLOBAL_COLOR_SCHEME_DUSK:
12678 case GLOBAL_COLOR_SCHEME_NIGHT:
12685 const int w = imgs.GetWidth();
12686 const int h = imgs.GetHeight();
12687 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12692 for (
int y = 1; y < h - 1; y++) {
12693 for (
int x = 1; x < w - 1; x++) {
12695 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12696 val = (int)(val * val_factor);
12697 index = (y * w) + x;
12710void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12711 Track *active_track = NULL;
12712 for (
Track *pTrackDraw : g_TrackList) {
12713 if (g_pActiveTrack == pTrackDraw) {
12714 active_track = pTrackDraw;
12718 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12721 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12724void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12725 Track *active_track = NULL;
12726 for (
Track *pTrackDraw : g_TrackList) {
12727 if (g_pActiveTrack == pTrackDraw) {
12728 active_track = pTrackDraw;
12732 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12735void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12736 Route *active_route = NULL;
12738 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12739 node = node->GetNext()) {
12740 Route *pRouteDraw = node->GetData();
12741 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12742 active_route = pRouteDraw;
12747 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12752 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12755void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12756 Route *active_route = NULL;
12758 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12759 node = node->GetNext()) {
12760 Route *pRouteDraw = node->GetData();
12761 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12762 active_route = pRouteDraw;
12766 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12769void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12770 if (!pWayPointMan)
return;
12772 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12778 node = node->GetNext();
12783 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12787 if (pWP->GetShowWaypointRangeRings() &&
12788 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12789 double factor = 1.00;
12790 if (pWP->GetWaypointRangeRingsStepUnits() ==
12792 factor = 1 / 1.852;
12794 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12795 pWP->GetWaypointRangeRingsStep() / 60.;
12799 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12800 pWP->m_lat + radius, pWP->m_lon + radius);
12801 if (!BltBBox.IntersectOut(radar_box)) {
12808 node = node->GetNext();
12812void ChartCanvas::DrawBlinkObjects(
void) {
12814 wxRect update_rect;
12816 if (!pWayPointMan)
return;
12818 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12828 node = node->GetNext();
12830 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12833void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12836 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12838 wxPoint lAnchorPoint1, lAnchorPoint2;
12841 if (pAnchorWatchPoint1) {
12842 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12846 if (pAnchorWatchPoint2) {
12847 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12852 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12853 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12855 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12856 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12857 dc.SetBrush(*ppBrush);
12861 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12866 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12871 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12876 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12881double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12884 wxPoint lAnchorPoint;
12887 double tlat1, tlon1;
12889 if (pAnchorWatchPoint) {
12890 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12891 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12892 dabs = fabs(d1 / 1852.);
12893 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12898 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12899 pow((
double)(lAnchorPoint.y - r1.y), 2));
12902 if (d1 < 0) lpp = -lpp;
12910void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12911 if (!ptcmgr)
return;
12913 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12915 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12916 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12921 if ((type ==
't') || (type ==
'T')) {
12922 if (BBox.Contains(lat, lon)) {
12924 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12930extern wxDateTime gTimeSource;
12932void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12933 if (!ptcmgr)
return;
12935 wxDateTime this_now = gTimeSource;
12936 bool cur_time = !gTimeSource.IsValid();
12937 if (cur_time) this_now = wxDateTime::Now();
12938 time_t t_this_now = this_now.GetTicks();
12940 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12941 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12942 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12943 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12945 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12946 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12949 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12950 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12953 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12954 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12955 wxBRUSHSTYLE_SOLID);
12956 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12957 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12958 wxBRUSHSTYLE_SOLID);
12960 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
12961 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12962 int font_size = wxMax(10, dFont->GetPointSize());
12965 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
12966 false, dFont->GetFaceName());
12968 dc.SetPen(*pblack_pen);
12969 dc.SetBrush(*pgreen_brush);
12973 case GLOBAL_COLOR_SCHEME_DAY:
12976 case GLOBAL_COLOR_SCHEME_DUSK:
12979 case GLOBAL_COLOR_SCHEME_NIGHT:
12980 bm = m_bmTideNight;
12987 int bmw = bm.GetWidth();
12988 int bmh = bm.GetHeight();
12990 float scale_factor = 1.0;
12994 float icon_pixelRefDim = 45;
12998 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
12999 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
13000 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13014 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13016 float nominal_icon_size_pixels = 48;
13017 float pix_factor = (2 * height) / nominal_icon_size_pixels;
13027 double targetHeight0 = 16.0;
13030 double displaySize = m_display_size_mm;
13031 displaySize = wxMax(displaySize, 100);
13033 float targetHeight = wxMin(targetHeight0, displaySize / 15);
13035 double pix_factor = targetHeight / symHeight;
13038 scale_factor *= pix_factor;
13040 float user_scale_factor = g_ChartScaleFactorExp;
13041 if (g_ChartScaleFactorExp > 1.0)
13042 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13045 scale_factor *= user_scale_factor;
13046 scale_factor *= GetContentScaleFactor();
13049 double marge = 0.05;
13050 std::vector<LLBBox> drawn_boxes;
13051 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13052 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13055 if ((type ==
't') || (type ==
'T'))
13060 if (BBox.ContainsMarge(lat, lon, marge)) {
13062 if (GetVP().chart_scale < 500000) {
13063 bool bdrawn =
false;
13064 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13065 if (drawn_boxes[i].Contains(lat, lon)) {
13070 if (bdrawn)
continue;
13073 this_box.Set(lat, lon, lat, lon);
13074 this_box.EnLarge(.005);
13075 drawn_boxes.push_back(this_box);
13081 if (GetVP().chart_scale > 500000) {
13082 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13086 dc.SetFont(*plabelFont);
13098 if (ptcmgr->GetTideFlowSens(
13099 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13103 ptcmgr->GetHightOrLowTide(
13104 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13105 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13117 if (tctime > t_this_now)
13118 ptcmgr->GetHightOrLowTide(
13119 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13120 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13124 ptcmgr->GetHightOrLowTide(
13125 t_this_now, FORWARD_TEN_MINUTES_STEP,
13126 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13140 int width = (int)(12 * scale_factor + 0.5);
13141 int height = (int)(45 * scale_factor + 0.5);
13142 int linew = wxMax(1, (
int)(scale_factor));
13143 int xDraw = r.x - (width / 2);
13144 int yDraw = r.y - (height / 2);
13147 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13148 int hs = (httime > lttime) ? -4 : 4;
13149 hs *= (int)(scale_factor + 0.5);
13150 if (ts > 0.995 || ts < 0.005) hs = 0;
13151 int ht_y = (int)(height * ts);
13154 pblack_pen->SetWidth(linew);
13155 dc.SetPen(*pblack_pen);
13156 dc.SetBrush(*pyelo_brush);
13157 dc.DrawRectangle(xDraw, yDraw, width, height);
13161 dc.SetPen(*pblue_pen);
13162 dc.SetBrush(*pblue_brush);
13163 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13164 (width - (4 * linew)), height - ht_y);
13170 arrow[0].x = xDraw + 2 * linew;
13171 arrow[1].x = xDraw + width / 2;
13172 arrow[2].x = xDraw + width - 2 * linew;
13173 pyelo_pen->SetWidth(linew);
13174 pblue_pen->SetWidth(linew);
13175 if (ts > 0.35 || ts < 0.15)
13177 hl = (int)(height * 0.25) + yDraw;
13179 arrow[1].y = hl + hs;
13182 dc.SetPen(*pyelo_pen);
13184 dc.SetPen(*pblue_pen);
13185 dc.DrawLines(3, arrow);
13187 if (ts > 0.60 || ts < 0.40)
13189 hl = (int)(height * 0.5) + yDraw;
13191 arrow[1].y = hl + hs;
13194 dc.SetPen(*pyelo_pen);
13196 dc.SetPen(*pblue_pen);
13197 dc.DrawLines(3, arrow);
13199 if (ts < 0.65 || ts > 0.85)
13201 hl = (int)(height * 0.75) + yDraw;
13203 arrow[1].y = hl + hs;
13206 dc.SetPen(*pyelo_pen);
13208 dc.SetPen(*pblue_pen);
13209 dc.DrawLines(3, arrow);
13213 s.Printf(_T(
"%3.1f"), nowlev);
13215 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13217 dc.GetTextExtent(s, &wx1, NULL);
13219 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13234void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13235 if (!ptcmgr)
return;
13237 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13239 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13240 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13245 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13246 if ((BBox.Contains(lat, lon))) {
13248 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13254void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13255 if (!ptcmgr)
return;
13257 float tcvalue, dir;
13261 double lon_last = 0.;
13262 double lat_last = 0.;
13264 double marge = 0.2;
13265 bool cur_time = !gTimeSource.IsValid();
13267 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13268 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13270 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13271 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13272 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13273 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13275 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13276 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13277 wxBRUSHSTYLE_SOLID);
13278 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13279 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13280 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13281 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13283 double skew_angle = GetVPRotation();
13285 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13286 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13287 int font_size = wxMax(10, dFont->GetPointSize());
13290 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13291 false, dFont->GetFaceName());
13293 float scale_factor = 1.0;
13300 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
13301 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
13302 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13308 float nominal_icon_size_pixels = 6;
13309 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
13316 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13318 float nominal_icon_size_pixels = 15;
13319 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13326 float icon_pixelRefDim = 5;
13331 double targetHeight0 = 2.0;
13334 double displaySize = m_display_size_mm;
13335 displaySize = wxMax(displaySize, 100);
13337 float targetHeight = wxMin(targetHeight0, displaySize / 50);
13338 double pix_factor = targetHeight / symHeight;
13341 scale_factor *= pix_factor;
13343 float user_scale_factor = g_ChartScaleFactorExp;
13344 if (g_ChartScaleFactorExp > 1.0)
13345 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13348 scale_factor *= user_scale_factor;
13350 scale_factor *= GetContentScaleFactor();
13353 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13354 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13359 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13360 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13365 int dd = (int)(5.0 * scale_factor + 0.5);
13376 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13377 dc.SetPen(*pblack_pen);
13378 dc.SetBrush(*porange_brush);
13379 dc.DrawPolygon(4, d);
13382 dc.SetBrush(*pblack_brush);
13383 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13387 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13401 double a1 = fabs(tcvalue) * 10.;
13403 a1 = wxMax(1.0, a1);
13404 double a2 = log10(a1);
13406 float cscale = scale_factor * a2 * 0.4;
13408 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13409 dc.SetPen(*porange_pen);
13410 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13414 if (bDrawCurrentValues) {
13415 dc.SetFont(*pTCFont);
13416 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13417 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13438void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
13439 pCwin =
new TCWin(
this, x, y, pvIDX);
13442#define NUM_CURRENT_ARROW_POINTS 9
13443static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13444 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13445 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13446 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13448void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13450 if (
scale > 1e-2) {
13451 float sin_rot = sin(rot_angle * PI / 180.);
13452 float cos_rot = cos(rot_angle * PI / 180.);
13456 float xt = CurrentArrowArray[0].x;
13457 float yt = CurrentArrowArray[0].y;
13459 float xp = (xt * cos_rot) - (yt * sin_rot);
13460 float yp = (xt * sin_rot) + (yt * cos_rot);
13461 int x1 = (int)(xp *
scale);
13462 int y1 = (int)(yp *
scale);
13465 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13466 xt = CurrentArrowArray[ip].x;
13467 yt = CurrentArrowArray[ip].y;
13469 float xp = (xt * cos_rot) - (yt * sin_rot);
13470 float yp = (xt * sin_rot) + (yt * cos_rot);
13471 int x2 = (int)(xp *
scale);
13472 int y2 = (int)(yp *
scale);
13474 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13482wxString ChartCanvas::FindValidUploadPort() {
13485 if (!g_uploadConnection.IsEmpty() &&
13486 g_uploadConnection.StartsWith(_T(
"Serial"))) {
13487 port = g_uploadConnection;
13493 for (
auto *cp : TheConnectionParams()) {
13494 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13495 port << _T(
"Serial:") << cp->Port;
13501void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13504 if (NULL == g_pais_query_dialog_active) {
13505 int pos_x = g_ais_query_dialog_x;
13506 int pos_y = g_ais_query_dialog_y;
13508 if (g_pais_query_dialog_active) {
13509 g_pais_query_dialog_active->Destroy();
13515 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13516 wxPoint(pos_x, pos_y));
13518 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13520 g_pais_query_dialog_active->SetMMSI(mmsi);
13521 g_pais_query_dialog_active->UpdateText();
13522 wxSize sz = g_pais_query_dialog_active->GetSize();
13524 bool b_reset_pos =
false;
13529 RECT frame_title_rect;
13530 frame_title_rect.left = pos_x;
13531 frame_title_rect.top = pos_y;
13532 frame_title_rect.right = pos_x + sz.x;
13533 frame_title_rect.bottom = pos_y + 30;
13535 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13536 b_reset_pos =
true;
13541 wxRect window_title_rect;
13542 window_title_rect.x = pos_x;
13543 window_title_rect.y = pos_y;
13544 window_title_rect.width = sz.x;
13545 window_title_rect.height = 30;
13547 wxRect ClientRect = wxGetClientDisplayRect();
13548 ClientRect.Deflate(
13550 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13554 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13557 g_pais_query_dialog_active->SetMMSI(mmsi);
13558 g_pais_query_dialog_active->UpdateText();
13561 g_pais_query_dialog_active->Show();
13564void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13565 bool cur_mode = GetQuiltMode();
13567 if (!GetQuiltMode())
13568 SetQuiltMode(
true);
13569 else if (GetQuiltMode()) {
13570 SetQuiltMode(
false);
13571 g_sticky_chart = GetQuiltReferenceChartIndex();
13574 if (cur_mode != GetQuiltMode()) {
13575 SetupCanvasQuiltMode();
13584 if (ps52plib) ps52plib->GenerateStateHash();
13586 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13587 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13590void ChartCanvas::DoCanvasStackDelta(
int direction) {
13591 if (!GetQuiltMode()) {
13592 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13593 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13594 if ((current_stack_index + direction) < 0)
return;
13596 if (m_bpersistent_quilt ) {
13598 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13600 if (IsChartQuiltableRef(new_dbIndex)) {
13601 ToggleCanvasQuiltMode();
13602 SelectQuiltRefdbChart(new_dbIndex);
13603 m_bpersistent_quilt =
false;
13606 SelectChartFromStack(current_stack_index + direction);
13609 std::vector<int> piano_chart_index_array =
13610 GetQuiltExtendedStackdbIndexArray();
13611 int refdb = GetQuiltRefChartdbIndex();
13614 int current_index = -1;
13615 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13616 if (refdb == piano_chart_index_array[i]) {
13621 if (current_index == -1)
return;
13624 int target_family = ctet.GetChartFamily();
13626 int new_index = -1;
13627 int check_index = current_index + direction;
13628 bool found =
false;
13629 int check_dbIndex = -1;
13630 int new_dbIndex = -1;
13634 (
unsigned int)check_index < piano_chart_index_array.size() &&
13635 (check_index >= 0)) {
13636 check_dbIndex = piano_chart_index_array[check_index];
13637 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13638 if (target_family == cte.GetChartFamily()) {
13640 new_index = check_index;
13641 new_dbIndex = check_dbIndex;
13645 check_index += direction;
13648 if (!found)
return;
13650 if (!IsChartQuiltableRef(new_dbIndex)) {
13651 ToggleCanvasQuiltMode();
13652 SelectdbChart(new_dbIndex);
13653 m_bpersistent_quilt =
true;
13655 SelectQuiltRefChart(new_index);
13659 gFrame->UpdateGlobalMenuItems();
13661 SetQuiltChartHiLiteIndex(-1);
13672void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13675 switch (event.GetId()) {
13687 DoCanvasStackDelta(1);
13692 DoCanvasStackDelta(-1);
13702 ShowCurrents(!GetbShowCurrent());
13709 ShowTides(!GetbShowTide());
13716 if (0 == m_routeState) {
13723 androidSetRouteAnnunciator(m_routeState == 1);
13729 SetAISCanvasDisplayStyle(-1);
13741void ChartCanvas::SetShowAIS(
bool show) {
13743 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13744 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13747void ChartCanvas::SetAttenAIS(
bool show) {
13748 m_bShowAISScaled = show;
13749 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13750 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13753void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13756 bool bShowAIS_Array[3] = {
true,
true,
false};
13757 bool bShowScaled_Array[3] = {
false,
true,
true};
13758 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13759 _(
"Attenuate less critical AIS targets"),
13760 _(
"Hide AIS Targets")};
13761 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13762 _T(
"AIS_Disabled")};
13764 int AIS_Toolbar_Switch = 0;
13765 if (StyleIndx == -1) {
13767 for (
int i = 1; i < ArraySize; i++) {
13768 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13769 (bShowScaled_Array[i] == m_bShowAISScaled))
13770 AIS_Toolbar_Switch = i;
13772 AIS_Toolbar_Switch++;
13773 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13774 AIS_Toolbar_Switch++;
13777 AIS_Toolbar_Switch = StyleIndx;
13780 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13782 int AIS_Toolbar_Switch_Next =
13783 AIS_Toolbar_Switch + 1;
13784 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13785 AIS_Toolbar_Switch_Next++;
13786 if (AIS_Toolbar_Switch_Next >= ArraySize)
13787 AIS_Toolbar_Switch_Next = 0;
13790 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13791 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13794void ChartCanvas::TouchAISToolActive(
void) {}
13796void ChartCanvas::UpdateAISTBTool(
void) {}
13804void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13806 bool b_update =
false;
13807 int cc1_edge_comp = 2;
13808 wxRect rect = m_Compass->
GetRect();
13809 wxSize parent_size = GetSize();
13811 parent_size *= m_displayScale;
13815 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
13816 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13817 wxRect compass_rect(compass_pt, rect.GetSize());
13819 m_Compass->Move(compass_pt);
13821 if (m_Compass && m_Compass->IsShown())
13822 m_Compass->UpdateStatus(b_force_new | b_update);
13824 wxPoint note_point =
13825 wxPoint(compass_rect.x - compass_rect.width, compass_rect.y);
13826 m_notification_button->Move(note_point);
13828 m_notification_button->UpdateStatus();
13829 if (b_force_new | b_update) Refresh();
13832void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13833 ChartTypeEnum New_Type,
13834 ChartFamilyEnum New_Family) {
13835 if (!GetpCurrentStack())
return;
13836 if (!ChartData)
return;
13838 if (index < GetpCurrentStack()->nEntry) {
13841 pTentative_Chart = ChartData->OpenStackChartConditional(
13842 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13844 if (pTentative_Chart) {
13845 if (m_singleChart) m_singleChart->Deactivate();
13847 m_singleChart = pTentative_Chart;
13848 m_singleChart->Activate();
13850 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13851 GetpCurrentStack(), m_singleChart->GetFullPath());
13864 double best_scale_ppm = GetBestVPScale(m_singleChart);
13865 double rotation = GetVPRotation();
13866 double oldskew = GetVPSkew();
13867 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13869 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13870 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13871 if (fabs(newskew) > 0.0001) rotation = newskew;
13874 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13876 UpdateGPSCompassStatusBox(
true);
13880 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13881 if (idx < 0)
return;
13883 std::vector<int> piano_active_chart_index_array;
13884 piano_active_chart_index_array.push_back(
13885 GetpCurrentStack()->GetCurrentEntrydbIndex());
13886 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13889void ChartCanvas::SelectdbChart(
int dbindex) {
13890 if (!GetpCurrentStack())
return;
13891 if (!ChartData)
return;
13893 if (dbindex >= 0) {
13896 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13898 if (pTentative_Chart) {
13899 if (m_singleChart) m_singleChart->Deactivate();
13901 m_singleChart = pTentative_Chart;
13902 m_singleChart->Activate();
13904 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13905 GetpCurrentStack(), m_singleChart->GetFullPath());
13918 double best_scale_ppm = GetBestVPScale(m_singleChart);
13922 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13932void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13935 if (!GetQuiltMode()) {
13936 if (GetpCurrentStack()) {
13937 int stack_index = -1;
13938 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13939 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13940 if (check_dbIndex < 0)
continue;
13942 ChartData->GetChartTableEntry(check_dbIndex);
13943 if (type == cte.GetChartType()) {
13946 }
else if (family == cte.GetChartFamily()) {
13952 if (stack_index >= 0) {
13953 SelectChartFromStack(stack_index);
13957 int sel_dbIndex = -1;
13958 std::vector<int> piano_chart_index_array =
13959 GetQuiltExtendedStackdbIndexArray();
13960 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13961 int check_dbIndex = piano_chart_index_array[i];
13962 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13963 if (type == cte.GetChartType()) {
13964 if (IsChartQuiltableRef(check_dbIndex)) {
13965 sel_dbIndex = check_dbIndex;
13968 }
else if (family == cte.GetChartFamily()) {
13969 if (IsChartQuiltableRef(check_dbIndex)) {
13970 sel_dbIndex = check_dbIndex;
13976 if (sel_dbIndex >= 0) {
13977 SelectQuiltRefdbChart(sel_dbIndex,
false);
13979 AdjustQuiltRefChart();
13986 SetQuiltChartHiLiteIndex(-1);
13991bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
13992 return std::find(m_tile_yesshow_index_array.begin(),
13993 m_tile_yesshow_index_array.end(),
13994 index) != m_tile_yesshow_index_array.end();
13997bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
13998 return std::find(m_tile_noshow_index_array.begin(),
13999 m_tile_noshow_index_array.end(),
14000 index) != m_tile_noshow_index_array.end();
14003void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14004 if (std::find(m_tile_noshow_index_array.begin(),
14005 m_tile_noshow_index_array.end(),
14006 index) == m_tile_noshow_index_array.end()) {
14007 m_tile_noshow_index_array.push_back(index);
14017void ChartCanvas::HandlePianoClick(
14018 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14019 if (g_options && g_options->IsShown())
14021 if (!m_pCurrentStack)
return;
14022 if (!ChartData)
return;
14037 double distance = 25000;
14038 int closest_index = -1;
14039 for (
int chart_index : selected_dbIndex_array) {
14040 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
14041 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14042 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14045 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14046 if (test_distance < distance) {
14047 distance = test_distance;
14048 closest_index = chart_index;
14052 int selected_dbIndex = selected_dbIndex_array[0];
14053 if (closest_index >= 0) selected_dbIndex = closest_index;
14055 if (!GetQuiltMode()) {
14056 if (m_bpersistent_quilt ) {
14057 if (IsChartQuiltableRef(selected_dbIndex)) {
14058 ToggleCanvasQuiltMode();
14059 SelectQuiltRefdbChart(selected_dbIndex);
14060 m_bpersistent_quilt =
false;
14062 SelectChartFromStack(selected_index);
14065 SelectChartFromStack(selected_index);
14066 g_sticky_chart = selected_dbIndex;
14070 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14074 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
14075 bool bfound =
false;
14076 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14077 if (m_tile_noshow_index_array[i] ==
14078 selected_dbIndex) {
14079 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14086 m_tile_noshow_index_array.push_back(selected_dbIndex);
14090 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14091 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14095 if (IsChartQuiltableRef(selected_dbIndex)) {
14101 bool set_scale =
false;
14102 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
14103 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14109 SelectQuiltRefdbChart(selected_dbIndex,
true);
14111 SelectQuiltRefdbChart(selected_dbIndex,
false);
14116 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14118 double proposed_scale_onscreen =
14121 if (g_bPreserveScaleOnX) {
14122 proposed_scale_onscreen =
14123 wxMin(proposed_scale_onscreen,
14125 GetCanvasWidth()));
14127 proposed_scale_onscreen =
14128 wxMin(proposed_scale_onscreen,
14130 GetCanvasWidth()));
14132 proposed_scale_onscreen =
14133 wxMax(proposed_scale_onscreen,
14142 ToggleCanvasQuiltMode();
14143 SelectdbChart(selected_dbIndex);
14144 m_bpersistent_quilt =
true;
14149 SetQuiltChartHiLiteIndex(-1);
14150 gFrame->UpdateGlobalMenuItems();
14152 HideChartInfoWindow();
14157void ChartCanvas::HandlePianoRClick(
14158 int x,
int y,
int selected_index,
14159 const std::vector<int> &selected_dbIndex_array) {
14160 if (g_options && g_options->IsShown())
14162 if (!GetpCurrentStack())
return;
14164 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14165 UpdateCanvasControlBar();
14167 SetQuiltChartHiLiteIndex(-1);
14170void ChartCanvas::HandlePianoRollover(
14171 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14172 int n_charts,
int scale) {
14173 if (g_options && g_options->IsShown())
14175 if (!GetpCurrentStack())
return;
14176 if (!ChartData)
return;
14178 if (ChartData->IsBusy())
return;
14180 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14182 if (!GetQuiltMode()) {
14183 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14186 std::vector<int> piano_chart_index_array;
14187 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14188 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14189 if ((GetpCurrentStack()->nEntry > 1) ||
14190 (piano_chart_index_array.size() >= 1)) {
14191 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14193 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14195 }
else if (GetpCurrentStack()->nEntry == 1) {
14197 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14198 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14199 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14201 }
else if ((-1 == selected_index) &&
14202 (0 == selected_dbIndex_array.size())) {
14203 ShowChartInfoWindow(key_location.x, -1);
14207 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14209 if ((GetpCurrentStack()->nEntry > 1) ||
14210 (piano_chart_index_array.size() >= 1)) {
14212 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14213 selected_dbIndex_array);
14214 else if (n_charts == 1)
14215 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14217 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14224void ChartCanvas::ClearPianoRollover() {
14225 ClearQuiltChartHiLiteIndexArray();
14226 ShowChartInfoWindow(0, -1);
14227 std::vector<int> vec;
14228 ShowCompositeInfoWindow(0, 0, 0, vec);
14232void ChartCanvas::UpdateCanvasControlBar(
void) {
14233 if (m_pianoFrozen)
return;
14235 if (!GetpCurrentStack())
return;
14236 if (!ChartData)
return;
14237 if (!g_bShowChartBar)
return;
14240 int sel_family = -1;
14242 std::vector<int> piano_chart_index_array;
14243 std::vector<int> empty_piano_chart_index_array;
14245 wxString old_hash = m_Piano->GetStoredHash();
14247 if (GetQuiltMode()) {
14248 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14249 GetQuiltFullScreendbIndexArray());
14251 std::vector<int> piano_active_chart_index_array =
14252 GetQuiltCandidatedbIndexArray();
14253 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14255 std::vector<int> piano_eclipsed_chart_index_array =
14256 GetQuiltEclipsedStackdbIndexArray();
14257 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14259 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14260 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14262 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14263 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14265 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
14266 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14269 if (m_singleChart) {
14270 sel_type = m_singleChart->GetChartType();
14271 sel_family = m_singleChart->GetChartFamily();
14276 std::vector<int> piano_skew_chart_index_array;
14277 std::vector<int> piano_tmerc_chart_index_array;
14278 std::vector<int> piano_poly_chart_index_array;
14280 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14282 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14283 double skew_norm = ctei.GetChartSkew();
14284 if (skew_norm > 180.) skew_norm -= 360.;
14286 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14287 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14290 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14291 if (fabs(skew_norm) > 1.)
14292 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14294 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14295 }
else if (fabs(skew_norm) > 1.)
14296 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14298 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14299 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14300 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14302 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14303 if (new_hash != old_hash) {
14304 m_Piano->FormatKeys();
14305 HideChartInfoWindow();
14306 m_Piano->ResetRollover();
14307 SetQuiltChartHiLiteIndex(-1);
14308 m_brepaint_piano =
true;
14314 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14316 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14317 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14318 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14319 if (e == CHART_FAMILY_RASTER) mask |= 1;
14320 if (e == CHART_FAMILY_VECTOR) {
14321 if (t == CHART_TYPE_CM93COMP)
14328 wxString s_indicated;
14329 if (sel_type == CHART_TYPE_CM93COMP)
14330 s_indicated = _T(
"cm93");
14332 if (sel_family == CHART_FAMILY_RASTER)
14333 s_indicated = _T(
"raster");
14334 else if (sel_family == CHART_FAMILY_VECTOR)
14335 s_indicated = _T(
"vector");
14338 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14341void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14343void ChartCanvas::PianoPopupMenu(
14344 int x,
int y,
int selected_index,
14345 const std::vector<int> &selected_dbIndex_array) {
14346 if (!GetpCurrentStack())
return;
14349 if (!GetQuiltMode())
return;
14351 m_piano_ctx_menu =
new wxMenu();
14353 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14363 menu_selected_dbIndex = selected_dbIndex_array[0];
14364 menu_selected_index = selected_index;
14367 bool b_is_in_noshow =
false;
14368 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14369 if (m_quilt_noshow_index_array[i] ==
14370 menu_selected_dbIndex)
14372 b_is_in_noshow =
true;
14377 if (b_is_in_noshow) {
14378 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14379 _(
"Show This Chart"));
14380 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14381 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14382 }
else if (GetpCurrentStack()->nEntry > 1) {
14383 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14384 _(
"Hide This Chart"));
14385 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14386 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14390 wxPoint pos = wxPoint(x, y - 30);
14393 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14394 PopupMenu(m_piano_ctx_menu, pos);
14396 delete m_piano_ctx_menu;
14397 m_piano_ctx_menu = NULL;
14399 HideChartInfoWindow();
14400 m_Piano->ResetRollover();
14402 SetQuiltChartHiLiteIndex(-1);
14403 ClearQuiltChartHiLiteIndexArray();
14408void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14409 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14410 if (m_quilt_noshow_index_array[i] ==
14411 menu_selected_dbIndex)
14413 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14419void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14420 if (!GetpCurrentStack())
return;
14421 if (!ChartData)
return;
14423 RemoveChartFromQuilt(menu_selected_dbIndex);
14427 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14428 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
14430 int i = menu_selected_index + 1;
14431 bool b_success =
false;
14432 while (i < GetpCurrentStack()->nEntry - 1) {
14433 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14434 if (type == ChartData->GetDBChartType(dbIndex)) {
14435 SelectQuiltRefChart(i);
14445 i = menu_selected_index - 1;
14447 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14448 if (type == ChartData->GetDBChartType(dbIndex)) {
14449 SelectQuiltRefChart(i);
14459void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14461 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14462 if (m_quilt_noshow_index_array[i] ==
14465 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14470 m_quilt_noshow_index_array.push_back(dbIndex);
14473bool ChartCanvas::UpdateS52State() {
14474 bool retval =
false;
14478 ps52plib->SetShowS57Text(m_encShowText);
14479 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14480 ps52plib->m_bShowSoundg = m_encShowDepth;
14481 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14482 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14485 if (!m_encShowLights)
14486 ps52plib->AddObjNoshow(
"LIGHTS");
14488 ps52plib->RemoveObjNoshow(
"LIGHTS");
14489 ps52plib->SetLightsOff(!m_encShowLights);
14490 ps52plib->m_bExtendLightSectors =
true;
14493 ps52plib->SetAnchorOn(m_encShowAnchor);
14494 ps52plib->SetQualityOfData(m_encShowDataQual);
14500void ChartCanvas::SetShowENCDataQual(
bool show) {
14501 m_encShowDataQual = show;
14502 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14503 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14505 m_s52StateHash = 0;
14508void ChartCanvas::SetShowENCText(
bool show) {
14509 m_encShowText = show;
14510 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14511 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14513 m_s52StateHash = 0;
14516void ChartCanvas::SetENCDisplayCategory(
int category) {
14517 m_encDisplayCategory = category;
14518 m_s52StateHash = 0;
14521void ChartCanvas::SetShowENCDepth(
bool show) {
14522 m_encShowDepth = show;
14523 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14524 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14526 m_s52StateHash = 0;
14529void ChartCanvas::SetShowENCLightDesc(
bool show) {
14530 m_encShowLightDesc = show;
14531 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14532 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14534 m_s52StateHash = 0;
14537void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14538 m_encShowBuoyLabels = show;
14539 m_s52StateHash = 0;
14542void ChartCanvas::SetShowENCLights(
bool show) {
14543 m_encShowLights = show;
14544 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14545 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14547 m_s52StateHash = 0;
14550void ChartCanvas::SetShowENCAnchor(
bool show) {
14551 m_encShowAnchor = show;
14552 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14553 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14555 m_s52StateHash = 0;
14558wxRect ChartCanvas::GetMUIBarRect() {
14561 rv = m_muiBar->GetRect();
14567void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14568 if (!GetAlertString().IsEmpty()) {
14569 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14570 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14572 dc.SetFont(*pfont);
14573 dc.SetPen(*wxTRANSPARENT_PEN);
14575 dc.SetBrush(wxColour(243, 229, 47));
14577 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14581 wxRect sbr = GetScaleBarRect();
14582 int xp = sbr.x + sbr.width + 10;
14583 int yp = (sbr.y + sbr.height) - h;
14585 int wdraw = w + 10;
14586 dc.DrawRectangle(xp, yp, wdraw, h);
14587 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14588 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14598#define BRIGHT_XCALIB
14599#define __OPCPN_USEICC__
14602#ifdef __OPCPN_USEICC__
14603int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14604 double co_green,
double co_blue);
14606wxString temp_file_name;
14610class ocpnCurtain:
public wxDialog
14612 DECLARE_CLASS( ocpnCurtain )
14613 DECLARE_EVENT_TABLE()
14616 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14618 bool ProcessEvent(wxEvent& event);
14622IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14624BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14627ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14629 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14632ocpnCurtain::~ocpnCurtain()
14636bool ocpnCurtain::ProcessEvent(wxEvent& event)
14638 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14639 return GetParent()->GetEventHandler()->ProcessEvent(event);
14644#include <windows.h>
14647typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14648typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14649SetDeviceGammaRamp_ptr_type
14650 g_pSetDeviceGammaRamp;
14651GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14653WORD *g_pSavedGammaMap;
14657int InitScreenBrightness(
void) {
14660 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14664 if (NULL == hGDI32DLL) {
14665 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14667 if (NULL != hGDI32DLL) {
14669 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14670 hGDI32DLL,
"SetDeviceGammaRamp");
14671 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14672 hGDI32DLL,
"GetDeviceGammaRamp");
14675 if ((NULL == g_pSetDeviceGammaRamp) ||
14676 (NULL == g_pGetDeviceGammaRamp)) {
14677 FreeLibrary(hGDI32DLL);
14686 if (!g_pSavedGammaMap) {
14687 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14690 bbr = g_pGetDeviceGammaRamp(
14691 hDC, g_pSavedGammaMap);
14692 ReleaseDC(NULL, hDC);
14697 wxRegKey *pRegKey =
new wxRegKey(
14698 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14699 _T(
"NT\\CurrentVersion\\ICM"));
14700 if (!pRegKey->Exists()) pRegKey->Create();
14701 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14703 g_brightness_init =
true;
14709 if (NULL == g_pcurtain) {
14710 if (gFrame->CanSetTransparent()) {
14712 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14713 wxPoint(0, 0), ::wxGetDisplaySize(),
14714 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14715 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14722 g_pcurtain->Hide();
14724 HWND hWnd = GetHwndOf(g_pcurtain);
14725 SetWindowLong(hWnd, GWL_EXSTYLE,
14726 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14727 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14728 g_pcurtain->SetTransparent(0);
14730 g_pcurtain->Maximize();
14731 g_pcurtain->Show();
14734 g_pcurtain->Enable();
14735 g_pcurtain->Disable();
14742 g_brightness_init =
true;
14748 wxString cmd(_T (
"xcalib -version" ));
14750 wxArrayString output;
14751 long r = wxExecute(cmd, output);
14754 _T(
" External application \"xcalib\" not found. Screen brightness ")
14755 _T(
"not changed."));
14757 g_brightness_init =
true;
14762int RestoreScreenBrightness(
void) {
14765 if (g_pSavedGammaMap) {
14766 HDC hDC = GetDC(NULL);
14767 g_pSetDeviceGammaRamp(hDC,
14769 ReleaseDC(NULL, hDC);
14771 free(g_pSavedGammaMap);
14772 g_pSavedGammaMap = NULL;
14776 g_pcurtain->Close();
14777 g_pcurtain->Destroy();
14781 g_brightness_init =
false;
14786#ifdef BRIGHT_XCALIB
14787 if (g_brightness_init) {
14789 cmd = _T(
"xcalib -clear");
14790 wxExecute(cmd, wxEXEC_ASYNC);
14791 g_brightness_init =
false;
14801int SetScreenBrightness(
int brightness) {
14808 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14810 g_pcurtain->Close();
14811 g_pcurtain->Destroy();
14815 InitScreenBrightness();
14817 if (NULL == hGDI32DLL) {
14819 wchar_t wdll_name[80];
14820 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14821 LPCWSTR cstr = wdll_name;
14823 hGDI32DLL = LoadLibrary(cstr);
14825 if (NULL != hGDI32DLL) {
14827 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14828 hGDI32DLL,
"SetDeviceGammaRamp");
14829 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14830 hGDI32DLL,
"GetDeviceGammaRamp");
14833 if ((NULL == g_pSetDeviceGammaRamp) ||
14834 (NULL == g_pGetDeviceGammaRamp)) {
14835 FreeLibrary(hGDI32DLL);
14842 HDC hDC = GetDC(NULL);
14853 int increment = brightness * 256 / 100;
14856 WORD GammaTable[3][256];
14859 for (
int i = 0; i < 256; i++) {
14860 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14861 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14862 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14864 table_val += increment;
14866 if (table_val > 65535) table_val = 65535;
14869 g_pSetDeviceGammaRamp(hDC, GammaTable);
14870 ReleaseDC(NULL, hDC);
14877 if (g_pSavedGammaMap) {
14878 HDC hDC = GetDC(NULL);
14879 g_pSetDeviceGammaRamp(hDC,
14881 ReleaseDC(NULL, hDC);
14884 if (brightness < 100) {
14885 if (NULL == g_pcurtain) InitScreenBrightness();
14888 int sbrite = wxMax(1, brightness);
14889 sbrite = wxMin(100, sbrite);
14891 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14895 g_pcurtain->Close();
14896 g_pcurtain->Destroy();
14906#ifdef BRIGHT_XCALIB
14908 if (!g_brightness_init) {
14909 last_brightness = 100;
14910 g_brightness_init =
true;
14911 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14912 InitScreenBrightness();
14915#ifdef __OPCPN_USEICC__
14918 if (!CreateSimpleICCProfileFile(
14919 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14920 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14921 wxString cmd(_T (
"xcalib " ));
14922 cmd += temp_file_name;
14924 wxExecute(cmd, wxEXEC_ASYNC);
14933 if (brightness > last_brightness) {
14935 cmd = _T(
"xcalib -clear");
14936 wxExecute(cmd, wxEXEC_ASYNC);
14938 ::wxMilliSleep(10);
14940 int brite_adj = wxMax(1, brightness);
14941 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14942 wxExecute(cmd, wxEXEC_ASYNC);
14944 int brite_adj = wxMax(1, brightness);
14945 int factor = (brite_adj * 100) / last_brightness;
14946 factor = wxMax(1, factor);
14948 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14949 wxExecute(cmd, wxEXEC_ASYNC);
14954 last_brightness = brightness;
14961#ifdef __OPCPN_USEICC__
14963#define MLUT_TAG 0x6d4c5554L
14964#define VCGT_TAG 0x76636774L
14966int GetIntEndian(
unsigned char *s) {
14971 p = (
unsigned char *)&ret;
14974 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14976 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14981unsigned short GetShortEndian(
unsigned char *s) {
14982 unsigned short ret;
14986 p = (
unsigned char *)&ret;
14989 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
14991 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
14997int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14998 double co_green,
double co_blue) {
15002 fp = fopen(file_name,
"wb");
15003 if (!fp)
return -1;
15009 for (
int i = 0; i < 128; i++) header[i] = 0;
15011 fwrite(header, 128, 1, fp);
15015 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15016 fwrite(&numTags, 1, 4, fp);
15018 int tagName0 = VCGT_TAG;
15019 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15020 fwrite(&tagName, 1, 4, fp);
15022 int tagOffset0 = 128 + 4 *
sizeof(int);
15023 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15024 fwrite(&tagOffset, 1, 4, fp);
15027 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15028 fwrite(&tagSize, 1, 4, fp);
15030 fwrite(&tagName, 1, 4, fp);
15032 fwrite(&tagName, 1, 4, fp);
15037 int gammatype0 = 0;
15038 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15039 fwrite(&gammatype, 1, 4, fp);
15041 int numChannels0 = 3;
15042 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15043 fwrite(&numChannels, 1, 2, fp);
15045 int numEntries0 = 256;
15046 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15047 fwrite(&numEntries, 1, 2, fp);
15049 int entrySize0 = 1;
15050 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15051 fwrite(&entrySize, 1, 2, fp);
15053 unsigned char ramp[256];
15056 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15057 fwrite(ramp, 256, 1, fp);
15060 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15061 fwrite(ramp, 256, 1, fp);
15064 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15065 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.