33#include <wx/graphics.h>
34#include <wx/listbook.h>
35#include <wx/clipbrd.h>
36#include <wx/aui/aui.h>
37#include <wx/progdlg.h>
47#include <wx/listimpl.cpp>
56#include "navutil_base.h"
64#include "nav_object_database.h"
65#include "RoutePropDlgImpl.h"
66#include "TrackPropDlg.h"
69#include "routemanagerdialog.h"
70#include "route_point_gui.h"
71#include "pluginmanager.h"
72#include "ocpn_pixel.h"
76#include "multiplexer.h"
79#include "glTextureDescriptor.h"
82#include "select_item.h"
84#include "SystemCmdSound.h"
86#include "ais_decoder.h"
87#include "ais_target_data.h"
88#include "AISTargetAlertDialog.h"
89#include "SendToGpsDlg.h"
91#include "OCPNRegion.h"
93#include "canvasMenu.h"
94#include "wx28compat.h"
98#include "OCPN_AUIManager.h"
100#include "CanvasConfig.h"
101#include "CanvasOptions.h"
103#include "ocpn_frame.h"
105#include "conn_params.h"
106#include "route_gui.h"
107#include "line_clip.h"
109#ifdef __OCPN__ANDROID__
110#include "androidUTIL.h"
114#include "glChartCanvas.h"
125#define _CRTDBG_MAP_ALLOC
128#define DEBUG_NEW new (_NORMAL_BLOCK, __FILE__, __LINE__)
138extern float g_ChartScaleFactorExp;
139extern float g_ShipScaleFactorExp;
140extern double g_mouse_zoom_sensitivity;
145#if defined(__MSVC__) && (_MSC_VER < 1700)
146#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
152#define OCPN_ALT_MENUBAR 1
160extern bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
161extern void catch_signals(
int signo);
163extern void AlphaBlending(
ocpnDC &dc,
int x,
int y,
int size_x,
int size_y,
164 float radius, wxColour color,
165 unsigned char transparency);
167extern double g_ChartNotRenderScaleFactor;
168extern double gLat, gLon, gCog, gSog, gHdt;
171extern bool bDBUpdateInProgress;
172extern ColorScheme global_color_scheme;
173extern int g_nbrightness;
178extern RouteList *pRouteList;
179extern std::vector<Track*> g_TrackList;
195extern double AnchorPointMinDist;
196extern bool AnchorAlertOn1;
197extern bool AnchorAlertOn2;
199extern int g_iDistanceFormat;
203extern wxString GetLayerName(
int id);
204extern wxString g_uploadConnection;
205extern bool g_bsimplifiedScalebar;
207extern bool bDrawCurrentValues;
209extern s52plib *ps52plib;
211extern bool bGPSValid;
212extern bool g_bTempShowMenuBar;
213extern bool g_bShowMenuBar;
214extern bool g_bShowCompassWin;
217extern bool g_bShowAreaNotices;
218extern int g_Show_Target_Name_Scale;
219extern bool g_bCPAWarn;
220extern bool g_bTCPA_Max;
224extern int g_iNavAidRadarRingsNumberVisible;
225extern float g_fNavAidRadarRingsStep;
226extern int g_pNavAidRadarRingsStepUnits;
227extern bool g_bWayPointPreventDragging;
228extern bool g_bEnableZoomToCursor;
229extern bool g_bShowChartBar;
230extern bool g_bInlandEcdis;
231extern int g_ENCSoundingScaleFactor;
232extern int g_ENCTextScaleFactor;
233extern int g_maxzoomin;
235extern float g_GLMinSymbolLineWidth;
236bool g_bAllowShipToActive;
237bool g_bShowShipToActive;
238int g_shipToActiveStyle;
239int g_shipToActiveColor;
242extern int g_ais_query_dialog_x, g_ais_query_dialog_y;
244extern int g_S57_dialog_sx, g_S57_dialog_sy;
247extern int g_detailslider_dialog_x, g_detailslider_dialog_y;
249extern bool g_b_overzoom_x;
250extern double g_plus_minus_zoom_factor;
252extern int g_OwnShipIconType;
253extern double g_n_ownship_length_meters;
254extern double g_n_ownship_beam_meters;
255extern double g_n_gps_antenna_offset_y;
256extern double g_n_gps_antenna_offset_x;
257extern int g_n_ownship_min_mm;
259extern double g_COGAvg;
261extern int g_click_stop;
262extern double g_ownship_predictor_minutes;
263extern double g_ownship_HDTpredictor_miles;
265extern bool g_bquiting;
267extern wxString g_sAIS_Alert_Sound_File;
268extern wxString g_anchorwatch_sound_file;
274extern bool g_bopengl;
275extern bool g_bdisable_opengl;
277extern bool g_bFullScreenQuilt;
279extern bool g_bsmoothpanzoom;
283extern bool g_b_assume_azerty;
285extern ChartGroupArray *g_pGroupArray;
286extern wxString g_default_routepoint_icon;
291extern OcpnSound *g_anchorwatch_sound;
293extern bool g_bShowTrue, g_bShowMag;
295extern bool g_bresponsive;
296extern int g_chart_zoom_modifier_raster;
297extern int g_chart_zoom_modifier_vector;
298extern int g_ChartScaleFactor;
304extern bool g_bShowFPS;
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;
315extern bool g_boptionsactive;
320static bool mouse_leftisdown;
322bool g_brouteCreating;
324bool g_bShowTrackPointTime;
330bool g_brightness_init;
333int g_cog_predictor_width;
334extern double g_display_size_mm;
338extern wxColour g_colourOwnshipRangeRingsColour;
342double g_defaultBoatSpeed;
343double g_defaultBoatSpeedUserUnit;
345extern int g_nAIS_activity_timer;
346extern bool g_bskew_comp;
347extern float g_compass_scalefactor;
348extern int g_COGAvgSec;
350wxGLContext *g_pGLcontext;
353extern unsigned int g_canvasConfig;
354extern wxString g_lastPluginMessage;
359extern float g_toolbar_scalefactor;
362wxString g_ObjQFileExt;
366extern double gLat, gLat;
368extern int g_GUIScaleFactor;
373#define MAX_BRIGHT 100
379EVT_PAINT(ChartCanvas::OnPaint)
380EVT_ACTIVATE(ChartCanvas::OnActivate)
381EVT_SIZE(ChartCanvas::OnSize)
382#ifndef HAVE_WX_GESTURE_EVENTS
383EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
385EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
386EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
387EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
388EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
389EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
390EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
391EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
392EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
393EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
394EVT_KEY_UP(ChartCanvas::OnKeyUp)
395EVT_CHAR(ChartCanvas::OnKeyChar)
396EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
397EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
398EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
399EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
400EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
406 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER) {
407 parent_frame = (
MyFrame *)frame;
408 m_canvasIndex = canvasIndex;
412 SetBackgroundColour(wxColour(0, 0, 0));
413 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
417 m_bDrawingRoute =
false;
418 m_bRouteEditing =
false;
419 m_bMarkEditing =
false;
420 m_bRoutePoinDragging =
false;
421 m_bIsInRadius =
false;
422 m_bMayToggleMenuBar =
true;
425 m_bShowNavobjects =
true;
427 m_bAppendingRoute =
false;
428 pThumbDIBShow = NULL;
429 m_bShowCurrent =
false;
431 bShowingCurrent =
false;
435 m_b_paint_enable =
true;
438 pss_overlay_bmp = NULL;
439 pss_overlay_mask = NULL;
440 m_bChartDragging =
false;
441 m_bMeasure_Active =
false;
442 m_bMeasure_DistCircle =
false;
443 m_pMeasureRoute = NULL;
444 m_pTrackRolloverWin = NULL;
445 m_pRouteRolloverWin = NULL;
446 m_pAISRolloverWin = NULL;
448 m_disable_edge_pan =
false;
449 m_dragoffsetSet =
false;
453 m_singleChart = NULL;
454 m_upMode = NORTH_UP_MODE;
456 m_bShowAISScaled =
false;
463 m_pSelectedRoute = NULL;
464 m_pSelectedTrack = NULL;
465 m_pRoutePointEditTarget = NULL;
466 m_pFoundPoint = NULL;
467 m_pMouseRoute = NULL;
468 m_prev_pMousePoint = NULL;
469 m_pEditRouteArray = NULL;
470 m_pFoundRoutePoint = NULL;
471 m_FinishRouteOnKillFocus =
true;
473 m_pRolloverRouteSeg = NULL;
474 m_pRolloverTrackSeg = NULL;
475 m_bsectors_shown =
false;
477 m_bbrightdir =
false;
482 m_pos_image_user_day = NULL;
483 m_pos_image_user_dusk = NULL;
484 m_pos_image_user_night = NULL;
485 m_pos_image_user_grey_day = NULL;
486 m_pos_image_user_grey_dusk = NULL;
487 m_pos_image_user_grey_night = NULL;
490 m_rotation_speed = 0;
496 m_pos_image_user_yellow_day = NULL;
497 m_pos_image_user_yellow_dusk = NULL;
498 m_pos_image_user_yellow_night = NULL;
500 SetOwnShipState(SHIP_INVALID);
502 undo =
new Undo(
this);
509 m_toolbar_scalefactor = 1.0;
510 m_toolbarOrientation = wxTB_HORIZONTAL;
511 m_focus_indicator_pix = 1;
513 m_pCurrentStack = NULL;
514 m_bpersistent_quilt =
false;
515 m_piano_ctx_menu = NULL;
518 g_ChartNotRenderScaleFactor = 2.0;
519 m_bShowScaleInStatusBar =
true;
522 m_bShowScaleInStatusBar =
false;
524 m_bShowOutlines =
false;
525 m_bDisplayGrid =
false;
526 m_bShowDepthUnits =
true;
527 m_encDisplayCategory = (int)STANDARD;
529 m_encShowLights =
true;
530 m_encShowAnchor =
true;
531 m_encShowDataQual =
false;
533 m_pQuilt =
new Quilt(
this);
535 SetAlertString(_T(
""));
539#ifdef HAVE_WX_GESTURE_EVENTS
540 m_oldVPSScale = -1.0;
541 m_popupWanted =
false;
570 singleClickEventIsValid =
false;
579 pCursorPencil = NULL;
584 SetCursor(*pCursorArrow);
586 pPanTimer =
new wxTimer(
this, m_MouseDragging);
589 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
590 pMovementTimer->Stop();
592 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
593 pMovementStopTimer->Stop();
595 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
596 pRotDefTimer->Stop();
598 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
599 m_DoubleClickTimer->Stop();
604 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
605 pCurTrackTimer->Stop();
606 m_curtrack_timer_msec = 10;
608 m_wheelzoom_stop_oneshot = 0;
609 m_last_wheel_dir = 0;
611 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
613 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
615 m_rollover_popup_timer_msec = 20;
617 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
619 m_b_rot_hidef =
true;
624 m_upMode = NORTH_UP_MODE;
625 m_bLookAhead =
false;
630 m_cs = GLOBAL_COLOR_SCHEME_DAY;
633 VPoint.view_scale_ppm = 1;
636 m_canvas_scale_factor = 1.;
638 m_canvas_width = 1000;
640 m_overzoomTextWidth = 0;
641 m_overzoomTextHeight = 0;
649 m_pEM_Fathoms = NULL;
651 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
653 m_pEM_OverZoom = NULL;
655 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
659 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"), 1. / g_Platform->GetDisplayDIPMult(
this));
662 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
665 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
668 double factor_dusk = 0.5;
669 double factor_night = 0.25;
672 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
674 int rimg_width = m_os_image_red_day.GetWidth();
675 int rimg_height = m_os_image_red_day.GetHeight();
677 m_os_image_red_dusk = m_os_image_red_day.Copy();
678 m_os_image_red_night = m_os_image_red_day.Copy();
680 for (
int iy = 0; iy < rimg_height; iy++) {
681 for (
int ix = 0; ix < rimg_width; ix++) {
682 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
683 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
684 m_os_image_red_day.GetGreen(ix, iy),
685 m_os_image_red_day.GetBlue(ix, iy));
686 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
687 hsv.value = hsv.value * factor_dusk;
688 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
689 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
691 hsv = wxImage::RGBtoHSV(rgb);
692 hsv.value = hsv.value * factor_night;
693 nrgb = wxImage::HSVtoRGB(hsv);
694 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
700 m_os_image_grey_day =
701 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
703 int gimg_width = m_os_image_grey_day.GetWidth();
704 int gimg_height = m_os_image_grey_day.GetHeight();
706 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
707 m_os_image_grey_night = m_os_image_grey_day.Copy();
709 for (
int iy = 0; iy < gimg_height; iy++) {
710 for (
int ix = 0; ix < gimg_width; ix++) {
711 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
712 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
713 m_os_image_grey_day.GetGreen(ix, iy),
714 m_os_image_grey_day.GetBlue(ix, iy));
715 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
716 hsv.value = hsv.value * factor_dusk;
717 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
718 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
720 hsv = wxImage::RGBtoHSV(rgb);
721 hsv.value = hsv.value * factor_night;
722 nrgb = wxImage::HSVtoRGB(hsv);
723 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
729 m_os_image_yellow_day = m_os_image_red_day.Copy();
731 gimg_width = m_os_image_yellow_day.GetWidth();
732 gimg_height = m_os_image_yellow_day.GetHeight();
734 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
735 m_os_image_yellow_night = m_os_image_red_day.Copy();
737 for (
int iy = 0; iy < gimg_height; iy++) {
738 for (
int ix = 0; ix < gimg_width; ix++) {
739 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
740 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
741 m_os_image_yellow_day.GetGreen(ix, iy),
742 m_os_image_yellow_day.GetBlue(ix, iy));
743 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
744 hsv.hue += 60. / 360.;
745 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
746 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
748 hsv = wxImage::RGBtoHSV(rgb);
749 hsv.value = hsv.value * factor_dusk;
750 hsv.hue += 60. / 360.;
751 nrgb = wxImage::HSVtoRGB(hsv);
752 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
754 hsv = wxImage::RGBtoHSV(rgb);
755 hsv.hue += 60. / 360.;
756 hsv.value = hsv.value * factor_night;
757 nrgb = wxImage::HSVtoRGB(hsv);
758 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
764 m_pos_image_red = &m_os_image_red_day;
765 m_pos_image_yellow = &m_os_image_yellow_day;
766 m_pos_image_grey = &m_os_image_grey_day;
770 m_pBrightPopup = NULL;
773 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
776 int gridFontSize = 8;
777#if defined(__WXOSX__) || defined(__WXGTK3__)
779 gridFontSize *= GetContentScaleFactor();
782 m_pgridFont = FontMgr::Get().FindOrCreateFont(
783 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, FALSE,
784 wxString(_T (
"Arial" )));
786 m_Piano =
new Piano(
this);
788 m_bShowCompassWin = g_bShowCompassWin;
791 m_Compass->SetScaleFactor(g_compass_scalefactor);
792 m_Compass->Show(m_bShowCompassWin);
794 m_bToolbarEnable =
false;
795 m_pianoFrozen =
false;
797 SetMinSize(wxSize(200, 200));
799 m_displayScale = 1.0;
800#if defined(__WXOSX__) || defined(__WXGTK3__)
802 m_displayScale = GetContentScaleFactor();
806#ifdef HAVE_WX_GESTURE_EVENTS
807 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE |
808 wxTOUCH_PRESS_GESTURES)) {
809 wxLogError(
"Failed to enable touch events");
812 Bind(wxEVT_GESTURE_ZOOM, &ChartCanvas::OnZoom,
this);
814 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
815 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
817 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
818 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
820 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
821 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
823 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
824 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
828ChartCanvas::~ChartCanvas() {
829 delete pThumbDIBShow;
837 delete pCursorPencil;
841 delete pMovementTimer;
842 delete pMovementStopTimer;
843 delete pCurTrackTimer;
845 delete m_DoubleClickTimer;
847 delete m_pTrackRolloverWin;
848 delete m_pRouteRolloverWin;
849 delete m_pAISRolloverWin;
850 delete m_pBrightPopup;
856 m_dc_route.SelectObject(wxNullBitmap);
859 delete pWorldBackgroundChart;
860 delete pss_overlay_bmp;
864 delete m_pEM_Fathoms;
866 delete m_pEM_OverZoom;
871 delete m_pos_image_user_day;
872 delete m_pos_image_user_dusk;
873 delete m_pos_image_user_night;
874 delete m_pos_image_user_grey_day;
875 delete m_pos_image_user_grey_dusk;
876 delete m_pos_image_user_grey_night;
877 delete m_pos_image_user_yellow_day;
878 delete m_pos_image_user_yellow_dusk;
879 delete m_pos_image_user_yellow_night;
883 if (!g_bdisable_opengl) {
886#if wxCHECK_VERSION(2, 9, 0)
887 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
894 MUIBar *muiBar = m_muiBar;
900void ChartCanvas::RebuildCursors() {
906 delete pCursorPencil;
910 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
912 double pencilScale = 1.0 / g_Platform->GetDisplayDIPMult(gFrame);
914 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
915 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
916 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
917 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
918 wxImage ICursorPencil = style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
919 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
921#if !defined(__WXMSW__) && !defined(__WXQT__)
922 ICursorLeft.ConvertAlphaToMask(128);
923 ICursorRight.ConvertAlphaToMask(128);
924 ICursorUp.ConvertAlphaToMask(128);
925 ICursorDown.ConvertAlphaToMask(128);
926 ICursorPencil.ConvertAlphaToMask(10);
927 ICursorCross.ConvertAlphaToMask(10);
930 if (ICursorLeft.Ok()) {
931 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
932 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
933 pCursorLeft =
new wxCursor(ICursorLeft);
935 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
937 if (ICursorRight.Ok()) {
938 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
939 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
940 pCursorRight =
new wxCursor(ICursorRight);
942 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
944 if (ICursorUp.Ok()) {
945 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
946 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
947 pCursorUp =
new wxCursor(ICursorUp);
949 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
951 if (ICursorDown.Ok()) {
952 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
953 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
954 pCursorDown =
new wxCursor(ICursorDown);
956 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
958 if (ICursorPencil.Ok()) {
959 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
960 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
961 pCursorPencil =
new wxCursor(ICursorPencil);
963 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
965 if (ICursorCross.Ok()) {
966 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
967 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
968 pCursorCross =
new wxCursor(ICursorCross);
970 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
972 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
973 pPlugIn_Cursor = NULL;
976void ChartCanvas::CanvasApplyLocale() {
977 CreateDepthUnitEmbossMaps(m_cs);
978 CreateOZEmbossMapData(m_cs);
981void ChartCanvas::SetupGlCanvas() {
982#ifndef __OCPN__ANDROID__
984 if (!g_bdisable_opengl) {
986 wxLogMessage(_T(
"Creating glChartCanvas"));
991 if (IsPrimaryCanvas()) {
998 wxGLContext *pctx =
new wxGLContext(m_glcc);
999 m_glcc->SetContext(pctx);
1000 g_pGLcontext = pctx;
1003 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
1005 m_glcc->SetContext(g_pGLcontext);
1014#ifdef __OCPN__ANDROID__
1015 if (!g_bdisable_opengl) {
1018 wxLogMessage(_T(
"Creating glChartCanvas"));
1022 if (IsPrimaryCanvas()) {
1023 qDebug() <<
"Creating Primary glChartCanvas";
1031 wxGLContext *pctx =
new wxGLContext(m_glcc);
1032 m_glcc->SetContext(pctx);
1033 g_pGLcontext = pctx;
1034 m_glcc->m_pParentCanvas =
this;
1037 qDebug() <<
"Creating Secondary glChartCanvas";
1043 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1046 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1047 m_glcc->SetContext(pwxctx);
1048 m_glcc->m_pParentCanvas =
this;
1056void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1057 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1061#ifdef __OCPN__ANDROID__
1072 if (m_routeState && m_FinishRouteOnKillFocus)
1073 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1075 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1079void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1080 m_routeFinishTimer.Stop();
1084 gFrame->UpdateGlobalMenuItems(
this);
1086 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1089void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1090 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1093#ifdef HAVE_WX_GESTURE_EVENTS
1094void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1100 m_popupWanted =
true;
1103void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1107void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1109void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1111void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1112 wxPoint pos =
event.GetPosition();
1116 if (!m_popupWanted) {
1117 wxMouseEvent ev(wxEVT_LEFT_UP);
1124 m_popupWanted =
false;
1126 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1133void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1136 wxPoint pos =
event.GetPosition();
1140void ChartCanvas::OnMotion(wxMouseEvent &event) {
1145 event.m_leftDown = m_leftdown;
1149void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1151 if (event.IsGestureEnd())
return;
1153 double factor =
event.GetZoomFactor();
1155 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1156 m_oldVPSScale = GetVPScale();
1159 double current_vps = GetVPScale();
1160 double wanted_factor = m_oldVPSScale / current_vps * factor;
1162 ZoomCanvas(wanted_factor,
true,
false);
1165 if (event.IsGestureStart()) {
1166 m_zoomStartPoint =
event.GetPosition();
1168 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1169 PanCanvas(-delta.x, -delta.y);
1170 m_zoomStartPoint =
event.GetPosition();
1174void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1176void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1177 DoRotateCanvas(0.0);
1181void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1182 SetViewPoint(pcc->iLat, pcc->iLon, pcc->iScale, 0., pcc->iRotation);
1186 m_restore_dbindex = pcc->DBindex;
1187 m_bFollow = pcc->bFollow;
1188 if (pcc->GroupID < 0) pcc->GroupID = 0;
1190 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1193 m_groupIndex = pcc->GroupID;
1195 if (pcc->bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1197 ShowTides(pcc->bShowTides);
1198 ShowCurrents(pcc->bShowCurrents);
1200 SetShowDepthUnits(pcc->bShowDepthUnits);
1201 SetShowGrid(pcc->bShowGrid);
1202 SetShowOutlines(pcc->bShowOutlines);
1204 SetShowAIS(pcc->bShowAIS);
1205 SetAttenAIS(pcc->bAttenAIS);
1208 SetShowENCText(pcc->bShowENCText);
1209 m_encDisplayCategory = pcc->nENCDisplayCategory;
1210 m_encShowDepth = pcc->bShowENCDepths;
1211 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1212 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1213 m_encShowLights = pcc->bShowENCLights;
1214 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1215 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1217 bool courseUp = pcc->bCourseUp;
1218 bool headUp = pcc->bHeadUp;
1219 m_upMode = NORTH_UP_MODE;
1221 m_upMode = COURSE_UP_MODE;
1223 m_upMode = HEAD_UP_MODE;
1225 m_bLookAhead = pcc->bLookahead;
1227 m_singleChart = NULL;
1230void ChartCanvas::ApplyGlobalSettings() {
1232 m_bShowCompassWin = g_bShowCompassWin;
1234 m_Compass->Show(m_bShowCompassWin);
1235 if (m_bShowCompassWin) m_Compass->UpdateStatus();
1239void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1240 bool groupOK = CheckGroup(m_groupIndex);
1243 SetGroupIndex(m_groupIndex,
true);
1247void ChartCanvas::SetShowGPS(
bool bshow) {
1248 if (m_bShowGPS != bshow) {
1251 m_Compass->SetScaleFactor(g_compass_scalefactor);
1252 m_Compass->Show(m_bShowCompassWin);
1257void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1259 m_Compass->Show(m_bShowCompassWin);
1260 if (m_bShowCompassWin) m_Compass->UpdateStatus();
1264void ChartCanvas::SetToolbarEnable(
bool bShow) {
1269 m_bToolbarEnable = bShow;
1272 if (GetToolbar()) GetToolbar()->Show(bShow);
1276int ChartCanvas::GetPianoHeight() {
1278 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1283void ChartCanvas::ConfigureChartBar() {
1286 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1287 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1289 if (GetQuiltMode()) {
1290 m_Piano->SetRoundedRectangles(
true);
1292 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1293 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1294 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1297void ChartCanvas::ShowTides(
bool bShow) {
1298 gFrame->LoadHarmonics();
1300 if (ptcmgr->IsReady()) {
1301 SetbShowTide(bShow);
1302 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_TIDE, bShow);
1303 wxString tip = _(
"Show Tides");
1304 if (bShow) tip = _(
"Hide Tides");
1305 if (m_toolBar) m_toolBar->SetToolShortHelp(ID_TIDE, tip);
1307 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1309 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1310 SetbShowTide(
false);
1311 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_TIDE,
false);
1312 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1315 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1316 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1327void ChartCanvas::ShowCurrents(
bool bShow) {
1328 gFrame->LoadHarmonics();
1330 if (ptcmgr->IsReady()) {
1331 SetbShowCurrent(bShow);
1332 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_CURRENT, bShow);
1333 wxString tip = _(
"Show Currents");
1334 if (bShow) tip = _(
"Hide Currents");
1335 if (m_toolBar) m_toolBar->SetToolShortHelp(ID_CURRENT, tip);
1337 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1339 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1340 SetbShowCurrent(
false);
1341 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_CURRENT,
false);
1342 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1345 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1346 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1358extern bool g_bPreserveScaleOnX;
1360extern int g_sticky_chart;
1362void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1364void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1365 SetAlertString(_T(
""));
1367 int new_index = index;
1368 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1370 bool bgroup_override =
false;
1371 int old_group_index = new_index;
1373 if (!CheckGroup(new_index)) {
1375 bgroup_override =
true;
1378 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1382 int current_chart_native_scale = GetCanvasChartNativeScale();
1385 m_groupIndex = new_index;
1388 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1391 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1395 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1399 g_sticky_chart = -1;
1403 UpdateCanvasOnGroupChange();
1406 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1408 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1411 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1412 double best_scale = GetBestStartScale(dbi_hint, vp);
1413 SetVPScale(best_scale);
1416 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1420 canvasChartsRefresh(dbi_hint);
1422 if (!autoSwitch && bgroup_override) {
1424 wxString msg(_(
"Group \""));
1426 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1427 msg += pGroup->m_group_name;
1429 msg += _(
"\" is empty.");
1431 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1438 if (bgroup_override) {
1439 wxString msg(_(
"Group \""));
1441 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1442 msg += pGroup->m_group_name;
1444 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1446 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1450bool ChartCanvas::CheckGroup(
int igroup) {
1451 if (!ChartData)
return true;
1453 if (igroup == 0)
return true;
1458 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1460 if (pGroup->m_element_array.empty())
1464 for (
const auto &elem : pGroup->m_element_array) {
1465 for (
unsigned int ic = 0;
1466 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1468 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1470 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1475 for (
const auto &elem : pGroup->m_element_array) {
1476 const wxString &element_root = elem.m_element_name;
1477 wxString test_string = _T(
"GSHH");
1478 if (element_root.Upper().Contains(test_string))
return true;
1484void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1485 if (!ChartData)
return;
1487 OCPNPlatform::ShowBusySpinner();
1489 double old_scale = GetVPScale();
1491 SetQuiltRefChart(-1);
1493 m_singleChart = NULL;
1499 if (!m_pCurrentStack) {
1501 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1504 if (-1 != dbi_hint) {
1505 if (GetQuiltMode()) {
1506 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1507 SetQuiltRefChart(dbi_hint);
1511 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1513 if (pTentative_Chart) {
1516 if (m_singleChart) m_singleChart->Deactivate();
1518 m_singleChart = pTentative_Chart;
1519 m_singleChart->Activate();
1521 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1522 GetpCurrentStack(), m_singleChart->GetFullPath());
1530 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1531 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1532 SetQuiltRefChart(selected_index);
1536 SetupCanvasQuiltMode();
1537 if (!GetQuiltMode() && m_singleChart == 0) {
1539 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1540 m_singleChart = pDummyChart;
1541 SetVPScale(old_scale);
1546 UpdateCanvasControlBar();
1547 UpdateGPSCompassStatusBox(
true);
1549 SetCursor(wxCURSOR_ARROW);
1551 OCPNPlatform::HideBusySpinner();
1554bool ChartCanvas::DoCanvasUpdate(
void) {
1556 double vpLat, vpLon;
1558 bool bNewChart =
false;
1559 bool bNewView =
false;
1560 bool bCanvasChartAutoOpen =
true;
1562 bool bNewPiano =
false;
1563 bool bOpenSpecified;
1569 if (bDBUpdateInProgress)
return false;
1570 if (!ChartData)
return false;
1572 if (ChartData->IsBusy())
return false;
1598 double dx = m_OSoffsetx;
1599 double dy = m_OSoffsety;
1600 double d_east = dx / GetVP().view_scale_ppm;
1601 double d_north = dy / GetVP().view_scale_ppm;
1603 if (GetUpMode() == NORTH_UP_MODE) {
1604 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1606 double offset_angle = atan2(d_north, d_east);
1607 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1608 double chart_angle = GetVPRotation();
1609 double target_angle = chart_angle + offset_angle;
1610 double d_east_mod = offset_distance * cos(target_angle);
1611 double d_north_mod = offset_distance * sin(target_angle);
1612 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1616 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1617 double angle = g_COGAvg + (GetVPRotation() * 180. / PI);
1619 double pixel_deltay =
1620 fabs(cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1621 double pixel_deltax = fabs(sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1623 double pixel_delta_tent =
1624 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1626 double pixel_delta = 0;
1631 if (!std::isnan(gSog)) {
1634 else if (gSog >= 3.0)
1635 pixel_delta = pixel_delta_tent;
1637 pixel_delta = pixel_delta_tent * (gSog - 1.0) / 2.0;
1640 double meters_to_shift =
1641 cos(gLat * PI / 180.) * pixel_delta / GetVPScale();
1643 double dir_to_shift = g_COGAvg;
1645 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1647 }
else if (m_bLookAhead && !bGPSValid) {
1661 if (GetQuiltMode()) {
1662 int current_db_index = -1;
1663 if (m_pCurrentStack)
1666 ->GetCurrentEntrydbIndex();
1674 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1676 if (m_pCurrentStack->nEntry) {
1677 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1679 SelectQuiltRefdbChart(new_dbIndex,
true);
1680 m_bautofind =
false;
1684 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1685 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1690 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1692 double proposed_scale_onscreen =
1693 GetCanvasScaleFactor() / GetVPScale();
1695 int initial_db_index = m_restore_dbindex;
1696 if (initial_db_index < 0) {
1697 if (m_pCurrentStack->nEntry) {
1699 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1704 if (m_pCurrentStack->nEntry) {
1705 int initial_type = ChartData->GetDBChartType(initial_db_index);
1710 if (!IsChartQuiltableRef(initial_db_index)) {
1714 int stack_index = 0;
1716 if (stack_index >= 0) {
1717 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1718 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1719 if (IsChartQuiltableRef(test_db_index) &&
1721 ChartData->GetDBChartType(initial_db_index))) {
1722 initial_db_index = test_db_index;
1730 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1732 SetQuiltRefChart(initial_db_index);
1733 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1741 if (pc->GetChartType() != CHART_TYPE_MBTILES)
1742 proposed_scale_onscreen =
1743 wxMin(proposed_scale_onscreen, 4.0 * pc->GetNativeScale());
1745 proposed_scale_onscreen =
1746 wxMin(proposed_scale_onscreen, 32.0 * pc->GetNativeScale());
1750 bNewView |= SetViewPoint(vpLat, vpLon,
1751 GetCanvasScaleFactor() / proposed_scale_onscreen,
1752 0, GetVPRotation());
1755 bNewView |= SetViewPoint(vpLat, vpLon, GetVPScale(), 0, GetVPRotation());
1761 pLast_Ch = m_singleChart;
1762 ChartTypeEnum new_open_type;
1763 ChartFamilyEnum new_open_family;
1765 new_open_type = pLast_Ch->GetChartType();
1766 new_open_family = pLast_Ch->GetChartFamily();
1768 new_open_type = CHART_TYPE_KAP;
1769 new_open_family = CHART_FAMILY_RASTER;
1772 bOpenSpecified = m_bFirstAuto;
1775 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1778 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1780 if (NULL == pDummyChart) {
1786 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1788 m_singleChart = pDummyChart;
1792 double set_scale = GetVPScale();
1793 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1795 bNewView |= SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1798 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1799 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1806 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1812 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1817 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1820 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1825 if (NULL != m_singleChart)
1826 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1827 m_singleChart->GetFullPath());
1830 m_pCurrentStack->CurrentStackEntry = tEntry;
1840 if (bCanvasChartAutoOpen) {
1841 bool search_direction =
1843 int start_index = 0;
1847 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1848 (LastStack.nEntry == 0)) {
1849 search_direction =
true;
1850 start_index = m_pCurrentStack->nEntry - 1;
1854 if (bOpenSpecified) {
1855 search_direction =
false;
1857 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1860 new_open_type = CHART_TYPE_DONTCARE;
1863 pProposed = ChartData->OpenStackChartConditional(
1864 m_pCurrentStack, start_index, search_direction, new_open_type,
1868 if (NULL == pProposed)
1869 pProposed = ChartData->OpenStackChartConditional(
1870 m_pCurrentStack, start_index, search_direction,
1871 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1873 if (NULL == pProposed)
1874 pProposed = ChartData->OpenStackChartConditional(
1875 m_pCurrentStack, start_index, search_direction,
1876 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1887 if (NULL == pProposed) {
1888 if (NULL == pDummyChart) {
1894 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1896 pProposed = pDummyChart;
1900 if (m_singleChart) m_singleChart->Deactivate();
1901 m_singleChart = pProposed;
1903 if (m_singleChart) {
1904 m_singleChart->Activate();
1905 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1906 m_pCurrentStack, m_singleChart->GetFullPath());
1911 if (NULL != m_singleChart) {
1913 double set_scale = GetVPScale();
1917 if (!GetVP().IsValid())
1918 set_scale = 1. / 20000.;
1920 double proposed_scale_onscreen;
1923 double new_scale_ppm =
1924 m_singleChart->GetNearestPreferredScalePPM(GetVPScale());
1925 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
1927 proposed_scale_onscreen = GetCanvasScaleFactor() / set_scale;
1932 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1933 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1934 double equivalent_vp_scale =
1935 GetCanvasScaleFactor() / proposed_scale_onscreen;
1936 double new_scale_ppm =
1937 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1938 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
1942 proposed_scale_onscreen =
1943 wxMin(proposed_scale_onscreen,
1944 m_singleChart->GetNormalScaleMax(GetCanvasScaleFactor(),
1946 proposed_scale_onscreen =
1947 wxMax(proposed_scale_onscreen,
1948 m_singleChart->GetNormalScaleMin(GetCanvasScaleFactor(),
1952 set_scale = GetCanvasScaleFactor() / proposed_scale_onscreen;
1955 bNewView |= SetViewPoint(vpLat, vpLon, set_scale,
1956 m_singleChart->GetChartSkew() * PI / 180.,
1963 if ((m_bFollow) && m_singleChart)
1964 bNewView |= SetViewPoint(vpLat, vpLon, GetVPScale(),
1965 m_singleChart->GetChartSkew() * PI / 180.,
1975 if (pthumbwin && pthumbwin->IsShown()) {
1976 if (pthumbwin->pThumbChart) {
1977 if (pthumbwin->pThumbChart->UpdateThumbData(gLat, gLon))
1978 pthumbwin->Refresh(TRUE);
1982 m_bFirstAuto =
false;
1986 if (bNewChart && !bNewView) Refresh(
false);
1991 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1994 return bNewChart | bNewView;
1997void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1998 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
2000 SetQuiltRefChart(db_index);
2002 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
2005 double best_scale_ppm = GetBestVPScale(pc);
2006 SetVPScale(best_scale_ppm);
2009 SetQuiltRefChart(-1);
2011 SetQuiltRefChart(-1);
2014void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
2015 std::vector<int> piano_chart_index_array =
2016 GetQuiltExtendedStackdbIndexArray();
2017 int current_db_index = piano_chart_index_array[selected_index];
2019 SelectQuiltRefdbChart(current_db_index);
2022double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2024 double proposed_scale_onscreen = GetCanvasScaleFactor() / GetVPScale();
2026 if ((g_bPreserveScaleOnX) ||
2027 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2028 double new_scale_ppm = GetVPScale();
2029 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
2033 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2034 double equivalent_vp_scale =
2035 GetCanvasScaleFactor() / proposed_scale_onscreen;
2036 double new_scale_ppm =
2037 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2038 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
2044 double max_underzoom_multiplier = 2.0;
2045 if (GetVP().b_quilt) {
2046 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2047 pchart->GetChartType(),
2048 pchart->GetChartFamily());
2049 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2052 proposed_scale_onscreen = wxMin(
2053 proposed_scale_onscreen,
2054 pchart->GetNormalScaleMax(GetCanvasScaleFactor(), GetCanvasWidth()) *
2055 max_underzoom_multiplier);
2058 proposed_scale_onscreen =
2059 wxMax(proposed_scale_onscreen,
2060 pchart->GetNormalScaleMin(GetCanvasScaleFactor(),
false));
2062 return GetCanvasScaleFactor() / proposed_scale_onscreen;
2067void ChartCanvas::SetupCanvasQuiltMode(
void) {
2070 ChartData->LockCache();
2072 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2076 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2077 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2078 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2079 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2081 m_Piano->SetRoundedRectangles(
true);
2084 int target_new_dbindex = -1;
2085 if (m_pCurrentStack) {
2086 target_new_dbindex =
2087 GetQuiltReferenceChartIndex();
2089 if (-1 != target_new_dbindex) {
2090 if (!IsChartQuiltableRef(target_new_dbindex)) {
2091 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2092 int type = ChartData->GetDBChartType(target_new_dbindex);
2095 int stack_index = m_pCurrentStack->CurrentStackEntry;
2097 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2098 (stack_index >= 0)) {
2099 int proj_tent = ChartData->GetDBChartProj(
2100 m_pCurrentStack->GetDBIndex(stack_index));
2101 int type_tent = ChartData->GetDBChartType(
2102 m_pCurrentStack->GetDBIndex(stack_index));
2104 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2105 if ((proj == proj_tent) && (type_tent == type)) {
2106 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2116 if (IsChartQuiltableRef(target_new_dbindex))
2117 SelectQuiltRefdbChart(target_new_dbindex,
2120 SelectQuiltRefdbChart(-1,
false);
2122 m_singleChart = NULL;
2125 AdjustQuiltRefChart();
2133 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2137 std::vector<int> empty_array;
2138 m_Piano->SetActiveKeyArray(empty_array);
2139 m_Piano->SetNoshowIndexArray(empty_array);
2140 m_Piano->SetEclipsedIndexArray(empty_array);
2143 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2144 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2145 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2146 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2148 m_Piano->SetRoundedRectangles(
false);
2154 if (!GetQuiltMode()) {
2155 if (ChartData && ChartData->IsValid()) {
2159 if (m_bFollow ==
true) {
2167 if (!m_singleChart) {
2170 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2178 int cur_max_scale = (int)1e8;
2180 ChartBase *pChart = GetFirstQuiltChart();
2184 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2186 if (pChart->GetNativeScale() < cur_max_scale) {
2187 Candidate_Chart = pChart;
2188 cur_max_scale = pChart->GetNativeScale();
2191 pChart = GetNextQuiltChart();
2194 m_singleChart = Candidate_Chart;
2198 if (NULL == m_singleChart) {
2199 m_singleChart = ChartData->OpenStackChartConditional(
2200 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2201 CHART_FAMILY_DONTCARE);
2207 InvalidateAllQuiltPatchs();
2209 if (m_singleChart) {
2210 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2211 std::vector<int> one_array;
2212 one_array.push_back(dbi);
2213 m_Piano->SetActiveKeyArray(one_array);
2216 if (m_singleChart) {
2217 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2221 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2225bool ChartCanvas::IsTempMenuBarEnabled() {
2228 wxGetOsVersion(&major);
2236double ChartCanvas::GetCanvasRangeMeters() {
2238 GetSize(&width, &height);
2239 int minDimension = wxMin(width, height);
2241 double range = (minDimension / GetVP().view_scale_ppm) / 2;
2242 range *= cos(GetVP().clat * PI / 180.);
2246void ChartCanvas::SetCanvasRangeMeters(
double range) {
2248 GetSize(&width, &height);
2249 int minDimension = wxMin(width, height);
2251 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2252 SetVPScale(scale_ppm / 2);
2255bool ChartCanvas::SetUserOwnship() {
2259 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2260 double factor_dusk = 0.5;
2261 double factor_night = 0.25;
2263 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2264 m_pos_image_user_day =
new wxImage;
2265 *m_pos_image_user_day = pbmp->ConvertToImage();
2266 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2268 int gimg_width = m_pos_image_user_day->GetWidth();
2269 int gimg_height = m_pos_image_user_day->GetHeight();
2272 m_pos_image_user_dusk =
new wxImage;
2273 m_pos_image_user_night =
new wxImage;
2275 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2276 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2278 for (
int iy = 0; iy < gimg_height; iy++) {
2279 for (
int ix = 0; ix < gimg_width; ix++) {
2280 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2281 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2282 m_pos_image_user_day->GetGreen(ix, iy),
2283 m_pos_image_user_day->GetBlue(ix, iy));
2284 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2285 hsv.value = hsv.value * factor_dusk;
2286 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2287 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2290 hsv = wxImage::RGBtoHSV(rgb);
2291 hsv.value = hsv.value * factor_night;
2292 nrgb = wxImage::HSVtoRGB(hsv);
2293 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2300 m_pos_image_user_grey_day =
new wxImage;
2301 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2303 m_pos_image_user_grey_dusk =
new wxImage;
2304 m_pos_image_user_grey_night =
new wxImage;
2306 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2307 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2309 for (
int iy = 0; iy < gimg_height; iy++) {
2310 for (
int ix = 0; ix < gimg_width; ix++) {
2311 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2312 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2313 m_pos_image_user_grey_day->GetGreen(ix, iy),
2314 m_pos_image_user_grey_day->GetBlue(ix, iy));
2315 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2316 hsv.value = hsv.value * factor_dusk;
2317 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2318 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2321 hsv = wxImage::RGBtoHSV(rgb);
2322 hsv.value = hsv.value * factor_night;
2323 nrgb = wxImage::HSVtoRGB(hsv);
2324 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2331 m_pos_image_user_yellow_day =
new wxImage;
2332 m_pos_image_user_yellow_dusk =
new wxImage;
2333 m_pos_image_user_yellow_night =
new wxImage;
2335 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2336 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2337 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2339 for (
int iy = 0; iy < gimg_height; iy++) {
2340 for (
int ix = 0; ix < gimg_width; ix++) {
2341 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2342 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2343 m_pos_image_user_grey_day->GetGreen(ix, iy),
2344 m_pos_image_user_grey_day->GetBlue(ix, iy));
2348 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2349 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2350 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2352 hsv = wxImage::RGBtoHSV(rgb);
2353 hsv.value = hsv.value * factor_dusk;
2354 nrgb = wxImage::HSVtoRGB(hsv);
2355 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2357 hsv = wxImage::RGBtoHSV(rgb);
2358 hsv.value = hsv.value * factor_night;
2359 nrgb = wxImage::HSVtoRGB(hsv);
2360 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2371void ChartCanvas::SetDisplaySizeMM(
double size) {
2372 m_display_size_mm = size;
2378 wxSize sd = g_Platform->getDisplaySize();
2379 double max_physical = wxMax(sd.x, sd.y);
2381 g_scaler = g_Platform->GetDisplayDIPMult(
this);
2383 m_pix_per_mm = (max_physical) / ((
double)m_display_size_mm);
2384 m_canvas_scale_factor = (max_physical) / (m_display_size_mm / 1000.);
2386 if (ps52plib) ps52plib->SetPPMM(m_pix_per_mm);
2390 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2392 m_display_size_mm, sd.x, sd.y);
2396 ::wxDisplaySize(&ssx, &ssy);
2397 msg.Printf(_T(
"wxDisplaySize(): %d %d"), ssx, ssy);
2400 m_focus_indicator_pix = wxRound(1 * GetPixPerMM());
2403void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2405 wxString msg(event.m_string.c_str(), wxConvUTF8);
2407 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2408 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2411 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2413 compress_msg_array.RemoveAt(event.thread);
2414 compress_msg_array.Insert( msg, event.thread);
2417 compress_msg_array.Add(msg);
2420 wxString combined_msg;
2421 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2422 combined_msg += compress_msg_array[i];
2423 combined_msg += _T(
"\n");
2427 pprog->Update(pprog_count, combined_msg, &skip );
2428 pprog->SetSize(pprog_size);
2433void ChartCanvas::InvalidateGL() {
2434 if (!m_glcc)
return;
2436 if (g_bopengl) m_glcc->Invalidate();
2438 if (m_Compass) m_Compass->UpdateStatus(
true);
2441int ChartCanvas::GetCanvasChartNativeScale() {
2443 if (!VPoint.b_quilt) {
2444 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2446 ret = (int)m_pQuilt->GetRefNativeScale();
2451ChartBase *ChartCanvas::GetChartAtCursor() {
2453 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2454 target_chart = m_singleChart;
2455 else if (VPoint.b_quilt)
2456 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2458 target_chart = NULL;
2459 return target_chart;
2462ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2466 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2468 target_chart = NULL;
2469 return target_chart;
2472int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2473 int new_dbIndex = -1;
2474 if (!VPoint.b_quilt) {
2475 if (m_pCurrentStack) {
2476 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2477 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2479 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2489 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2491 for (
unsigned int is = 0; is < im; is++) {
2493 m_pQuilt->GetExtendedStackIndexArray()[is]);
2496 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2506void ChartCanvas::EnablePaint(
bool b_enable) {
2507 m_b_paint_enable = b_enable;
2509 if (m_glcc) m_glcc->EnablePaint(b_enable);
2513bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2515void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2517std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2518 return m_pQuilt->GetQuiltIndexArray();
2522void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2523 VPoint.b_quilt = b_quilt;
2524 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2527bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2529int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2530 return m_pQuilt->GetRefChartdbIndex();
2533void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2534 m_pQuilt->InvalidateAllQuiltPatchs();
2537ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2538 return m_pQuilt->GetLargestScaleChart();
2541ChartBase *ChartCanvas::GetFirstQuiltChart() {
2542 return m_pQuilt->GetFirstChart();
2545ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2547int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2549void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2550 m_pQuilt->SetHiliteIndex(dbIndex);
2553std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2555 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2558int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2559 return m_pQuilt->GetRefChartdbIndex();
2562std::vector<int> ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2563 return m_pQuilt->GetExtendedStackIndexArray();
2566std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2567 return m_pQuilt->GetEclipsedStackIndexArray();
2570void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2572double ChartCanvas::GetQuiltMaxErrorFactor() {
2573 return m_pQuilt->GetMaxErrorFactor();
2576bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2577 return m_pQuilt->IsChartQuiltableRef(db_index);
2581 double chartMaxScale =
2582 chart->GetNormalScaleMax(GetCanvasScaleFactor(), GetCanvasWidth());
2583 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.chart_scale);
2586void ChartCanvas::StartMeasureRoute() {
2587 if (!m_routeState) {
2588 if (m_bMeasure_Active) {
2590 NavObjectChanges::getInstance());
2591 m_pMeasureRoute = NULL;
2594 m_bMeasure_Active =
true;
2595 m_nMeasureState = 1;
2596 m_bDrawingRoute =
false;
2598 SetCursor(*pCursorPencil);
2603void ChartCanvas::CancelMeasureRoute() {
2604 m_bMeasure_Active =
false;
2605 m_nMeasureState = 0;
2606 m_bDrawingRoute =
false;
2608 g_pRouteMan->
DeleteRoute(m_pMeasureRoute, NavObjectChanges::getInstance());
2609 m_pMeasureRoute = NULL;
2611 SetCursor(*pCursorArrow);
2614ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2616void ChartCanvas::SetVP(
ViewPort &vp) { VPoint = vp; }
2624void ChartCanvas::TriggerDeferredFocus() {
2627 m_deferredFocusTimer.Start(20,
true);
2629#if defined(__WXGTK__) || defined(__WXOSX__)
2640void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2645void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2647 if (g_pi_manager->SendKeyEventToPlugins(event))
2651 int key_char =
event.GetKeyCode();
2653 if (g_benable_rotate) {
2674void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2676 if (g_pi_manager->SendKeyEventToPlugins(event))
2680 bool b_handled =
false;
2682 m_modkeys =
event.GetModifiers();
2684 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2686#ifdef OCPN_ALT_MENUBAR
2692 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2694 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2695 if (!g_bTempShowMenuBar) {
2696 g_bTempShowMenuBar =
true;
2697 parent_frame->ApplyGlobalSettings(
false);
2699 m_bMayToggleMenuBar =
false;
2705 if (event.GetKeyCode() != WXK_ALT) {
2706 m_bMayToggleMenuBar =
false;
2713 switch (event.GetKeyCode()) {
2720 event.GetPosition(&x, &y);
2721 m_FinishRouteOnKillFocus =
false;
2722 CallPopupMenu(x, y);
2723 m_FinishRouteOnKillFocus =
true;
2727 m_modkeys |= wxMOD_ALT;
2731 m_modkeys |= wxMOD_CONTROL;
2735 if (m_modkeys == wxMOD_CONTROL)
2736 parent_frame->DoStackDown(
this);
2737 else if (g_bsmoothpanzoom) {
2738 StartTimedMovement();
2741 PanCanvas(-panspeed, 0);
2747 if (g_bsmoothpanzoom) {
2748 StartTimedMovement();
2751 PanCanvas(0, -panspeed);
2756 if (m_modkeys == wxMOD_CONTROL)
2757 parent_frame->DoStackUp(
this);
2758 else if (g_bsmoothpanzoom) {
2759 StartTimedMovement();
2762 PanCanvas(panspeed, 0);
2768 if (g_bsmoothpanzoom) {
2769 StartTimedMovement();
2772 PanCanvas(0, panspeed);
2781 SetShowENCText(!GetShowENCText());
2787 if (!m_bMeasure_Active) {
2788 if (event.ShiftDown())
2789 m_bMeasure_DistCircle =
true;
2791 m_bMeasure_DistCircle =
false;
2793 StartMeasureRoute();
2795 CancelMeasureRoute();
2797 SetCursor(*pCursorArrow);
2807 parent_frame->ToggleColorScheme();
2809 TriggerDeferredFocus();
2813 int mod = m_modkeys & wxMOD_SHIFT;
2814 if (mod != m_brightmod) {
2816 m_bbrightdir = !m_bbrightdir;
2819 if (!m_bbrightdir) {
2820 g_nbrightness -= 10;
2821 if (g_nbrightness <= MIN_BRIGHT) {
2822 g_nbrightness = MIN_BRIGHT;
2823 m_bbrightdir =
true;
2826 g_nbrightness += 10;
2827 if (g_nbrightness >= MAX_BRIGHT) {
2828 g_nbrightness = MAX_BRIGHT;
2829 m_bbrightdir =
false;
2833 SetScreenBrightness(g_nbrightness);
2834 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2843 parent_frame->DoStackDown(
this);
2847 parent_frame->DoStackUp(
this);
2852 ToggleCanvasQuiltMode();
2857 parent_frame->ToggleFullScreen();
2862 if (m_modkeys == wxMOD_ALT)
2863 m_nMeasureState = *(
volatile int *)(0);
2865 ToggleChartOutlines();
2870 parent_frame->ActivateMOB();
2874 case WXK_NUMPAD_ADD:
2876 ZoomCanvas(g_plus_minus_zoom_factor,
false);
2879 case WXK_NUMPAD_SUBTRACT:
2880 case WXK_PAGEDOWN: {
2881 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2886 if (m_bMeasure_Active) {
2887 if (m_nMeasureState > 2) {
2888 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2889 m_pMeasureRoute->m_lastMousePointIndex =
2890 m_pMeasureRoute->GetnPoints();
2892 gFrame->RefreshAllCanvas();
2894 CancelMeasureRoute();
2895 StartMeasureRoute();
2903 if (event.GetKeyCode() < 128)
2905 int key_char =
event.GetKeyCode();
2909 if (!g_b_assume_azerty) {
2913 ZoomCanvas(g_plus_minus_zoom_factor,
false);
2918 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2923 if (g_benable_rotate) {
2947 ZoomCanvas(g_plus_minus_zoom_factor,
false);
2952 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2957 if (event.ControlDown()) key_char -= 64;
2959 if (key_char >=
'0' && key_char <=
'9')
2960 SetGroupIndex(key_char -
'0');
2965 SetShowENCAnchor(!GetShowENCAnchor());
2971 parent_frame->ToggleColorScheme();
2976 event.GetPosition(&x, &y);
2977 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2978 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2980 if (!pPopupDetailSlider) {
2981 if (VPoint.b_quilt) {
2983 if (m_pQuilt->GetChartAtPix(
2988 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2990 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2995 if (m_singleChart) {
2996 ChartType = m_singleChart->GetChartType();
2997 ChartFam = m_singleChart->GetChartFamily();
3001 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3002 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3004 this, -1, ChartType, ChartFam,
3005 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3006 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
3007 if (pPopupDetailSlider) pPopupDetailSlider->Show();
3011 if (pPopupDetailSlider) pPopupDetailSlider->Close();
3012 pPopupDetailSlider = NULL;
3018 SetShowENCLights(!GetShowENCLights());
3024 if (event.ShiftDown())
3025 m_bMeasure_DistCircle =
true;
3027 m_bMeasure_DistCircle =
false;
3029 StartMeasureRoute();
3033 if (g_bInlandEcdis && ps52plib) {
3034 SetENCDisplayCategory((_DisCat)STANDARD);
3039 ToggleChartOutlines();
3043 ToggleCanvasQuiltMode();
3047 parent_frame->ToggleTestPause();
3051 parent_frame->ToggleRocks();
3055 SetShowENCDepth(!m_encShowDepth);
3060 SetShowENCText(!GetShowENCText());
3065 SetShowENCDataQual(!GetShowENCDataQual());
3070 m_bShowNavobjects = !m_bShowNavobjects;
3085 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3090 if (event.ControlDown()) gFrame->DropMarker(
false);
3096 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3097 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3098 if ((indexActive + 1) <= r->GetnPoints()) {
3109 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3115 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3121 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3128 parent_frame->DoSettings();
3132 parent_frame->Close();
3140 if (NULL == pGoToPositionDialog)
3143 pGoToPositionDialog->SetCanvas(
this);
3144 pGoToPositionDialog->Show();
3148 if (undo->AnythingToRedo()) {
3149 undo->RedoNextAction();
3156 if (event.ShiftDown()) {
3157 if (undo->AnythingToRedo()) {
3158 undo->RedoNextAction();
3163 if (undo->AnythingToUndo()) {
3164 undo->UndoLastAction();
3173 if (m_bMeasure_Active) {
3174 CancelMeasureRoute();
3176 SetCursor(*pCursorArrow);
3179 gFrame->RefreshAllCanvas();
3193 switch (gamma_state) {
3213 SetScreenBrightness(g_nbrightness);
3218 if (event.ControlDown()) {
3219 m_bShowCompassWin = !m_bShowCompassWin;
3220 SetShowGPSCompassWindow(m_bShowCompassWin);
3234 if (!b_handled)
event.Skip();
3238void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3240 if (g_pi_manager->SendKeyEventToPlugins(event))
3244 switch (event.GetKeyCode()) {
3246 parent_frame->SwitchKBFocus(
this);
3252 if (!m_pany) m_panspeed = 0;
3258 if (!m_panx) m_panspeed = 0;
3261 case WXK_NUMPAD_ADD:
3262 case WXK_NUMPAD_SUBTRACT:
3265 if (m_mustmove) DoMovement(m_mustmove);
3271 m_modkeys &= ~wxMOD_ALT;
3272#ifdef OCPN_ALT_MENUBAR
3277 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3278 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3279 parent_frame->ApplyGlobalSettings(
false);
3281 m_bMayToggleMenuBar =
true;
3287 m_modkeys &= ~wxMOD_CONTROL;
3291 if (event.GetKeyCode() < 128)
3293 int key_char =
event.GetKeyCode();
3297 if (!g_b_assume_azerty) {
3305 DoMovement(m_mustmove);
3311 DoMovement(m_mustmove);
3312 m_rotation_speed = 0;
3320 DoMovement(m_mustmove);
3330void ChartCanvas::ToggleChartOutlines(
void) {
3331 m_bShowOutlines = !m_bShowOutlines;
3337 if (g_bopengl) InvalidateGL();
3341void ChartCanvas::ToggleLookahead() {
3342 m_bLookAhead = !m_bLookAhead;
3347void ChartCanvas::SetUpMode(
int mode) {
3350 if (mode != NORTH_UP_MODE) {
3353 if (!std::isnan(gCog)) stuff = gCog;
3355 if (g_COGAvgSec > 0) {
3356 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3359 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3361 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3362 SetVPRotation(GetVPSkew());
3367 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3368 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3370 UpdateGPSCompassStatusBox(
true);
3371 gFrame->DoChartUpdate();
3374bool ChartCanvas::DoCanvasCOGSet(
void) {
3375 if (GetUpMode() == NORTH_UP_MODE)
return false;
3377 if (std::isnan(g_COGAvg))
return true;
3379 double old_VPRotate = m_VPRotate;
3381 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3382 m_VPRotate = -gHdt * PI / 180.;
3383 }
else if (GetUpMode() == COURSE_UP_MODE)
3384 m_VPRotate = -g_COGAvg * PI / 180.;
3386 SetVPRotation(m_VPRotate);
3387 bool bnew_chart = DoCanvasUpdate();
3389 if ((bnew_chart) || (old_VPRotate != m_VPRotate)) ReloadVP();
3394void ChartCanvas::StopMovement() {
3395 m_panx = m_pany = 0;
3398 m_rotation_speed = 0;
3401#if !defined(__WXGTK__) && !defined(__WXQT__)
3412bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3414 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3416 if (!pMovementTimer->IsRunning()) {
3418 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3421 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3426 m_last_movement_time = wxDateTime::UNow();
3437void ChartCanvas::DoTimedMovement() {
3438 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3442 wxDateTime now = wxDateTime::UNow();
3444 if (m_last_movement_time.IsValid())
3445 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3447 m_last_movement_time = now;
3455void ChartCanvas::DoMovement(
long dt) {
3457 if (dt == 0) dt = 1;
3460 if (m_mustmove < 0) m_mustmove = 0;
3462 if (m_pan_drag.x || m_pan_drag.y) {
3463 PanCanvas(m_pan_drag.x, m_pan_drag.y);
3464 m_pan_drag.x = m_pan_drag.y = 0;
3467 if (m_panx || m_pany) {
3468 const double slowpan = .1, maxpan = 2;
3469 if (m_modkeys == wxMOD_ALT)
3470 m_panspeed = slowpan;
3472 m_panspeed += (double)dt / 500;
3473 m_panspeed = wxMin(maxpan, m_panspeed);
3475 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3478 if (m_zoom_factor != 1) {
3479 double alpha = 400, beta = 1.5;
3480 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3482 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3484 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3489 if (zoom_factor > 1) {
3490 if (VPoint.chart_scale / zoom_factor <= m_zoom_target)
3491 zoom_factor = VPoint.chart_scale / m_zoom_target;
3494 else if (zoom_factor < 1) {
3495 if (VPoint.chart_scale / zoom_factor >= m_zoom_target)
3496 zoom_factor = VPoint.chart_scale / m_zoom_target;
3500 if (fabs(zoom_factor - 1) > 1e-4)
3501 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3503 if (m_wheelzoom_stop_oneshot > 0) {
3504 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3505 m_wheelzoom_stop_oneshot = 0;
3510 if (zoom_factor > 1) {
3511 if (VPoint.chart_scale <= m_zoom_target) {
3512 m_wheelzoom_stop_oneshot = 0;
3515 }
else if (zoom_factor < 1) {
3516 if (VPoint.chart_scale >= m_zoom_target) {
3517 m_wheelzoom_stop_oneshot = 0;
3524 if (m_rotation_speed) {
3525 double speed = m_rotation_speed;
3526 if (m_modkeys == wxMOD_ALT) speed /= 10;
3527 DoRotateCanvas(VPoint.rotation + speed * PI / 180 * dt / 1000.0);
3531void ChartCanvas::SetColorScheme(ColorScheme cs) {
3532 SetAlertString(_T(
""));
3536 case GLOBAL_COLOR_SCHEME_DAY:
3537 m_pos_image_red = &m_os_image_red_day;
3538 m_pos_image_grey = &m_os_image_grey_day;
3539 m_pos_image_yellow = &m_os_image_yellow_day;
3540 m_pos_image_user = m_pos_image_user_day;
3541 m_pos_image_user_grey = m_pos_image_user_grey_day;
3542 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3543 m_cTideBitmap = m_bmTideDay;
3544 m_cCurrentBitmap = m_bmCurrentDay;
3547 case GLOBAL_COLOR_SCHEME_DUSK:
3548 m_pos_image_red = &m_os_image_red_dusk;
3549 m_pos_image_grey = &m_os_image_grey_dusk;
3550 m_pos_image_yellow = &m_os_image_yellow_dusk;
3551 m_pos_image_user = m_pos_image_user_dusk;
3552 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3553 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3554 m_cTideBitmap = m_bmTideDusk;
3555 m_cCurrentBitmap = m_bmCurrentDusk;
3557 case GLOBAL_COLOR_SCHEME_NIGHT:
3558 m_pos_image_red = &m_os_image_red_night;
3559 m_pos_image_grey = &m_os_image_grey_night;
3560 m_pos_image_yellow = &m_os_image_yellow_night;
3561 m_pos_image_user = m_pos_image_user_night;
3562 m_pos_image_user_grey = m_pos_image_user_grey_night;
3563 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3564 m_cTideBitmap = m_bmTideNight;
3565 m_cCurrentBitmap = m_bmCurrentNight;
3568 m_pos_image_red = &m_os_image_red_day;
3569 m_pos_image_grey = &m_os_image_grey_day;
3570 m_pos_image_yellow = &m_os_image_yellow_day;
3571 m_pos_image_user = m_pos_image_user_day;
3572 m_pos_image_user_grey = m_pos_image_user_grey_day;
3573 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3574 m_cTideBitmap = m_bmTideDay;
3575 m_cCurrentBitmap = m_bmCurrentDay;
3579 CreateDepthUnitEmbossMaps(cs);
3580 CreateOZEmbossMapData(cs);
3583 m_fog_color = wxColor(
3587 case GLOBAL_COLOR_SCHEME_DUSK:
3590 case GLOBAL_COLOR_SCHEME_NIGHT:
3596 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3597 m_fog_color.Blue() * dim);
3601 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3602 SetBackgroundColour( wxColour(0,0,0) );
3604 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3607 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3609 SetBackgroundColour( wxNullColour );
3614 UpdateToolbarColorScheme(cs);
3616 m_Piano->SetColorScheme(cs);
3618 m_Compass->SetColorScheme(cs);
3620 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3622 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3624 if (g_bopengl && m_glcc) {
3625 m_glcc->SetColorScheme(cs);
3626 g_glTextureManager->ClearAllRasterTextures();
3631 m_brepaint_piano =
true;
3638wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3639 wxImage img = Bitmap.ConvertToImage();
3640 int sx = img.GetWidth();
3641 int sy = img.GetHeight();
3643 wxImage new_img(img);
3645 for (
int i = 0; i < sx; i++) {
3646 for (
int j = 0; j < sy; j++) {
3647 if (!img.IsTransparent(i, j)) {
3648 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3649 (
unsigned char)(img.GetGreen(i, j) * factor),
3650 (
unsigned char)(img.GetBlue(i, j) * factor));
3655 wxBitmap ret = wxBitmap(new_img);
3660void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3662 wxFont *pfont = FontMgr::Get().FindOrCreateFont(
3663 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3665 if (!m_pBrightPopup) {
3668 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3672 m_pBrightPopup->SetSize(x, y);
3673 m_pBrightPopup->Move(120, 120);
3676 int bmpsx = m_pBrightPopup->GetSize().x;
3677 int bmpsy = m_pBrightPopup->GetSize().y;
3679 wxBitmap bmp(bmpsx, bmpsx);
3680 wxMemoryDC mdc(bmp);
3682 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3683 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3684 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3685 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3688 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3690 mdc.SetFont(*pfont);
3693 if (brightness == max)
3695 else if (brightness == min)
3698 val.Printf(_T(
"%3d"), brightness);
3700 mdc.DrawText(val, 0, 0);
3702 mdc.SelectObject(wxNullBitmap);
3704 m_pBrightPopup->SetBitmap(bmp);
3705 m_pBrightPopup->Show();
3706 m_pBrightPopup->Refresh();
3709void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3710 m_b_rot_hidef =
true;
3714void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3715 if (!g_bRollover)
return;
3717 bool b_need_refresh =
false;
3719 wxSize win_size = GetSize() * m_displayScale;
3720 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3723 bool showAISRollover =
false;
3724 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3725 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
3726 SelectItem *pFind = pSelectAIS->FindSelection(
3727 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_AISTARGET);
3729 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3730 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3733 showAISRollover =
true;
3735 if (NULL == m_pAISRolloverWin) {
3737 m_pAISRolloverWin->IsActive(
false);
3738 b_need_refresh =
true;
3739 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3740 m_AISRollover_MMSI != FoundAIS_MMSI) {
3746 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3747 m_pAISRolloverWin->IsActive(
false);
3748 m_AISRollover_MMSI = 0;
3753 m_AISRollover_MMSI = FoundAIS_MMSI;
3755 if (!m_pAISRolloverWin->IsActive()) {
3756 wxString s = ptarget->GetRolloverString();
3757 m_pAISRolloverWin->SetString(s);
3759 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3760 AIS_ROLLOVER, win_size);
3761 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3762 m_pAISRolloverWin->IsActive(
true);
3763 b_need_refresh =
true;
3767 m_AISRollover_MMSI = 0;
3768 showAISRollover =
false;
3773 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3774 m_pAISRolloverWin->IsActive(
false);
3775 m_AISRollover_MMSI = 0;
3776 b_need_refresh =
true;
3781 bool showRouteRollover =
false;
3783 if (NULL == m_pRolloverRouteSeg) {
3787 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
3788 SelectableItemList SelList = pSelect->FindSelectionList(
3789 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTESEGMENT);
3790 wxSelectableItemListNode *node = SelList.GetFirst();
3796 if (pr && pr->IsVisible()) {
3797 m_pRolloverRouteSeg = pFindSel;
3798 showRouteRollover =
true;
3800 if (NULL == m_pRouteRolloverWin) {
3802 m_pRouteRolloverWin->IsActive(
false);
3805 if (!m_pRouteRolloverWin->IsActive()) {
3813 DistanceBearingMercator(
3814 segShow_point_b->m_lat, segShow_point_b->m_lon,
3815 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3817 if (!pr->m_bIsInLayer)
3818 s.Append(_(
"Route") + _T(
": "));
3820 s.Append(_(
"Layer Route: "));
3822 if (pr->m_RouteNameString.IsEmpty())
3823 s.Append(_(
"(unnamed)"));
3825 s.Append(pr->m_RouteNameString);
3827 s << _T(
"\n") << _(
"Total Length: ")
3828 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
3829 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3830 << segShow_point_b->GetName() << _T(
"\n");
3833 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
3837 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
3839 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
3840 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
3842 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
3846 s << FormatDistanceAdaptive(dist);
3851 double shiptoEndLeg = 0.;
3852 bool validActive =
false;
3853 if (pr->IsActive() &&
3854 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
3857 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
3858 wxRoutePointListNode *node =
3859 (pr->pRoutePointList)->GetFirst()->GetNext();
3861 float dist_to_endleg = 0;
3865 prp = node->GetData();
3867 shiptoEndLeg += prp->m_seg_len;
3868 else if (prp->m_bIsActive)
3870 dist_to_endleg += prp->m_seg_len;
3871 if (prp->IsSame(segShow_point_a))
break;
3872 node = node->GetNext();
3874 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
3879 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
3880 << segShow_point_b->GetName() << _T(
"\n");
3883 ->GetCurrentRngToActivePoint();
3888 s << FormatDistanceAdaptive(shiptoEndLeg);
3892 if (!std::isnan(gCog) && !std::isnan(gSog))
3894 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
3897 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
3898 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
3900 << wxString(ttg_sec > SECONDS_PER_DAY
3901 ? ttg_span.Format(_(
"%Dd %H:%M"))
3902 : ttg_span.Format(_(
"%H:%M")));
3903 wxDateTime dtnow, eta;
3904 eta = dtnow.SetToCurrent().Add(ttg_span);
3905 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
3906 << eta.Format(_T(
" %d %H:%M"));
3908 s << _T(
" ---- ----");
3910 m_pRouteRolloverWin->SetString(s);
3912 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3913 LEG_ROLLOVER, win_size);
3914 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
3915 m_pRouteRolloverWin->IsActive(
true);
3916 b_need_refresh =
true;
3917 showRouteRollover =
true;
3921 node = node->GetNext();
3925 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
3926 if (!pSelect->IsSelectableSegmentSelected(ctx, m_cursor_lat, m_cursor_lon,
3927 m_pRolloverRouteSeg))
3928 showRouteRollover =
false;
3929 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
3930 showRouteRollover =
false;
3932 showRouteRollover =
true;
3936 if (m_routeState) showRouteRollover =
false;
3939 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
3940 showRouteRollover =
false;
3942 if (m_pRouteRolloverWin &&
3943 !showRouteRollover) {
3944 m_pRouteRolloverWin->IsActive(
false);
3945 m_pRolloverRouteSeg = NULL;
3946 m_pRouteRolloverWin->Destroy();
3947 m_pRouteRolloverWin = NULL;
3948 b_need_refresh =
true;
3949 }
else if (m_pRouteRolloverWin && showRouteRollover) {
3950 m_pRouteRolloverWin->IsActive(
true);
3951 b_need_refresh =
true;
3956 bool showTrackRollover =
false;
3958 if (NULL == m_pRolloverTrackSeg) {
3962 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
3963 SelectableItemList SelList = pSelect->FindSelectionList(
3964 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_TRACKSEGMENT);
3965 wxSelectableItemListNode *node = SelList.GetFirst();
3971 if (pt && pt->IsVisible()) {
3972 m_pRolloverTrackSeg = pFindSel;
3973 showTrackRollover =
true;
3975 if (NULL == m_pTrackRolloverWin) {
3977 m_pTrackRolloverWin->IsActive(
false);
3980 if (!m_pTrackRolloverWin->IsActive()) {
3988 DistanceBearingMercator(
3989 segShow_point_b->m_lat, segShow_point_b->m_lon,
3990 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3992 if (!pt->m_bIsInLayer)
3993 s.Append(_(
"Track") + _T(
": "));
3995 s.Append(_(
"Layer Track: "));
3997 if (pt->GetName().IsEmpty())
3998 s.Append(_(
"(unnamed)"));
4000 s.Append(pt->GetName());
4001 double tlenght = pt->Length();
4002 s << _T(
"\n") << _(
"Total Track: ")
4003 << FormatDistanceAdaptive(tlenght);
4004 if (pt->GetLastPoint()->GetTimeString() &&
4005 pt->GetPoint(0)->GetTimeString()) {
4006 wxTimeSpan ttime = pt->GetLastPoint()->GetCreateTime() -
4007 pt->GetPoint(0)->GetCreateTime();
4008 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4009 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4010 << getUsrSpeedUnit();
4011 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4012 : ttime.Format(_T(
" %H:%M")));
4014 if (g_bShowTrackPointTime && segShow_point_b->GetTimeString())
4015 s << _T(
"\n") << _(
"Segment Created: ")
4016 << segShow_point_b->GetTimeString();
4020 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4025 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4027 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4028 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4030 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4034 s << FormatDistanceAdaptive(dist);
4036 if (segShow_point_a->GetTimeString() &&
4037 segShow_point_b->GetTimeString()) {
4038 double segmentSpeed =
4039 toUsrSpeed(dist / ((segShow_point_b->GetCreateTime() -
4040 segShow_point_a->GetCreateTime())
4044 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4045 << getUsrSpeedUnit();
4048 m_pTrackRolloverWin->SetString(s);
4050 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4051 LEG_ROLLOVER, win_size);
4052 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4053 m_pTrackRolloverWin->IsActive(
true);
4054 b_need_refresh =
true;
4055 showTrackRollover =
true;
4059 node = node->GetNext();
4063 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
4064 if (!pSelect->IsSelectableSegmentSelected(ctx, m_cursor_lat, m_cursor_lon,
4065 m_pRolloverTrackSeg))
4066 showTrackRollover =
false;
4067 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4068 showTrackRollover =
false;
4070 showTrackRollover =
true;
4074 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4075 showTrackRollover =
false;
4078 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4079 showTrackRollover =
false;
4085 if (m_pTrackRolloverWin &&
4086 !showTrackRollover) {
4087 m_pTrackRolloverWin->IsActive(
false);
4088 m_pRolloverTrackSeg = NULL;
4089 m_pTrackRolloverWin->Destroy();
4090 m_pTrackRolloverWin = NULL;
4091 b_need_refresh =
true;
4092 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4093 m_pTrackRolloverWin->IsActive(
true);
4094 b_need_refresh =
true;
4097 if (b_need_refresh) Refresh();
4100void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4101 if (s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4102 extendedSectorLegs)) {
4103 if (!m_bsectors_shown) {
4105 m_bsectors_shown =
true;
4108 if (m_bsectors_shown) {
4110 m_bsectors_shown =
false;
4118#if defined(__WXGTK__) || defined(__WXQT__)
4123 double cursor_lat, cursor_lon;
4124 GetCanvasPixPoint(mouse_x, mouse_y, cursor_lat, cursor_lon);
4126 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4127 while (cursor_lon < -180.) cursor_lon += 360.;
4129 while (cursor_lon > 180.) cursor_lon -= 360.;
4131 SetCursorStatus(cursor_lat, cursor_lon);
4137void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4138 if (!parent_frame->m_pStatusBar)
return;
4142 s1 += toSDMM(1, cursor_lat);
4144 s1 += toSDMM(2, cursor_lon);
4146 if (STAT_FIELD_CURSOR_LL >= 0)
4147 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4149 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4153 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4155 s.Printf(
"%03d%c(M) ", (
int)gFrame->GetMag(brg), 0x00B0);
4157 s.Printf(
"%03d%c ", (
int)brg, 0x00B0);
4159 s << FormatDistanceAdaptive(dist);
4171 if (g_bShowLiveETA) {
4174 float boatSpeedDefault = g_defaultBoatSpeed;
4179 if (!std::isnan(gSog)) {
4181 if (boatSpeed < 0.5) {
4184 realTimeETA = dist / boatSpeed * 60;
4193 s << minutesToHoursDays(realTimeETA);
4198 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4199 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4201 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4206 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4214wxString minutesToHoursDays(
float timeInMinutes) {
4217 if (timeInMinutes == 0) {
4222 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4223 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4228 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4231 hours = (int)timeInMinutes / 60;
4232 min = (int)timeInMinutes % 60;
4235 s << wxString::Format(_T(
"%d"), hours);
4238 s << wxString::Format(_T(
"%d"), hours);
4240 s << wxString::Format(_T(
"%d"), min);
4247 else if (timeInMinutes > 24 * 60) {
4250 days = (int)(timeInMinutes / 60) / 24;
4251 hours = (int)(timeInMinutes / 60) % 24;
4254 s << wxString::Format(_T(
"%d"), days);
4257 s << wxString::Format(_T(
"%d"), days);
4259 s << wxString::Format(_T(
"%d"), hours);
4271void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4273 GetCanvasPixPoint(mouse_x, mouse_y, clat, clon);
4278void ChartCanvas::GetDoubleCanvasPointPix(
double rlat,
double rlon,
4279 wxPoint2DDouble *r) {
4280 return GetDoubleCanvasPointPixVP(GetVP(), rlat, rlon, r);
4283void ChartCanvas::GetDoubleCanvasPointPixVP(
ViewPort &vp,
double rlat,
4284 double rlon, wxPoint2DDouble *r) {
4295 if (!g_bopengl && m_singleChart &&
4296 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4297 (((fabs(vp.rotation) < .0001) && (fabs(vp.skew) < .0001)) ||
4298 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4299 (m_singleChart->GetChartProjectionType() !=
4300 PROJECTION_TRANSVERSE_MERCATOR) &&
4301 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4302 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4303 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4317 Cur_BSB_Ch->SetVPRasterParms(vp);
4318 double rpixxd, rpixyd;
4319 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4328 *r = vp.GetDoublePixFromLL(rlat, rlon);
4333bool ChartCanvas::GetCanvasPointPix(
double rlat,
double rlon, wxPoint *r) {
4334 return GetCanvasPointPixVP(GetVP(), rlat, rlon, r);
4337bool ChartCanvas::GetCanvasPointPixVP(
ViewPort &vp,
double rlat,
double rlon,
4340 GetDoubleCanvasPointPixVP(vp, rlat, rlon, &p);
4345 if (std::isnan(p.m_x)) {
4346 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4350 if( (abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6) )
4351 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4353 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4358void ChartCanvas::GetCanvasPixPoint(
double x,
double y,
double &lat,
4372 if (!g_bopengl && m_singleChart &&
4373 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4374 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4375 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4376 (m_singleChart->GetChartProjectionType() !=
4377 PROJECTION_TRANSVERSE_MERCATOR) &&
4378 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4379 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4380 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4391 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4394 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4399 else if (slon > 180.)
4410 GetVP().GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4414void ChartCanvas::ZoomCanvasSimple(
double factor) {
4415 DoZoomCanvas(factor,
false);
4416 extendedSectorLegs.clear();
4419void ChartCanvas::ZoomCanvas(
double factor,
bool can_zoom_to_cursor,
4421 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4423 if (g_bsmoothpanzoom) {
4424 if (StartTimedMovement(stoptimer)) {
4426 m_zoom_factor = factor;
4429 m_zoom_target = VPoint.chart_scale / factor;
4431 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4433 DoZoomCanvas(factor, can_zoom_to_cursor);
4436 extendedSectorLegs.clear();
4439void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4441 if (!ChartData)
return;
4442 if (!m_pCurrentStack)
return;
4444 if (g_bShowCompassWin) {
4445 m_bShowCompassWin =
true;
4446 SetShowGPSCompassWindow(
true);
4453 if (m_bzooming)
return;
4456 double old_ppm = GetVP().view_scale_ppm;
4459 double zlat = m_cursor_lat;
4460 double zlon = m_cursor_lon;
4462 double proposed_scale_onscreen =
4463 GetVP().chart_scale /
4465 bool b_do_zoom =
false;
4474 if (!VPoint.b_quilt) {
4477 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4478 if (new_db_index >= 0)
4479 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4481 if (m_pCurrentStack)
4482 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4492 double min_allowed_scale =
4495 if (proposed_scale_onscreen < min_allowed_scale) {
4496 if (min_allowed_scale == GetCanvasScaleFactor() / (GetVPScale())) {
4500 proposed_scale_onscreen = min_allowed_scale;
4504 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4507 }
else if (factor < 1) {
4512 bool b_smallest =
false;
4514 if (!VPoint.b_quilt) {
4519 LLBBox viewbox = VPoint.GetBBox();
4521 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4522 double max_allowed_scale;
4524 max_allowed_scale = GetCanvasScaleFactor() / m_absolute_min_scale_ppm;
4536 if (proposed_scale_onscreen > max_allowed_scale) {
4538 proposed_scale_onscreen = max_allowed_scale;
4543 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4544 if (new_db_index >= 0)
4545 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4547 if (m_pCurrentStack)
4548 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4551 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4553 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4554 proposed_scale_onscreen =
4555 wxMin(proposed_scale_onscreen,
4556 GetCanvasScaleFactor() / m_absolute_min_scale_ppm);
4560 if ((GetCanvasScaleFactor() / proposed_scale_onscreen) <
4561 m_absolute_min_scale_ppm)
4566 GetVPScale() * (GetVP().chart_scale / proposed_scale_onscreen);
4569 if (can_zoom_to_cursor && g_bEnableZoomToCursor) {
4572 SetVPScale(new_scale,
false);
4575 GetCanvasPointPix(zlat, zlon, &r);
4576 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4578 SetVPScale(new_scale);
4580 if (m_bFollow) DoCanvasUpdate();
4587void ChartCanvas::RotateCanvas(
double dir) {
4590 if (g_bsmoothpanzoom) {
4591 if (StartTimedMovement()) {
4593 m_rotation_speed = dir * 60;
4596 double speed = dir * 10;
4597 if (m_modkeys == wxMOD_ALT) speed /= 20;
4598 DoRotateCanvas(VPoint.rotation + PI / 180 * speed);
4602void ChartCanvas::DoRotateCanvas(
double rotation) {
4603 while (rotation < 0) rotation += 2 * PI;
4604 while (rotation > 2 * PI) rotation -= 2 * PI;
4606 if (rotation == VPoint.rotation || std::isnan(rotation))
return;
4608 SetVPRotation(rotation);
4609 parent_frame->UpdateRotationState(VPoint.rotation);
4612void ChartCanvas::DoTiltCanvas(
double tilt) {
4613 while (tilt < 0) tilt = 0;
4614 while (tilt > .95) tilt = .95;
4616 if (tilt == VPoint.tilt || std::isnan(tilt))
return;
4622void ChartCanvas::TogglebFollow(
void) {
4629void ChartCanvas::ClearbFollow(
void) {
4632 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_FOLLOW,
false);
4633 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4635 UpdateFollowButtonState();
4639 parent_frame->SetChartUpdatePeriod();
4642void ChartCanvas::SetbFollow(
void) {
4643 JumpToPosition(gLat, gLon, GetVPScale());
4646 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_FOLLOW,
true);
4647 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4649 UpdateFollowButtonState();
4653 if ((fabs(m_OSoffsetx) > VPoint.pix_width / 2) ||
4654 (fabs(m_OSoffsety) > VPoint.pix_height / 2)) {
4661 parent_frame->SetChartUpdatePeriod();
4664void ChartCanvas::UpdateFollowButtonState(
void) {
4667 m_muiBar->SetFollowButtonState(0);
4670 m_muiBar->SetFollowButtonState(2);
4672 m_muiBar->SetFollowButtonState(1);
4676#ifdef __OCPN__ANDROID__
4678 androidSetFollowTool(0);
4681 androidSetFollowTool(2);
4683 androidSetFollowTool(1);
4688void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4689 if (lon > 180.0) lon -= 360.0;
4695 if (!GetQuiltMode()) {
4697 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4698 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4700 if (scale_ppm != GetVPScale()) {
4702 VPoint.chart_scale = m_canvas_scale_factor / (scale_ppm);
4703 AdjustQuiltRefChart();
4705 SetViewPoint(lat, lon, scale_ppm, 0, GetVPRotation());
4710 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_FOLLOW,
false);
4712 UpdateFollowButtonState();
4720bool ChartCanvas::PanCanvas(
double dx,
double dy) {
4721 if (!ChartData)
return false;
4723 extendedSectorLegs.clear();
4727 wxPoint2DDouble p(VPoint.pix_width / 2.0, VPoint.pix_height / 2.0);
4731 GetCanvasPixPoint(p.m_x + trunc(dx), p.m_y + trunc(dy), dlat, dlon);
4733 if (iters++ > 5)
return false;
4734 if (!std::isnan(dlat))
break;
4737 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
4743 else if (dlat < -90)
4746 if (dlon > 360.) dlon -= 360.;
4747 if (dlon < -360.) dlon += 360.;
4762 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4764 SetViewPoint(dlat, dlon, VPoint.view_scale_ppm, VPoint.skew, VPoint.rotation);
4766 if (VPoint.b_quilt) {
4767 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4768 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
4770 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
4772 double tweak_scale_ppm =
4773 pc->GetNearestPreferredScalePPM(VPoint.view_scale_ppm);
4774 SetVPScale(tweak_scale_ppm);
4781 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
4783 double offset_angle = atan2(offy, offx);
4784 double offset_distance = sqrt((offy * offy) + (offx * offx));
4785 double chart_angle = GetVPRotation();
4786 double target_angle = chart_angle - offset_angle;
4787 double d_east_mod = offset_distance * cos(target_angle);
4788 double d_north_mod = offset_distance * sin(target_angle);
4790 m_OSoffsetx = d_east_mod * VPoint.view_scale_ppm;
4791 m_OSoffsety = -d_north_mod * VPoint.view_scale_ppm;
4796 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.pix_width / 2) ||
4797 (fabs(m_OSoffsety) > VPoint.pix_height / 2))) {
4799 if (m_toolBar) m_toolBar->GetToolbar()->ToggleTool(ID_FOLLOW,
false);
4801 UpdateFollowButtonState();
4806 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
4811void ChartCanvas::ReloadVP(
bool b_adjust) {
4812 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
4814 LoadVP(VPoint, b_adjust);
4817void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
4819 if (g_bopengl && m_glcc) {
4820 m_glcc->Invalidate();
4821 if (m_glcc->GetSize() != GetSize()) {
4822 m_glcc->SetSize(GetSize());
4827 m_cache_vp.Invalidate();
4828 m_bm_cache_vp.Invalidate();
4831 VPoint.Invalidate();
4833 if (m_pQuilt) m_pQuilt->Invalidate();
4841 SetViewPoint(vp.clat, vp.clon, vp.view_scale_ppm, vp.skew, vp.rotation,
4842 vp.m_projection_type, b_adjust);
4846void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
4847 m_pQuilt->SetReferenceChart(dbIndex);
4848 VPoint.Invalidate();
4849 m_pQuilt->Invalidate();
4852double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
4854 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
4856 return vp.view_scale_ppm;
4861int ChartCanvas::AdjustQuiltRefChart() {
4864 wxASSERT(ChartData);
4866 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
4868 double min_ref_scale =
4869 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
4870 double max_ref_scale =
4871 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
4873 if (VPoint.chart_scale < min_ref_scale) {
4874 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.chart_scale);
4875 }
else if (VPoint.chart_scale > max_ref_scale) {
4876 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.chart_scale);
4878 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
4880 int ref_family = pc->GetChartFamily();
4883 unsigned int target_stack_index = 0;
4884 int target_stack_index_check =
4885 m_pQuilt->GetExtendedStackIndexArray()
4886 [m_pQuilt->GetRefChartdbIndex()];
4888 if (wxNOT_FOUND != target_stack_index_check)
4889 target_stack_index = target_stack_index_check;
4891 int extended_array_count =
4892 m_pQuilt->GetExtendedStackIndexArray().size();
4893 while ((!brender_ok) &&
4894 ((
int)target_stack_index < (extended_array_count - 1))) {
4895 target_stack_index++;
4897 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
4899 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
4900 IsChartQuiltableRef(test_db_index)) {
4903 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
4905 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
4912 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
4913 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
4914 IsChartQuiltableRef(new_db_index)) {
4915 m_pQuilt->SetReferenceChart(new_db_index);
4918 ret = m_pQuilt->GetRefChartdbIndex();
4920 ret = m_pQuilt->GetRefChartdbIndex();
4923 ret = m_pQuilt->GetRefChartdbIndex();
4932void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
4933 delete m_pCurrentStack;
4934 m_pCurrentStack = NULL;
4936 wxASSERT(ChartData);
4937 ChartData->BuildChartStack(m_pCurrentStack, VPoint.clat, VPoint.clon,
4946bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
4947 double latNE,
double lonNE) {
4949 double latc = (latSW + latNE) / 2.0;
4950 double lonc = (lonSW + lonNE) / 2.0;
4953 double ne_easting, ne_northing;
4954 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
4956 double sw_easting, sw_northing;
4957 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
4959 double scale_ppm = VPoint.pix_height / fabs(ne_northing - sw_northing);
4961 return SetViewPoint(latc, lonc, scale_ppm, VPoint.skew, VPoint.rotation);
4964bool ChartCanvas::SetVPScale(
double scale,
bool refresh) {
4965 return SetViewPoint(VPoint.clat, VPoint.clon,
scale, VPoint.skew,
4966 VPoint.rotation, VPoint.m_projection_type,
true, refresh);
4969bool ChartCanvas::SetVPProjection(
int projection) {
4975 double prev_true_scale_ppm = m_true_scale_ppm;
4976 return SetViewPoint(VPoint.clat, VPoint.clon, VPoint.view_scale_ppm,
4977 VPoint.skew, VPoint.rotation, projection) &&
4979 VPoint.view_scale_ppm * prev_true_scale_ppm / m_true_scale_ppm,
4980 m_absolute_min_scale_ppm));
4983bool ChartCanvas::SetViewPoint(
double lat,
double lon) {
4984 return SetViewPoint(lat, lon, VPoint.view_scale_ppm, VPoint.skew,
4988bool ChartCanvas::SetVPRotation(
double angle) {
4989 return SetViewPoint(VPoint.clat, VPoint.clon, VPoint.view_scale_ppm, VPoint.skew,
4993bool ChartCanvas::SetViewPoint(
double lat,
double lon,
double scale_ppm,
4994 double skew,
double rotation,
int projection,
4995 bool b_adjust,
bool b_refresh) {
5002 if (VPoint.IsValid()) {
5003 if ((fabs(VPoint.view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5004 (fabs(VPoint.skew - skew) < 1e-9) &&
5005 (fabs(VPoint.rotation - rotation) < 1e-9) &&
5006 (fabs(VPoint.clat - lat) < 1e-9) && (fabs(VPoint.clon - lon) < 1e-9) &&
5007 (VPoint.m_projection_type == projection ||
5008 projection == PROJECTION_UNKNOWN))
5012 if (VPoint.m_projection_type != projection)
5013 VPoint.InvalidateTransformCache();
5021 VPoint.rotation = rotation;
5022 VPoint.view_scale_ppm = scale_ppm;
5023 if (projection != PROJECTION_UNKNOWN)
5024 VPoint.SetProjectionType(projection);
5025 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5026 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5029 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5030 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5031 if (VPoint.clat > 89.5)
5033 else if (VPoint.clat < -89.5)
5034 VPoint.clat = -89.5;
5039 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5040 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5041 VPoint.view_scale_ppm = wxMax(VPoint.view_scale_ppm, 2e-4);
5048 if ((VPoint.pix_width <= 0) ||
5049 (VPoint.pix_height <= 0))
5052 bool bwasValid = VPoint.IsValid();
5056 if (last_vp.view_scale_ppm != scale_ppm) {
5057 m_cache_vp.Invalidate();
5062 VPoint.chart_scale = m_canvas_scale_factor / (scale_ppm);
5067 const wxPoint pt = wxGetMousePosition();
5068 int mouseX = pt.x - GetScreenPosition().x;
5069 int mouseY = pt.y - GetScreenPosition().y;
5070 if ((mouseX > 0) && (mouseX < VPoint.pix_width) && (mouseY > 0) &&
5071 (mouseY < VPoint.pix_height)) {
5073 GetCanvasPixPoint(mouseX, mouseY, lat, lon);
5076 if (g_pi_manager) g_pi_manager->SendCursorLatLonToAllPlugIns(lat, lon);
5079 if (!VPoint.b_quilt && m_singleChart) {
5084 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5088 if ((!m_cache_vp.IsValid()) ||
5089 (m_cache_vp.view_scale_ppm != VPoint.view_scale_ppm)) {
5093 wxPoint cp_last, cp_this;
5094 GetCanvasPointPix(m_cache_vp.clat, m_cache_vp.clon, &cp_last);
5095 GetCanvasPointPix(VPoint.clat, VPoint.clon, &cp_this);
5097 if (cp_last != cp_this) {
5103 if (m_pCurrentStack) {
5104 assert(ChartData != 0);
5105 int current_db_index;
5107 m_pCurrentStack->GetCurrentEntrydbIndex();
5109 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5111 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5114 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5118 if (VPoint.b_quilt) {
5119 if (last_vp.view_scale_ppm != scale_ppm)
5120 m_pQuilt->InvalidateAllQuiltPatchs();
5124 if (!m_pCurrentStack)
return false;
5126 int current_db_index;
5128 m_pCurrentStack->GetCurrentEntrydbIndex();
5130 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5131 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5134 int current_ref_stack_index = -1;
5135 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5136 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5137 current_ref_stack_index = i;
5140 if (g_bFullScreenQuilt) {
5141 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5145 bool b_needNewRef =
false;
5148 if ((-1 == current_ref_stack_index) &&
5149 (m_pQuilt->GetRefChartdbIndex() >= 0))
5150 b_needNewRef =
true;
5157 bool renderable =
true;
5159 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5160 if (referenceChart) {
5161 double chartMaxScale = referenceChart->GetNormalScaleMax(
5162 GetCanvasScaleFactor(), GetCanvasWidth());
5163 renderable = chartMaxScale * 64 >= VPoint.chart_scale;
5165 if (!renderable) b_needNewRef =
true;
5170 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5171 int target_scale = cte_ref.GetScale();
5172 int target_type = cte_ref.GetChartType();
5173 int candidate_stack_index;
5180 candidate_stack_index = 0;
5181 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5183 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5184 int candidate_scale = cte_candidate.GetScale();
5185 int candidate_type = cte_candidate.GetChartType();
5187 if ((candidate_scale >= target_scale) &&
5188 (candidate_type == target_type)) {
5189 bool renderable =
true;
5190 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5191 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5192 if (tentative_referenceChart) {
5193 double chartMaxScale =
5194 tentative_referenceChart->GetNormalScaleMax(
5195 GetCanvasScaleFactor(), GetCanvasWidth());
5196 renderable = chartMaxScale * 1.5 > VPoint.chart_scale;
5199 if (renderable)
break;
5202 candidate_stack_index++;
5207 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5208 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5209 while (candidate_stack_index >= 0) {
5210 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5213 ChartData->GetChartTableEntry(idx);
5214 int candidate_scale = cte_candidate.GetScale();
5215 int candidate_type = cte_candidate.GetChartType();
5217 if ((candidate_scale <= target_scale) &&
5218 (candidate_type == target_type))
5221 candidate_stack_index--;
5226 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5227 (candidate_stack_index < 0))
5228 candidate_stack_index = 0;
5230 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5232 m_pQuilt->SetReferenceChart(new_ref_index);
5238 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5243 bool renderable =
true;
5245 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5246 if (referenceChart) {
5247 double chartMaxScale = referenceChart->GetNormalScaleMax(
5248 GetCanvasScaleFactor(), GetCanvasWidth());
5249 renderable = chartMaxScale * 1.5 > VPoint.chart_scale;
5250 proj = ChartData->GetDBChartProj(ref_db_index);
5252 proj = PROJECTION_MERCATOR;
5254 VPoint.b_MercatorProjectionOverride =
5255 (m_pQuilt->GetnCharts() == 0 || !renderable);
5257 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5259 VPoint.SetProjectionType(proj);
5266 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5270 if (b_adjust) m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5277#ifdef __OCPN__ANDROID__
5285 if ((last_vp.view_scale_ppm != scale_ppm) || !bwasValid) {
5289 m_pQuilt->Invalidate();
5304 ChartData->PurgeCacheUnusedCharts(0.7);
5306 if (b_refresh) Refresh(
false);
5313 }
else if (!g_bopengl) {
5314 OcpnProjType projection = PROJECTION_UNKNOWN;
5317 projection = m_singleChart->GetChartProjectionType();
5318 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5319 VPoint.SetProjectionType(projection);
5323 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5324 m_cache_vp.Invalidate();
5328 UpdateCanvasControlBar();
5330 VPoint.chart_scale = 1.0;
5334 if (VPoint.GetBBox().GetValid()) {
5337 VPoint.ref_scale = m_singleChart->GetNativeScale();
5339 VPoint.ref_scale = m_pQuilt->GetRefNativeScale();
5344 wxPoint2DDouble r, r1;
5346 double delta_check =
5347 (VPoint.pix_height / VPoint.view_scale_ppm) / (1852. * 60);
5350 double check_point = wxMin(89., VPoint.clat);
5352 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5355 DistanceBearingMercator(check_point, VPoint.clon, check_point + delta_check,
5356 VPoint.clon, 0, &rhumbDist);
5358 GetDoubleCanvasPointPix(check_point, VPoint.clon, &r1);
5359 GetDoubleCanvasPointPix(check_point + delta_check, VPoint.clon, &r);
5360 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5361 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5363 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5367 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5373 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5375 if (m_true_scale_ppm)
5376 VPoint.chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5378 VPoint.chart_scale = 1.0;
5381 double round_factor = 1000.;
5382 if (VPoint.chart_scale <= 1000.)
5384 else if (VPoint.chart_scale <= 10000.)
5385 round_factor = 100.;
5386 else if (VPoint.chart_scale <= 100000.)
5387 round_factor = 1000.;
5389 double true_scale_display =
5390 wxRound(VPoint.chart_scale / round_factor) * round_factor;
5393 m_displayed_scale_factor = VPoint.ref_scale / VPoint.chart_scale;
5395 if (m_displayed_scale_factor > 10.0)
5396 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5397 m_displayed_scale_factor);
5398 else if (m_displayed_scale_factor > 1.0)
5399 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5400 m_displayed_scale_factor);
5401 else if (m_displayed_scale_factor > 0.1) {
5402 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5403 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5404 }
else if (m_displayed_scale_factor > 0.01) {
5405 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5406 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5409 _T(
"%s %4.0f (---)"), _(
"Scale"),
5410 true_scale_display);
5414 if (g_bopengl && g_bShowFPS) {
5417 if (g_gl_ms_per_frame > 0) {
5418 fps = 1000. / g_gl_ms_per_frame;
5419 fps_str.Printf(_T(
" %3d fps"), (
int)fps);
5425 m_scaleValue = true_scale_display;
5427 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5429 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5430 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5432 bool b_noshow =
false;
5436 wxClientDC dc(parent_frame->GetStatusBar());
5438 wxFont *templateFont = FontMgr::Get().GetFont(_(
"StatusBar"), 0);
5439 dc.SetFont(*templateFont);
5440 dc.GetTextExtent(text, &w, &h);
5445 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5446 if (w && w > rect.width) {
5447 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5448 m_displayed_scale_factor);
5452 dc.GetTextExtent(text, &w, &h);
5454 if (w && w > rect.width) {
5460 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5465 m_vLat = VPoint.clat;
5466 m_vLon = VPoint.clon;
5480static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5484static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5485 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5487wxColour ChartCanvas::PredColor() {
5490 if (SHIP_NORMAL == m_ownship_state)
5491 return GetGlobalColor(_T (
"URED" ));
5493 else if (SHIP_LOWACCURACY == m_ownship_state)
5494 return GetGlobalColor(_T (
"YELO1" ));
5496 return GetGlobalColor(_T (
"NODTA" ));
5499wxColour ChartCanvas::ShipColor() {
5503 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5505 if (SHIP_LOWACCURACY == m_ownship_state)
5506 return GetGlobalColor(_T (
"YELO1" ));
5508 return GetGlobalColor(_T (
"URED" ));
5511void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc, wxPoint lShipMidPoint) {
5512 dc.SetPen(wxPen(PredColor(), 2));
5514 if (SHIP_NORMAL == m_ownship_state)
5515 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5517 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5519 dc.DrawEllipse(lShipMidPoint.x - 10, lShipMidPoint.y - 10, 20, 20);
5520 dc.DrawEllipse(lShipMidPoint.x - 6, lShipMidPoint.y - 6, 12, 12);
5522 dc.DrawLine(lShipMidPoint.x - 12, lShipMidPoint.y, lShipMidPoint.x + 12,
5524 dc.DrawLine(lShipMidPoint.x, lShipMidPoint.y - 12, lShipMidPoint.x,
5525 lShipMidPoint.y + 12);
5528void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5529 wxPoint GPSOffsetPixels,
5530 wxPoint lGPSPoint) {
5534 float ref_dim = m_display_size_mm / 24;
5535 ref_dim = wxMin(ref_dim, 12);
5536 ref_dim = wxMax(ref_dim, 6);
5538 wxColour cPred = PredColor();
5545 double nominal_line_width_pix = wxMax(
5547 floor(m_pix_per_mm / 2));
5551 if (nominal_line_width_pix > g_cog_predictor_width)
5552 g_cog_predictor_width = nominal_line_width_pix;
5555 wxPoint lPredPoint, lHeadPoint;
5557 float pCog = std::isnan(gCog) ? 0 : gCog;
5558 float pSog = std::isnan(gSog) ? 0 : gSog;
5560 double pred_lat, pred_lon;
5561 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5562 &pred_lat, &pred_lon);
5563 GetCanvasPointPix(pred_lat, pred_lon, &lPredPoint);
5573 float ndelta_pix = 10.;
5574 double hdg_pred_lat, hdg_pred_lon;
5575 bool b_render_hdt =
false;
5576 if (!std::isnan(gHdt)) {
5578 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5580 GetCanvasPointPix(hdg_pred_lat, hdg_pred_lon, &lHeadPoint);
5581 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5582 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5583 if (dist > ndelta_pix ) {
5584 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5585 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5590 wxPoint lShipMidPoint;
5591 lShipMidPoint.x = lGPSPoint.x + GPSOffsetPixels.x;
5592 lShipMidPoint.y = lGPSPoint.y + GPSOffsetPixels.y;
5593 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5594 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5596 if (lpp >= img_height / 2) {
5597 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5598 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5599 !std::isnan(gSog)) {
5601 float dash_length = ref_dim;
5602 wxDash dash_long[2];
5604 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5605 g_cog_predictor_width);
5606 dash_long[1] = dash_long[0] / 2.0;
5610 if (dash_length > 250.) {
5611 dash_long[0] = 250. / g_cog_predictor_width;
5612 dash_long[1] = dash_long[0] / 2;
5615 wxPen ppPen2(cPred, g_cog_predictor_width, wxPENSTYLE_USER_DASH);
5616 ppPen2.SetDashes(2, dash_long);
5619 lGPSPoint.x + GPSOffsetPixels.x, lGPSPoint.y + GPSOffsetPixels.y,
5620 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5622 if (g_cog_predictor_width > 1) {
5623 float line_width = g_cog_predictor_width / 3.;
5625 wxDash dash_long3[2];
5626 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5627 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5629 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
5630 wxPENSTYLE_USER_DASH);
5631 ppPen3.SetDashes(2, dash_long3);
5634 lGPSPoint.x + GPSOffsetPixels.x, lGPSPoint.y + GPSOffsetPixels.y,
5635 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5639 double png_pred_icon_scale_factor = .4;
5640 if (g_ShipScaleFactorExp > 1.0)
5641 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5643 png_pred_icon_scale_factor *= 1.0 / g_scaler;
5647 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
5648 (
float)(lPredPoint.x - lShipMidPoint.x));
5649 cog_rad += (float)PI;
5651 for (
int i = 0; i < 4; i++) {
5653 double pxa = (double)(s_png_pred_icon[j]);
5654 double pya = (double)(s_png_pred_icon[j + 1]);
5656 pya *= png_pred_icon_scale_factor;
5657 pxa *= png_pred_icon_scale_factor;
5659 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
5660 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
5662 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
5663 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
5667 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
5670 dc.SetBrush(wxBrush(cPred));
5672 dc.StrokePolygon(4, icon);
5678 float hdt_dash_length = ref_dim * 0.4;
5680 float hdt_width = g_cog_predictor_width * 0.8;
5681 wxDash dash_short[2];
5683 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
5686 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
5689 wxPen ppPen2(cPred, hdt_width, wxPENSTYLE_USER_DASH);
5690 ppPen2.SetDashes(2, dash_short);
5694 lGPSPoint.x + GPSOffsetPixels.x, lGPSPoint.y + GPSOffsetPixels.y,
5695 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
5697 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
5699 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
5701 double nominal_circle_size_pixels = wxMax(
5702 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
5705 if (g_ShipScaleFactorExp > 1.0)
5706 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5708 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
5709 lHeadPoint.y + GPSOffsetPixels.y,
5710 nominal_circle_size_pixels / 2);
5714 if (g_iNavAidRadarRingsNumberVisible) {
5715 double factor = 1.00;
5716 if (g_pNavAidRadarRingsStepUnits == 1)
5719 factor *= g_fNavAidRadarRingsStep;
5723 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
5724 GetCanvasPointPix(tlat, tlon, &r);
5726 double lpp = sqrt(pow((
double)(lGPSPoint.x - r.x), 2) +
5727 pow((
double)(lGPSPoint.y - r.y), 2));
5728 int pix_radius = (int)lpp;
5730 extern wxColor GetDimColor(wxColor c);
5731 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
5733 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
5736 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
5738 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
5739 dc.StrokeCircle(lGPSPoint.x, lGPSPoint.y, i * pix_radius);
5743void ChartCanvas::ComputeShipScaleFactor(
5744 float icon_hdt,
int ownShipWidth,
int ownShipLength, wxPoint &lShipMidPoint,
5745 wxPoint &GPSOffsetPixels, wxPoint lGPSPoint,
float &scale_factor_x,
5746 float &scale_factor_y) {
5747 float screenResolution = m_pix_per_mm;
5750 double ship_bow_lat, ship_bow_lon;
5751 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
5752 &ship_bow_lat, &ship_bow_lon);
5753 wxPoint lShipBowPoint;
5754 wxPoint2DDouble b_point =
5755 GetVP().GetDoublePixFromLL(ship_bow_lat, ship_bow_lon);
5756 wxPoint2DDouble a_point = GetVP().GetDoublePixFromLL(gLat, gLon);
5758 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
5759 powf((
float)(b_point.m_y - a_point.m_y), 2));
5762 float shipLength_mm = shipLength_px / screenResolution;
5765 float ownship_min_mm = g_n_ownship_min_mm;
5766 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
5769 float hdt_ant = icon_hdt + 180.;
5770 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
5771 float dx = g_n_gps_antenna_offset_x / 1852.;
5772 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
5780 if (shipLength_mm < ownship_min_mm) {
5781 dy /= shipLength_mm / ownship_min_mm;
5782 dx /= shipLength_mm / ownship_min_mm;
5785 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
5787 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
5788 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
5791 GetCanvasPointPix(ship_mid_lat1, ship_mid_lon1, &lShipMidPoint);
5792 GPSOffsetPixels.x = lShipMidPoint.x - lGPSPoint.x;
5793 GPSOffsetPixels.y = lShipMidPoint.y - lGPSPoint.y;
5795 float scale_factor = shipLength_px / ownShipLength;
5798 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
5801 scale_factor = wxMax(scale_factor, scale_factor_min);
5803 scale_factor_y = scale_factor;
5804 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
5805 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
5808void ChartCanvas::ShipDraw(
ocpnDC &dc) {
5809 if (!GetVP().IsValid())
return;
5811 wxPoint lGPSPoint, lShipMidPoint, GPSOffsetPixels(0, 0);
5814 float pCog = std::isnan(gCog) ? 0 : gCog;
5815 float pSog = std::isnan(gSog) ? 0 : gSog;
5817 GetCanvasPointPix(gLat, gLon, &lGPSPoint);
5818 lShipMidPoint = lGPSPoint;
5822 float icon_hdt = pCog;
5823 if (!std::isnan(gHdt)) icon_hdt = gHdt;
5826 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
5830 double osd_head_lat, osd_head_lon;
5831 wxPoint osd_head_point;
5833 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
5836 GetCanvasPointPix(osd_head_lat, osd_head_lon, &osd_head_point);
5838 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.y),
5839 (
float)(osd_head_point.x - lShipMidPoint.x));
5840 icon_rad += (float)PI;
5842 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().rotation;
5846 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
5850 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
5851 if (GetVP().chart_scale >
5854 ShipDrawLargeScale(dc, lShipMidPoint);
5860 if (m_pos_image_user)
5861 pos_image = m_pos_image_user->Copy();
5862 else if (SHIP_NORMAL == m_ownship_state)
5863 pos_image = m_pos_image_red->Copy();
5864 if (SHIP_LOWACCURACY == m_ownship_state)
5865 pos_image = m_pos_image_yellow->Copy();
5866 else if (SHIP_NORMAL != m_ownship_state)
5867 pos_image = m_pos_image_grey->Copy();
5870 if (m_pos_image_user) {
5871 pos_image = m_pos_image_user->Copy();
5873 if (SHIP_LOWACCURACY == m_ownship_state)
5874 pos_image = m_pos_image_user_yellow->Copy();
5875 else if (SHIP_NORMAL != m_ownship_state)
5876 pos_image = m_pos_image_user_grey->Copy();
5879 img_height = pos_image.GetHeight();
5881 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
5882 g_OwnShipIconType > 0)
5884 int ownShipWidth = 22;
5885 int ownShipLength = 84;
5886 if (g_OwnShipIconType == 1) {
5887 ownShipWidth = pos_image.GetWidth();
5888 ownShipLength = pos_image.GetHeight();
5891 float scale_factor_x, scale_factor_y;
5892 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
5893 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
5894 scale_factor_x, scale_factor_y);
5896 if (g_OwnShipIconType == 1) {
5897 pos_image.Rescale(ownShipWidth * scale_factor_x,
5898 ownShipLength * scale_factor_y,
5899 wxIMAGE_QUALITY_HIGH);
5900 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
5902 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
5905 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
5906 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
5907 if (rot_image.GetAlpha(ip, jp) > 64)
5908 rot_image.SetAlpha(ip, jp, 255);
5910 wxBitmap os_bm(rot_image);
5912 int w = os_bm.GetWidth();
5913 int h = os_bm.GetHeight();
5916 dc.DrawBitmap(os_bm, lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2,
5920 dc.CalcBoundingBox(lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2);
5921 dc.CalcBoundingBox(lShipMidPoint.x - w / 2 + w,
5922 lShipMidPoint.y - h / 2 + h);
5925 else if (g_OwnShipIconType == 2) {
5926 wxPoint ownship_icon[10];
5928 for (
int i = 0; i < 10; i++) {
5930 float pxa = (float)(s_ownship_icon[j]);
5931 float pya = (float)(s_ownship_icon[j + 1]);
5932 pya *= scale_factor_y;
5933 pxa *= scale_factor_x;
5935 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
5936 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
5938 ownship_icon[i].x = (int)(px) + lShipMidPoint.x;
5939 ownship_icon[i].y = (int)(py) + lShipMidPoint.y;
5942 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
5944 dc.SetBrush(wxBrush(ShipColor()));
5946 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
5949 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
5951 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
5955 img_height = ownShipLength * scale_factor_y;
5959 if (m_pos_image_user) circle_rad = 1;
5961 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
5962 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
5963 dc.StrokeCircle(lGPSPoint.x, lGPSPoint.y, circle_rad);
5966 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
5968 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
5971 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
5972 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
5973 if (rot_image.GetAlpha(ip, jp) > 64)
5974 rot_image.SetAlpha(ip, jp, 255);
5976 wxBitmap os_bm(rot_image);
5978 if (g_ShipScaleFactorExp > 1) {
5979 wxImage scaled_image = os_bm.ConvertToImage();
5980 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
5982 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
5983 scaled_image.GetHeight() * factor,
5984 wxIMAGE_QUALITY_HIGH));
5986 int w = os_bm.GetWidth();
5987 int h = os_bm.GetHeight();
5990 dc.DrawBitmap(os_bm, lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2,
5995 if (m_pos_image_user) circle_rad = 1;
5997 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
5998 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
5999 dc.StrokeCircle(lShipMidPoint.x, lShipMidPoint.y, circle_rad);
6002 dc.CalcBoundingBox(lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2);
6003 dc.CalcBoundingBox(lShipMidPoint.x - w / 2 + w,
6004 lShipMidPoint.y - h / 2 + h);
6009 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6022void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6023 float &MinorSpacing) {
6028 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6029 {.000001f, 45.0f, 15.0f},
6030 {.0002f, 30.0f, 10.0f},
6031 {.0003f, 10.0f, 2.0f},
6032 {.0008f, 5.0f, 1.0f},
6033 {.001f, 2.0f, 30.0f / 60.0f},
6034 {.003f, 1.0f, 20.0f / 60.0f},
6035 {.006f, 0.5f, 10.0f / 60.0f},
6036 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6037 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6038 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6039 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6040 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6041 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6042 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6043 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6046 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6047 if (view_scale_ppm < lltab[tabi][0])
break;
6048 MajorSpacing = lltab[tabi][1];
6049 MinorSpacing = lltab[tabi][2];
6063wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6064 int deg = (int)fabs(latlon);
6065 float min = fabs((fabs(latlon) - deg) * 60.0);
6075 }
else if (latlon < 0.0) {
6087 if (spacing >= 1.0) {
6088 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6089 }
else if (spacing >= (1.0 / 60.0)) {
6090 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6092 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6109void ChartCanvas::GridDraw(
ocpnDC &dc) {
6110 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6112 double nlat, elon, slat, wlon;
6115 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6117 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6119 dc.SetFont(*m_pgridFont);
6120 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6123 h = m_canvas_height;
6125 GetCanvasPixPoint(0, 0, nlat,
6127 GetCanvasPixPoint(w, h, slat,
6134 dlon = dlon + 360.0;
6137 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6140 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6143 while (lat < nlat) {
6146 CalcGridText(lat, gridlatMajor,
true);
6147 GetCanvasPointPix(lat, (elon + wlon) / 2, &r);
6148 dc.DrawLine(0, r.y, w, r.y,
false);
6149 dc.DrawText(st, 0, r.y);
6150 lat = lat + gridlatMajor;
6152 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6156 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6159 while (lat < nlat) {
6161 GetCanvasPointPix(lat, (elon + wlon) / 2, &r);
6162 dc.DrawLine(0, r.y, 10, r.y,
false);
6163 dc.DrawLine(w - 10, r.y, w, r.y,
false);
6164 lat = lat + gridlatMinor;
6168 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6171 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6174 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6176 wxString st = CalcGridText(lon, gridlonMajor,
false);
6177 GetCanvasPointPix((nlat + slat) / 2, lon, &r);
6178 dc.DrawLine(r.x, 0, r.x, h,
false);
6179 dc.DrawText(st, r.x, 0);
6180 lon = lon + gridlonMajor;
6185 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6189 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6191 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6193 GetCanvasPointPix((nlat + slat) / 2, lon, &r);
6194 dc.DrawLine(r.x, 0, r.x, 10,
false);
6195 dc.DrawLine(r.x, h - 10, r.x, h,
false);
6196 lon = lon + gridlonMinor;
6203void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6205 double blat, blon, tlat, tlon;
6208 int x_origin = m_bDisplayGrid ? 60 : 20;
6209 int y_origin = m_canvas_height - 50;
6215 if (GetVP().chart_scale > 80000)
6219 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6220 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6225 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6226 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6229 GetCanvasPixPoint(x_origin, y_origin, blat, blon);
6230 double rotation = -VPoint.rotation;
6232 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6233 GetCanvasPointPix(tlat, tlon, &r);
6234 int l1 = (y_origin - r.y) / count;
6236 for (
int i = 0; i < count; i++) {
6243 dc.DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6246 double blat, blon, tlat, tlon;
6248 int x_origin = 5.0 * GetPixPerMM();
6249 int chartbar_height = GetChartbarHeight();
6253 int y_origin = m_canvas_height - chartbar_height - 5;
6255 GetCanvasPixPoint(x_origin, y_origin, blat, blon);
6256 GetCanvasPixPoint(x_origin + m_canvas_width, y_origin, tlat, tlon);
6259 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6262 int unit = g_iDistanceFormat;
6264 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6265 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6268 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6269 float places = floor(logdist), rem = logdist - places;
6270 dist = pow(10, places);
6277 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6278 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6279 double rotation = -VPoint.rotation;
6281 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6284 GetCanvasPointPix(tlat, tlon, &r);
6285 int l1 = r.x - x_origin;
6287 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6292 dc.DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6293 dc.DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6294 dc.DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6296 dc.SetFont(*m_pgridFont);
6297 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6299 dc.GetTextExtent(s, &w, &h);
6300 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6304void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6309 double ra_max = 40.;
6311 wxPen pen_save = dc.GetPen();
6313 wxDateTime now = wxDateTime::Now();
6319 x0 = x1 = x + radius;
6324 while (angle < 360.) {
6325 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6328 if (angle > 360.) angle = 360.;
6330 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6338 x1 = (int)(x + cos(angle * PI / 180.) * r);
6339 y1 = (int)(y + sin(angle * PI / 180.) * r);
6341 dc.DrawLine(x0, y0, x1, y1);
6349 dc.DrawLine(x + radius, y, x1, y1);
6351 dc.SetPen(pen_save);
6354static bool bAnchorSoundPlaying =
false;
6356static void onSoundFinished(
void *ptr) { bAnchorSoundPlaying =
false; }
6358void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6360 bool play_sound =
false;
6361 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6362 if (AnchorAlertOn1) {
6363 wxPoint TargetPoint;
6364 GetCanvasPointPix(pAnchorWatchPoint1->m_lat, pAnchorWatchPoint1->m_lon,
6366 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6367 TargetPoint.y, 100);
6371 AnchorAlertOn1 =
false;
6373 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6374 if (AnchorAlertOn2) {
6375 wxPoint TargetPoint;
6376 GetCanvasPointPix(pAnchorWatchPoint2->m_lat, pAnchorWatchPoint2->m_lon,
6378 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6379 TargetPoint.y, 100);
6383 AnchorAlertOn2 =
false;
6385 if (play_sound && !bAnchorSoundPlaying) {
6386 auto cmd_sound =
dynamic_cast<SystemCmdSound*
>(g_anchorwatch_sound);
6387 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6388 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6389 if (g_anchorwatch_sound->IsOk()) {
6390 bAnchorSoundPlaying =
true;
6391 g_anchorwatch_sound->SetFinishedCallback(onSoundFinished, NULL);
6392 g_anchorwatch_sound->Play();
6394 }
else if (g_anchorwatch_sound->IsOk()) {
6395 g_anchorwatch_sound->Stop();
6400void ChartCanvas::UpdateShips() {
6403 wxClientDC dc(
this);
6404 if (!dc.IsOk())
return;
6406 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6407 wxMemoryDC temp_dc(test_bitmap);
6409 temp_dc.ResetBoundingBox();
6410 temp_dc.DestroyClippingRegion();
6411 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6417 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6418 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6421 GetCanvasPointPix(p->m_lat, p->m_lon, &px);
6422 ocpndc.CalcBoundingBox(px.x, px.y);
6427 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6428 temp_dc.MaxY() - temp_dc.MinY());
6430 wxRect own_ship_update_rect = ship_draw_rect;
6432 if (!own_ship_update_rect.IsEmpty()) {
6435 own_ship_update_rect.Union(ship_draw_last_rect);
6436 own_ship_update_rect.Inflate(2);
6439 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6441 ship_draw_last_rect = ship_draw_rect;
6443 temp_dc.SelectObject(wxNullBitmap);
6446void ChartCanvas::UpdateAlerts() {
6451 wxClientDC dc(
this);
6455 dc.GetSize(&sx, &sy);
6458 wxBitmap test_bitmap(sx, sy, -1);
6462 temp_dc.SelectObject(test_bitmap);
6464 temp_dc.ResetBoundingBox();
6465 temp_dc.DestroyClippingRegion();
6466 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6473 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6474 temp_dc.MaxX() - temp_dc.MinX(),
6475 temp_dc.MaxY() - temp_dc.MinY());
6477 if (!alert_rect.IsEmpty())
6478 alert_rect.Inflate(2);
6480 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6483 wxRect alert_update_rect = alert_draw_rect;
6484 alert_update_rect.Union(alert_rect);
6487 RefreshRect(alert_update_rect,
false);
6491 alert_draw_rect = alert_rect;
6493 temp_dc.SelectObject(wxNullBitmap);
6496void ChartCanvas::UpdateAIS() {
6497 if (!g_pAIS)
return;
6502 wxClientDC dc(
this);
6506 dc.GetSize(&sx, &sy);
6514 if (g_pAIS->GetTargetList().size() > 10) {
6515 ais_rect = wxRect(0, 0, sx, sy);
6518 wxBitmap test_bitmap(sx, sy, -1);
6522 temp_dc.SelectObject(test_bitmap);
6524 temp_dc.ResetBoundingBox();
6525 temp_dc.DestroyClippingRegion();
6526 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6530 AISDraw(ocpndc, GetVP(),
this);
6531 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6535 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6536 temp_dc.MaxY() - temp_dc.MinY());
6538 if (!ais_rect.IsEmpty())
6539 ais_rect.Inflate(2);
6541 temp_dc.SelectObject(wxNullBitmap);
6544 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6547 wxRect ais_update_rect = ais_draw_rect;
6548 ais_update_rect.Union(ais_rect);
6551 RefreshRect(ais_update_rect,
false);
6555 ais_draw_rect = ais_rect;
6558void ChartCanvas::ToggleCPAWarn() {
6559 g_bCPAWarn = !g_bCPAWarn;
6560 wxString mess = _(
"ON");
6562 g_bTCPA_Max =
false;
6565 else { g_bTCPA_Max =
true; }
6567 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6568 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6571 OCPNMessageBox(
this,
6572 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
6573 _(
"CPA") + _T(
" ") + mess, 4, 4);
6577void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6579void ChartCanvas::OnSize(wxSizeEvent &event) {
6580 GetClientSize(&m_canvas_width, &m_canvas_height);
6583 m_canvas_width *= m_displayScale;
6584 m_canvas_height *= m_displayScale;
6587 VPoint.pix_width = m_canvas_width;
6588 VPoint.pix_height = m_canvas_height;
6594 SetVPScale(GetVPScale());
6596 m_absolute_min_scale_ppm =
6598 (1.2 * WGS84_semimajor_axis_meters * PI);
6601 gFrame->ProcessCanvasResize();
6611 SetMUIBarPosition();
6612 UpdateFollowButtonState();
6613 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6618 xr_margin = m_canvas_width * 95 / 100;
6619 xl_margin = m_canvas_width * 5 / 100;
6620 yt_margin = m_canvas_height * 5 / 100;
6621 yb_margin = m_canvas_height * 95 / 100;
6624 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
6628 pscratch_bm =
new wxBitmap(VPoint.pix_width, VPoint.pix_height, -1);
6629 m_brepaint_piano =
true;
6632 m_dc_route.SelectObject(wxNullBitmap);
6634 proute_bm =
new wxBitmap(VPoint.pix_width, VPoint.pix_height, -1);
6635 m_dc_route.SelectObject(*proute_bm);
6638 m_cached_chart_bm.Create(VPoint.pix_width, VPoint.pix_height, -1);
6641 m_working_bm.Create(VPoint.pix_width, VPoint.pix_height, -1);
6644 SetVPScale(GetVPScale());
6649 m_glcc->OnSize(event);
6658void ChartCanvas::ProcessNewGUIScale() {
6666void ChartCanvas::CreateMUIBar() {
6667 if (g_useMUI && !m_muiBar) {
6671 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
6673 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
6674 m_muiBar->SetColorScheme(m_cs);
6675 m_muiBarHOSize = m_muiBar->GetSize();
6679 SetMUIBarPosition();
6680 UpdateFollowButtonState();
6681 m_muiBar->UpdateDynamicValues();
6682 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6687void ChartCanvas::SetMUIBarPosition() {
6691 int pianoWidth = GetClientSize().x * (g_btouch ? 0.7f : 0.6f);
6695 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
6696 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
6698 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
6702 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
6703 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
6705 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
6709 m_muiBar->SetBestPosition();
6713void ChartCanvas::DestroyMuiBar() {
6715 m_muiBar->Destroy();
6720void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
6722 if (NULL == m_pCIWin) {
6727 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
6734 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
6735 pc = ChartData->OpenChartFromDBAndLock(
6736 dbIndex, FULL_INIT);
6738 int char_width, char_height;
6739 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
6740 if (pc) ChartData->UnLockCacheChart(dbIndex);
6742 m_pCIWin->SetString(s);
6743 m_pCIWin->FitToChars(char_width, char_height);
6746 p.x = x / GetContentScaleFactor();
6747 if ((p.x + m_pCIWin->GetWinSize().x) > (m_canvas_width / GetContentScaleFactor()))
6748 p.x = ((m_canvas_width / GetContentScaleFactor())
6749 - m_pCIWin->GetWinSize().x) / 2;
6752 (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor()
6753 - 4 - m_pCIWin->GetWinSize().y;
6755 m_pCIWin->dbIndex = dbIndex;
6756 m_pCIWin->SetPosition(p);
6757 m_pCIWin->SetBitmap();
6758 m_pCIWin->Refresh();
6762 HideChartInfoWindow();
6766void ChartCanvas::HideChartInfoWindow(
void) {
6769 m_pCIWin->Destroy();
6772#ifdef __OCPN__ANDROID__
6773 androidForceFullRepaint();
6778void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
6779 wxMouseEvent ev(wxEVT_MOTION);
6782 ev.m_leftDown = mouse_leftisdown;
6784 wxEvtHandler *evthp = GetEventHandler();
6786 ::wxPostEvent(evthp, ev);
6789void ChartCanvas::MovementTimerEvent(wxTimerEvent &) { DoTimedMovement(); }
6791void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
6793bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
6795 if (m_disable_edge_pan)
return false;
6798 int pan_margin = m_canvas_width * margin / 100;
6799 int pan_timer_set = 200;
6800 double pan_delta = GetVP().pix_width * delta / 100;
6804 if (x > m_canvas_width - pan_margin) {
6809 else if (x < pan_margin) {
6814 if (y < pan_margin) {
6819 else if (y > m_canvas_height - pan_margin) {
6828 wxMouseState state = ::wxGetMouseState();
6829#if wxCHECK_VERSION(3, 0, 0)
6830 if (!state.LeftIsDown())
6832 if (!state.LeftDown())
6837 if ((bft) && !pPanTimer->IsRunning()) {
6838 PanCanvas(pan_x, pan_y);
6839 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
6845 if ((!bft) && pPanTimer->IsRunning()) {
6855void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
6856 bool setBeingEdited) {
6857 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
6858 m_pRoutePointEditTarget = NULL;
6859 m_pFoundPoint = NULL;
6862 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
6863 SelectableItemList SelList = pSelect->FindSelectionList(
6864 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTEPOINT);
6865 wxSelectableItemListNode *node = SelList.GetFirst();
6867 pFind = node->GetData();
6872 m_pEditRouteArray = g_pRouteMan->GetRouteArrayContaining(frp);
6875 bool brp_viz =
false;
6876 if (m_pEditRouteArray) {
6877 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
6878 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
6879 if (pr->IsVisible()) {
6885 brp_viz = frp->IsVisible();
6889 if (m_pEditRouteArray)
6891 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
6892 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
6893 pr->m_bIsBeingEdited = setBeingEdited;
6895 m_bRouteEditing = setBeingEdited;
6898 frp->m_bRPIsBeingEdited = setBeingEdited;
6899 m_bMarkEditing = setBeingEdited;
6902 m_pRoutePointEditTarget = frp;
6903 m_pFoundPoint = pFind;
6907 node = node->GetNext();
6911void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
6912 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
6913 singleClickEventIsValid =
false;
6914 m_DoubleClickTimer->Stop();
6919bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
6920 if (!m_bChartDragging && !m_bDrawingRoute) {
6921 if (m_Compass && m_Compass->IsShown() &&
6922 m_Compass->GetRect().Contains(event.GetPosition())) {
6923 if (m_Compass->MouseEvent(event)) {
6924 cursor_region = CENTER;
6925 if (!g_btouch) SetCanvasCursor(event);
6930 if (MouseEventChartBar(event))
return true;
6935bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
6936 if (!g_bShowChartBar)
return false;
6938 if (!m_Piano->MouseEvent(event))
return false;
6940 cursor_region = CENTER;
6941 if (!g_btouch) SetCanvasCursor(event);
6950 event.GetPosition(&x, &y);
6952 x *= m_displayScale;
6953 y *= m_displayScale;
6955 m_MouseDragging =
event.Dragging();
6961 if (event.Dragging()) {
6962 if ((x == mouse_x) && (y == mouse_y))
return true;
6968 mouse_leftisdown =
event.LeftDown();
6969 GetCanvasPixPoint(x, y, m_cursor_lat, m_cursor_lon);
6972 cursor_region = CENTER;
6974 int chartbar_height = GetChartbarHeight();
6976 if (m_Compass && m_Compass->IsShown() &&
6977 m_Compass->GetRect().Contains(event.GetPosition())) {
6978 cursor_region = CENTER;
6979 }
else if (x > xr_margin) {
6980 cursor_region = MID_RIGHT;
6981 }
else if (x < xl_margin) {
6982 cursor_region = MID_LEFT;
6983 }
else if (y > yb_margin - chartbar_height &&
6984 y < m_canvas_height - chartbar_height) {
6985 cursor_region = MID_TOP;
6986 }
else if (y < yt_margin) {
6987 cursor_region = MID_BOT;
6989 cursor_region = CENTER;
6992 if (!g_btouch) SetCanvasCursor(event);
6996 leftIsDown =
event.LeftDown();
6999 if (event.LeftDown()) {
7000 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7003 g_bTempShowMenuBar =
false;
7004 parent_frame->ApplyGlobalSettings(
false);
7012 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7013 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7017 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7018 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7022 if (g_pi_manager->SendMouseEventToPlugins(event))
7028 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7030 if (m_DoubleClickTimer->IsRunning()) {
7031 m_DoubleClickTimer->Stop();
7036 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7037 singleClickEvent = event;
7038 singleClickEventIsValid =
true;
7047 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7048 if (g_click_stop > 0) {
7056 if (GetUpMode() == COURSE_UP_MODE) {
7057 m_b_rot_hidef =
false;
7058 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7060 pRotDefTimer->Stop();
7063 bool bRoll = !g_btouch;
7064#ifdef __OCPN__ANDROID__
7065 bRoll = g_bRollover;
7068 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7069 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7070 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7071 m_RolloverPopupTimer.Start(
7075 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7079 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7088#if !defined(__WXGTK__) && !defined(__WXQT__)
7089 SetCursorStatus(m_cursor_lat, m_cursor_lon);
7096 if ((x >= 0) && (y >= 0))
7097 g_pi_manager->SendCursorLatLonToAllPlugIns(m_cursor_lat, m_cursor_lon);
7101 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7102 wxPoint p = ClientToScreen(wxPoint(x, y));
7106 wxRect rect = m_toolBar->GetScreenRect();
7108 if (rect.Contains(p.x, p.y)) m_toolBar->Submerge();
7115 if (m_routeState >= 2) {
7118 m_bDrawingRoute =
true;
7120 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7125 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7128 m_bDrawingRoute =
true;
7130 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7137void ChartCanvas::CallPopupMenu(
int x,
int y) {
7145 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7151 slat = m_cursor_lat;
7152 slon = m_cursor_lon;
7154#if defined(__WXMAC__) || defined(__OCPN__ANDROID__)
7158 wxClientDC cdc(GetParent());
7170 if (m_pSelectedRoute) {
7171 m_pSelectedRoute->m_bRtIsSelected =
false;
7172 m_pSelectedRoute->DeSelectRoute();
7174 if (g_bopengl && m_glcc) {
7179 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7182 if (m_pFoundRoutePoint) {
7183 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7185 RefreshRect(m_pFoundRoutePoint->CurrentRect_in_DC);
7190 if (g_btouch && m_pRoutePointEditTarget) {
7191 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7192 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7193 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7197 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
7198 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7199 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7201 pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7203 pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7207 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7210 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7216 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7219 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7220 seltype |= SELTYPE_AISTARGET;
7225 m_pFoundRoutePoint = NULL;
7230 Route *pSelectedActiveRoute = NULL;
7231 Route *pSelectedVizRoute = NULL;
7234 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
7235 SelectableItemList SelList =
7236 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7237 wxSelectableItemListNode *node = SelList.GetFirst();
7244 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(prp);
7247 bool brp_viz =
false;
7249 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7251 if (pr->IsVisible()) {
7256 if (!brp_viz && prp->IsShared())
7258 brp_viz = prp->IsVisible();
7261 brp_viz = prp->IsVisible();
7263 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7268 m_pSelectedRoute = NULL;
7270 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7272 if (pr->m_bRtIsActive) {
7273 pSelectedActiveRoute = pr;
7274 pFoundActiveRoutePoint = prp;
7279 if (NULL == pSelectedVizRoute) {
7280 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7282 if (pr->IsVisible()) {
7283 pSelectedVizRoute = pr;
7284 pFoundVizRoutePoint = prp;
7290 delete proute_array;
7293 node = node->GetNext();
7297 if (pFoundActiveRoutePoint) {
7298 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7299 m_pSelectedRoute = pSelectedActiveRoute;
7300 }
else if (pFoundVizRoutePoint) {
7301 m_pFoundRoutePoint = pFoundVizRoutePoint;
7302 m_pSelectedRoute = pSelectedVizRoute;
7305 m_pFoundRoutePoint = pFirstVizPoint;
7307 if (m_pSelectedRoute) {
7308 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7309 }
else if (m_pFoundRoutePoint)
7310 seltype |= SELTYPE_MARKPOINT;
7314 if (m_pFoundRoutePoint) {
7315 m_pFoundRoutePoint->m_bPtIsSelected =
true;
7317 RoutePointGui(*m_pFoundRoutePoint).CalculateDCRect(m_dc_route,
this, &wp_rect);
7318 RefreshRect(wp_rect,
true);
7326 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
7327 SelectableItemList SelList =
7328 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7330 if (NULL == m_pSelectedRoute)
7333 wxSelectableItemListNode *node = SelList.GetFirst();
7338 if (pr->IsVisible()) {
7339 m_pSelectedRoute = pr;
7342 node = node->GetNext();
7346 if (m_pSelectedRoute) {
7347 if (NULL == m_pFoundRoutePoint)
7348 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7350 m_pSelectedRoute->m_bRtIsSelected = !(seltype & SELTYPE_ROUTEPOINT);
7351 if (m_pSelectedRoute->m_bRtIsSelected) {
7353 if (g_bopengl && m_glcc) {
7358 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7361 seltype |= SELTYPE_ROUTESEGMENT;
7365 if (pFindTrackSeg) {
7366 m_pSelectedTrack = NULL;
7367 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
7368 SelectableItemList SelList =
7369 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7372 wxSelectableItemListNode *node = SelList.GetFirst();
7377 if (pt->IsVisible()) {
7378 m_pSelectedTrack = pt;
7381 node = node->GetNext();
7384 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7387 bool bseltc =
false;
7400 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
7401 SelectableItemList SelList = pSelectTC->FindSelectionList(
7402 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_CURRENTPOINT);
7405 wxSelectableItemListNode *node = SelList.GetFirst();
7406 pFind = node->GetData();
7407 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7409 if (SelList.GetCount() > 1) {
7410 node = node->GetNext();
7412 pFind = node->GetData();
7414 if (pIDX_candidate->IDX_type ==
'c') {
7415 pIDX_best_candidate = pIDX_candidate;
7419 node = node->GetNext();
7422 wxSelectableItemListNode *node = SelList.GetFirst();
7423 pFind = node->GetData();
7424 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7427 m_pIDXCandidate = pIDX_best_candidate;
7430 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
7434 seltype |= SELTYPE_CURRENTPOINT;
7437 else if (pFindTide) {
7438 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7441 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
7445 seltype |= SELTYPE_TIDEPOINT;
7449 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7452 InvokeCanvasMenu(x, y, seltype);
7455 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
7456 m_pSelectedRoute->m_bRtIsSelected =
false;
7459 m_pSelectedRoute = NULL;
7461 if (m_pFoundRoutePoint) {
7462 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
7463 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7465 m_pFoundRoutePoint = NULL;
7473bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
7475 if (std::isnan(m_cursor_lat))
return false;
7481 event.GetPosition(&x, &y);
7487 SelectRadius = g_Platform->GetSelectRadiusPix() /
7488 (m_true_scale_ppm * 1852 * 60);
7495 if (event.LeftDClick() && (cursor_region == CENTER)) {
7496 m_DoubleClickTimer->Start();
7497 singleClickEventIsValid =
false;
7500 GetCanvasPixPoint(x, y, zlat, zlon);
7502 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
7505 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
7508 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7509 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
7510 wxWindow *pwin = wxDynamicCast(
this, wxWindow);
7511 ShowAISTargetQueryDialog(pwin, m_FoundAIS_MMSI);
7517 SelectableItemList rpSelList =
7518 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
7519 wxSelectableItemListNode *node = rpSelList.GetFirst();
7520 bool b_onRPtarget =
false;
7524 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
7525 b_onRPtarget =
true;
7528 node = node->GetNext();
7533 if (m_pRoutePointEditTarget) {
7535 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
7538 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7539 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7540 if (g_btouch)
RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7542 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this, &wp_rect);
7543 m_pRoutePointEditTarget = NULL;
7544 RefreshRect(wp_rect,
true);
7548 node = rpSelList.GetFirst();
7553 wxArrayPtrVoid *proute_array =
7554 g_pRouteMan->GetRouteArrayContaining(frp);
7558 bool brp_viz =
false;
7560 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7562 if (pr->IsVisible()) {
7570 brp_viz = frp->IsVisible();
7572 brp_viz = frp->IsVisible();
7575 ShowMarkPropertiesDialog(frp);
7583 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
7587 if (pr->IsVisible()) {
7588 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
7593 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
7597 if (pt->IsVisible()) {
7598 ShowTrackPropertiesDialog(pt);
7605 ShowObjectQueryWindow(x, y, zlat, zlon);
7610 if (event.LeftDown()) {
7626 bool appending =
false;
7627 bool inserting =
false;
7630 SetCursor(*pCursorPencil);
7631 rlat = m_cursor_lat;
7632 rlon = m_cursor_lon;
7634 m_bRouteEditing =
true;
7636 if (m_routeState == 1) {
7637 m_pMouseRoute =
new Route();
7638 pRouteList->Append(m_pMouseRoute);
7647 double nearby_radius_meters =
7648 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
7651 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
7652 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
7653 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
7654 wxArrayPtrVoid *proute_array =
7655 g_pRouteMan->GetRouteArrayContaining(pNearbyPoint);
7659 bool brp_viz =
false;
7661 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7663 if (pr->IsVisible()) {
7669 pNearbyPoint->IsShared())
7672 pNearbyPoint->IsVisible();
7674 brp_viz = pNearbyPoint->IsVisible();
7677 m_FinishRouteOnKillFocus =
7679 int dlg_return = OCPNMessageBox(
7680 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
7681 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
7682 m_FinishRouteOnKillFocus =
true;
7684 if (dlg_return == wxID_YES) {
7685 pMousePoint = pNearbyPoint;
7688 if (m_routeState > 1)
7689 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
7690 Undo_HasParent, NULL);
7693 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
7694 bool procede =
false;
7698 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
7704 m_FinishRouteOnKillFocus =
false;
7710 _(
"Insert first part of this route in the new route?");
7711 if (tail->GetIndexOf(pMousePoint) ==
7714 dmsg = _(
"Insert this route in the new route?");
7716 if (tail->GetIndexOf(pMousePoint) != 1) {
7717 dlg_return = OCPNMessageBox(
7718 this, dmsg, _(
"OpenCPN Route Create"),
7719 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
7720 m_FinishRouteOnKillFocus =
true;
7722 if (dlg_return == wxID_YES) {
7729 _(
"Append last part of this route to the new route?");
7730 if (tail->GetIndexOf(pMousePoint) == 1)
7732 "Append this route to the new route?");
7737 if (tail->GetLastPoint() != pMousePoint) {
7738 dlg_return = OCPNMessageBox(
7739 this, dmsg, _(
"OpenCPN Route Create"),
7740 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
7741 m_FinishRouteOnKillFocus =
true;
7743 if (dlg_return == wxID_YES) {
7754 if (!FindRouteContainingWaypoint(pMousePoint))
7755 pMousePoint->SetShared(
true);
7760 if (NULL == pMousePoint) {
7761 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
7762 _T(
""), wxEmptyString);
7763 pMousePoint->SetNameShown(
false);
7765 pConfig->AddNewWayPoint(pMousePoint, -1);
7766 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
7768 if (m_routeState > 1)
7769 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
7770 Undo_IsOrphanded, NULL);
7773 if (m_pMouseRoute) {
7774 if (m_routeState == 1) {
7776 m_pMouseRoute->AddPoint(pMousePoint);
7778 if (m_pMouseRoute->m_NextLegGreatCircle) {
7779 double rhumbBearing, rhumbDist, gcBearing, gcDist;
7780 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
7781 &rhumbBearing, &rhumbDist);
7782 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
7783 rlat, &gcDist, &gcBearing, NULL);
7784 double gcDistNM = gcDist / 1852.0;
7787 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
7788 pow(rhumbDist - gcDistNM - 1, 0.5);
7791 msg << _(
"For this leg the Great Circle route is ")
7792 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
7793 << _(
" shorter than rhumbline.\n\n")
7794 << _(
"Would you like include the Great Circle routing points "
7797 m_FinishRouteOnKillFocus =
false;
7798 m_disable_edge_pan =
true;
7801 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
7802 wxYES_NO | wxNO_DEFAULT);
7804 m_disable_edge_pan =
false;
7805 m_FinishRouteOnKillFocus =
true;
7807 if (answer == wxID_YES) {
7809 RoutePoint *prevGcPoint = m_prev_pMousePoint;
7810 wxRealPoint gcCoord;
7812 for (
int i = 1; i <= segmentCount; i++) {
7813 double fraction = (double)i * (1.0 / (
double)segmentCount);
7814 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
7815 gcDist * fraction, gcBearing,
7816 &gcCoord.x, &gcCoord.y, NULL);
7818 if (i < segmentCount) {
7819 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
7820 _T(
""), wxEmptyString);
7821 gcPoint->SetNameShown(
false);
7822 pConfig->AddNewWayPoint(gcPoint, -1);
7823 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
7826 gcPoint = pMousePoint;
7829 m_pMouseRoute->AddPoint(gcPoint);
7830 pSelect->AddSelectableRouteSegment(
7831 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
7832 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
7833 prevGcPoint = gcPoint;
7836 undo->CancelUndoableAction(
true);
7839 m_pMouseRoute->AddPoint(pMousePoint);
7840 pSelect->AddSelectableRouteSegment(
7841 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
7842 pMousePoint, m_pMouseRoute);
7843 undo->AfterUndoableAction(m_pMouseRoute);
7847 m_pMouseRoute->AddPoint(pMousePoint);
7848 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
7849 rlon, m_prev_pMousePoint,
7850 pMousePoint, m_pMouseRoute);
7851 undo->AfterUndoableAction(m_pMouseRoute);
7857 m_prev_pMousePoint = pMousePoint;
7859 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
7865 int connect = tail->GetIndexOf(pMousePoint);
7870 int length = tail->GetnPoints();
7875 start = connect + 1;
7880 m_pMouseRoute->RemovePoint(
7884 for (i = start; i <= stop; i++) {
7885 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
7887 m_pMouseRoute->m_lastMousePointIndex =
7888 m_pMouseRoute->GetnPoints();
7890 gFrame->RefreshAllCanvas();
7894 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
7896 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
7897 m_pMouseRoute->FinalizeForRendering();
7899 gFrame->RefreshAllCanvas();
7903 else if (m_bMeasure_Active && m_nMeasureState)
7905 SetCursor(*pCursorPencil);
7907 if (m_nMeasureState == 1) {
7908 m_pMeasureRoute =
new Route();
7909 pRouteList->Append(m_pMeasureRoute);
7915 wxString(_T (
"circle" )),
7916 wxEmptyString, wxEmptyString);
7917 pMousePoint->m_bShowName =
false;
7918 pMousePoint->SetShowWaypointRangeRings(
false );
7920 m_pMeasureRoute->AddPoint(pMousePoint);
7922 m_prev_rlat = m_cursor_lat;
7923 m_prev_rlon = m_cursor_lon;
7924 m_prev_pMousePoint = pMousePoint;
7925 m_pMeasureRoute->m_lastMousePointIndex = m_pMeasureRoute->GetnPoints();
7928 gFrame->RefreshAllCanvas();
7933 FindRoutePointsAtCursor(SelectRadius,
true);
7938 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
7946 if (ret)
return true;
7949 if (event.Dragging()) {
7952 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
7954 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
7956 SelectableItemList SelList = pSelect->FindSelectionList(
7957 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTEPOINT);
7958 wxSelectableItemListNode *node = SelList.GetFirst();
7960 pFind = node->GetData();
7962 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
7963 node = node->GetNext();
7968 if (m_pRoutePointEditTarget &&
7969 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
7971 SelectableItemList SelList = pSelect->FindSelectionList(
7972 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_DRAGHANDLE);
7973 wxSelectableItemListNode *node = SelList.GetFirst();
7975 pFind = node->GetData();
7977 if (m_pRoutePointEditTarget == frp) {
7978 m_bIsInRadius =
true;
7981 node = node->GetNext();
7984 if (!m_dragoffsetSet) {
7985 RoutePointGui(*m_pRoutePointEditTarget).PresetDragOffset(
this, mouse_x, mouse_y);
7986 m_dragoffsetSet =
true;
7991 if (m_bRouteEditing && m_pRoutePointEditTarget) {
7992 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
7994 if (NULL == g_pMarkInfoDialog) {
7995 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
7996 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
7997 DraggingAllowed =
false;
7999 if (m_pRoutePointEditTarget &&
8000 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8001 DraggingAllowed =
false;
8003 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8005 if (DraggingAllowed) {
8006 if (!undo->InUndoableAction()) {
8007 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8008 Undo_NeedsCopy, m_pFoundPoint);
8014 if (!g_bopengl && m_pEditRouteArray) {
8015 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8016 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8021 if (g_pRouteMan->IsRouteValid(pr)) {
8023 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8024 pre_rect.Union(route_rect);
8029 double new_cursor_lat = m_cursor_lat;
8030 double new_cursor_lon = m_cursor_lon;
8032 if (CheckEdgePan(x, y,
true, 5, 2))
8033 GetCanvasPixPoint(x, y, new_cursor_lat, new_cursor_lon);
8039 RoutePointGui(*m_pRoutePointEditTarget).SetPointFromDraghandlePoint(
this, mouse_x,
8042 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8043 m_pRoutePointEditTarget,
8044 SELTYPE_DRAGHANDLE);
8045 m_pFoundPoint->m_slat =
8046 m_pRoutePointEditTarget->m_lat;
8047 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8049 m_pRoutePointEditTarget->m_lat =
8051 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8052 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8053 m_pFoundPoint->m_slat =
8055 m_pFoundPoint->m_slon = new_cursor_lon;
8059 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8060 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8061 g_pMarkInfoDialog->UpdateProperties(
true);
8071 if (m_pEditRouteArray) {
8072 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8074 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8075 if (g_pRouteMan->IsRouteValid(pr)) {
8077 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8078 post_rect.Union(route_rect);
8084 pre_rect.Union(post_rect);
8085 RefreshRect(pre_rect,
false);
8087 gFrame->RefreshCanvasOther(
this);
8088 m_bRoutePoinDragging =
true;
8093 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8094 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8096 if (NULL == g_pMarkInfoDialog) {
8097 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8098 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8099 DraggingAllowed =
false;
8101 if (m_pRoutePointEditTarget &&
8102 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8103 DraggingAllowed =
false;
8105 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8107 if (DraggingAllowed) {
8108 if (!undo->InUndoableAction()) {
8109 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8110 Undo_NeedsCopy, m_pFoundPoint);
8118 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8119 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8121 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8122 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8124 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8129 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this, &pre_rect);
8130 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8131 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8132 (
int)(lppmax - (pre_rect.height / 2)));
8139 RoutePointGui(*m_pRoutePointEditTarget).SetPointFromDraghandlePoint(
this, mouse_x,
8142 pSelect->ModifySelectablePoint(m_cursor_lat, m_cursor_lon,
8143 m_pRoutePointEditTarget,
8144 SELTYPE_DRAGHANDLE);
8145 m_pFoundPoint->m_slat =
8146 m_pRoutePointEditTarget->m_lat;
8147 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8149 m_pRoutePointEditTarget->m_lat =
8151 m_pRoutePointEditTarget->m_lon = m_cursor_lon;
8152 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8153 m_pFoundPoint->m_slat = m_cursor_lat;
8154 m_pFoundPoint->m_slon = m_cursor_lon;
8158 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8159 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8160 g_pMarkInfoDialog->UpdateProperties(
true);
8165 if (!g_btouch) InvalidateGL();
8170 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this,
8172 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8173 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8174 (
int)(lppmax - (post_rect.height / 2)));
8177 pre_rect.Union(post_rect);
8178 RefreshRect(pre_rect,
false);
8180 gFrame->RefreshCanvasOther(
this);
8181 m_bRoutePoinDragging =
true;
8186 if (ret)
return true;
8189 if (event.LeftUp()) {
8190 bool b_startedit_route =
false;
8191 m_dragoffsetSet =
false;
8194 m_bChartDragging =
false;
8195 m_bIsInRadius =
false;
8200 m_bedge_pan =
false;
8205 bool appending =
false;
8206 bool inserting =
false;
8209 rlat = m_cursor_lat;
8210 rlon = m_cursor_lon;
8212 if (m_pRoutePointEditTarget) {
8213 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8214 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8216 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this, &wp_rect);
8217 RefreshRect(wp_rect,
true);
8218 m_pRoutePointEditTarget = NULL;
8220 m_bRouteEditing =
true;
8222 if (m_routeState == 1) {
8223 m_pMouseRoute =
new Route();
8224 m_pMouseRoute->SetHiLite(50);
8225 pRouteList->Append(m_pMouseRoute);
8234 double nearby_radius_meters =
8235 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8238 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8239 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8240 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8243 m_FinishRouteOnKillFocus =
8245 dlg_return = OCPNMessageBox(
8246 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8247 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8248 m_FinishRouteOnKillFocus =
true;
8250 dlg_return = wxID_YES;
8252 if (dlg_return == wxID_YES) {
8253 pMousePoint = pNearbyPoint;
8256 if (m_routeState > 1)
8257 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8258 Undo_HasParent, NULL);
8259 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8261 bool procede =
false;
8265 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8271 m_FinishRouteOnKillFocus =
false;
8272 if (m_routeState == 1) {
8276 _(
"Insert first part of this route in the new route?");
8277 if (tail->GetIndexOf(pMousePoint) ==
8280 dmsg = _(
"Insert this route in the new route?");
8282 if (tail->GetIndexOf(pMousePoint) != 1) {
8284 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8285 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8286 m_FinishRouteOnKillFocus =
true;
8288 if (dlg_return == wxID_YES) {
8295 _(
"Append last part of this route to the new route?");
8296 if (tail->GetIndexOf(pMousePoint) == 1)
8298 "Append this route to the new route?");
8302 if (tail->GetLastPoint() != pMousePoint) {
8304 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8305 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8306 m_FinishRouteOnKillFocus =
true;
8308 if (dlg_return == wxID_YES) {
8319 if (!FindRouteContainingWaypoint(pMousePoint))
8320 pMousePoint->SetShared(
true);
8324 if (NULL == pMousePoint) {
8325 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8326 _T(
""), wxEmptyString);
8327 pMousePoint->SetNameShown(
false);
8329 pConfig->AddNewWayPoint(pMousePoint, -1);
8330 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8332 if (m_routeState > 1)
8333 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8334 Undo_IsOrphanded, NULL);
8337 if (m_routeState == 1) {
8339 m_pMouseRoute->AddPoint(pMousePoint);
8341 if (m_pMouseRoute->m_NextLegGreatCircle) {
8342 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8343 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8344 &rhumbBearing, &rhumbDist);
8345 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
8346 &gcDist, &gcBearing, NULL);
8347 double gcDistNM = gcDist / 1852.0;
8350 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8351 pow(rhumbDist - gcDistNM - 1, 0.5);
8354 msg << _(
"For this leg the Great Circle route is ")
8355 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8356 << _(
" shorter than rhumbline.\n\n")
8357 << _(
"Would you like include the Great Circle routing points "
8361 m_FinishRouteOnKillFocus =
false;
8362 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8363 wxYES_NO | wxNO_DEFAULT);
8364 m_FinishRouteOnKillFocus =
true;
8366 int answer = wxID_NO;
8369 if (answer == wxID_YES) {
8371 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8372 wxRealPoint gcCoord;
8374 for (
int i = 1; i <= segmentCount; i++) {
8375 double fraction = (double)i * (1.0 / (
double)segmentCount);
8376 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8377 gcDist * fraction, gcBearing,
8378 &gcCoord.x, &gcCoord.y, NULL);
8380 if (i < segmentCount) {
8381 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8382 _T(
""), wxEmptyString);
8383 gcPoint->SetNameShown(
false);
8384 pConfig->AddNewWayPoint(gcPoint, -1);
8385 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8388 gcPoint = pMousePoint;
8391 m_pMouseRoute->AddPoint(gcPoint);
8392 pSelect->AddSelectableRouteSegment(
8393 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8394 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8395 prevGcPoint = gcPoint;
8398 undo->CancelUndoableAction(
true);
8401 m_pMouseRoute->AddPoint(pMousePoint);
8402 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8403 rlon, m_prev_pMousePoint,
8404 pMousePoint, m_pMouseRoute);
8405 undo->AfterUndoableAction(m_pMouseRoute);
8409 m_pMouseRoute->AddPoint(pMousePoint);
8410 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8411 rlon, m_prev_pMousePoint,
8412 pMousePoint, m_pMouseRoute);
8413 undo->AfterUndoableAction(m_pMouseRoute);
8419 m_prev_pMousePoint = pMousePoint;
8420 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
8426 int connect = tail->GetIndexOf(pMousePoint);
8431 int length = tail->GetnPoints();
8436 start = connect + 1;
8441 m_pMouseRoute->RemovePoint(
8445 for (i = start; i <= stop; i++) {
8446 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8448 m_pMouseRoute->m_lastMousePointIndex =
8449 m_pMouseRoute->GetnPoints();
8451 gFrame->RefreshAllCanvas();
8455 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8457 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8458 m_pMouseRoute->FinalizeForRendering();
8463 }
else if (m_bMeasure_Active && m_nMeasureState)
8466 m_bedge_pan =
false;
8470 if (m_nMeasureState == 1) {
8471 m_pMeasureRoute =
new Route();
8472 pRouteList->Append(m_pMeasureRoute);
8477 if (m_pMeasureRoute){
8479 wxString(_T (
"circle" )),
8480 wxEmptyString, wxEmptyString);
8481 pMousePoint->m_bShowName =
false;
8483 m_pMeasureRoute->AddPoint(pMousePoint);
8485 m_prev_rlat = m_cursor_lat;
8486 m_prev_rlon = m_cursor_lon;
8487 m_prev_pMousePoint = pMousePoint;
8488 m_pMeasureRoute->m_lastMousePointIndex = m_pMeasureRoute->GetnPoints();
8493 CancelMeasureRoute();
8499 bool bSelectAllowed =
true;
8500 if (NULL == g_pMarkInfoDialog) {
8501 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
8502 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8503 bSelectAllowed =
false;
8510 if (m_bRoutePoinDragging) bSelectAllowed =
false;
8512 if (bSelectAllowed) {
8513 bool b_was_editing_mark = m_bMarkEditing;
8514 bool b_was_editing_route = m_bRouteEditing;
8515 FindRoutePointsAtCursor(SelectRadius,
8521 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->m_bIsInLayer)
8522 m_pRoutePointEditTarget = NULL;
8524 if (!b_was_editing_route) {
8525 if (m_pEditRouteArray) {
8526 b_startedit_route =
true;
8530 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
8531 m_pTrackRolloverWin->IsActive(
false);
8533 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
8534 m_pRouteRolloverWin->IsActive(
false);
8538 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8540 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8545 if (g_pRouteMan->IsRouteValid(pr)) {
8548 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8549 pre_rect.Union(route_rect);
8552 RefreshRect(pre_rect,
true);
8555 b_startedit_route =
false;
8559 if (m_pRoutePointEditTarget) {
8560 if (b_was_editing_mark ||
8561 b_was_editing_route) {
8562 if (m_lastRoutePointEditTarget) {
8563 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8564 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
8565 RoutePointGui(*m_lastRoutePointEditTarget).EnableDragHandle(
false);
8566 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
8567 SELTYPE_DRAGHANDLE);
8571 if (m_pRoutePointEditTarget) {
8572 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
true;
8573 m_pRoutePointEditTarget->m_bPtIsSelected =
true;
8574 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
8575 wxPoint2DDouble dragHandlePoint =
8576 RoutePointGui(*m_pRoutePointEditTarget).GetDragHandlePoint(
this);
8577 pSelect->AddSelectablePoint(
8578 dragHandlePoint.m_y, dragHandlePoint.m_x,
8579 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
8582 if (m_lastRoutePointEditTarget) {
8583 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8584 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
8585 RoutePointGui(*m_lastRoutePointEditTarget).EnableDragHandle(
false);
8586 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
8587 SELTYPE_DRAGHANDLE);
8590 wxArrayPtrVoid *lastEditRouteArray =
8591 g_pRouteMan->GetRouteArrayContaining(
8592 m_lastRoutePointEditTarget);
8593 if (lastEditRouteArray) {
8594 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
8596 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
8597 if (g_pRouteMan->IsRouteValid(pr)) {
8598 pr->m_bIsBeingEdited =
false;
8611 if (m_lastRoutePointEditTarget) {
8613 RoutePointGui(*m_lastRoutePointEditTarget).CalculateDCRect(m_dc_route,
this,
8615 RefreshRect(wp_rect,
true);
8618 if (m_pRoutePointEditTarget) {
8620 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this,
8622 RefreshRect(wp_rect,
true);
8630 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale());
8631 bool b_start_rollover =
false;
8632 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
8633 SelectItem *pFind = pSelectAIS->FindSelection(
8634 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_AISTARGET);
8635 if (pFind) b_start_rollover =
true;
8638 if (!b_start_rollover && !b_startedit_route) {
8639 SelectableItemList SelList = pSelect->FindSelectionList(
8640 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTESEGMENT);
8641 wxSelectableItemListNode *node = SelList.GetFirst();
8647 if (pr && pr->IsVisible()) {
8648 b_start_rollover =
true;
8651 node = node->GetNext();
8655 if (!b_start_rollover && !b_startedit_route) {
8656 SelectableItemList SelList = pSelect->FindSelectionList(
8657 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_TRACKSEGMENT);
8658 wxSelectableItemListNode *node = SelList.GetFirst();
8664 if (tr && tr->IsVisible()) {
8665 b_start_rollover =
true;
8668 node = node->GetNext();
8672 if (b_start_rollover)
8673 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
8675 Route *tail, *current;
8676 bool appending =
false;
8677 bool inserting =
false;
8679 if (m_bRouteEditing ) {
8681 if (m_pRoutePointEditTarget) {
8687 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
8688 double nearby_radius_meters =
8689 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8690 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
8691 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
8692 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
8693 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
8694 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
8697 if (m_pEditRouteArray && !pNearbyPoint->m_bIsolatedMark) {
8698 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8700 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8701 if (pr && pr->pRoutePointList) {
8702 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
8715 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
8720 OCPNMessageBox(
this,
8721 _(
"Replace this RoutePoint by the nearby "
8723 _(
"OpenCPN RoutePoint change"),
8724 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8725 if (dlg_return == wxID_YES) {
8730 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
8732 current = FindRouteContainingWaypoint(
8733 m_pRoutePointEditTarget);
8735 if (tail && current && (tail != current)) {
8737 connect = tail->GetIndexOf(pNearbyPoint);
8738 int index_current_route =
8739 current->GetIndexOf(m_pRoutePointEditTarget);
8740 index_last = current->GetIndexOf(current->GetLastPoint());
8741 dlg_return1 = wxID_NO;
8743 index_current_route) {
8745 if (connect != tail->GetnPoints()) {
8748 _(
"Last part of route to be appended to dragged "
8752 _(
"Full route to be appended to dragged route?");
8754 dlg_return1 = OCPNMessageBox(
8755 this, dmsg, _(
"OpenCPN Route Create"),
8756 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8757 if (dlg_return1 == wxID_YES) {
8761 }
else if (index_current_route ==
8766 _(
"First part of route to be inserted into dragged "
8768 if (connect == tail->GetnPoints())
8770 "Full route to be inserted into dragged route?");
8772 dlg_return1 = OCPNMessageBox(
8773 this, dmsg, _(
"OpenCPN Route Create"),
8774 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8775 if (dlg_return1 == wxID_YES) {
8782 if (m_pRoutePointEditTarget->IsShared()) {
8784 dlg_return = OCPNMessageBox(
8786 _(
"Do you really want to delete and replace this "
8788 _T(
"\n") + _(
"which has been created manually?"),
8789 (
"OpenCPN RoutePoint warning"),
8790 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8793 if (dlg_return == wxID_YES) {
8794 pMousePoint = pNearbyPoint;
8795 if (pMousePoint->m_bIsolatedMark) {
8796 pMousePoint->SetShared(
true);
8798 pMousePoint->m_bIsolatedMark =
8800 pMousePoint->m_bIsInRoute =
true;
8806 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
8808 if (m_pEditRouteArray) {
8809 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8811 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8812 if (g_pRouteMan->IsRouteValid(pr)) {
8816 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
8818 pSelect->DeleteAllSelectableRoutePoints(pr);
8819 pSelect->DeleteAllSelectableRouteSegments(pr);
8821 pr->pRoutePointList->Insert(nRP, pMousePoint);
8822 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
8824 pSelect->AddAllSelectableRouteSegments(pr);
8825 pSelect->AddAllSelectableRoutePoints(pr);
8827 pr->FinalizeForRendering();
8828 pr->UpdateSegmentDistances();
8829 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
8835 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
8836 if (m_pEditRouteArray) {
8837 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8839 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8840 if (g_pRouteMan->IsRouteValid(pr)) {
8841 if (pRoutePropDialog->GetRoute() == pr) {
8842 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
8857 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
8858 pWayPointMan->RemoveRoutePoint(m_pRoutePointEditTarget);
8860 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
8861 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8862 g_pMarkInfoDialog->Hide();
8864 delete m_pRoutePointEditTarget;
8865 m_lastRoutePointEditTarget = NULL;
8866 m_pRoutePointEditTarget = NULL;
8867 undo->AfterUndoableAction(pMousePoint);
8868 undo->InvalidateUndo();
8873 else if (m_bMarkEditing) {
8874 if (m_pRoutePointEditTarget)
8875 if (m_bRoutePoinDragging)
8876 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
8879 if (m_pRoutePointEditTarget)
8880 undo->AfterUndoableAction(m_pRoutePointEditTarget);
8882 if (!m_pRoutePointEditTarget) {
8883 delete m_pEditRouteArray;
8884 m_pEditRouteArray = NULL;
8885 m_bRouteEditing =
false;
8887 m_bRoutePoinDragging =
false;
8894 int length = tail->GetnPoints();
8895 for (
int i = connect + 1; i <= length; i++) {
8896 current->AddPointAndSegment(tail->GetPoint(i),
false);
8897 if (current) current->m_lastMousePointIndex = current->GetnPoints();
8899 gFrame->RefreshAllCanvas();
8902 current->FinalizeForRendering();
8903 current->m_bIsBeingEdited =
false;
8906 for (
int i = 1; i < connect; i++) {
8907 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
8909 current->FinalizeForRendering();
8910 current->m_bIsBeingEdited =
false;
8914 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
8915 if (m_pEditRouteArray) {
8916 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8917 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8918 if (g_pRouteMan->IsRouteValid(pr)) {
8919 if (pRoutePropDialog->GetRoute() == pr) {
8920 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
8930 if (m_bRouteEditing) {
8931 Route *tail, *current;
8932 bool appending =
false;
8933 bool inserting =
false;
8936 if (m_pRoutePointEditTarget) {
8937 m_pRoutePointEditTarget->m_bBlink =
false;
8941 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
8942 double nearby_radius_meters =
8943 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8944 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
8945 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
8946 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
8947 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
8948 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
8949 bool duplicate =
false;
8950 if (m_pEditRouteArray && !pNearbyPoint->m_bIsolatedMark) {
8951 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8953 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8954 if (pr && pr->pRoutePointList) {
8955 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
8968 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
8973 OCPNMessageBox(
this,
8974 _(
"Replace this RoutePoint by the nearby "
8976 _(
"OpenCPN RoutePoint change"),
8977 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8978 if (dlg_return == wxID_YES) {
8982 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
8984 current = FindRouteContainingWaypoint(
8985 m_pRoutePointEditTarget);
8987 if (tail && current && (tail != current)) {
8989 connect = tail->GetIndexOf(pNearbyPoint);
8990 int index_current_route =
8991 current->GetIndexOf(m_pRoutePointEditTarget);
8992 index_last = current->GetIndexOf(current->GetLastPoint());
8993 dlg_return1 = wxID_NO;
8995 index_current_route) {
8997 if (connect != tail->GetnPoints()) {
9000 _(
"Last part of route to be appended to dragged "
9004 _(
"Full route to be appended to dragged route?");
9006 dlg_return1 = OCPNMessageBox(
9007 this, dmsg, _(
"OpenCPN Route Create"),
9008 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9009 if (dlg_return1 == wxID_YES) {
9013 }
else if (index_current_route ==
9018 _(
"First part of route to be inserted into dragged "
9020 if (connect == tail->GetnPoints())
9022 "Full route to be inserted into dragged route?");
9024 dlg_return1 = OCPNMessageBox(
9025 this, dmsg, _(
"OpenCPN Route Create"),
9026 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9027 if (dlg_return1 == wxID_YES) {
9034 if (m_pRoutePointEditTarget->IsShared()) {
9035 dlg_return = wxID_NO;
9036 dlg_return = OCPNMessageBox(
9038 _(
"Do you really want to delete and replace this "
9040 _T(
"\n") + _(
"which has been created manually?"),
9041 (
"OpenCPN RoutePoint warning"),
9042 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9045 if (dlg_return == wxID_YES) {
9046 pMousePoint = pNearbyPoint;
9047 if (pMousePoint->m_bIsolatedMark) {
9048 pMousePoint->SetShared(
true);
9050 pMousePoint->m_bIsolatedMark =
9052 pMousePoint->m_bIsInRoute =
true;
9058 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9060 if (m_pEditRouteArray) {
9061 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9063 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9064 if (g_pRouteMan->IsRouteValid(pr)) {
9067 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9069 pSelect->DeleteAllSelectableRoutePoints(pr);
9070 pSelect->DeleteAllSelectableRouteSegments(pr);
9072 pr->pRoutePointList->Insert(nRP, pMousePoint);
9073 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9075 pSelect->AddAllSelectableRouteSegments(pr);
9076 pSelect->AddAllSelectableRoutePoints(pr);
9078 pr->FinalizeForRendering();
9079 pr->UpdateSegmentDistances();
9080 pr->m_bIsBeingEdited =
false;
9082 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9094 int length = tail->GetnPoints();
9095 for (
int i = connect + 1; i <= length; i++) {
9096 current->AddPointAndSegment(tail->GetPoint(i),
false);
9098 current->m_lastMousePointIndex = current->GetnPoints();
9100 gFrame->RefreshAllCanvas();
9103 current->FinalizeForRendering();
9104 current->m_bIsBeingEdited =
false;
9108 for (
int i = 1; i < connect; i++) {
9109 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9111 current->FinalizeForRendering();
9112 current->m_bIsBeingEdited =
false;
9116 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9117 if (m_pEditRouteArray) {
9118 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9120 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9121 if (g_pRouteMan->IsRouteValid(pr)) {
9122 if (pRoutePropDialog->GetRoute() == pr) {
9123 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9131 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9132 pWayPointMan->RemoveRoutePoint(m_pRoutePointEditTarget);
9134 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9135 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9136 g_pMarkInfoDialog->Hide();
9138 delete m_pRoutePointEditTarget;
9139 m_lastRoutePointEditTarget = NULL;
9140 undo->AfterUndoableAction(pMousePoint);
9141 undo->InvalidateUndo();
9143 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9144 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9146 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9149 delete m_pEditRouteArray;
9150 m_pEditRouteArray = NULL;
9154 m_bRouteEditing =
false;
9155 m_pRoutePointEditTarget = NULL;
9157 if (m_toolBar && !m_toolBar->IsToolbarShown()) SurfaceToolbar();
9161 else if (m_bMarkEditing) {
9162 if (m_pRoutePointEditTarget) {
9163 if (m_bRoutePoinDragging)
9164 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9165 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9166 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9168 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this, &wp_rect);
9169 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9170 RefreshRect(wp_rect,
true);
9172 m_pRoutePointEditTarget = NULL;
9173 m_bMarkEditing =
false;
9174 if (m_toolBar && !m_toolBar->IsToolbarShown()) SurfaceToolbar();
9178 else if (leftIsDown) {
9183 if (!m_bChartDragging && !m_bMeasure_Active) {
9185 m_bChartDragging =
false;
9189 m_bRoutePoinDragging =
false;
9192 if (ret)
return true;
9195 if (event.RightDown()) {
9206 m_FinishRouteOnKillFocus =
false;
9207 CallPopupMenu(mx, my);
9208 m_FinishRouteOnKillFocus =
true;
9216bool ChartCanvas::MouseEventProcessCanvas(wxMouseEvent &event) {
9218 event.GetPosition(&x, &y);
9220 x *= m_displayScale;
9221 y *= m_displayScale;
9227 int wheel_dir =
event.GetWheelRotation();
9230 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9231 wheel_dir = wheel_dir > 0 ? 1 : -1;
9233 double factor = g_mouse_zoom_sensitivity;
9234 if (wheel_dir < 0) factor = 1 / factor;
9236 if (g_bsmoothpanzoom) {
9237 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9238 if (wheel_dir == m_last_wheel_dir) {
9239 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9244 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9245 m_wheelstopwatch.Start(0);
9250 m_last_wheel_dir = wheel_dir;
9252 ZoomCanvas(factor,
true,
false);
9255 if (event.LeftDown()) {
9257 if ((GetCanvasCount() > 1) && (
this != g_focusCanvas)) {
9262 last_drag.x = x, last_drag.y = y;
9263 panleftIsDown =
true;
9266 if (event.LeftUp()) {
9267 if (panleftIsDown) {
9269 panleftIsDown =
false;
9272 if (!m_bChartDragging && !m_bMeasure_Active) {
9273 switch (cursor_region) {
9295 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
9300 m_bChartDragging =
false;
9306 if (event.Dragging() && event.LeftIsDown()) {
9323 if (
false == m_bChartDragging) {
9324 last_drag.x = x, last_drag.y = y;
9325 m_bChartDragging =
true;
9329 if ((last_drag.x != x) || (last_drag.y != y)) {
9332 m_bChartDragging =
true;
9333 StartTimedMovement();
9334 m_pan_drag.x += last_drag.x - x;
9335 m_pan_drag.y += last_drag.y - y;
9337 last_drag.x = x, last_drag.y = y;
9341 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
9343 m_DoubleClickTimer->Start();
9344 singleClickEventIsValid =
false;
9353void ChartCanvas::MouseEvent(wxMouseEvent &event) {
9354 if (MouseEventOverlayWindows(event))
return;
9358 if (!MouseEventProcessObjects(event)) MouseEventProcessCanvas(event);
9361void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
9364 wxCursor *ptarget_cursor = pCursorArrow;
9365 if (!pPlugIn_Cursor) {
9366 ptarget_cursor = pCursorArrow;
9367 if ((!m_routeState) &&
9368 (!m_bMeasure_Active) ) {
9369 if (cursor_region == MID_RIGHT) {
9370 ptarget_cursor = pCursorRight;
9371 }
else if (cursor_region == MID_LEFT) {
9372 ptarget_cursor = pCursorLeft;
9373 }
else if (cursor_region == MID_TOP) {
9374 ptarget_cursor = pCursorDown;
9375 }
else if (cursor_region == MID_BOT) {
9376 ptarget_cursor = pCursorUp;
9378 ptarget_cursor = pCursorArrow;
9380 }
else if (m_bMeasure_Active ||
9382 ptarget_cursor = pCursorPencil;
9384 ptarget_cursor = pPlugIn_Cursor;
9387 SetCursor(*ptarget_cursor);
9390void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
9391 SetCursor(*pCursorArrow);
9394void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
9398 wxArrayString files;
9400 ChartBase *target_chart = GetChartAtCursor();
9402 file.Assign(target_chart->GetFullPath());
9403 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
9404 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
9407 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
9409 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
9410 unsigned int im = stackIndexArray.size();
9411 int scale = 2147483647;
9412 if (VPoint.b_quilt && im > 0) {
9413 for (
unsigned int is = 0; is < im; is++) {
9414 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
9415 CHART_TYPE_MBTILES) {
9416 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
9418 VPoint.GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
9419 if (ChartData->GetChartTableEntry(stackIndexArray[is])
9421 .Contains(lat, lon)) {
9422 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
9425 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
9426 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
9434 std::vector<Ais8_001_22 *> area_notices;
9436 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
9437 float vp_scale = GetVPScale();
9439 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
9440 auto target_data = target.second;
9441 if (!target_data->area_notices.empty()) {
9442 for (
auto &ani : target_data->area_notices) {
9447 for (Ais8_001_22_SubAreaList::iterator sa =
9448 area_notice.sub_areas.begin();
9449 sa != area_notice.sub_areas.end(); ++sa) {
9450 switch (sa->shape) {
9451 case AIS8_001_22_SHAPE_CIRCLE: {
9452 wxPoint target_point;
9453 GetCanvasPointPix(sa->latitude, sa->longitude, &target_point);
9454 bbox.Expand(target_point);
9455 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
9458 case AIS8_001_22_SHAPE_POLYGON:
9459 case AIS8_001_22_SHAPE_POLYLINE: {
9460 for (
int i = 0; i < 4; ++i) {
9461 double lat = sa->latitude;
9462 double lon = sa->longitude;
9463 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
9465 wxPoint target_point;
9466 GetCanvasPointPix(lat, lon, &target_point);
9467 bbox.Expand(target_point);
9473 if (bbox.PointInBox(x, y)) {
9474 area_notices.push_back(&area_notice);
9481 if (target_chart || !area_notices.empty() || file.HasName()) {
9483 int sel_rad_pix = 5;
9484 float SelectRadius = sel_rad_pix / (GetVP().view_scale_ppm * 1852 * 60);
9489 SetCursor(wxCURSOR_WAIT);
9490 bool lightsVis = m_encShowLights;
9491 if (!lightsVis) SetShowENCLights(
true);
9494 ListOfObjRazRules *rule_list = NULL;
9495 ListOfPI_S57Obj *pi_rule_list = NULL;
9498 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
9499 else if (target_plugin_chart)
9500 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
9501 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
9503 ListOfObjRazRules *overlay_rule_list = NULL;
9504 ChartBase *overlay_chart = GetOverlayChartAtCursor();
9507 if (CHs57_Overlay) {
9508 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
9509 zlat, zlon, SelectRadius, &GetVP());
9512 if (!lightsVis) SetShowENCLights(
false);
9515 wxFont *dFont = FontMgr::Get().GetFont(_(
"ObjectQuery"));
9516 wxString face = dFont->GetFaceName();
9518 if (NULL == g_pObjectQueryDialog) {
9519 g_pObjectQueryDialog =
9520 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
9521 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
9524 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
9525 wxColor fg = FontMgr::Get().GetFontColor(_(
"ObjectQuery"));
9529 fg = g_pObjectQueryDialog->GetForegroundColour();
9533 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
9534 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
9537 int points = dFont->GetPointSize();
9539 int points = dFont->GetPointSize() + 1;
9543 for (
int i = -2; i < 5; i++) {
9544 sizes[i + 2] = points + i + (i > 0 ? i : 0);
9546 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
9548 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
9550 if (overlay_rule_list && CHs57_Overlay) {
9551 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
9552 objText << _T(
"<hr noshade>");
9555 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
9556 an != area_notices.end(); ++an) {
9557 objText << _T(
"<b>AIS Area Notice:</b> " );
9558 objText << ais8_001_22_notice_names[(*an)->notice_type];
9559 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
9560 (*an)->sub_areas.begin();
9561 sa != (*an)->sub_areas.end(); ++sa)
9562 if (!sa->text.empty()) objText << sa->text;
9563 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
9564 objText << _T(
"<hr noshade>" );
9568 objText << Chs57->CreateObjDescriptions(rule_list);
9569 else if (target_plugin_chart)
9570 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
9573 objText << _T(
"</font>");
9574 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
9577 wxString AddFiles, filenameOK;
9579 if (!target_plugin_chart) {
9582 AddFiles = wxString::Format(
9583 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
9585 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
9586 _T(
"cellpadding=3>"),
9587 file.GetFullName());
9589 file.Assign(file.GetPath(), wxT(
""));
9590 wxDir dir( file.GetFullPath() );
9592 bool cont = dir.GetFirst( &filename,
"", wxDIR_FILES );
9595 file.Assign( dir.GetNameWithSep().append( filename) );
9596 wxString FormatString = _T(
"<td valign=top><font size=-2><a href=\"%s\">%s</a></font></td>");
9597 if( g_ObjQFileExt.Find( file.GetExt().Lower() ) != wxNOT_FOUND )
9599 filenameOK=file.GetFullPath();
9601 if ( 3*((
int)filecount/3) == filecount )
9602 FormatString.Prepend(_T(
"<tr>"));
9604 FormatString.Prepend(_T(
"<td>  </td>"));
9606 AddFiles << wxString::Format(FormatString, file.GetFullPath(), file.GetFullName());
9609 cont = dir.GetNext(&filename);
9611 objText << AddFiles << _T(
"</table>");
9614 objText << _T(
"</body></html>");
9616 if (Chs57 || target_plugin_chart || (filecount > 1)) {
9617 g_pObjectQueryDialog->SetHTMLPage(objText);
9618 g_pObjectQueryDialog->Show();
9620 if ((!Chs57 && filecount == 1)){
9622 wxHtmlLinkInfo hli(filenameOK);
9623 wxHtmlLinkEvent hle(1, hli);
9624 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
9627 if (rule_list) rule_list->Clear();
9630 if (overlay_rule_list) overlay_rule_list->Clear();
9631 delete overlay_rule_list;
9633 if (pi_rule_list) pi_rule_list->Clear();
9634 delete pi_rule_list;
9636 SetCursor(wxCURSOR_ARROW);
9640void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
9642 if (!g_pMarkInfoDialog) {
9649 wxSize canvas_size = GetSize();
9651 int best_size_y = wxMin(400 / OCPN_GetWinDIPScaleFactor(), canvas_size.y);
9652 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
9654 g_pMarkInfoDialog->Layout();
9656 wxPoint canvas_pos = GetPosition();
9657 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
9659 bool newFit =
false;
9660 if (canvas_size.x < fitted_size.x) {
9661 fitted_size.x = canvas_size.x - 40;
9662 if (canvas_size.y < fitted_size.y)
9663 fitted_size.y -= 40;
9665 if (canvas_size.y < fitted_size.y) {
9666 fitted_size.y = canvas_size.y - 40;
9667 if (canvas_size.x < fitted_size.x)
9668 fitted_size.x -= 40;
9672 g_pMarkInfoDialog->SetSize(fitted_size);
9673 g_pMarkInfoDialog->Centre();
9677 markPoint->m_bRPIsBeingEdited =
false;
9679 g_pMarkInfoDialog->SetRoutePoint(markPoint);
9680 g_pMarkInfoDialog->UpdateProperties();
9681 if (markPoint->m_bIsInLayer) {
9682 wxString caption(wxString::Format(_T(
"%s, %s: %s"),
9683 _(
"Waypoint Properties"), _(
"Layer"),
9684 GetLayerName(markPoint->m_LayerID)));
9685 g_pMarkInfoDialog->SetDialogTitle(caption);
9687 g_pMarkInfoDialog->SetDialogTitle(_(
"Waypoint Properties"));
9689 g_pMarkInfoDialog->Show();
9690 g_pMarkInfoDialog->Raise();
9691 g_pMarkInfoDialog->InitialFocus();
9692 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
9695void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
9696 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
9697 pRoutePropDialog->SetRouteAndUpdate(selected);
9699 pRoutePropDialog->Show();
9700 pRoutePropDialog->Raise();
9702 pRoutePropDialog = RoutePropDlgImpl::getInstance(
9705 if (g_bresponsive) {
9706 wxSize canvas_size = GetSize();
9707 wxPoint canvas_pos = GetPosition();
9708 wxSize fitted_size = pRoutePropDialog->GetSize();
9711 if (canvas_size.x < fitted_size.x) {
9712 fitted_size.x = canvas_size.x;
9713 if (canvas_size.y < fitted_size.y)
9714 fitted_size.y -= 20;
9716 if (canvas_size.y < fitted_size.y) {
9717 fitted_size.y = canvas_size.y;
9718 if (canvas_size.x < fitted_size.x)
9719 fitted_size.x -= 20;
9722 pRoutePropDialog->SetSize(fitted_size);
9723 pRoutePropDialog->Centre();
9728 wxPoint xxp = ClientToScreen(canvas_pos);
9732 pRoutePropDialog->SetRouteAndUpdate(selected);
9734 pRoutePropDialog->Show();
9739void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
9740 pTrackPropDialog = TrackPropDlg::getInstance(
9743 pTrackPropDialog->SetTrackAndUpdate(selected);
9746 pTrackPropDialog->Show();
9751void pupHandler_PasteWaypoint() {
9754 int pasteBuffer = kml.ParsePasteBuffer();
9755 RoutePoint *pasted = kml.GetParsedRoutePoint();
9756 if (!pasted)
return;
9758 double nearby_radius_meters =
9759 g_Platform->GetSelectRadiusPix() /
9760 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
9762 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
9763 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
9765 int answer = wxID_NO;
9766 if (nearPoint && !nearPoint->m_bIsInLayer) {
9769 "There is an existing waypoint at the same location as the one you are "
9770 "pasting. Would you like to merge the pasted data with it?\n\n");
9771 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
9772 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
9773 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
9776 if (answer == wxID_YES) {
9777 nearPoint->SetName(pasted->GetName());
9778 nearPoint->m_MarkDescription = pasted->m_MarkDescription;
9779 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
9780 pRouteManagerDialog->UpdateWptListCtrl();
9783 if (answer == wxID_NO) {
9785 newPoint->m_bIsolatedMark =
true;
9786 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
9788 pConfig->AddNewWayPoint(newPoint, -1);
9789 pWayPointMan->AddRoutePoint(newPoint);
9790 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
9791 pRouteManagerDialog->UpdateWptListCtrl();
9792 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
9793 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
9796 gFrame->InvalidateAllGL();
9797 gFrame->RefreshAllCanvas(
false);
9800void pupHandler_PasteRoute() {
9803 int pasteBuffer = kml.ParsePasteBuffer();
9804 Route *pasted = kml.GetParsedRoute();
9805 if (!pasted)
return;
9807 double nearby_radius_meters =
9808 g_Platform->GetSelectRadiusPix() /
9809 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
9815 bool mergepoints =
false;
9816 bool createNewRoute =
true;
9817 int existingWaypointCounter = 0;
9819 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
9820 curPoint = pasted->GetPoint(i);
9821 nearPoint = pWayPointMan->GetNearbyWaypoint(
9822 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
9825 existingWaypointCounter++;
9829 curPoint->m_bPtIsSelected =
true;
9833 int answer = wxID_NO;
9837 "There are existing waypoints at the same location as some of the ones "
9838 "you are pasting. Would you like to just merge the pasted data into "
9840 msg << _(
"Answering 'No' will create all new waypoints for this route.");
9841 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
9842 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9844 if (answer == wxID_CANCEL) {
9851 if (mergepoints && answer == wxID_YES &&
9852 existingWaypointCounter == pasted->GetnPoints()) {
9853 wxRouteListNode *route_node = pRouteList->GetFirst();
9854 while (route_node) {
9855 Route *proute = route_node->GetData();
9857 if (pasted->m_RouteNameString == proute->m_RouteNameString) {
9858 createNewRoute =
false;
9861 route_node = route_node->GetNext();
9865 Route *newRoute = 0;
9868 if (createNewRoute) {
9869 newRoute =
new Route();
9870 newRoute->m_RouteNameString = pasted->m_RouteNameString;
9873 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
9874 curPoint = pasted->GetPoint(i);
9875 if (answer == wxID_YES && curPoint->m_bPtIsSelected) {
9876 curPoint->m_bPtIsSelected =
false;
9877 newPoint = pWayPointMan->GetNearbyWaypoint(
9878 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
9879 newPoint->SetName(curPoint->GetName());
9880 newPoint->m_MarkDescription = curPoint->m_MarkDescription;
9882 if (createNewRoute) newRoute->AddPoint(newPoint);
9884 curPoint->m_bPtIsSelected =
false;
9887 newPoint->m_bIsolatedMark =
false;
9888 newPoint->SetIconName(_T(
"circle"));
9889 newPoint->m_bIsVisible =
true;
9890 newPoint->m_bShowName =
false;
9891 newPoint->SetShared(
false);
9893 newRoute->AddPoint(newPoint);
9894 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
9896 pConfig->AddNewWayPoint(newPoint, -1);
9897 pWayPointMan->AddRoutePoint(newPoint);
9899 if (i > 1 && createNewRoute)
9900 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
9901 curPoint->m_lat, curPoint->m_lon,
9902 prevPoint, newPoint, newRoute);
9903 prevPoint = newPoint;
9906 if (createNewRoute) {
9907 pRouteList->Append(newRoute);
9908 pConfig->AddNewRoute(newRoute);
9910 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9911 pRoutePropDialog->SetRouteAndUpdate(newRoute);
9914 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
9915 pRouteManagerDialog->UpdateRouteListCtrl();
9916 pRouteManagerDialog->UpdateWptListCtrl();
9918 gFrame->InvalidateAllGL();
9919 gFrame->RefreshAllCanvas(
false);
9921 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
9922 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
9925void pupHandler_PasteTrack() {
9928 int pasteBuffer = kml.ParsePasteBuffer();
9929 Track *pasted = kml.GetParsedTrack();
9930 if (!pasted)
return;
9938 newTrack->SetName(pasted->GetName());
9940 for (
int i = 0; i < pasted->GetnPoints(); i++) {
9941 curPoint = pasted->GetPoint(i);
9945 wxDateTime now = wxDateTime::Now();
9946 newPoint->SetCreateTime(curPoint->GetCreateTime());
9948 newTrack->AddPoint(newPoint);
9951 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
9952 newPoint->m_lat, newPoint->m_lon,
9953 prevPoint, newPoint, newTrack);
9955 prevPoint = newPoint;
9958 g_TrackList.push_back(newTrack);
9959 pConfig->AddNewTrack(newTrack);
9961 gFrame->InvalidateAllGL();
9962 gFrame->RefreshAllCanvas(
false);
9965bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
9967 m_pFoundRoutePoint, m_FoundAIS_MMSI,
9971 wxEVT_COMMAND_MENU_SELECTED,
9972 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
9974 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
9977 wxEVT_COMMAND_MENU_SELECTED,
9978 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
9980 delete m_canvasMenu;
9981 m_canvasMenu = NULL;
9991void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
9995 m_canvasMenu->PopupMenuHandler(event);
10000void ChartCanvas::StartRoute(
void) {
10002 if (g_brouteCreating)
return;
10004 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10006 g_brouteCreating =
true;
10008 m_bDrawingRoute =
false;
10009 SetCursor(*pCursorPencil);
10010 SetCanvasToolbarItemState(ID_ROUTE,
true);
10011 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10013 HideGlobalToolbar();
10015#ifdef __OCPN__ANDROID__
10016 androidSetRouteAnnunciator(
true);
10020void ChartCanvas::FinishRoute(
void) {
10022 m_prev_pMousePoint = NULL;
10023 m_bDrawingRoute =
false;
10025 SetCanvasToolbarItemState(ID_ROUTE,
false);
10026 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10027#ifdef __OCPN__ANDROID__
10028 androidSetRouteAnnunciator(
false);
10031 SetCursor(*pCursorArrow);
10033 if (m_pMouseRoute) {
10034 if (m_bAppendingRoute)
10035 pConfig->UpdateRoute(m_pMouseRoute);
10037 if (m_pMouseRoute->GetnPoints() > 1) {
10038 pConfig->AddNewRoute(m_pMouseRoute);
10041 NavObjectChanges::getInstance());
10042 m_pMouseRoute = NULL;
10045 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10047 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10048 (pRoutePropDialog->IsShown())) {
10049 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10052 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10053 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10054 pRouteManagerDialog->UpdateRouteListCtrl();
10057 m_bAppendingRoute =
false;
10058 m_pMouseRoute = NULL;
10060 m_pSelectedRoute = NULL;
10062 undo->InvalidateUndo();
10063 gFrame->RefreshAllCanvas(
true);
10065 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10067 ShowGlobalToolbar();
10069 g_brouteCreating =
false;
10072void ChartCanvas::HideGlobalToolbar() {
10073 if (m_canvasIndex == 0) {
10074 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10078void ChartCanvas::ShowGlobalToolbar() {
10079 if (m_canvasIndex == 0) {
10080 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10084void ChartCanvas::ShowAISTargetList(
void) {
10085 if (NULL == g_pAISTargetList) {
10089 g_pAISTargetList->UpdateAISTargetList();
10092void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10093 if (!m_bShowOutlines)
return;
10095 if (!ChartData)
return;
10097 int nEntry = ChartData->GetChartTableEntries();
10099 for (
int i = 0; i < nEntry; i++) {
10103 bool b_group_draw =
false;
10104 if (m_groupIndex > 0) {
10105 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10106 int index = pt->GetGroupArray()[ig];
10107 if (m_groupIndex == index) {
10108 b_group_draw =
true;
10113 b_group_draw =
true;
10115 if (b_group_draw) RenderChartOutline(dc, i, vp);
10121 if (VPoint.b_quilt) {
10122 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10123 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10127 }
else if (m_singleChart &&
10128 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10132 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10133 double zoom_factor = GetVP().view_scale_ppm / chart_native_ppm;
10135 if (zoom_factor > 8.0) {
10136 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10139 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10147void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10149 if (g_bopengl && m_glcc) {
10151 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10156 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10157 if (!ChartData->IsChartAvailable(dbIndex))
return;
10160 float plylat, plylon;
10161 float plylat1, plylon1;
10163 int pixx, pixy, pixx1, pixy1;
10166 ChartData->GetDBBoundingBox(dbIndex, box);
10170 if (box.GetLonRange() == 360)
return;
10172 double lon_bias = 0;
10174 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10176 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10178 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10179 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10181 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10182 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10185 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10188 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10189 if (0 == nAuxPlyEntries)
10193 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10194 plylon += lon_bias;
10196 GetCanvasPointPix(plylat, plylon, &r);
10200 for (
int i = 0; i < nPly - 1; i++) {
10201 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
10202 plylon1 += lon_bias;
10204 GetCanvasPointPix(plylat1, plylon1, &r1);
10208 int pixxs1 = pixx1;
10209 int pixys1 = pixy1;
10211 bool b_skip =
false;
10213 if (vp.chart_scale > 5e7) {
10215 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
10216 pow((
double)(pixy1 - pixy), 2)) /
10222 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10227 if (fabs(dist - distgc) > 10000. * 1852.)
10233 ClipResult res = cohen_sutherland_line_clip_i(
10234 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10235 if (res != Invisible && !b_skip)
10236 dc.DrawLine(pixx, pixy, pixx1, pixy1,
false);
10244 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
10245 plylon1 += lon_bias;
10247 GetCanvasPointPix(plylat1, plylon1, &r1);
10251 ClipResult res = cohen_sutherland_line_clip_i(
10252 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10253 if (res != Invisible) dc.DrawLine(pixx, pixy, pixx1, pixy1,
false);
10260 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10261 for (
int j = 0; j < nAuxPlyEntries; j++) {
10263 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
10264 GetCanvasPointPix(plylat, plylon, &r);
10268 for (
int i = 0; i < nAuxPly - 1; i++) {
10269 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
10271 GetCanvasPointPix(plylat1, plylon1, &r1);
10275 int pixxs1 = pixx1;
10276 int pixys1 = pixy1;
10278 bool b_skip =
false;
10280 if (vp.chart_scale > 5e7) {
10282 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
10283 ((pixy1 - pixy) * (pixy1 - pixy))) /
10288 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10293 if (fabs(dist - distgc) > 10000. * 1852.)
10299 ClipResult res = cohen_sutherland_line_clip_i(
10300 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10301 if (res != Invisible && !b_skip) dc.DrawLine(pixx, pixy, pixx1, pixy1);
10309 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
10310 GetCanvasPointPix(plylat1, plylon1, &r1);
10314 ClipResult res = cohen_sutherland_line_clip_i(
10315 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10316 if (res != Invisible) dc.DrawLine(pixx, pixy, pixx1, pixy1,
false);
10321static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
10322 const wxString &second) {
10323 wxFont *dFont = FontMgr::Get().GetFont(_(
"RouteLegInfoRollover"));
10325 int pointsize = dFont->GetPointSize();
10326 pointsize /= OCPN_GetWinDIPScaleFactor();
10328 wxFont *psRLI_font = FontMgr::Get().FindOrCreateFont(
10329 pointsize, dFont->GetFamily(), dFont->GetStyle(),
10330 dFont->GetWeight(),
false, dFont->GetFaceName());
10333 dc.SetFont(*psRLI_font);
10341 int hilite_offset = 3;
10344 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
10345 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
10347 dc.GetTextExtent(first, &w1, &h1);
10348 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
10351 h1 *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
10352 h2 *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
10354 w = wxMax(w1, w2) + (h1 / 2);
10355 w *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
10359 xp = ref_point.x - w;
10361 yp += hilite_offset;
10363 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
10365 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
10366 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
10368 dc.DrawText(first, xp, yp);
10369 if (second.Len()) dc.DrawText(second, xp, yp + h1);
10372void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
10373 if (!g_bAllowShipToActive)
return;
10375 Route *rt = g_pRouteMan->GetpActiveRoute();
10378 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
10379 wxPoint2DDouble pa, pb;
10380 GetDoubleCanvasPointPix(gLat, gLon, &pa);
10381 GetDoubleCanvasPointPix(rp->m_lat, rp->m_lon, &pb);
10385 g_pRouteMan->GetRoutePen()->GetWidth();
10386 if (rt->m_width != wxPENSTYLE_INVALID)
10387 width = rt->m_width;
10388 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
10389 g_shipToActiveStyle, 5)];
10390 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
10392 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
10394 g_pRouteMan->GetActiveRoutePen()->GetColour();
10395 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
10398 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
10401 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x, (
int)pb.m_y,
10406 glLineWidth(wxMax(g_GLMinSymbolLineWidth, width));
10409#ifdef USE_ANDROID_GLES2
10410 dc.DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
10412 glColor3ub(color.Red(), color.Green(), color.Blue());
10414 glVertex2f(pa.m_x, pa.m_y);
10415 glVertex2f(pb.m_x, pb.m_y);
10418 glDisable(GL_LINE_STIPPLE);
10420 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
10421 (
int)pb.m_y, GetVP());
10427void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
10429 if (m_routeState >= 2) route = m_pMouseRoute;
10430 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
10431 route = m_pMeasureRoute;
10433 if (!route)
return;
10436 if( !g_pRouteMan->IsRouteValid(route) )
10439 double render_lat = m_cursor_lat;
10440 double render_lon = m_cursor_lon;
10442 int np = route->GetnPoints();
10444 if (g_btouch && (np > 1)) np--;
10446 render_lat = rp.m_lat;
10447 render_lon = rp.m_lon;
10450 double rhumbBearing, rhumbDist;
10451 DistanceBearingMercator(m_cursor_lat, m_cursor_lon, render_lat, render_lon,
10452 &rhumbBearing, &rhumbDist);
10453 double brg = rhumbBearing;
10454 double dist = rhumbDist;
10458 double gcBearing, gcBearing2, gcDist;
10459 Geodesic::GreatCircleDistBear(render_lon, render_lat, m_cursor_lon,
10460 m_cursor_lat, &gcDist, &gcBearing,
10462 double gcDistm = gcDist / 1852.0;
10464 if ((render_lat == m_cursor_lat) && (render_lon == m_cursor_lon))
10465 rhumbBearing = 90.;
10467 wxPoint destPoint, lastPoint;
10469 route->m_NextLegGreatCircle =
false;
10470 int milesDiff = rhumbDist - gcDistm;
10471 if (milesDiff > 1) {
10474 route->m_NextLegGreatCircle =
true;
10478 RouteGui(*route).DrawPointWhich(dc,
this, route->m_lastMousePointIndex, &lastPoint);
10480 if (route->m_NextLegGreatCircle) {
10481 for (
int i = 1; i <= milesDiff; i++) {
10482 double p = (double)i * (1.0 / (
double)milesDiff);
10484 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
10485 &pLon, &pLat, &gcBearing2);
10486 destPoint = VPoint.GetPixFromLL(pLat, pLon);
10487 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
false);
10488 lastPoint = destPoint;
10491 if (r_rband.x && r_rband.y) {
10492 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
false);
10493 if (m_bMeasure_DistCircle) {
10494 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
10495 powf((
float)(r_rband.y - lastPoint.y), 2));
10497 dc.SetPen(*g_pRouteMan->GetRoutePen());
10498 dc.SetBrush(*wxTRANSPARENT_BRUSH);
10499 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
10505 wxString routeInfo;
10507 routeInfo << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
10511 double latAverage = (m_cursor_lat + render_lat) / 2;
10512 double lonAverage = (m_cursor_lon + render_lon) / 2;
10513 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
10515 routeInfo << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
10519 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
10522 if (!route->m_bIsInLayer)
10523 s0.Append(_(
"Route") + _T(
": "));
10525 s0.Append(_(
"Layer Route: "));
10527 double disp_length = route->m_route_length;
10528 if (!g_btouch) disp_length += dist;
10529 s0 += FormatDistanceAdaptive(disp_length);
10531 RouteLegInfo(dc, r_rband, routeInfo, s0);
10533 m_brepaint_piano =
true;
10536void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
10537 if (!m_bShowVisibleSectors)
return;
10539 if (g_bDeferredInitDone) {
10541 double rhumbBearing, rhumbDist;
10542 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
10543 &rhumbBearing, &rhumbDist);
10545 if (rhumbDist > 0.05)
10547 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
10548 m_sectorlegsVisible);
10549 m_sector_glat = gLat;
10550 m_sector_glon = gLon;
10552 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
10556void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
10564void ChartCanvas::UpdateCanvasS52PLIBConfig() {
10565 if (!ps52plib)
return;
10567 if (VPoint.b_quilt) {
10568 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
10570 if (m_pQuilt->IsQuiltVector()) {
10571 if (ps52plib->GetStateHash() != m_s52StateHash) {
10573 m_s52StateHash = ps52plib->GetStateHash();
10577 if (ps52plib->GetStateHash() != m_s52StateHash) {
10579 m_s52StateHash = ps52plib->GetStateHash();
10584 bool bSendPlibState =
true;
10585 if (VPoint.b_quilt) {
10586 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
10589 if (bSendPlibState) {
10591 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
10592 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
10593 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
10594 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
10595 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
10598 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
10599 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
10600 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
10601 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] =
10603 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] =
10604 GetShowENCDataQual();
10605 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
10606 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
10608 v[_T(
"OpenCPN S52PLIB DisplayCategory")] = GetENCDisplayCategory();
10610 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
10611 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
10615 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
10616 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
10617 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
10618 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] = ps52plib->m_bShowS57ImportantTextOnly;
10619 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
10620 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
10621 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
10622 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
10623 v[_T(
"OpenCPN S52PLIB ColorShades")] = S52_getMarinerParam( S52_MAR_TWO_SHADES );
10626 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
10627 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
10628 v[_T(
"OpenCPN Scale Factor Exp")] = g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
10629 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
10635 if (!g_lastPluginMessage.IsSameAs(out)) {
10637 g_pi_manager->SendMessageToAllPlugins(wxString(_T(
"OpenCPN Config")),
10644void ChartCanvas::OnPaint(wxPaintEvent &event) {
10645 wxPaintDC dc(
this);
10655 if (!m_b_paint_enable) {
10660 UpdateCanvasS52PLIBConfig();
10663 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
10665 if (m_glcc && g_bopengl) {
10666 if (!s_in_update) {
10676 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
10678 wxRegion ru = GetUpdateRegion();
10680 int rx, ry, rwidth, rheight;
10681 ru.GetBox(rx, ry, rwidth, rheight);
10685#ifdef ocpnUSE_DIBSECTION
10688 wxMemoryDC temp_dc;
10691 long height = GetVP().pix_height;
10696 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
10697 height += m_Piano->GetHeight();
10699 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
10703 int thumbx, thumby, thumbsx, thumbsy;
10704 pthumbwin->GetPosition(&thumbx, &thumby);
10705 pthumbwin->GetSize(&thumbsx, &thumbsy);
10706 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
10708 if (pthumbwin->IsShown()) {
10709 rgn_chart.Subtract(rgn_thumbwin);
10710 ru.Subtract(rgn_thumbwin);
10716 wxRegion rgn_blit = ru;
10717 if (g_bShowChartBar) {
10718 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
10719 GetClientSize().x, m_Piano->GetHeight());
10722 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
10723 if (style->chartStatusWindowTransparent)
10724 m_brepaint_piano =
true;
10726 ru.Subtract(chart_bar_rect);
10730 if (m_Compass && m_Compass->IsShown()) {
10731 wxRect compassRect = m_Compass->GetRect();
10732 if (ru.Contains(compassRect) != wxOutRegion) {
10733 ru.Subtract(compassRect);
10738 bool b_newview =
true;
10740 if ((m_cache_vp.view_scale_ppm == VPoint.view_scale_ppm) &&
10741 (m_cache_vp.rotation == VPoint.rotation) &&
10742 (m_cache_vp.clat == VPoint.clat) && (m_cache_vp.clon == VPoint.clon) &&
10743 m_cache_vp.IsValid()) {
10749 bool b_rcache_ok =
false;
10750 if (fabs(VPoint.skew) > 0.01 || fabs(VPoint.rotation) > 0.01)
10751 b_rcache_ok = !b_newview;
10754 if (VPoint.b_MercatorProjectionOverride)
10755 VPoint.SetProjectionType(PROJECTION_MERCATOR);
10758 svp.pix_width = svp.rv_rect.width;
10759 svp.pix_height = svp.rv_rect.height;
10765 OCPNRegion chart_get_region(wxRect(0, 0, svp.pix_width, svp.pix_height));
10769 if (b_rcache_ok) chart_get_region.Clear();
10772 if (VPoint.b_quilt)
10774 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
10776 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
10779 if (bvectorQuilt && (m_cache_vp.view_scale_ppm != VPoint.view_scale_ppm ||
10780 m_cache_vp.rotation != VPoint.rotation)) {
10781 OCPNPlatform::ShowBusySpinner();
10785 if ((m_working_bm.GetWidth() != svp.pix_width) ||
10786 (m_working_bm.GetHeight() != svp.pix_height))
10787 m_working_bm.Create(svp.pix_width, svp.pix_height,
10790 if (fabs(VPoint.rotation) < 0.01) {
10791 bool b_save =
true;
10793 if (g_SencThreadManager) {
10794 if (g_SencThreadManager->GetJobCount()) {
10796 m_cache_vp.Invalidate();
10810 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
10812 wxPoint c_old = VPoint.GetPixFromLL(VPoint.clat, VPoint.clon);
10813 wxPoint c_new = m_bm_cache_vp.GetPixFromLL(VPoint.clat, VPoint.clon);
10815 int dy = c_new.y - c_old.y;
10816 int dx = c_new.x - c_old.x;
10821 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
10825 temp_dc.SelectObject(m_working_bm);
10827 wxMemoryDC cache_dc;
10828 cache_dc.SelectObject(m_cached_chart_bm);
10832 temp_dc.Blit(0, 0, VPoint.pix_width - dx,
10833 VPoint.pix_height - dy, &cache_dc, dx, dy);
10835 temp_dc.Blit(-dx, 0, VPoint.pix_width + dx,
10836 VPoint.pix_height - dy, &cache_dc, 0, dy);
10841 temp_dc.Blit(0, -dy, VPoint.pix_width - dx,
10842 VPoint.pix_height + dy, &cache_dc, dx, 0);
10844 temp_dc.Blit(-dx, -dy, VPoint.pix_width + dx,
10845 VPoint.pix_height + dy, &cache_dc, 0, 0);
10852 update_region.Union(
10853 wxRect(0, VPoint.pix_height - dy, VPoint.pix_width, dy));
10855 update_region.Union(wxRect(0, 0, VPoint.pix_width, -dy));
10860 update_region.Union(
10861 wxRect(VPoint.pix_width - dx, 0, dx, VPoint.pix_height));
10863 update_region.Union(wxRect(0, 0, -dx, VPoint.pix_height));
10867 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
10869 cache_dc.SelectObject(wxNullBitmap);
10873 temp_dc.SelectObject(m_cached_chart_bm);
10876 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
10880 temp_dc.SelectObject(m_working_bm);
10881 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
10886 temp_dc.SelectObject(m_cached_chart_bm);
10891 temp_dc.SelectObject(m_working_bm);
10892 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
10905 wxMemoryDC scratch_dc_0;
10906 scratch_dc_0.SelectObject(m_cached_chart_bm);
10907 scratch_dc_0.Blit(0, 0, svp.pix_width, svp.pix_height, &temp_dc, 0, 0);
10909 scratch_dc_0.SelectObject(wxNullBitmap);
10918 temp_dc.SelectObject(m_working_bm);
10920 wxRect(0, 0, svp.pix_width, svp.pix_height));
10921 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
10922 chart_get_all_region);
10925 if (busy) OCPNPlatform::HideBusySpinner();
10931 if (!m_singleChart) {
10932 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
10937 if (!chart_get_region.IsEmpty()) {
10938 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
10942 if (temp_dc.IsOk()) {
10947 if (!VPoint.b_quilt) {
10950 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
10951 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
10958 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
10959 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
10962 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
10964 temp_dc.DestroyClippingRegion();
10967 OCPNRegion backgroundRegion(wxRect(0, 0, svp.pix_width, svp.pix_height));
10969 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
10971 if (!backgroundRegion.IsEmpty()) {
10977 wxColour water = pWorldBackgroundChart->water;
10978 if (water.IsOk()) {
10979 temp_dc.SetPen(*wxTRANSPARENT_PEN);
10980 temp_dc.SetBrush(wxBrush(water));
10982 while (upd.HaveRects()) {
10983 wxRect rect = upd.GetRect();
10984 temp_dc.DrawRectangle(rect);
10989 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
10990 temp_dc.SetDeviceClippingRegion(*clip_region);
10991 delete clip_region;
10994 double r = VPoint.rotation;
10995 SetVPRotation(VPoint.skew);
10997 pWorldBackgroundChart->RenderViewOnDC(bgdc, VPoint);
11002 wxMemoryDC *pChartDC = &temp_dc;
11003 wxMemoryDC rotd_dc;
11005 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11007 if (!b_rcache_ok) {
11009 wxMemoryDC tbase_dc;
11010 wxBitmap bm_base(svp.pix_width, svp.pix_height, -1);
11011 tbase_dc.SelectObject(bm_base);
11012 tbase_dc.Blit(0, 0, svp.pix_width, svp.pix_height, &temp_dc, 0, 0);
11013 tbase_dc.SelectObject(wxNullBitmap);
11015 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11018 wxImage base_image;
11019 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11025 double angle = GetVP().skew - GetVP().rotation;
11027 bool b_rot_ok =
false;
11028 if (base_image.IsOk()) {
11031 m_b_rot_hidef =
false;
11035 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11036 m_b_rot_hidef, &m_roffset);
11038 if ((rot_vp.view_scale_ppm == VPoint.view_scale_ppm) &&
11039 (rot_vp.rotation == VPoint.rotation) &&
11040 (rot_vp.clat == VPoint.clat) && (rot_vp.clon == VPoint.clon) &&
11041 rot_vp.IsValid() && (ri.IsOk())) {
11048 m_prot_bm =
new wxBitmap(ri);
11051 m_roffset.x += VPoint.rv_rect.x;
11052 m_roffset.y += VPoint.rv_rect.y;
11055 if (m_prot_bm && m_prot_bm->IsOk()) {
11056 rotd_dc.SelectObject(*m_prot_bm);
11057 pChartDC = &rotd_dc;
11059 pChartDC = &temp_dc;
11060 m_roffset = wxPoint(0, 0);
11063 pChartDC = &temp_dc;
11064 m_roffset = wxPoint(0, 0);
11067 wxPoint offset = m_roffset;
11070 m_cache_vp = VPoint;
11073 wxMemoryDC mscratch_dc;
11074 mscratch_dc.SelectObject(*pscratch_bm);
11076 mscratch_dc.ResetBoundingBox();
11077 mscratch_dc.DestroyClippingRegion();
11078 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11081 wxRegionIterator upd(rgn_blit);
11083 wxRect rect = upd.GetRect();
11085 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11086 rect.x - offset.x, rect.y - offset.y);
11092 if (g_canvasConfig != 0) {
11093 if (
this == wxWindow::FindFocus()) {
11094 g_focusCanvas =
this;
11096 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11097 mscratch_dc.SetPen(wxPen(colour));
11098 mscratch_dc.SetBrush(wxBrush(colour));
11100 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11101 mscratch_dc.DrawRectangle(activeRect);
11106 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11107 unsigned int im = stackIndexArray.size();
11108 if (VPoint.b_quilt && im > 0) {
11109 std::vector<int> tiles_to_show;
11110 for (
unsigned int is = 0; is < im; is++) {
11112 ChartData->GetChartTableEntry(stackIndexArray[is]);
11113 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11116 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11117 tiles_to_show.push_back(stackIndexArray[is]);
11121 if (tiles_to_show.size())
11122 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11126 ocpnDC scratch_dc(mscratch_dc);
11127 DrawOverlayObjects(scratch_dc, ru);
11130 RebuildTideSelectList(GetVP().GetBBox());
11131 DrawAllTidesInBBox(scratch_dc, GetVP().GetBBox());
11134 if (m_bShowCurrent) {
11135 RebuildCurrentSelectList(GetVP().GetBBox());
11136 DrawAllCurrentsInBBox(scratch_dc, GetVP().GetBBox());
11139 if (m_brepaint_piano && g_bShowChartBar) {
11140 int canvas_height = GetClientSize().y;
11141 canvas_height *= m_displayScale;
11142 m_Piano->Paint(canvas_height - m_Piano->GetHeight(), mscratch_dc);
11146 if (m_Compass) m_Compass->Paint(scratch_dc);
11148 RenderAlertMessage(mscratch_dc, GetVP());
11152#ifdef ocpnUSE_DIBSECTION
11157 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11158 q_dc.SelectObject(qbm);
11161 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11164 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11165 q_dc.SetBrush(qbr);
11166 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11169 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11172 q_dc.SelectObject(wxNullBitmap);
11179 if( VPoint.b_quilt ) {
11180 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11181 ChartBase *chart = m_pQuilt->GetRefChart();
11182 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11187 ChPI->ClearPLIBTextList();
11190 ps52plib->ClearTextList();
11194 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11196 wxColor maskBackground = wxColour(1,0,0);
11197 t_dc.SelectObject( qbm );
11198 t_dc.SetBackground(wxBrush(maskBackground));
11202 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
11205 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
11206 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
11209 wxRegionIterator upd_final( ru );
11210 while( upd_final ) {
11211 wxRect rect = upd_final.GetRect();
11212 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
11216 t_dc.SelectObject( wxNullBitmap );
11222 if (VPoint.b_quilt) {
11223 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
11224 ChartBase *chart = m_pQuilt->GetRefChart();
11225 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
11229 ChPI->ClearPLIBTextList();
11231 if (ps52plib) ps52plib->ClearTextList();
11236 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
11238 if (g_bShowChartBar && m_Piano) {
11239 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
11240 GetVP().pix_width, m_Piano->GetHeight());
11243 if (!style->chartStatusWindowTransparent)
11244 chart_all_text_region.Subtract(chart_bar_rect);
11247 if (m_Compass && m_Compass->IsShown()) {
11248 wxRect compassRect = m_Compass->GetRect();
11249 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
11250 chart_all_text_region.Subtract(compassRect);
11254 mscratch_dc.DestroyClippingRegion();
11256 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
11257 chart_all_text_region);
11263 wxRegionIterator upd_final(rgn_blit);
11264 while (upd_final) {
11265 wxRect rect = upd_final.GetRect();
11266 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
11287 temp_dc.SelectObject(wxNullBitmap);
11289 mscratch_dc.SelectObject(wxNullBitmap);
11291 dc.DestroyClippingRegion();
11294 m_muiBar->Refresh();
11300void ChartCanvas::PaintCleanup() {
11312 m_bTCupdate =
false;
11316 WarpPointer(warp_x, warp_y);
11323 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
11327wxColour GetErrorGraphicColor(
double val)
11346 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
11347 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
11348 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
11349 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
11350 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
11351 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
11352 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
11353 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
11354 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
11355 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
11356 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
11357 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
11358 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
11359 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
11360 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
11361 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
11362 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
11363 else if( val >= 48) c.Set(_T(
"#410000"));
11368void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
11370 wxImage gr_image(vp->pix_width, vp->pix_height);
11371 gr_image.InitAlpha();
11373 double maxval = -10000;
11374 double minval = 10000;
11379 GetCanvasPixPoint(0, 0, rlat, rlon);
11381 for(
int i=1; i < vp->pix_height-1; i++)
11383 for(
int j=0; j < vp->pix_width; j++)
11389 GetCanvasPixPoint(j, i, glat, glon);
11391 maxval = wxMax(maxval, (glat - rlat));
11392 minval = wxMin(minval, (glat - rlat));
11398 GetCanvasPixPoint(0, 0, rlat, rlon);
11399 for(
int i=1; i < vp->pix_height-1; i++)
11401 for(
int j=0; j < vp->pix_width; j++)
11407 GetCanvasPixPoint(j, i, glat, glon);
11409 double f = ((glat - rlat)-minval)/(maxval - minval);
11411 double dy = (f * 40);
11413 wxColour c = GetErrorGraphicColor(dy);
11414 unsigned char r = c.Red();
11415 unsigned char g = c.Green();
11416 unsigned char b = c.Blue();
11418 gr_image.SetRGB(j, i, r,g,b);
11419 if((glat - rlat )!= 0)
11420 gr_image.SetAlpha(j, i, 128);
11422 gr_image.SetAlpha(j, i, 255);
11429 wxBitmap *pbm =
new wxBitmap(gr_image);
11430 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
11431 pbm->SetMask(gr_mask);
11433 pmdc->DrawBitmap(*pbm, 0,0);
11441void ChartCanvas::CancelMouseRoute() {
11443 m_pMouseRoute = NULL;
11444 m_bDrawingRoute =
false;
11447int ChartCanvas::GetNextContextMenuId() {
11448 return CanvasMenuHandler::GetNextContextMenuId();
11451bool ChartCanvas::SetCursor(
const wxCursor &c) {
11453 if (g_bopengl && m_glcc)
11454 return m_glcc->SetCursor(c);
11457 return wxWindow::SetCursor(c);
11460void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
11461 if (g_bquiting)
return;
11463 GetCanvasPixPoint(mouse_x, mouse_y, m_cursor_lat, m_cursor_lon);
11471 if (!m_RolloverPopupTimer.IsRunning() &&
11472 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
11473 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
11474 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
11475 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
11478 if (m_glcc && g_bopengl) {
11481 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
11483 m_glcc->Refresh(eraseBackground,
11494 if (pthumbwin && pthumbwin->IsShown()) {
11495 pthumbwin->Raise();
11496 pthumbwin->Refresh(
false);
11500 if (m_pCIWin && m_pCIWin->IsShown()) {
11502 m_pCIWin->Refresh(
false);
11510 wxWindow::Refresh(eraseBackground, rect);
11513void ChartCanvas::Update() {
11514 if (m_glcc && g_bopengl) {
11519 wxWindow::Update();
11523 if (!pemboss)
return;
11524 int x = pemboss->x, y = pemboss->y;
11525 const double factor = 200;
11527 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
11528 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
11529 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
11532 wxMemoryDC snip_dc;
11533 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
11534 snip_dc.SelectObject(snip_bmp);
11536 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
11537 snip_dc.SelectObject(wxNullBitmap);
11539 wxImage snip_img = snip_bmp.ConvertToImage();
11542 unsigned char *pdata = snip_img.GetData();
11544 for (
int y = 0; y < pemboss->height; y++) {
11545 int map_index = (y * pemboss->width);
11546 for (
int x = 0; x < pemboss->width; x++) {
11547 double val = (pemboss->pmap[map_index] * factor) / 256.;
11549 int nred = (int)((*pdata) + val);
11550 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
11551 *pdata++ = (
unsigned char)nred;
11553 int ngreen = (int)((*pdata) + val);
11554 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
11555 *pdata++ = (
unsigned char)ngreen;
11557 int nblue = (int)((*pdata) + val);
11558 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
11559 *pdata++ = (
unsigned char)nblue;
11567 wxBitmap emb_bmp(snip_img);
11570 wxMemoryDC result_dc;
11571 result_dc.SelectObject(emb_bmp);
11574 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
11576 result_dc.SelectObject(wxNullBitmap);
11580 double zoom_factor = GetVP().ref_scale / GetVP().chart_scale;
11582 if (GetQuiltMode()) {
11584 int refIndex = GetQuiltRefChartdbIndex();
11585 if (refIndex >= 0) {
11586 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
11587 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
11588 if (current_type == CHART_TYPE_MBTILES) {
11589 ChartBase *pChart = m_pQuilt->GetRefChart();
11592 zoom_factor = ptc->GetZoomFactor();
11597 if (zoom_factor <= 3.9)
return NULL;
11599 if (m_singleChart) {
11600 if (zoom_factor <= 3.9)
return NULL;
11605 if (m_pEM_OverZoom) {
11606 m_pEM_OverZoom->x = 4;
11607 m_pEM_OverZoom->y = 0;
11608 if (g_MainToolbar && IsPrimaryCanvas()) {
11609 wxRect masterToolbarRect = g_MainToolbar->GetRect();
11610 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
11613 return m_pEM_OverZoom;
11616void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
11626 g_overlayCanvas =
this;
11628 if (g_pi_manager) {
11629 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
11630 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_LEGACY);
11633 AISDrawAreaNotices(dc, GetVP(),
this);
11635 wxDC *pdc = dc.GetDC();
11637 pdc->DestroyClippingRegion();
11638 wxDCClipper(*pdc, ru);
11641 if (m_bShowNavobjects) {
11642 DrawAllTracksInBBox(dc, GetVP().GetBBox());
11643 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
11644 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
11645 DrawAnchorWatchPoints(dc);
11647 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
11648 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
11651 AISDraw(dc, GetVP(),
this);
11655 RenderVisibleSectorLights(dc);
11657 RenderAllChartOutlines(dc, GetVP());
11658 RenderRouteLegs(dc);
11659 RenderShipToActive(dc,
false);
11661 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
11662 if (g_pi_manager) {
11663 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_OVER_SHIPS);
11666 DrawEmboss(dc, EmbossDepthScale());
11667 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
11668 if (g_pi_manager) {
11669 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_OVER_EMBOSS);
11672 if (m_pTrackRolloverWin) {
11673 m_pTrackRolloverWin->Draw(dc);
11674 m_brepaint_piano =
true;
11677 if (m_pRouteRolloverWin) {
11678 m_pRouteRolloverWin->Draw(dc);
11679 m_brepaint_piano =
true;
11682 if (m_pAISRolloverWin) {
11683 m_pAISRolloverWin->Draw(dc);
11684 m_brepaint_piano =
true;
11687 if (g_pi_manager) {
11688 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_OVER_UI);
11693 if (!m_bShowDepthUnits)
return NULL;
11695 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
11697 if (GetQuiltMode()) {
11698 wxString s = m_pQuilt->GetQuiltDepthUnit();
11700 if (s == _T(
"FEET"))
11701 depth_unit_type = DEPTH_UNIT_FEET;
11702 else if (s.StartsWith(_T(
"FATHOMS")))
11703 depth_unit_type = DEPTH_UNIT_FATHOMS;
11704 else if (s.StartsWith(_T(
"METERS")))
11705 depth_unit_type = DEPTH_UNIT_METERS;
11706 else if (s.StartsWith(_T(
"METRES")))
11707 depth_unit_type = DEPTH_UNIT_METERS;
11708 else if (s.StartsWith(_T(
"METRIC")))
11709 depth_unit_type = DEPTH_UNIT_METERS;
11710 else if (s.StartsWith(_T(
"METER")))
11711 depth_unit_type = DEPTH_UNIT_METERS;
11714 if (m_singleChart) {
11715 depth_unit_type = m_singleChart->GetDepthUnitType();
11716 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11717 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
11722 switch (depth_unit_type) {
11723 case DEPTH_UNIT_FEET:
11726 case DEPTH_UNIT_METERS:
11727 ped = m_pEM_Meters;
11729 case DEPTH_UNIT_FATHOMS:
11730 ped = m_pEM_Fathoms;
11736 ped->x = (GetVP().pix_width - ped->width);
11738 if (m_Compass && m_bShowCompassWin) {
11739 wxRect r = m_Compass->GetRect();
11740 ped->y = r.y + r.height;
11747void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
11750 if (style->embossFont == wxEmptyString) {
11751 wxFont *dFont = FontMgr::Get().GetFont(_(
"Dialog"), 0);
11753 font.SetPointSize(60);
11754 font.SetWeight(wxFONTWEIGHT_BOLD);
11756 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
11757 wxFONTWEIGHT_BOLD,
false, style->embossFont);
11759 int emboss_width = 500;
11760 int emboss_height = 200;
11764 delete m_pEM_Meters;
11765 delete m_pEM_Fathoms;
11769 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
11771 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
11773 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
11776#define OVERZOOM_TEXT _("OverZoom")
11778void ChartCanvas::SetOverzoomFont() {
11783 if (style->embossFont == wxEmptyString) {
11784 wxFont *dFont = FontMgr::Get().GetFont(_(
"Dialog"), 0);
11786 font.SetPointSize(40);
11787 font.SetWeight(wxFONTWEIGHT_BOLD);
11789 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
11790 wxFONTWEIGHT_BOLD,
false, style->embossFont);
11792 wxClientDC dc(
this);
11794 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
11796 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
11797 font.SetPointSize(font.GetPointSize() - 1);
11799 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
11801 m_overzoomFont = font;
11802 m_overzoomTextWidth = w;
11803 m_overzoomTextHeight = h;
11806void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
11807 delete m_pEM_OverZoom;
11809 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
11811 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
11812 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
11815emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
11816 int height,
const wxString &str,
11821 wxBitmap bmp(width, height, -1);
11824 wxMemoryDC temp_dc;
11825 temp_dc.SelectObject(bmp);
11828 temp_dc.SetBackground(*wxWHITE_BRUSH);
11829 temp_dc.SetTextBackground(*wxWHITE);
11830 temp_dc.SetTextForeground(*wxBLACK);
11834 temp_dc.SetFont(font);
11837 temp_dc.GetTextExtent(str, &str_w, &str_h);
11839 temp_dc.DrawText(str, 1, 1);
11842 temp_dc.SelectObject(wxNullBitmap);
11845 wxImage img = bmp.ConvertToImage();
11847 int image_width = str_w * 105 / 100;
11848 int image_height = str_h * 105 / 100;
11849 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
11850 wxMin(image_height, img.GetHeight()));
11851 wxImage imgs = img.GetSubImage(r);
11855 case GLOBAL_COLOR_SCHEME_DAY:
11859 case GLOBAL_COLOR_SCHEME_DUSK:
11862 case GLOBAL_COLOR_SCHEME_NIGHT:
11869 const int w = imgs.GetWidth();
11870 const int h = imgs.GetHeight();
11871 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
11876 for (
int y = 1; y < h - 1; y++) {
11877 for (
int x = 1; x < w - 1; x++) {
11879 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
11880 val = (int)(val * val_factor);
11881 index = (y * w) + x;
11894void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
11895 Track *active_track = NULL;
11896 for (
Track* pTrackDraw : g_TrackList) {
11897 if (g_pActiveTrack == pTrackDraw) {
11898 active_track = pTrackDraw;
11902 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
11905 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
11908void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
11909 Track *active_track = NULL;
11910 for (
Track* pTrackDraw : g_TrackList) {
11911 if (g_pActiveTrack == pTrackDraw) {
11912 active_track = pTrackDraw;
11916 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
11919void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
11920 Route *active_route = NULL;
11922 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
11923 node = node->GetNext()) {
11924 Route *pRouteDraw = node->GetData();
11925 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
11926 active_route = pRouteDraw;
11931 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
11936 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
11939void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
11940 Route *active_route = NULL;
11942 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
11943 node = node->GetNext()) {
11944 Route *pRouteDraw = node->GetData();
11945 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
11946 active_route = pRouteDraw;
11950 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
11953void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
11954 if (!pWayPointMan)
return;
11956 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
11961 if (pWP->m_bIsInRoute) {
11962 node = node->GetNext();
11967 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
11971 if (pWP->GetShowWaypointRangeRings() &&
11972 (pWP->GetWaypointRangeRingsNumber() > 0)) {
11973 double factor = 1.00;
11974 if (pWP->GetWaypointRangeRingsStepUnits() ==
11976 factor = 1 / 1.852;
11978 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
11979 pWP->GetWaypointRangeRingsStep() / 60.;
11983 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
11984 pWP->m_lat + radius, pWP->m_lon + radius);
11985 if (!BltBBox.IntersectOut(radar_box)) {
11992 node = node->GetNext();
11996void ChartCanvas::DrawBlinkObjects(
void) {
11998 wxRect update_rect;
12000 if (!pWayPointMan)
return;
12002 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12007 if (pWP->m_bBlink) {
12008 update_rect.Union(pWP->CurrentRect_in_DC);
12012 node = node->GetNext();
12014 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12017void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12020 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12022 wxPoint lAnchorPoint1, lAnchorPoint2;
12025 if (pAnchorWatchPoint1) {
12026 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12027 GetCanvasPointPix(pAnchorWatchPoint1->m_lat, pAnchorWatchPoint1->m_lon,
12030 if (pAnchorWatchPoint2) {
12031 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12032 GetCanvasPointPix(pAnchorWatchPoint2->m_lat, pAnchorWatchPoint2->m_lon,
12036 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12037 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12039 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12040 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12041 dc.SetBrush(*ppBrush);
12045 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12050 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12055 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12060 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12065double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12068 wxPoint lAnchorPoint;
12071 double tlat1, tlon1;
12073 if (pAnchorWatchPoint) {
12074 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12075 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12076 dabs = fabs(d1 / 1852.);
12077 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12079 GetCanvasPointPix(tlat1, tlon1, &r1);
12080 GetCanvasPointPix(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon,
12082 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12083 pow((
double)(lAnchorPoint.y - r1.y), 2));
12086 if (d1 < 0) lpp = -lpp;
12094void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12095 if (!ptcmgr)
return;
12097 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12099 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12100 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12101 double lon = pIDX->IDX_lon;
12102 double lat = pIDX->IDX_lat;
12104 char type = pIDX->IDX_type;
12105 if ((type ==
't') || (type ==
'T')) {
12106 if (BBox.Contains(lat, lon)) {
12108 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12114extern wxDateTime gTimeSource;
12116void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12117 if (!ptcmgr)
return;
12119 wxDateTime this_now = gTimeSource;
12120 bool cur_time = !gTimeSource.IsValid();
12121 if (cur_time) this_now = wxDateTime::Now();
12122 time_t t_this_now = this_now.GetTicks();
12124 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12125 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12126 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12127 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12129 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12130 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12133 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12134 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12137 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12138 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12139 wxBRUSHSTYLE_SOLID);
12140 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12141 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12142 wxBRUSHSTYLE_SOLID);
12144 wxFont *dFont = FontMgr::Get().GetFont(_(
"ExtendedTideIcon"));
12145 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12146 int font_size = wxMax(10, dFont->GetPointSize());
12147 font_size /= g_Platform->GetDisplayDIPMult(
this);
12148 wxFont *plabelFont =
12149 FontMgr::Get().FindOrCreateFont(font_size,
12150 dFont->GetFamily(), dFont->GetStyle(),
12151 dFont->GetWeight(),
false,
12152 dFont->GetFaceName());
12154 dc.SetPen(*pblack_pen);
12155 dc.SetBrush(*pgreen_brush);
12159 case GLOBAL_COLOR_SCHEME_DAY:
12162 case GLOBAL_COLOR_SCHEME_DUSK:
12165 case GLOBAL_COLOR_SCHEME_NIGHT:
12166 bm = m_bmTideNight;
12173 int bmw = bm.GetWidth();
12174 int bmh = bm.GetHeight();
12176 float scale_factor = 1.0;
12180 float icon_pixelRefDim = 45;
12183 float nominal_icon_size_mm = g_Platform->GetDisplaySizeMM() *25 / 1000;
12184 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
12185 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
12186 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12189#ifndef __OCPN__ANDROID__
12200 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
12201 height *= g_Platform->GetDisplayDIPMult(
this);
12202 float nominal_icon_size_pixels = 48;
12203 float pix_factor = (2 * height) / nominal_icon_size_pixels;
12214 double targetHeight0 = 16.0;
12217 double displaySize = m_display_size_mm;
12218 displaySize = wxMax(displaySize, 100);
12220 float targetHeight = wxMin(targetHeight0, displaySize / 15);
12222 double pix_factor = targetHeight / symHeight;
12225 scale_factor *= pix_factor;
12227 float user_scale_factor = g_ChartScaleFactorExp;
12228 if (g_ChartScaleFactorExp > 1.0)
12229 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
12232 scale_factor *= user_scale_factor;
12233 scale_factor *= GetContentScaleFactor();
12237 double lon_last = 0.;
12238 double lat_last = 0.;
12239 double marge = 0.05;
12240 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12241 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12243 char type = pIDX->IDX_type;
12244 if ((type ==
't') || (type ==
'T'))
12246 double lon = pIDX->IDX_lon;
12247 double lat = pIDX->IDX_lat;
12249 if (BBox.ContainsMarge(lat, lon, marge)) {
12251 GetCanvasPointPix(lat, lon, &r);
12253 if (GetVP().chart_scale > 500000) {
12254 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
12258 dc.SetFont(*plabelFont);
12270 if (ptcmgr->GetTideFlowSens(
12271 t_this_now, BACKWARD_TEN_MINUTES_STEP,
12272 pIDX->IDX_rec_num, nowlev, val, wt)) {
12275 ptcmgr->GetHightOrLowTide(
12276 t_this_now + BACKWARD_TEN_MINUTES_STEP,
12277 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
12278 wt, pIDX->IDX_rec_num, val, tctime);
12289 if (tctime > t_this_now)
12290 ptcmgr->GetHightOrLowTide(
12291 t_this_now, BACKWARD_TEN_MINUTES_STEP,
12292 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
12293 pIDX->IDX_rec_num, val, tctime);
12296 ptcmgr->GetHightOrLowTide(
12297 t_this_now, FORWARD_TEN_MINUTES_STEP,
12298 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->IDX_rec_num,
12312 int width = (int)(12 * scale_factor + 0.5);
12313 int height = (int)(45 * scale_factor + 0.5);
12314 int linew = wxMax(1, (
int)(scale_factor));
12315 int xDraw = r.x - (width / 2);
12316 int yDraw = r.y - (height / 2);
12319 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
12320 int hs = (httime > lttime) ? -4 : 4;
12321 hs *= (int)(scale_factor + 0.5);
12322 if (ts > 0.995 || ts < 0.005) hs = 0;
12323 int ht_y = (int)(height * ts);
12326 pblack_pen->SetWidth(linew);
12327 dc.SetPen(*pblack_pen);
12328 dc.SetBrush(*pyelo_brush);
12329 dc.DrawRectangle(xDraw, yDraw, width, height);
12333 dc.SetPen(*pblue_pen);
12334 dc.SetBrush(*pblue_brush);
12335 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
12336 (width - (4 * linew)), height - ht_y);
12342 arrow[0].x = xDraw + 2 * linew;
12343 arrow[1].x = xDraw + width / 2;
12344 arrow[2].x = xDraw + width - 2 * linew;
12345 pyelo_pen->SetWidth(linew);
12346 pblue_pen->SetWidth(linew);
12347 if (ts > 0.35 || ts < 0.15)
12349 hl = (int)(height * 0.25) + yDraw;
12351 arrow[1].y = hl + hs;
12354 dc.SetPen(*pyelo_pen);
12356 dc.SetPen(*pblue_pen);
12357 dc.DrawLines(3, arrow);
12359 if (ts > 0.60 || ts < 0.40)
12361 hl = (int)(height * 0.5) + yDraw;
12363 arrow[1].y = hl + hs;
12366 dc.SetPen(*pyelo_pen);
12368 dc.SetPen(*pblue_pen);
12369 dc.DrawLines(3, arrow);
12371 if (ts < 0.65 || ts > 0.85)
12373 hl = (int)(height * 0.75) + yDraw;
12375 arrow[1].y = hl + hs;
12378 dc.SetPen(*pyelo_pen);
12380 dc.SetPen(*pblue_pen);
12381 dc.DrawLines(3, arrow);
12385 s.Printf(_T(
"%3.1f"), nowlev);
12387 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
12389 dc.GetTextExtent(s, &wx1, NULL);
12390 wx1 *= g_Platform->GetDisplayDIPMult(
this);
12391 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
12408void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
12409 if (!ptcmgr)
return;
12411 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
12413 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12414 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12415 double lon = pIDX->IDX_lon;
12416 double lat = pIDX->IDX_lat;
12418 char type = pIDX->IDX_type;
12419 if (((type ==
'c') || (type ==
'C')) && (!pIDX->b_skipTooDeep)) {
12420 if ((BBox.Contains(lat, lon))) {
12422 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
12428void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
12429 if (!ptcmgr)
return;
12431 float tcvalue, dir;
12435 double lon_last = 0.;
12436 double lat_last = 0.;
12438 double marge = 0.2;
12439 bool cur_time = !gTimeSource.IsValid();
12441 double true_scale_display = floor(VPoint.chart_scale / 100.) * 100.;
12442 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
12444 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12445 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12446 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
12447 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
12449 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
12450 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
12451 wxBRUSHSTYLE_SOLID);
12452 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
12453 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
12454 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
12455 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
12457 double skew_angle = GetVPRotation();
12459 wxFont *dFont = FontMgr::Get().GetFont(_(
"CurrentValue"));
12460 int font_size = wxMax(10, dFont->GetPointSize());
12461 font_size /= g_Platform->GetDisplayDIPMult(
this);
12463 FontMgr::Get().FindOrCreateFont(font_size,
12464 dFont->GetFamily(), dFont->GetStyle(),
12465 dFont->GetWeight(),
false,
12466 dFont->GetFaceName());
12469 float scale_factor = 1.0;
12475 float nominal_icon_size_mm = g_Platform->GetDisplaySizeMM() *3 / 1000;
12476 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
12477 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
12478 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12484 float nominal_icon_size_pixels = 6;
12485 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
12488#ifndef __OCPN__ANDROID__
12492 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
12493 height *= g_Platform->GetDisplayDIPMult(
this);
12494 float nominal_icon_size_pixels = 15;
12495 float pix_factor = (1 * height) / nominal_icon_size_pixels;
12502 float icon_pixelRefDim = 5;
12507 double targetHeight0 = 2.0;
12510 double displaySize = m_display_size_mm;
12511 displaySize = wxMax(displaySize, 100);
12513 float targetHeight = wxMin(targetHeight0, displaySize / 50);
12514 double pix_factor = targetHeight / symHeight;
12517 scale_factor *= pix_factor;
12519 float user_scale_factor = g_ChartScaleFactorExp;
12520 if (g_ChartScaleFactorExp > 1.0)
12521 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
12524 scale_factor *= user_scale_factor;
12526 scale_factor *= GetContentScaleFactor();
12529 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12530 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12531 double lon = pIDX->IDX_lon;
12532 double lat = pIDX->IDX_lat;
12534 char type = pIDX->IDX_type;
12535 if (((type ==
'c') || (type ==
'C')) && (1 )) {
12536 if (!pIDX->b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
12538 GetCanvasPointPix(lat, lon, &r);
12541 int dd = (int)(5.0 * scale_factor + 0.5);
12552 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
12553 dc.SetPen(*pblack_pen);
12554 dc.SetBrush(*porange_brush);
12555 dc.DrawPolygon(4, d);
12558 dc.SetBrush(*pblack_brush);
12559 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
12562 if (GetVP().chart_scale < 1000000) {
12563 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
12577 double a1 = fabs(tcvalue) * 10.;
12579 a1 = wxMax(1.0, a1);
12580 double a2 = log10(a1);
12582 float cscale = scale_factor * a2 * 0.4;
12584 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
12585 dc.SetPen(*porange_pen);
12586 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
12590 if (bDrawCurrentValues) {
12591 dc.SetFont(*pTCFont);
12592 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
12593 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
12614void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
12615 pCwin =
new TCWin(
this, x, y, pvIDX);
12618#define NUM_CURRENT_ARROW_POINTS 9
12619static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
12620 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
12621 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
12622 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
12624void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
12626 if (
scale > 1e-2) {
12627 float sin_rot = sin(rot_angle * PI / 180.);
12628 float cos_rot = cos(rot_angle * PI / 180.);
12632 float xt = CurrentArrowArray[0].x;
12633 float yt = CurrentArrowArray[0].y;
12635 float xp = (xt * cos_rot) - (yt * sin_rot);
12636 float yp = (xt * sin_rot) + (yt * cos_rot);
12637 int x1 = (int)(xp *
scale);
12638 int y1 = (int)(yp *
scale);
12641 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
12642 xt = CurrentArrowArray[ip].x;
12643 yt = CurrentArrowArray[ip].y;
12645 float xp = (xt * cos_rot) - (yt * sin_rot);
12646 float yp = (xt * sin_rot) + (yt * cos_rot);
12647 int x2 = (int)(xp *
scale);
12648 int y2 = (int)(yp *
scale);
12650 dc.DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
12658wxString ChartCanvas::FindValidUploadPort() {
12661 if (!g_uploadConnection.IsEmpty() &&
12662 g_uploadConnection.StartsWith(_T(
"Serial"))) {
12663 port = g_uploadConnection;
12666 else if (TheConnectionParams()) {
12669 for (
size_t i = 0; i < TheConnectionParams()->Count(); i++) {
12671 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
12672 port << _T(
"Serial:") << cp->Port;
12678void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
12681 if (NULL == g_pais_query_dialog_active) {
12682 int pos_x = g_ais_query_dialog_x;
12683 int pos_y = g_ais_query_dialog_y;
12685 if (g_pais_query_dialog_active) {
12686 delete g_pais_query_dialog_active;
12692 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
12693 wxPoint(pos_x, pos_y));
12695 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
12696 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
12697 g_pais_query_dialog_active->SetMMSI(mmsi);
12698 g_pais_query_dialog_active->UpdateText();
12699 wxSize sz = g_pais_query_dialog_active->GetSize();
12701 bool b_reset_pos =
false;
12706 RECT frame_title_rect;
12707 frame_title_rect.left = pos_x;
12708 frame_title_rect.top = pos_y;
12709 frame_title_rect.right = pos_x + sz.x;
12710 frame_title_rect.bottom = pos_y + 30;
12712 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
12713 b_reset_pos =
true;
12718 wxRect window_title_rect;
12719 window_title_rect.x = pos_x;
12720 window_title_rect.y = pos_y;
12721 window_title_rect.width = sz.x;
12722 window_title_rect.height = 30;
12724 wxRect ClientRect = wxGetClientDisplayRect();
12725 ClientRect.Deflate(
12727 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
12731 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
12734 g_pais_query_dialog_active->SetMMSI(mmsi);
12735 g_pais_query_dialog_active->UpdateText();
12738 g_pais_query_dialog_active->Show();
12741void ChartCanvas::ToggleCanvasQuiltMode(
void) {
12742 bool cur_mode = GetQuiltMode();
12744 if (!GetQuiltMode())
12745 SetQuiltMode(
true);
12746 else if (GetQuiltMode()) {
12747 SetQuiltMode(
false);
12748 g_sticky_chart = GetQuiltReferenceChartIndex();
12751 if (cur_mode != GetQuiltMode()) {
12752 SetupCanvasQuiltMode();
12761 if (ps52plib) ps52plib->GenerateStateHash();
12763 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
12764 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
12767void ChartCanvas::DoCanvasStackDelta(
int direction) {
12768 if (!GetQuiltMode()) {
12769 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
12770 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
12771 if ((current_stack_index + direction) < 0)
return;
12773 if (m_bpersistent_quilt ) {
12775 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
12777 if (IsChartQuiltableRef(new_dbIndex)) {
12778 ToggleCanvasQuiltMode();
12779 SelectQuiltRefdbChart(new_dbIndex);
12780 m_bpersistent_quilt =
false;
12783 SelectChartFromStack(current_stack_index + direction);
12786 std::vector<int> piano_chart_index_array =
12787 GetQuiltExtendedStackdbIndexArray();
12788 int refdb = GetQuiltRefChartdbIndex();
12791 int current_index = -1;
12792 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
12793 if (refdb == piano_chart_index_array[i]) {
12798 if (current_index == -1)
return;
12801 int target_family = ctet.GetChartFamily();
12803 int new_index = -1;
12804 int check_index = current_index + direction;
12805 bool found =
false;
12806 int check_dbIndex = -1;
12807 int new_dbIndex = -1;
12811 (
unsigned int)check_index < piano_chart_index_array.size() &&
12812 (check_index >= 0)) {
12813 check_dbIndex = piano_chart_index_array[check_index];
12814 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
12815 if (target_family == cte.GetChartFamily()) {
12817 new_index = check_index;
12818 new_dbIndex = check_dbIndex;
12822 check_index += direction;
12825 if (!found)
return;
12827 if (!IsChartQuiltableRef(new_dbIndex)) {
12828 ToggleCanvasQuiltMode();
12829 SelectdbChart(new_dbIndex);
12830 m_bpersistent_quilt =
true;
12832 SelectQuiltRefChart(new_index);
12836 gFrame->UpdateGlobalMenuItems();
12838 SetQuiltChartHiLiteIndex(-1);
12849void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
12852 switch (event.GetId()) {
12854 ZoomCanvasSimple(g_plus_minus_zoom_factor);
12859 ZoomCanvasSimple(1.0 / g_plus_minus_zoom_factor);
12864 DoCanvasStackDelta(1);
12869 DoCanvasStackDelta(-1);
12879 ShowCurrents(!GetbShowCurrent());
12886 ShowTides(!GetbShowTide());
12893 if (0 == m_routeState) {
12899#ifdef __OCPN__ANDROID__
12900 androidSetRouteAnnunciator(m_routeState == 1);
12906 SetAISCanvasDisplayStyle(-1);
12918void ChartCanvas::SetToolbarPosition(wxPoint position) {
12919 m_toolbarPosition = position;
12922void ChartCanvas::SetToolbarOrientation(
long orient) {
12923 m_toolbarOrientation = orient;
12926wxPoint ChartCanvas::GetToolbarPosition() {
12928 wxPoint tbp = m_toolBar->GetPosition();
12930 return ScreenToClient(tbp);
12932 return wxPoint(0, 0);
12935long ChartCanvas::GetToolbarOrientation() {
12937 return m_toolBar->GetOrient();
12942void ChartCanvas::SubmergeToolbar(
void) {
12943 if (m_toolBar) m_toolBar->Submerge();
12946void ChartCanvas::SurfaceToolbar(
void) {
12947 if (m_toolBar) m_toolBar->Surface();
12950bool ChartCanvas::IsToolbarShown() {
12952 if (m_toolBar) rv = m_toolBar->IsShown();
12956void ChartCanvas::ToggleToolbar(
bool b_smooth) {
12958 if (m_toolBar->IsShown()) {
12962 m_toolBar->Raise();
12967void ChartCanvas::DestroyToolbar() {
12968 if (m_toolBar) m_toolBar->DestroyToolBar();
12978void ChartCanvas::UpdateToolbarColorScheme(ColorScheme cs) {
12979 if (!m_toolBar)
return;
12982 if (m_toolBar->GetColorScheme() != cs) {
12983 m_toolBar->SetColorScheme(cs);
12985 if (m_toolBar->IsToolbarShown()) {
12986 m_toolBar->DestroyToolBar();
12987 m_toolBar->CreateMyToolbar();
12988 if (m_toolBar->isSubmergedToGrabber())
12989 m_toolBar->SubmergeToGrabber();
12994 if (m_toolBar->GetToolbar()) {
12996 m_toolBar->GetToolbar()->ToggleTool(ID_FOLLOW, m_bFollow);
12997 m_toolBar->GetToolbar()->ToggleTool(ID_CURRENT, GetbShowCurrent());
12998 m_toolBar->GetToolbar()->ToggleTool(ID_TIDE, GetbShowTide());
13004void ChartCanvas::SetCanvasToolbarItemState(
int tool_id,
bool state) {
13005 if (GetToolbar() && GetToolbar()->GetToolbar())
13006 GetToolbar()->GetToolbar()->ToggleTool(tool_id, state);
13009extern bool g_bAllowShowScaled;
13011void ChartCanvas::SetShowAIS(
bool show) {
13013 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13014 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13017void ChartCanvas::SetAttenAIS(
bool show) {
13018 m_bShowAISScaled = show;
13019 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13020 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13023void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13026 bool bShowAIS_Array[3] = {
true,
true,
false};
13027 bool bShowScaled_Array[3] = {
false,
true,
true};
13028 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13029 _(
"Attenuate less critical AIS targets"),
13030 _(
"Hide AIS Targets")};
13031 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13032 _T(
"AIS_Disabled")};
13034 int AIS_Toolbar_Switch = 0;
13035 if (StyleIndx == -1) {
13037 for (
int i = 1; i < ArraySize; i++) {
13038 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13039 (bShowScaled_Array[i] == m_bShowAISScaled))
13040 AIS_Toolbar_Switch = i;
13042 AIS_Toolbar_Switch++;
13043 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13044 AIS_Toolbar_Switch++;
13047 AIS_Toolbar_Switch = StyleIndx;
13050 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13052 int AIS_Toolbar_Switch_Next =
13053 AIS_Toolbar_Switch + 1;
13054 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13055 AIS_Toolbar_Switch_Next++;
13056 if (AIS_Toolbar_Switch_Next >= ArraySize)
13057 AIS_Toolbar_Switch_Next = 0;
13060 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13061 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13063 m_toolBar->SetToolShortHelp(ID_AIS,
13064 ToolShortHelp_Array[AIS_Toolbar_Switch_Next]);
13065 if (m_toolBar->m_pTBAISTool) {
13066 m_toolBar->GetToolbar()->SetToolNormalBitmapEx(
13067 m_toolBar->m_pTBAISTool, iconName_Array[AIS_Toolbar_Switch]);
13068 m_toolBar->GetToolbar()->Refresh();
13069 m_toolBar->m_tblastAISiconName = iconName_Array[AIS_Toolbar_Switch];
13074void ChartCanvas::TouchAISToolActive(
void) {
13075 if (!m_toolBar)
return;
13079 if (m_toolBar->m_pTBAISTool) {
13080 if ((!g_pAIS->IsAISSuppressed()) && (!g_pAIS->IsAISAlertGeneral())) {
13081 g_nAIS_activity_timer = 5;
13083 wxString iconName = _T(
"AIS_Normal_Active");
13084 if (g_pAIS->IsAISAlertGeneral()) iconName = _T(
"AIS_AlertGeneral_Active");
13085 if (g_pAIS->IsAISSuppressed()) iconName = _T(
"AIS_Suppressed_Active");
13086 if (!m_bShowAIS) iconName = _T(
"AIS_Disabled");
13088 if (m_toolBar->m_tblastAISiconName != iconName) {
13089 if (m_toolBar->GetToolbar()) {
13090 m_toolBar->GetToolbar()->SetToolNormalBitmapEx(
13091 m_toolBar->m_pTBAISTool, iconName);
13092 m_toolBar->GetToolbar()->Refresh();
13093 m_toolBar->m_tblastAISiconName = iconName;
13100void ChartCanvas::UpdateAISTBTool(
void) {
13101 if (!g_pAIS)
return;
13102 if (!m_toolBar)
return;
13108 if (m_toolBar->m_pTBAISTool) {
13109 bool b_update =
false;
13111 iconName = _T(
"AIS");
13112 if (g_pAIS->IsAISSuppressed()) iconName = _T(
"AIS_Suppressed");
13113 if (g_pAIS->IsAISAlertGeneral()) iconName = _T(
"AIS_AlertGeneral");
13114 if (!m_bShowAIS) iconName = _T(
"AIS_Disabled");
13117 if (g_nAIS_activity_timer) {
13118 g_nAIS_activity_timer--;
13120 if (0 == g_nAIS_activity_timer)
13123 iconName = _T(
"AIS_Normal_Active");
13124 if (g_pAIS->IsAISSuppressed()) iconName = _T(
"AIS_Suppressed_Active");
13125 if (g_pAIS->IsAISAlertGeneral())
13126 iconName = _T(
"AIS_AlertGeneral_Active");
13127 if (!m_bShowAIS) iconName = _T(
"AIS_Disabled");
13131 if ((m_toolBar->m_tblastAISiconName != iconName)) b_update =
true;
13133 if (b_update && m_toolBar->GetToolbar()) {
13134 m_toolBar->GetToolbar()->SetToolNormalBitmapEx(m_toolBar->m_pTBAISTool,
13136 m_toolBar->GetToolbar()->Refresh();
13137 m_toolBar->m_tblastAISiconName = iconName;
13148void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13150 bool b_update =
false;
13151 int cc1_edge_comp = 2;
13152 wxRect rect = m_Compass->GetRect();
13153 wxSize parent_size = GetSize();
13155 parent_size *= m_displayScale;
13159 wxPoint tentative_pt(parent_size.x - rect.width - cc1_edge_comp,
13160 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13161 wxRect tentative_rect(tentative_pt, rect.GetSize());
13166 if (m_toolBar->GetScreenRect() != m_mainlast_tb_rect || b_force_new) {
13167 wxRect tb_rect = m_toolBar->GetScreenRect();
13168 wxPoint tentative_pt_in_screen(ClientToScreen(tentative_pt));
13169 wxRect tentative_rect_in_screen(tentative_pt_in_screen.x,
13170 tentative_pt_in_screen.y, rect.width,
13175 if (!tb_rect.Intersects(tentative_rect_in_screen))
13176 m_Compass->Move(tentative_pt);
13178 m_Compass->Move(wxPoint(GetSize().x - rect.width - cc1_edge_comp,
13179 GetSize().y - (rect.height + cc1_edge_comp)));
13181 if (rect != m_Compass->GetRect()) {
13183 m_brepaint_piano =
true;
13186 m_mainlast_tb_rect = tb_rect;
13189 m_Compass->Move(tentative_pt);
13192 if (m_Compass && m_Compass->IsShown())
13193 m_Compass->UpdateStatus(b_force_new | b_update);
13195 if (b_force_new | b_update) Refresh();
13198void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13199 ChartTypeEnum New_Type,
13200 ChartFamilyEnum New_Family) {
13201 if (!GetpCurrentStack())
return;
13202 if (!ChartData)
return;
13204 if (index < GetpCurrentStack()->nEntry) {
13207 pTentative_Chart = ChartData->OpenStackChartConditional(
13208 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13210 if (pTentative_Chart) {
13211 if (m_singleChart) m_singleChart->Deactivate();
13213 m_singleChart = pTentative_Chart;
13214 m_singleChart->Activate();
13216 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13217 GetpCurrentStack(), m_singleChart->GetFullPath());
13230 double best_scale_ppm = GetBestVPScale(m_singleChart);
13231 double rotation = GetVPRotation();
13232 double oldskew = GetVPSkew();
13233 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13235 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13236 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13237 if (fabs(newskew) > 0.0001) rotation = newskew;
13240 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13242 UpdateGPSCompassStatusBox(
true);
13246 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13247 if (idx < 0)
return;
13249 std::vector<int> piano_active_chart_index_array;
13250 piano_active_chart_index_array.push_back(
13251 GetpCurrentStack()->GetCurrentEntrydbIndex());
13252 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13255void ChartCanvas::SelectdbChart(
int dbindex) {
13256 if (!GetpCurrentStack())
return;
13257 if (!ChartData)
return;
13259 if (dbindex >= 0) {
13262 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13264 if (pTentative_Chart) {
13265 if (m_singleChart) m_singleChart->Deactivate();
13267 m_singleChart = pTentative_Chart;
13268 m_singleChart->Activate();
13270 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13271 GetpCurrentStack(), m_singleChart->GetFullPath());
13284 double best_scale_ppm = GetBestVPScale(m_singleChart);
13287 SetViewPoint(zLat, zLon, best_scale_ppm,
13288 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13298void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13299 double target_scale = GetVP().view_scale_ppm;
13301 if (!GetQuiltMode()) {
13302 if (GetpCurrentStack()) {
13303 int stack_index = -1;
13304 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13305 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13306 if (check_dbIndex < 0)
continue;
13308 ChartData->GetChartTableEntry(check_dbIndex);
13309 if (type == cte.GetChartType()) {
13312 }
else if (family == cte.GetChartFamily()) {
13318 if (stack_index >= 0) {
13319 SelectChartFromStack(stack_index);
13323 int sel_dbIndex = -1;
13324 std::vector<int> piano_chart_index_array =
13325 GetQuiltExtendedStackdbIndexArray();
13326 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13327 int check_dbIndex = piano_chart_index_array[i];
13328 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13329 if (type == cte.GetChartType()) {
13330 if (IsChartQuiltableRef(check_dbIndex)) {
13331 sel_dbIndex = check_dbIndex;
13334 }
else if (family == cte.GetChartFamily()) {
13335 if (IsChartQuiltableRef(check_dbIndex)) {
13336 sel_dbIndex = check_dbIndex;
13342 if (sel_dbIndex >= 0) {
13343 SelectQuiltRefdbChart(sel_dbIndex,
false);
13345 AdjustQuiltRefChart();
13349 SetVPScale(target_scale);
13352 SetQuiltChartHiLiteIndex(-1);
13357bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
13358 return std::find(m_tile_yesshow_index_array.begin(),
13359 m_tile_yesshow_index_array.end(),
13360 index) != m_tile_yesshow_index_array.end();
13363bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
13364 return std::find(m_tile_noshow_index_array.begin(),
13365 m_tile_noshow_index_array.end(),
13366 index) != m_tile_noshow_index_array.end();
13369void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
13370 if (std::find(m_tile_noshow_index_array.begin(),
13371 m_tile_noshow_index_array.end(),
13372 index) == m_tile_noshow_index_array.end()) {
13373 m_tile_noshow_index_array.push_back(index);
13383void ChartCanvas::HandlePianoClick(
int selected_index,
int selected_dbIndex) {
13384 if (g_boptionsactive)
13386 if (!m_pCurrentStack)
return;
13387 if (!ChartData)
return;
13395 if (!GetQuiltMode()) {
13396 if (m_bpersistent_quilt ) {
13397 if (IsChartQuiltableRef(selected_dbIndex)) {
13398 ToggleCanvasQuiltMode();
13399 SelectQuiltRefdbChart(selected_dbIndex);
13400 m_bpersistent_quilt =
false;
13402 SelectChartFromStack(selected_index);
13405 SelectChartFromStack(selected_index);
13406 g_sticky_chart = selected_dbIndex;
13410 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
13415 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
13416 bool bfound =
false;
13417 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
13418 if (m_tile_noshow_index_array[i] ==
13419 selected_dbIndex) {
13420 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
13427 m_tile_noshow_index_array.push_back(selected_dbIndex);
13431 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
13432 m_tile_yesshow_index_array.push_back(selected_dbIndex);
13436 if (IsChartQuiltableRef(selected_dbIndex)) {
13442 bool set_scale =
false;
13443 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
13444 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
13450 SelectQuiltRefdbChart(selected_dbIndex,
true);
13452 SelectQuiltRefdbChart(selected_dbIndex,
false);
13457 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
13459 double proposed_scale_onscreen =
13460 GetCanvasScaleFactor() / GetVPScale();
13462 if (g_bPreserveScaleOnX) {
13463 proposed_scale_onscreen =
13464 wxMin(proposed_scale_onscreen,
13465 100 * pc->GetNormalScaleMax(GetCanvasScaleFactor(),
13466 GetCanvasWidth()));
13468 proposed_scale_onscreen =
13469 wxMin(proposed_scale_onscreen,
13470 20 * pc->GetNormalScaleMax(GetCanvasScaleFactor(),
13471 GetCanvasWidth()));
13473 proposed_scale_onscreen =
13474 wxMax(proposed_scale_onscreen,
13475 pc->GetNormalScaleMin(GetCanvasScaleFactor(),
13479 SetVPScale(GetCanvasScaleFactor() / proposed_scale_onscreen);
13483 ToggleCanvasQuiltMode();
13484 SelectdbChart(selected_dbIndex);
13485 m_bpersistent_quilt =
true;
13490 SetQuiltChartHiLiteIndex(-1);
13491 gFrame->UpdateGlobalMenuItems();
13493 HideChartInfoWindow();
13498void ChartCanvas::HandlePianoRClick(
int x,
int y,
int selected_index,
13499 int selected_dbIndex) {
13500 if (g_boptionsactive)
13502 if (!GetpCurrentStack())
return;
13504 PianoPopupMenu(x, y, selected_index, selected_dbIndex);
13505 UpdateCanvasControlBar();
13507 SetQuiltChartHiLiteIndex(-1);
13510void ChartCanvas::HandlePianoRollover(
int selected_index,
13511 int selected_dbIndex) {
13512 if (g_boptionsactive)
13514 if (!GetpCurrentStack())
return;
13515 if (!ChartData)
return;
13517 if (ChartData->IsBusy())
return;
13519 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
13521 if (!GetQuiltMode()) {
13522 ShowChartInfoWindow(key_location.x, selected_dbIndex);
13524 std::vector<int> piano_chart_index_array =
13525 GetQuiltExtendedStackdbIndexArray();
13527 if ((GetpCurrentStack()->nEntry > 1) ||
13528 (piano_chart_index_array.size() >= 1)) {
13529 ShowChartInfoWindow(key_location.x, selected_dbIndex);
13530 SetQuiltChartHiLiteIndex(selected_dbIndex);
13533 }
else if (GetpCurrentStack()->nEntry == 1) {
13535 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
13536 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
13537 ShowChartInfoWindow(key_location.x, selected_dbIndex);
13539 }
else if ((-1 == selected_index) && (-1 == selected_dbIndex)) {
13540 ShowChartInfoWindow(key_location.x, selected_dbIndex);
13546void ChartCanvas::UpdateCanvasControlBar(
void) {
13547 if (m_pianoFrozen)
return;
13549 if (!GetpCurrentStack())
return;
13550 if (!ChartData)
return;
13551 if (!g_bShowChartBar)
return;
13554 int sel_family = -1;
13556 std::vector<int> piano_chart_index_array;
13557 std::vector<int> empty_piano_chart_index_array;
13559 wxString old_hash = m_Piano->GetStoredHash();
13561 if (GetQuiltMode()) {
13562 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
13563 m_Piano->SetKeyArray(piano_chart_index_array);
13565 std::vector<int> piano_active_chart_index_array =
13566 GetQuiltCandidatedbIndexArray();
13567 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13569 std::vector<int> piano_eclipsed_chart_index_array =
13570 GetQuiltEclipsedStackdbIndexArray();
13571 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
13573 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
13574 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
13576 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
13577 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
13579 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
13580 m_Piano->SetKeyArray(piano_chart_index_array);
13583 if (m_singleChart) {
13584 sel_type = m_singleChart->GetChartType();
13585 sel_family = m_singleChart->GetChartFamily();
13590 std::vector<int> piano_skew_chart_index_array;
13591 std::vector<int> piano_tmerc_chart_index_array;
13592 std::vector<int> piano_poly_chart_index_array;
13594 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
13596 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
13597 double skew_norm = ctei.GetChartSkew();
13598 if (skew_norm > 180.) skew_norm -= 360.;
13600 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
13601 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
13604 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
13605 if (fabs(skew_norm) > 1.)
13606 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
13608 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
13609 }
else if (fabs(skew_norm) > 1.)
13610 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
13612 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
13613 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
13614 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
13616 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
13617 if (new_hash != old_hash) {
13618 m_Piano->FormatKeys();
13619 HideChartInfoWindow();
13620 m_Piano->ResetRollover();
13621 SetQuiltChartHiLiteIndex(-1);
13622 m_brepaint_piano =
true;
13628 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
13630 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
13631 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
13632 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
13633 if (e == CHART_FAMILY_RASTER) mask |= 1;
13634 if (e == CHART_FAMILY_VECTOR) {
13635 if (t == CHART_TYPE_CM93COMP)
13642 wxString s_indicated;
13643 if (sel_type == CHART_TYPE_CM93COMP)
13644 s_indicated = _T(
"cm93");
13646 if (sel_family == CHART_FAMILY_RASTER)
13647 s_indicated = _T(
"raster");
13648 else if (sel_family == CHART_FAMILY_VECTOR)
13649 s_indicated = _T(
"vector");
13652 g_Platform->setChartTypeMaskSel(mask, s_indicated);
13655void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
13657void ChartCanvas::PianoPopupMenu(
int x,
int y,
int selected_index,
13658 int selected_dbIndex) {
13659 if (!GetpCurrentStack())
return;
13662 if (!GetQuiltMode())
return;
13664 menu_selected_dbIndex = selected_dbIndex;
13665 menu_selected_index = selected_index;
13667 m_piano_ctx_menu =
new wxMenu();
13670 bool b_is_in_noshow =
false;
13671 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
13672 if (m_quilt_noshow_index_array[i] ==
13675 b_is_in_noshow =
true;
13680 if (b_is_in_noshow) {
13681 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART, _(
"Show This Chart"));
13682 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
13683 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
13684 }
else if (GetpCurrentStack()->nEntry > 1) {
13685 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
13686 _(
"Hide This Chart"));
13687 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
13688 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
13691 wxPoint pos = wxPoint(x, y - 30);
13694 if (m_piano_ctx_menu->GetMenuItems().GetCount())
13695 PopupMenu(m_piano_ctx_menu, pos);
13697 delete m_piano_ctx_menu;
13698 m_piano_ctx_menu = NULL;
13700 HideChartInfoWindow();
13701 m_Piano->ResetRollover();
13703 SetQuiltChartHiLiteIndex(-1);
13708void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
13709 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
13710 if (m_quilt_noshow_index_array[i] ==
13711 menu_selected_dbIndex)
13713 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
13719void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
13720 if (!GetpCurrentStack())
return;
13721 if (!ChartData)
return;
13723 RemoveChartFromQuilt(menu_selected_dbIndex);
13727 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
13728 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
13730 int i = menu_selected_index + 1;
13731 bool b_success =
false;
13732 while (i < GetpCurrentStack()->nEntry - 1) {
13733 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
13734 if (type == ChartData->GetDBChartType(dbIndex)) {
13735 SelectQuiltRefChart(i);
13745 i = menu_selected_index - 1;
13747 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
13748 if (type == ChartData->GetDBChartType(dbIndex)) {
13749 SelectQuiltRefChart(i);
13759void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
13761 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
13762 if (m_quilt_noshow_index_array[i] ==
13765 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
13770 m_quilt_noshow_index_array.push_back(dbIndex);
13773bool ChartCanvas::UpdateS52State() {
13774 bool retval =
false;
13778 ps52plib->SetShowS57Text(m_encShowText);
13779 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
13780 ps52plib->m_bShowSoundg = m_encShowDepth;
13781 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
13782 ps52plib->m_bShowLdisText = m_encShowLightDesc;
13785 if (!m_encShowLights)
13786 ps52plib->AddObjNoshow(
"LIGHTS");
13788 ps52plib->RemoveObjNoshow(
"LIGHTS");
13789 ps52plib->SetLightsOff(!m_encShowLights);
13790 ps52plib->m_bExtendLightSectors =
true;
13793 ps52plib->SetAnchorOn(m_encShowAnchor);
13794 ps52plib->SetQualityOfData(m_encShowDataQual);
13800void ChartCanvas::SetShowENCDataQual(
bool show) {
13801 m_encShowDataQual = show;
13802 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13803 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13805 m_s52StateHash = 0;
13808void ChartCanvas::SetShowENCText(
bool show) {
13809 m_encShowText = show;
13810 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13811 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13813 m_s52StateHash = 0;
13816void ChartCanvas::SetENCDisplayCategory(
int category) {
13817 m_encDisplayCategory = category;
13818 m_s52StateHash = 0;
13821void ChartCanvas::SetShowENCDepth(
bool show) {
13822 m_encShowDepth = show;
13823 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13824 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13826 m_s52StateHash = 0;
13829void ChartCanvas::SetShowENCLightDesc(
bool show) {
13830 m_encShowLightDesc = show;
13831 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13832 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13834 m_s52StateHash = 0;
13837void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
13838 m_encShowBuoyLabels = show;
13839 m_s52StateHash = 0;
13842void ChartCanvas::SetShowENCLights(
bool show) {
13843 m_encShowLights = show;
13844 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13845 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13847 m_s52StateHash = 0;
13850void ChartCanvas::SetShowENCAnchor(
bool show) {
13851 m_encShowAnchor = show;
13852 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13853 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13855 m_s52StateHash = 0;
13858wxRect ChartCanvas::GetMUIBarRect() {
13861 rv = m_muiBar->GetRect();
13867void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
13868 if (!GetAlertString().IsEmpty()) {
13869 wxFont *pfont = wxTheFontList->FindOrCreateFont(
13870 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
13872 dc.SetFont(*pfont);
13873 dc.SetPen(*wxTRANSPARENT_PEN);
13875 dc.SetBrush(wxColour(243, 229, 47));
13877 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
13881 wxRect sbr = GetScaleBarRect();
13882 int xp = sbr.x + sbr.width + 10;
13883 int yp = (sbr.y + sbr.height) - h;
13885 int wdraw = w + 10;
13886 dc.DrawRectangle(xp, yp, wdraw, h);
13887 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
13888 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
13898#define BRIGHT_XCALIB
13899#define __OPCPN_USEICC__
13902#ifdef __OPCPN_USEICC__
13903int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
13904 double co_green,
double co_blue);
13906wxString temp_file_name;
13910class ocpnCurtain:
public wxDialog
13912 DECLARE_CLASS( ocpnCurtain )
13913 DECLARE_EVENT_TABLE()
13916 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
13918 bool ProcessEvent(wxEvent& event);
13922IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
13924BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
13927ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
13929 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
13932ocpnCurtain::~ocpnCurtain()
13936bool ocpnCurtain::ProcessEvent(wxEvent& event)
13938 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
13939 return GetParent()->GetEventHandler()->ProcessEvent(event);
13944#include <windows.h>
13947typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
13948typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
13949SetDeviceGammaRamp_ptr_type
13950 g_pSetDeviceGammaRamp;
13951GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
13953WORD *g_pSavedGammaMap;
13957int InitScreenBrightness(
void) {
13959 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
13963 if (NULL == hGDI32DLL) {
13964 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
13966 if (NULL != hGDI32DLL) {
13968 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
13969 hGDI32DLL,
"SetDeviceGammaRamp");
13970 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
13971 hGDI32DLL,
"GetDeviceGammaRamp");
13974 if ((NULL == g_pSetDeviceGammaRamp) ||
13975 (NULL == g_pGetDeviceGammaRamp)) {
13976 FreeLibrary(hGDI32DLL);
13985 if (!g_pSavedGammaMap) {
13986 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
13989 bbr = g_pGetDeviceGammaRamp(
13990 hDC, g_pSavedGammaMap);
13991 ReleaseDC(NULL, hDC);
13996 wxRegKey *pRegKey =
new wxRegKey(
13997 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
13998 _T(
"NT\\CurrentVersion\\ICM"));
13999 if (!pRegKey->Exists()) pRegKey->Create();
14000 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14002 g_brightness_init =
true;
14007 if (NULL == g_pcurtain) {
14008 if (gFrame->CanSetTransparent()) {
14010 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14011 wxPoint(0, 0), ::wxGetDisplaySize(),
14012 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14013 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14020 g_pcurtain->Hide();
14022 HWND hWnd = GetHwndOf(g_pcurtain);
14023 SetWindowLong(hWnd, GWL_EXSTYLE,
14024 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14025 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14026 g_pcurtain->SetTransparent(0);
14028 g_pcurtain->Maximize();
14029 g_pcurtain->Show();
14032 g_pcurtain->Enable();
14033 g_pcurtain->Disable();
14040 g_brightness_init =
true;
14046 wxString cmd(_T (
"xcalib -version" ));
14048 wxArrayString output;
14049 long r = wxExecute(cmd, output);
14052 _T(
" External application \"xcalib\" not found. Screen brightness ")
14053 _T(
"not changed."));
14055 g_brightness_init =
true;
14060int RestoreScreenBrightness(
void) {
14063 if (g_pSavedGammaMap) {
14064 HDC hDC = GetDC(NULL);
14065 g_pSetDeviceGammaRamp(hDC,
14067 ReleaseDC(NULL, hDC);
14069 free(g_pSavedGammaMap);
14070 g_pSavedGammaMap = NULL;
14074 g_pcurtain->Close();
14075 g_pcurtain->Destroy();
14079 g_brightness_init =
false;
14084#ifdef BRIGHT_XCALIB
14085 if (g_brightness_init) {
14087 cmd = _T(
"xcalib -clear");
14088 wxExecute(cmd, wxEXEC_ASYNC);
14089 g_brightness_init =
false;
14099int SetScreenBrightness(
int brightness) {
14105 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14107 g_pcurtain->Close();
14108 g_pcurtain->Destroy();
14112 InitScreenBrightness();
14114 if (NULL == hGDI32DLL) {
14116 wchar_t wdll_name[80];
14117 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14118 LPCWSTR cstr = wdll_name;
14120 hGDI32DLL = LoadLibrary(cstr);
14122 if (NULL != hGDI32DLL) {
14124 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14125 hGDI32DLL,
"SetDeviceGammaRamp");
14126 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14127 hGDI32DLL,
"GetDeviceGammaRamp");
14130 if ((NULL == g_pSetDeviceGammaRamp) ||
14131 (NULL == g_pGetDeviceGammaRamp)) {
14132 FreeLibrary(hGDI32DLL);
14139 HDC hDC = GetDC(NULL);
14150 int increment = brightness * 256 / 100;
14153 WORD GammaTable[3][256];
14156 for (
int i = 0; i < 256; i++) {
14157 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14158 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14159 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14161 table_val += increment;
14163 if (table_val > 65535) table_val = 65535;
14166 g_pSetDeviceGammaRamp(hDC, GammaTable);
14167 ReleaseDC(NULL, hDC);
14171 if (g_pSavedGammaMap) {
14172 HDC hDC = GetDC(NULL);
14173 g_pSetDeviceGammaRamp(hDC,
14175 ReleaseDC(NULL, hDC);
14178 if (brightness < 100) {
14179 if (NULL == g_pcurtain) InitScreenBrightness();
14182 int sbrite = wxMax(1, brightness);
14183 sbrite = wxMin(100, sbrite);
14185 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14189 g_pcurtain->Close();
14190 g_pcurtain->Destroy();
14200#ifdef BRIGHT_XCALIB
14202 if (!g_brightness_init) {
14203 last_brightness = 100;
14204 g_brightness_init =
true;
14205 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14206 InitScreenBrightness();
14209#ifdef __OPCPN_USEICC__
14212 if (!CreateSimpleICCProfileFile(
14213 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14214 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14215 wxString cmd(_T (
"xcalib " ));
14216 cmd += temp_file_name;
14218 wxExecute(cmd, wxEXEC_ASYNC);
14227 if (brightness > last_brightness) {
14229 cmd = _T(
"xcalib -clear");
14230 wxExecute(cmd, wxEXEC_ASYNC);
14232 ::wxMilliSleep(10);
14234 int brite_adj = wxMax(1, brightness);
14235 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14236 wxExecute(cmd, wxEXEC_ASYNC);
14238 int brite_adj = wxMax(1, brightness);
14239 int factor = (brite_adj * 100) / last_brightness;
14240 factor = wxMax(1, factor);
14242 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14243 wxExecute(cmd, wxEXEC_ASYNC);
14248 last_brightness = brightness;
14255#ifdef __OPCPN_USEICC__
14257#define MLUT_TAG 0x6d4c5554L
14258#define VCGT_TAG 0x76636774L
14260int GetIntEndian(
unsigned char *s) {
14265 p = (
unsigned char *)&ret;
14268 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14270 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14275unsigned short GetShortEndian(
unsigned char *s) {
14276 unsigned short ret;
14280 p = (
unsigned char *)&ret;
14283 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
14285 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
14291int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14292 double co_green,
double co_blue) {
14296 fp = fopen(file_name,
"wb");
14297 if (!fp)
return -1;
14303 for (
int i = 0; i < 128; i++) header[i] = 0;
14305 fwrite(header, 128, 1, fp);
14309 int numTags = GetIntEndian((
unsigned char *)&numTags0);
14310 fwrite(&numTags, 1, 4, fp);
14312 int tagName0 = VCGT_TAG;
14313 int tagName = GetIntEndian((
unsigned char *)&tagName0);
14314 fwrite(&tagName, 1, 4, fp);
14316 int tagOffset0 = 128 + 4 *
sizeof(int);
14317 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
14318 fwrite(&tagOffset, 1, 4, fp);
14321 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
14322 fwrite(&tagSize, 1, 4, fp);
14324 fwrite(&tagName, 1, 4, fp);
14326 fwrite(&tagName, 1, 4, fp);
14331 int gammatype0 = 0;
14332 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
14333 fwrite(&gammatype, 1, 4, fp);
14335 int numChannels0 = 3;
14336 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
14337 fwrite(&numChannels, 1, 2, fp);
14339 int numEntries0 = 256;
14340 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
14341 fwrite(&numEntries, 1, 2, fp);
14343 int entrySize0 = 1;
14344 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
14345 fwrite(&entrySize, 1, 2, fp);
14347 unsigned char ramp[256];
14350 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
14351 fwrite(ramp, 256, 1, fp);
14354 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
14355 fwrite(ramp, 256, 1, fp);
14358 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
14359 fwrite(ramp, 256, 1, fp);
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.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool Compose(const ViewPort &vp)
bool ActivateNextPoint(Route *pr, bool skipped)
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
bool RenderNextSmallerCellOutlines(ocpnDC &dc, ViewPort &vp, ChartCanvas *cc)