33#include <wx/graphics.h>
34#include <wx/clipbrd.h>
35#include <wx/aui/aui.h>
39#include <wx/listimpl.cpp>
41#include "model/ais_decoder.h"
43#include "model/ais_target_data.h"
45#include "model/conn_params.h"
46#include "model/cutil.h"
47#include "model/geodesic.h"
49#include "model/idents.h"
50#include "model/multiplexer.h"
51#include "model/nav_object_database.h"
52#include "model/navutil_base.h"
53#include "model/own_ship.h"
55#include "model/route.h"
56#include "model/routeman.h"
57#include "model/select.h"
58#include "model/select_item.h"
59#include "model/track.h"
60#include "model/wx28compat.h"
63#include "AISTargetAlertDialog.h"
64#include "CanvasConfig.h"
65#include "canvasMenu.h"
66#include "CanvasOptions.h"
75#include "hotkeys_dlg.h"
77#include "glTextureDescriptor.h"
79#include "iENCToolbar.h"
86#include "NMEALogWindow.h"
87#include "OCPN_AUIManager.h"
89#include "ocpn_frame.h"
90#include "ocpn_pixel.h"
91#include "OCPNRegion.h"
94#include "pluginmanager.h"
97#include "routemanagerdialog.h"
98#include "route_point_gui.h"
100#include "RoutePropDlgImpl.h"
104#include "SendToGpsDlg.h"
105#include "shapefile_basemap.h"
107#include "SystemCmdSound.h"
111#include "tide_time.h"
114#include "track_gui.h"
115#include "TrackPropDlg.h"
118#include "s57_ocpn_utils.h"
121#include "androidUTIL.h"
125#include "glChartCanvas.h"
129#include <wx/msw/msvcrt.h>
138extern float g_ShipScaleFactorExp;
139extern double g_mouse_zoom_sensitivity;
144#define printf printf2
146int __cdecl printf2(
const char *format, ...) {
150 va_start(argptr, format);
151 int ret = vsnprintf(str,
sizeof(str), format, argptr);
153 OutputDebugStringA(str);
158#if defined(__MSVC__) && (_MSC_VER < 1700)
159#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
165#define OCPN_ALT_MENUBAR 1
173extern bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
174extern void catch_signals(
int signo);
176extern void AlphaBlending(
ocpnDC &dc,
int x,
int y,
int size_x,
int size_y,
177 float radius, wxColour color,
178 unsigned char transparency);
180extern double g_ChartNotRenderScaleFactor;
182extern bool bDBUpdateInProgress;
183extern ColorScheme global_color_scheme;
184extern int g_nbrightness;
189extern RouteList *pRouteList;
190extern std::vector<Track *> g_TrackList;
201extern double AnchorPointMinDist;
202extern bool AnchorAlertOn1;
203extern bool AnchorAlertOn2;
208extern wxString GetLayerName(
int id);
209extern wxString g_uploadConnection;
210extern bool g_bsimplifiedScalebar;
212extern bool bDrawCurrentValues;
214extern s52plib *ps52plib;
216extern bool g_bTempShowMenuBar;
217extern bool g_bShowMenuBar;
218extern bool g_bShowCompassWin;
223extern int g_iNavAidRadarRingsNumberVisible;
224extern bool g_bNavAidRadarRingsShown;
225extern float g_fNavAidRadarRingsStep;
226extern int g_pNavAidRadarRingsStepUnits;
227extern bool g_bWayPointPreventDragging;
228extern bool g_bEnableZoomToCursor;
229extern bool g_bShowChartBar;
230extern int g_ENCSoundingScaleFactor;
231extern int g_ENCTextScaleFactor;
232extern int g_maxzoomin;
234bool g_bShowShipToActive;
235int g_shipToActiveStyle;
236int g_shipToActiveColor;
240extern int g_S57_dialog_sx, g_S57_dialog_sy;
243extern int g_detailslider_dialog_x, g_detailslider_dialog_y;
245extern bool g_b_overzoom_x;
246extern double g_plus_minus_zoom_factor;
248extern int g_OwnShipIconType;
249extern double g_n_ownship_length_meters;
250extern double g_n_ownship_beam_meters;
251extern double g_n_gps_antenna_offset_y;
252extern double g_n_gps_antenna_offset_x;
253extern int g_n_ownship_min_mm;
255extern double g_COGAvg;
257extern int g_click_stop;
259extern double g_ownship_predictor_minutes;
260extern int g_cog_predictor_style;
261extern wxString g_cog_predictor_color;
262extern int g_cog_predictor_endmarker;
263extern int g_ownship_HDTpredictor_style;
264extern wxString g_ownship_HDTpredictor_color;
265extern int g_ownship_HDTpredictor_endmarker;
266extern int g_ownship_HDTpredictor_width;
267extern double g_ownship_HDTpredictor_miles;
269extern bool g_bquiting;
276extern bool g_bopengl;
278extern bool g_bFullScreenQuilt;
280extern bool g_bsmoothpanzoom;
281extern bool g_bSmoothRecenter;
285extern bool g_b_assume_azerty;
287extern ChartGroupArray *g_pGroupArray;
292extern OcpnSound *g_anchorwatch_sound;
294extern bool g_bresponsive;
295extern int g_chart_zoom_modifier_raster;
296extern int g_chart_zoom_modifier_vector;
297extern int g_ChartScaleFactor;
302extern double g_gl_ms_per_frame;
303extern bool g_benable_rotate;
304extern bool g_bRollover;
306extern bool g_bSpaceDropMark;
307extern bool g_bAutoHideToolbar;
308extern int g_nAutoHideToolbar;
309extern bool g_bDeferredInitDone;
311extern wxString g_CmdSoundString;
336static bool mouse_leftisdown;
338bool g_brouteCreating;
340bool g_bShowTrackPointTime;
346bool g_brightness_init;
349int g_cog_predictor_width;
350extern double g_display_size_mm;
354extern wxColour g_colourOwnshipRangeRingsColour;
358extern double g_defaultBoatSpeed;
359double g_defaultBoatSpeedUserUnit;
361extern int g_nAIS_activity_timer;
362extern bool g_bskew_comp;
363extern float g_compass_scalefactor;
364extern int g_COGAvgSec;
365extern bool g_btenhertz;
367wxGLContext *g_pGLcontext;
370extern unsigned int g_canvasConfig;
375extern float g_toolbar_scalefactor;
378wxString g_ObjQFileExt;
383extern int g_GUIScaleFactor;
386wxString g_lastS52PLIBPluginMessage;
387extern bool g_bChartBarEx;
388bool g_PrintingInProgress;
391#define MAX_BRIGHT 100
397EVT_PAINT(ChartCanvas::OnPaint)
398EVT_ACTIVATE(ChartCanvas::OnActivate)
399EVT_SIZE(ChartCanvas::OnSize)
400#ifndef HAVE_WX_GESTURE_EVENTS
401EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
403EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
404EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
405EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
406EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
407EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
408EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
409EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
410EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
411EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
412EVT_KEY_UP(ChartCanvas::OnKeyUp)
413EVT_CHAR(ChartCanvas::OnKeyChar)
414EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
415EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
416EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
417EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
418EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
419EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
420EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
421EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
427 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER) {
428 parent_frame = (
MyFrame *)frame;
429 m_canvasIndex = canvasIndex;
433 SetBackgroundColour(wxColour(0, 0, 0));
434 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
438 m_bDrawingRoute =
false;
439 m_bRouteEditing =
false;
440 m_bMarkEditing =
false;
441 m_bRoutePoinDragging =
false;
442 m_bIsInRadius =
false;
443 m_bMayToggleMenuBar =
true;
446 m_bShowNavobjects =
true;
448 m_bAppendingRoute =
false;
449 pThumbDIBShow = NULL;
450 m_bShowCurrent =
false;
452 bShowingCurrent =
false;
456 m_b_paint_enable =
true;
459 pss_overlay_bmp = NULL;
460 pss_overlay_mask = NULL;
461 m_bChartDragging =
false;
462 m_bMeasure_Active =
false;
463 m_bMeasure_DistCircle =
false;
464 m_pMeasureRoute = NULL;
465 m_pTrackRolloverWin = NULL;
466 m_pRouteRolloverWin = NULL;
467 m_pAISRolloverWin = NULL;
469 m_disable_edge_pan =
false;
470 m_dragoffsetSet =
false;
474 m_singleChart = NULL;
475 m_upMode = NORTH_UP_MODE;
477 m_bShowAISScaled =
false;
478 m_timed_move_vp_active =
false;
485 m_pSelectedRoute = NULL;
486 m_pSelectedTrack = NULL;
487 m_pRoutePointEditTarget = NULL;
488 m_pFoundPoint = NULL;
489 m_pMouseRoute = NULL;
490 m_prev_pMousePoint = NULL;
491 m_pEditRouteArray = NULL;
492 m_pFoundRoutePoint = NULL;
493 m_FinishRouteOnKillFocus =
true;
495 m_pRolloverRouteSeg = NULL;
496 m_pRolloverTrackSeg = NULL;
497 m_bsectors_shown =
false;
499 m_bbrightdir =
false;
504 m_pos_image_user_day = NULL;
505 m_pos_image_user_dusk = NULL;
506 m_pos_image_user_night = NULL;
507 m_pos_image_user_grey_day = NULL;
508 m_pos_image_user_grey_dusk = NULL;
509 m_pos_image_user_grey_night = NULL;
512 m_rotation_speed = 0;
518 m_pos_image_user_yellow_day = NULL;
519 m_pos_image_user_yellow_dusk = NULL;
520 m_pos_image_user_yellow_night = NULL;
522 SetOwnShipState(SHIP_INVALID);
524 undo =
new Undo(
this);
530 m_focus_indicator_pix = 1;
532 m_pCurrentStack = NULL;
533 m_bpersistent_quilt =
false;
534 m_piano_ctx_menu = NULL;
537 g_ChartNotRenderScaleFactor = 2.0;
538 m_bShowScaleInStatusBar =
true;
541 m_bShowScaleInStatusBar =
false;
542 m_show_focus_bar =
true;
544 m_bShowOutlines =
false;
545 m_bDisplayGrid =
false;
546 m_bShowDepthUnits =
true;
547 m_encDisplayCategory = (int)STANDARD;
549 m_encShowLights =
true;
550 m_encShowAnchor =
true;
551 m_encShowDataQual =
false;
553 m_pQuilt =
new Quilt(
this);
555 SetAlertString(_T(
""));
558 g_PrintingInProgress =
false;
560#ifdef HAVE_WX_GESTURE_EVENTS
561 m_oldVPSScale = -1.0;
562 m_popupWanted =
false;
568 singleClickEventIsValid =
false;
577 pCursorPencil = NULL;
582 SetCursor(*pCursorArrow);
584 pPanTimer =
new wxTimer(
this, m_MouseDragging);
587 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
588 pMovementTimer->Stop();
590 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
591 pMovementStopTimer->Stop();
593 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
594 pRotDefTimer->Stop();
596 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
597 m_DoubleClickTimer->Stop();
599 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
600 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
601 m_chart_drag_inertia_active =
false;
603 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
604 m_animationActive =
false;
608 m_panx_target_final = m_pany_target_final = 0;
609 m_panx_target_now = m_pany_target_now = 0;
611 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
612 pCurTrackTimer->Stop();
613 m_curtrack_timer_msec = 10;
615 m_wheelzoom_stop_oneshot = 0;
616 m_last_wheel_dir = 0;
618 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
620 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
622 m_rollover_popup_timer_msec = 20;
624 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
626 m_b_rot_hidef =
true;
631 m_upMode = NORTH_UP_MODE;
632 m_bLookAhead =
false;
636 m_cs = GLOBAL_COLOR_SCHEME_DAY;
639 VPoint.view_scale_ppm = 1;
643 m_canvas_scale_factor = 1.;
645 m_canvas_width = 1000;
647 m_overzoomTextWidth = 0;
648 m_overzoomTextHeight = 0;
652 gShapeBasemap.Reset();
657 m_pEM_Fathoms = NULL;
659 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
661 m_pEM_OverZoom = NULL;
663 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
667 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"),
671 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
674 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
677 double factor_dusk = 0.5;
678 double factor_night = 0.25;
681 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
683 int rimg_width = m_os_image_red_day.GetWidth();
684 int rimg_height = m_os_image_red_day.GetHeight();
686 m_os_image_red_dusk = m_os_image_red_day.Copy();
687 m_os_image_red_night = m_os_image_red_day.Copy();
689 for (
int iy = 0; iy < rimg_height; iy++) {
690 for (
int ix = 0; ix < rimg_width; ix++) {
691 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
692 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
693 m_os_image_red_day.GetGreen(ix, iy),
694 m_os_image_red_day.GetBlue(ix, iy));
695 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
696 hsv.value = hsv.value * factor_dusk;
697 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
698 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
700 hsv = wxImage::RGBtoHSV(rgb);
701 hsv.value = hsv.value * factor_night;
702 nrgb = wxImage::HSVtoRGB(hsv);
703 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
709 m_os_image_grey_day =
710 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
712 int gimg_width = m_os_image_grey_day.GetWidth();
713 int gimg_height = m_os_image_grey_day.GetHeight();
715 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
716 m_os_image_grey_night = m_os_image_grey_day.Copy();
718 for (
int iy = 0; iy < gimg_height; iy++) {
719 for (
int ix = 0; ix < gimg_width; ix++) {
720 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
721 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
722 m_os_image_grey_day.GetGreen(ix, iy),
723 m_os_image_grey_day.GetBlue(ix, iy));
724 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
725 hsv.value = hsv.value * factor_dusk;
726 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
727 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
729 hsv = wxImage::RGBtoHSV(rgb);
730 hsv.value = hsv.value * factor_night;
731 nrgb = wxImage::HSVtoRGB(hsv);
732 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
738 m_os_image_yellow_day = m_os_image_red_day.Copy();
740 gimg_width = m_os_image_yellow_day.GetWidth();
741 gimg_height = m_os_image_yellow_day.GetHeight();
743 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
744 m_os_image_yellow_night = m_os_image_red_day.Copy();
746 for (
int iy = 0; iy < gimg_height; iy++) {
747 for (
int ix = 0; ix < gimg_width; ix++) {
748 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
749 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
750 m_os_image_yellow_day.GetGreen(ix, iy),
751 m_os_image_yellow_day.GetBlue(ix, iy));
752 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
753 hsv.hue += 60. / 360.;
754 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
755 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
757 hsv = wxImage::RGBtoHSV(rgb);
758 hsv.value = hsv.value * factor_dusk;
759 hsv.hue += 60. / 360.;
760 nrgb = wxImage::HSVtoRGB(hsv);
761 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
763 hsv = wxImage::RGBtoHSV(rgb);
764 hsv.hue += 60. / 360.;
765 hsv.value = hsv.value * factor_night;
766 nrgb = wxImage::HSVtoRGB(hsv);
767 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
773 m_pos_image_red = &m_os_image_red_day;
774 m_pos_image_yellow = &m_os_image_yellow_day;
775 m_pos_image_grey = &m_os_image_grey_day;
779 m_pBrightPopup = NULL;
782 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
785 int gridFontSize = 8;
786#if defined(__WXOSX__) || defined(__WXGTK3__)
788 gridFontSize *= GetContentScaleFactor();
792 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
793 FALSE, wxString(_T (
"Arial" )));
795 m_Piano =
new Piano(
this);
797 m_bShowCompassWin =
true;
800 m_Compass->SetScaleFactor(g_compass_scalefactor);
801 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
803 m_pianoFrozen =
false;
805 SetMinSize(wxSize(200, 200));
807 m_displayScale = 1.0;
808#if defined(__WXOSX__) || defined(__WXGTK3__)
810 m_displayScale = GetContentScaleFactor();
812 VPoint.SetPixelScale(m_displayScale);
814#ifdef HAVE_WX_GESTURE_EVENTS
817 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
818 wxLogError(
"Failed to enable touch events");
823 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
824 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
826 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
827 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
829 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
830 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
832 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
833 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
838ChartCanvas::~ChartCanvas() {
839 delete pThumbDIBShow;
847 delete pCursorPencil;
851 delete pMovementTimer;
852 delete pMovementStopTimer;
853 delete pCurTrackTimer;
855 delete m_DoubleClickTimer;
857 delete m_pTrackRolloverWin;
858 delete m_pRouteRolloverWin;
859 delete m_pAISRolloverWin;
860 delete m_pBrightPopup;
866 m_dc_route.SelectObject(wxNullBitmap);
869 delete pWorldBackgroundChart;
870 delete pss_overlay_bmp;
874 delete m_pEM_Fathoms;
876 delete m_pEM_OverZoom;
881 delete m_pos_image_user_day;
882 delete m_pos_image_user_dusk;
883 delete m_pos_image_user_night;
884 delete m_pos_image_user_grey_day;
885 delete m_pos_image_user_grey_dusk;
886 delete m_pos_image_user_grey_night;
887 delete m_pos_image_user_yellow_day;
888 delete m_pos_image_user_yellow_dusk;
889 delete m_pos_image_user_yellow_night;
893 if (!g_bdisable_opengl) {
896#if wxCHECK_VERSION(2, 9, 0)
897 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
904 MUIBar *muiBar = m_muiBar;
908 delete m_pCurrentStack;
913void ChartCanvas::RebuildCursors() {
919 delete pCursorPencil;
923 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
927 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
928 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
929 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
930 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
931 wxImage ICursorPencil =
932 style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
933 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
935#if !defined(__WXMSW__) && !defined(__WXQT__)
936 ICursorLeft.ConvertAlphaToMask(128);
937 ICursorRight.ConvertAlphaToMask(128);
938 ICursorUp.ConvertAlphaToMask(128);
939 ICursorDown.ConvertAlphaToMask(128);
940 ICursorPencil.ConvertAlphaToMask(10);
941 ICursorCross.ConvertAlphaToMask(10);
944 if (ICursorLeft.Ok()) {
945 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
946 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
947 pCursorLeft =
new wxCursor(ICursorLeft);
949 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
951 if (ICursorRight.Ok()) {
952 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
953 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
954 pCursorRight =
new wxCursor(ICursorRight);
956 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
958 if (ICursorUp.Ok()) {
959 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
960 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
961 pCursorUp =
new wxCursor(ICursorUp);
963 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
965 if (ICursorDown.Ok()) {
966 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
967 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
968 pCursorDown =
new wxCursor(ICursorDown);
970 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
972 if (ICursorPencil.Ok()) {
973 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
974 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
975 pCursorPencil =
new wxCursor(ICursorPencil);
977 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
979 if (ICursorCross.Ok()) {
980 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
981 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
982 pCursorCross =
new wxCursor(ICursorCross);
984 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
986 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
987 pPlugIn_Cursor = NULL;
990void ChartCanvas::CanvasApplyLocale() {
991 CreateDepthUnitEmbossMaps(m_cs);
992 CreateOZEmbossMapData(m_cs);
995void ChartCanvas::SetupGlCanvas() {
998 if (!g_bdisable_opengl) {
1000 wxLogMessage(_T(
"Creating glChartCanvas"));
1005 if (IsPrimaryCanvas()) {
1012 wxGLContext *pctx =
new wxGLContext(m_glcc);
1013 m_glcc->SetContext(pctx);
1014 g_pGLcontext = pctx;
1017 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
1019 m_glcc->SetContext(g_pGLcontext);
1029 if (!g_bdisable_opengl) {
1032 wxLogMessage(_T(
"Creating glChartCanvas"));
1036 if (IsPrimaryCanvas()) {
1037 qDebug() <<
"Creating Primary glChartCanvas";
1045 wxGLContext *pctx =
new wxGLContext(m_glcc);
1046 m_glcc->SetContext(pctx);
1047 g_pGLcontext = pctx;
1048 m_glcc->m_pParentCanvas =
this;
1051 qDebug() <<
"Creating Secondary glChartCanvas";
1057 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1060 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1061 m_glcc->SetContext(pwxctx);
1062 m_glcc->m_pParentCanvas =
this;
1070void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1071 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1086 if (m_routeState && m_FinishRouteOnKillFocus)
1087 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1089 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1093void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1094 m_routeFinishTimer.Stop();
1098 gFrame->UpdateGlobalMenuItems(
this);
1100 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1103void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1104 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1107#ifdef HAVE_WX_GESTURE_EVENTS
1108void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1114 m_popupWanted =
true;
1117void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1121void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1123void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1125void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1126 wxPoint pos =
event.GetPosition();
1130 if (!m_popupWanted) {
1131 wxMouseEvent ev(wxEVT_LEFT_UP);
1138 m_popupWanted =
false;
1140 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1147void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1150 wxPoint pos =
event.GetPosition();
1154void ChartCanvas::OnMotion(wxMouseEvent &event) {
1159 event.m_leftDown = m_leftdown;
1163void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1165 if (event.IsGestureEnd())
return;
1167 double factor =
event.GetZoomFactor();
1169 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1174 double wanted_factor = m_oldVPSScale / current_vps * factor;
1179 if (event.IsGestureStart()) {
1180 m_zoomStartPoint =
event.GetPosition();
1182 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1184 m_zoomStartPoint =
event.GetPosition();
1188void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1190void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1191 DoRotateCanvas(0.0);
1195void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1200 m_restore_dbindex = pcc->DBindex;
1202 if (pcc->GroupID < 0) pcc->GroupID = 0;
1204 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1207 m_groupIndex = pcc->GroupID;
1209 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1223 m_encDisplayCategory = pcc->nENCDisplayCategory;
1224 m_encShowDepth = pcc->bShowENCDepths;
1225 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1226 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1227 m_encShowLights = pcc->bShowENCLights;
1228 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1229 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1230 m_encShowDataQual = pcc->bShowENCDataQuality;
1234 m_upMode = NORTH_UP_MODE;
1236 m_upMode = COURSE_UP_MODE;
1238 m_upMode = HEAD_UP_MODE;
1242 m_singleChart = NULL;
1245void ChartCanvas::ApplyGlobalSettings() {
1248 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1249 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1253void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1254 bool groupOK = CheckGroup(m_groupIndex);
1257 SetGroupIndex(m_groupIndex,
true);
1261void ChartCanvas::SetShowGPS(
bool bshow) {
1262 if (m_bShowGPS != bshow) {
1265 m_Compass->SetScaleFactor(g_compass_scalefactor);
1266 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1271void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1272 m_bShowCompassWin = bshow;
1274 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1275 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1279int ChartCanvas::GetPianoHeight() {
1281 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1286void ChartCanvas::ConfigureChartBar() {
1289 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1290 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1292 if (GetQuiltMode()) {
1293 m_Piano->SetRoundedRectangles(
true);
1295 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1296 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1297 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1300void ChartCanvas::ShowTides(
bool bShow) {
1301 gFrame->LoadHarmonics();
1303 if (ptcmgr->IsReady()) {
1304 SetbShowTide(bShow);
1306 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1308 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1309 SetbShowTide(
false);
1310 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1313 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1314 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1325void ChartCanvas::ShowCurrents(
bool bShow) {
1326 gFrame->LoadHarmonics();
1328 if (ptcmgr->IsReady()) {
1329 SetbShowCurrent(bShow);
1330 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1332 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1333 SetbShowCurrent(
false);
1334 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1337 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1338 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1350extern bool g_bPreserveScaleOnX;
1352extern int g_sticky_chart;
1354void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1356void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1357 SetAlertString(_T(
""));
1359 int new_index = index;
1360 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1362 bool bgroup_override =
false;
1363 int old_group_index = new_index;
1365 if (!CheckGroup(new_index)) {
1367 bgroup_override =
true;
1370 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1374 int current_chart_native_scale = GetCanvasChartNativeScale();
1377 m_groupIndex = new_index;
1380 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1383 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1387 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1391 g_sticky_chart = -1;
1395 UpdateCanvasOnGroupChange();
1398 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1400 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1403 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1404 double best_scale = GetBestStartScale(dbi_hint, vp);
1408 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1412 canvasChartsRefresh(dbi_hint);
1414 UpdateCanvasControlBar();
1416 if (!autoSwitch && bgroup_override) {
1418 wxString msg(_(
"Group \""));
1420 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1421 msg += pGroup->m_group_name;
1423 msg += _(
"\" is empty.");
1425 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1432 if (bgroup_override) {
1433 wxString msg(_(
"Group \""));
1435 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1436 msg += pGroup->m_group_name;
1438 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1440 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1444bool ChartCanvas::CheckGroup(
int igroup) {
1445 if (!ChartData)
return true;
1447 if (igroup == 0)
return true;
1452 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1454 if (pGroup->m_element_array.empty())
1458 for (
const auto &elem : pGroup->m_element_array) {
1459 for (
unsigned int ic = 0;
1460 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1462 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1464 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1469 for (
const auto &elem : pGroup->m_element_array) {
1470 const wxString &element_root = elem.m_element_name;
1471 wxString test_string = _T(
"GSHH");
1472 if (element_root.Upper().Contains(test_string))
return true;
1478void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1479 if (!ChartData)
return;
1481 AbstractPlatform::ShowBusySpinner();
1485 SetQuiltRefChart(-1);
1487 m_singleChart = NULL;
1493 if (!m_pCurrentStack) {
1495 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1498 if (-1 != dbi_hint) {
1499 if (GetQuiltMode()) {
1500 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1501 SetQuiltRefChart(dbi_hint);
1505 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1507 if (pTentative_Chart) {
1510 if (m_singleChart) m_singleChart->Deactivate();
1512 m_singleChart = pTentative_Chart;
1513 m_singleChart->Activate();
1515 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1516 GetpCurrentStack(), m_singleChart->GetFullPath());
1524 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1525 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1526 SetQuiltRefChart(selected_index);
1530 SetupCanvasQuiltMode();
1531 if (!GetQuiltMode() && m_singleChart == 0) {
1533 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1534 m_singleChart = pDummyChart;
1540 UpdateCanvasControlBar();
1541 UpdateGPSCompassStatusBox(
true);
1543 SetCursor(wxCURSOR_ARROW);
1545 AbstractPlatform::HideBusySpinner();
1548bool ChartCanvas::DoCanvasUpdate(
void) {
1550 double vpLat, vpLon;
1551 bool blong_jump =
false;
1552 meters_to_shift = 0;
1555 bool bNewChart =
false;
1556 bool bNewView =
false;
1557 bool bCanvasChartAutoOpen =
true;
1559 bool bNewPiano =
false;
1560 bool bOpenSpecified;
1566 if (bDBUpdateInProgress)
return false;
1567 if (!ChartData)
return false;
1569 if (ChartData->IsBusy())
return false;
1595 double dx = m_OSoffsetx;
1596 double dy = m_OSoffsety;
1600 if (GetUpMode() == NORTH_UP_MODE) {
1601 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1603 double offset_angle = atan2(d_north, d_east);
1604 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1605 double chart_angle = GetVPRotation();
1606 double target_angle = chart_angle + offset_angle;
1607 double d_east_mod = offset_distance * cos(target_angle);
1608 double d_north_mod = offset_distance * sin(target_angle);
1609 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1612 extern double gCog_gt;
1615 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1616 double cog_to_use = gCog;
1618 (fabs(gCog - gCog_gt) > 20)) {
1619 cog_to_use = gCog_gt;
1622 if (!g_btenhertz) cog_to_use = g_COGAvg;
1624 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1626 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1627 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1629 double pixel_delta_tent =
1630 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1632 double pixel_delta = 0;
1637 if (!std::isnan(gSog)) {
1641 pixel_delta = pixel_delta_tent;
1644 meters_to_shift = 0;
1646 if (!std::isnan(gCog)) {
1647 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1648 dir_to_shift = cog_to_use;
1649 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1655 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1669 if (GetQuiltMode()) {
1670 int current_db_index = -1;
1671 if (m_pCurrentStack)
1674 ->GetCurrentEntrydbIndex();
1682 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1684 if (m_pCurrentStack->nEntry) {
1685 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1687 SelectQuiltRefdbChart(new_dbIndex,
true);
1688 m_bautofind =
false;
1692 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1693 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1698 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1704 double proposed_scale_onscreen =
1707 int initial_db_index = m_restore_dbindex;
1708 if (initial_db_index < 0) {
1709 if (m_pCurrentStack->nEntry) {
1711 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1716 if (m_pCurrentStack->nEntry) {
1717 int initial_type = ChartData->GetDBChartType(initial_db_index);
1722 if (!IsChartQuiltableRef(initial_db_index)) {
1726 int stack_index = 0;
1728 if (stack_index >= 0) {
1729 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1730 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1731 if (IsChartQuiltableRef(test_db_index) &&
1733 ChartData->GetDBChartType(initial_db_index))) {
1734 initial_db_index = test_db_index;
1742 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1744 SetQuiltRefChart(initial_db_index);
1745 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1753 0, GetVPRotation());
1758 bool super_jump =
false;
1760 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1761 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1762 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1764 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead) {
1766 if (blong_jump) nstep = 20;
1767 StartTimedMovementVP(vpLat, vpLon, nstep);
1776 pLast_Ch = m_singleChart;
1777 ChartTypeEnum new_open_type;
1778 ChartFamilyEnum new_open_family;
1780 new_open_type = pLast_Ch->GetChartType();
1781 new_open_family = pLast_Ch->GetChartFamily();
1783 new_open_type = CHART_TYPE_KAP;
1784 new_open_family = CHART_FAMILY_RASTER;
1787 bOpenSpecified = m_bFirstAuto;
1790 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1793 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1795 if (NULL == pDummyChart) {
1801 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1803 m_singleChart = pDummyChart;
1808 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1810 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1813 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1814 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1821 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1827 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1832 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1835 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1840 if (NULL != m_singleChart)
1841 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1842 m_singleChart->GetFullPath());
1845 m_pCurrentStack->CurrentStackEntry = tEntry;
1855 if (bCanvasChartAutoOpen) {
1856 bool search_direction =
1858 int start_index = 0;
1862 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1863 (LastStack.nEntry == 0)) {
1864 search_direction =
true;
1865 start_index = m_pCurrentStack->nEntry - 1;
1869 if (bOpenSpecified) {
1870 search_direction =
false;
1872 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1875 new_open_type = CHART_TYPE_DONTCARE;
1878 pProposed = ChartData->OpenStackChartConditional(
1879 m_pCurrentStack, start_index, search_direction, new_open_type,
1883 if (NULL == pProposed)
1884 pProposed = ChartData->OpenStackChartConditional(
1885 m_pCurrentStack, start_index, search_direction,
1886 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1888 if (NULL == pProposed)
1889 pProposed = ChartData->OpenStackChartConditional(
1890 m_pCurrentStack, start_index, search_direction,
1891 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1902 if (NULL == pProposed) {
1903 if (NULL == pDummyChart) {
1909 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1911 pProposed = pDummyChart;
1915 if (m_singleChart) m_singleChart->Deactivate();
1916 m_singleChart = pProposed;
1918 if (m_singleChart) {
1919 m_singleChart->Activate();
1920 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1921 m_pCurrentStack, m_singleChart->GetFullPath());
1926 if (NULL != m_singleChart) {
1932 if (!GetVP().IsValid())
1933 set_scale = 1. / 20000.;
1935 double proposed_scale_onscreen;
1938 double new_scale_ppm =
1939 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1947 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1948 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1949 double equivalent_vp_scale =
1951 double new_scale_ppm =
1952 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1957 proposed_scale_onscreen =
1958 wxMin(proposed_scale_onscreen,
1961 proposed_scale_onscreen =
1962 wxMax(proposed_scale_onscreen,
1971 m_singleChart->GetChartSkew() * PI / 180.,
1978 if ((m_bFollow) && m_singleChart)
1980 m_singleChart->GetChartSkew() * PI / 180.,
1989 m_bFirstAuto =
false;
1993 if (bNewChart && !bNewView) Refresh(
false);
1998 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
2001 return bNewChart | bNewView;
2004void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
2005 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
2007 SetQuiltRefChart(db_index);
2009 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
2012 double best_scale_ppm = GetBestVPScale(pc);
2016 SetQuiltRefChart(-1);
2018 SetQuiltRefChart(-1);
2021void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
2022 std::vector<int> piano_chart_index_array =
2023 GetQuiltExtendedStackdbIndexArray();
2024 int current_db_index = piano_chart_index_array[selected_index];
2026 SelectQuiltRefdbChart(current_db_index);
2029double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2033 if ((g_bPreserveScaleOnX) ||
2034 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2040 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2041 double equivalent_vp_scale =
2043 double new_scale_ppm =
2044 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2051 double max_underzoom_multiplier = 2.0;
2052 if (GetVP().b_quilt) {
2053 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2054 pchart->GetChartType(),
2055 pchart->GetChartFamily());
2056 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2059 proposed_scale_onscreen = wxMin(
2060 proposed_scale_onscreen,
2062 max_underzoom_multiplier);
2065 proposed_scale_onscreen =
2066 wxMax(proposed_scale_onscreen,
2074void ChartCanvas::SetupCanvasQuiltMode(
void) {
2077 ChartData->LockCache();
2079 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2083 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2084 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2085 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2086 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2088 m_Piano->SetRoundedRectangles(
true);
2091 int target_new_dbindex = -1;
2092 if (m_pCurrentStack) {
2093 target_new_dbindex =
2094 GetQuiltReferenceChartIndex();
2096 if (-1 != target_new_dbindex) {
2097 if (!IsChartQuiltableRef(target_new_dbindex)) {
2098 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2099 int type = ChartData->GetDBChartType(target_new_dbindex);
2102 int stack_index = m_pCurrentStack->CurrentStackEntry;
2104 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2105 (stack_index >= 0)) {
2106 int proj_tent = ChartData->GetDBChartProj(
2107 m_pCurrentStack->GetDBIndex(stack_index));
2108 int type_tent = ChartData->GetDBChartType(
2109 m_pCurrentStack->GetDBIndex(stack_index));
2111 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2112 if ((proj == proj_tent) && (type_tent == type)) {
2113 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2123 if (IsChartQuiltableRef(target_new_dbindex))
2124 SelectQuiltRefdbChart(target_new_dbindex,
2127 SelectQuiltRefdbChart(-1,
false);
2129 m_singleChart = NULL;
2132 AdjustQuiltRefChart();
2140 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2144 std::vector<int> empty_array;
2145 m_Piano->SetActiveKeyArray(empty_array);
2146 m_Piano->SetNoshowIndexArray(empty_array);
2147 m_Piano->SetEclipsedIndexArray(empty_array);
2150 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2151 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2152 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2153 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2155 m_Piano->SetRoundedRectangles(
false);
2161 if (!GetQuiltMode()) {
2162 if (ChartData && ChartData->IsValid()) {
2166 if (m_bFollow ==
true) {
2174 if (!m_singleChart) {
2177 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2185 int cur_max_scale = (int)1e8;
2187 ChartBase *pChart = GetFirstQuiltChart();
2191 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2193 if (pChart->GetNativeScale() < cur_max_scale) {
2194 Candidate_Chart = pChart;
2195 cur_max_scale = pChart->GetNativeScale();
2198 pChart = GetNextQuiltChart();
2201 m_singleChart = Candidate_Chart;
2205 if (NULL == m_singleChart) {
2206 m_singleChart = ChartData->OpenStackChartConditional(
2207 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2208 CHART_FAMILY_DONTCARE);
2214 InvalidateAllQuiltPatchs();
2216 if (m_singleChart) {
2217 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2218 std::vector<int> one_array;
2219 one_array.push_back(dbi);
2220 m_Piano->SetActiveKeyArray(one_array);
2223 if (m_singleChart) {
2224 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2228 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2232bool ChartCanvas::IsTempMenuBarEnabled() {
2235 wxGetOsVersion(&major);
2243double ChartCanvas::GetCanvasRangeMeters() {
2245 GetSize(&width, &height);
2246 int minDimension = wxMin(width, height);
2249 range *= cos(GetVP().clat * PI / 180.);
2253void ChartCanvas::SetCanvasRangeMeters(
double range) {
2255 GetSize(&width, &height);
2256 int minDimension = wxMin(width, height);
2258 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2262bool ChartCanvas::SetUserOwnship() {
2266 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2267 double factor_dusk = 0.5;
2268 double factor_night = 0.25;
2270 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2271 m_pos_image_user_day =
new wxImage;
2272 *m_pos_image_user_day = pbmp->ConvertToImage();
2273 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2275 int gimg_width = m_pos_image_user_day->GetWidth();
2276 int gimg_height = m_pos_image_user_day->GetHeight();
2279 m_pos_image_user_dusk =
new wxImage;
2280 m_pos_image_user_night =
new wxImage;
2282 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2283 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2285 for (
int iy = 0; iy < gimg_height; iy++) {
2286 for (
int ix = 0; ix < gimg_width; ix++) {
2287 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2288 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2289 m_pos_image_user_day->GetGreen(ix, iy),
2290 m_pos_image_user_day->GetBlue(ix, iy));
2291 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2292 hsv.value = hsv.value * factor_dusk;
2293 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2294 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2297 hsv = wxImage::RGBtoHSV(rgb);
2298 hsv.value = hsv.value * factor_night;
2299 nrgb = wxImage::HSVtoRGB(hsv);
2300 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2307 m_pos_image_user_grey_day =
new wxImage;
2308 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2310 m_pos_image_user_grey_dusk =
new wxImage;
2311 m_pos_image_user_grey_night =
new wxImage;
2313 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2314 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2316 for (
int iy = 0; iy < gimg_height; iy++) {
2317 for (
int ix = 0; ix < gimg_width; ix++) {
2318 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2319 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2320 m_pos_image_user_grey_day->GetGreen(ix, iy),
2321 m_pos_image_user_grey_day->GetBlue(ix, iy));
2322 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2323 hsv.value = hsv.value * factor_dusk;
2324 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2325 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2328 hsv = wxImage::RGBtoHSV(rgb);
2329 hsv.value = hsv.value * factor_night;
2330 nrgb = wxImage::HSVtoRGB(hsv);
2331 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2338 m_pos_image_user_yellow_day =
new wxImage;
2339 m_pos_image_user_yellow_dusk =
new wxImage;
2340 m_pos_image_user_yellow_night =
new wxImage;
2342 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2343 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2344 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2346 for (
int iy = 0; iy < gimg_height; iy++) {
2347 for (
int ix = 0; ix < gimg_width; ix++) {
2348 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2349 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2350 m_pos_image_user_grey_day->GetGreen(ix, iy),
2351 m_pos_image_user_grey_day->GetBlue(ix, iy));
2355 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2356 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2357 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2359 hsv = wxImage::RGBtoHSV(rgb);
2360 hsv.value = hsv.value * factor_dusk;
2361 nrgb = wxImage::HSVtoRGB(hsv);
2362 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2364 hsv = wxImage::RGBtoHSV(rgb);
2365 hsv.value = hsv.value * factor_night;
2366 nrgb = wxImage::HSVtoRGB(hsv);
2367 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2379 m_display_size_mm = size;
2386 double horizontal = sd.x;
2390 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2391 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2394 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2395 ps52plib->SetPPMM(m_pix_per_mm);
2400 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2402 m_display_size_mm, sd.x, sd.y);
2406 ssx = g_monitor_info[g_current_monitor].width;
2407 ssy = g_monitor_info[g_current_monitor].height;
2408 msg.Printf(_T(
"monitor size: %d %d"), ssx, ssy);
2411 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2414void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2416 wxString msg(event.m_string.c_str(), wxConvUTF8);
2418 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2419 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2422 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2424 compress_msg_array.RemoveAt(event.thread);
2425 compress_msg_array.Insert( msg, event.thread);
2428 compress_msg_array.Add(msg);
2431 wxString combined_msg;
2432 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2433 combined_msg += compress_msg_array[i];
2434 combined_msg += _T(
"\n");
2438 pprog->Update(pprog_count, combined_msg, &skip );
2439 pprog->SetSize(pprog_size);
2444void ChartCanvas::InvalidateGL() {
2445 if (!m_glcc)
return;
2447 if (g_bopengl) m_glcc->Invalidate();
2449 if (m_Compass) m_Compass->UpdateStatus(
true);
2452int ChartCanvas::GetCanvasChartNativeScale() {
2454 if (!VPoint.b_quilt) {
2455 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2457 ret = (int)m_pQuilt->GetRefNativeScale();
2462ChartBase *ChartCanvas::GetChartAtCursor() {
2464 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2465 target_chart = m_singleChart;
2466 else if (VPoint.b_quilt)
2467 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2469 target_chart = NULL;
2470 return target_chart;
2473ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2477 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2479 target_chart = NULL;
2480 return target_chart;
2483int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2484 int new_dbIndex = -1;
2485 if (!VPoint.b_quilt) {
2486 if (m_pCurrentStack) {
2487 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2488 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2490 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2500 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2502 for (
unsigned int is = 0; is < im; is++) {
2504 m_pQuilt->GetExtendedStackIndexArray()[is]);
2507 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2517void ChartCanvas::EnablePaint(
bool b_enable) {
2518 m_b_paint_enable = b_enable;
2520 if (m_glcc) m_glcc->EnablePaint(b_enable);
2524bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2526void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2528std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2529 return m_pQuilt->GetQuiltIndexArray();
2533void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2534 VPoint.b_quilt = b_quilt;
2535 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2538bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2540int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2541 return m_pQuilt->GetRefChartdbIndex();
2544void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2545 m_pQuilt->InvalidateAllQuiltPatchs();
2548ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2549 return m_pQuilt->GetLargestScaleChart();
2552ChartBase *ChartCanvas::GetFirstQuiltChart() {
2553 return m_pQuilt->GetFirstChart();
2556ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2558int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2560void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2561 m_pQuilt->SetHiliteIndex(dbIndex);
2564void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2565 m_pQuilt->SetHiliteIndexArray(hilite_array);
2568void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2569 m_pQuilt->ClearHiliteIndexArray();
2572std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2574 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2577int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2578 return m_pQuilt->GetRefChartdbIndex();
2581std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2582 return m_pQuilt->GetExtendedStackIndexArray();
2585std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2586 return m_pQuilt->GetFullscreenIndexArray();
2589std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2590 return m_pQuilt->GetEclipsedStackIndexArray();
2593void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2595double ChartCanvas::GetQuiltMaxErrorFactor() {
2596 return m_pQuilt->GetMaxErrorFactor();
2599bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2600 return m_pQuilt->IsChartQuiltableRef(db_index);
2604 double chartMaxScale =
2606 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2609void ChartCanvas::StartMeasureRoute() {
2610 if (!m_routeState) {
2611 if (m_bMeasure_Active) {
2613 NavObjectChanges::getInstance());
2614 m_pMeasureRoute = NULL;
2617 m_bMeasure_Active =
true;
2618 m_nMeasureState = 1;
2619 m_bDrawingRoute =
false;
2621 SetCursor(*pCursorPencil);
2626void ChartCanvas::CancelMeasureRoute() {
2627 m_bMeasure_Active =
false;
2628 m_nMeasureState = 0;
2629 m_bDrawingRoute =
false;
2631 g_pRouteMan->
DeleteRoute(m_pMeasureRoute, NavObjectChanges::getInstance());
2632 m_pMeasureRoute = NULL;
2634 SetCursor(*pCursorArrow);
2637ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2639void ChartCanvas::SetVP(
ViewPort &vp) {
2650void ChartCanvas::TriggerDeferredFocus() {
2653 m_deferredFocusTimer.Start(20,
true);
2655#if defined(__WXGTK__) || defined(__WXOSX__)
2666void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2671void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2672 if (SendKeyEventToPlugins(event))
2676 int key_char =
event.GetKeyCode();
2679 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2685 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2690 if (g_benable_rotate) {
2711void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2712 if (SendKeyEventToPlugins(event))
2716 bool b_handled =
false;
2718 m_modkeys =
event.GetModifiers();
2720 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2722#ifdef OCPN_ALT_MENUBAR
2728 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2730 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2731 if (!g_bTempShowMenuBar) {
2732 g_bTempShowMenuBar =
true;
2733 parent_frame->ApplyGlobalSettings(
false);
2735 m_bMayToggleMenuBar =
false;
2741 if (event.GetKeyCode() != WXK_ALT) {
2742 m_bMayToggleMenuBar =
false;
2749 switch (event.GetKeyCode()) {
2756 event.GetPosition(&x, &y);
2757 m_FinishRouteOnKillFocus =
false;
2758 CallPopupMenu(x, y);
2759 m_FinishRouteOnKillFocus =
true;
2763 m_modkeys |= wxMOD_ALT;
2767 m_modkeys |= wxMOD_CONTROL;
2772 case WXK_RAW_CONTROL:
2773 m_modkeys |= wxMOD_RAW_CONTROL;
2778 if (m_modkeys == wxMOD_CONTROL)
2779 parent_frame->DoStackDown(
this);
2780 else if (g_bsmoothpanzoom) {
2781 StartTimedMovement();
2790 if (g_bsmoothpanzoom) {
2791 StartTimedMovement();
2799 if (m_modkeys == wxMOD_CONTROL)
2800 parent_frame->DoStackUp(
this);
2801 else if (g_bsmoothpanzoom) {
2802 StartTimedMovement();
2811 if (g_bsmoothpanzoom) {
2812 StartTimedMovement();
2824 SetShowENCText(!GetShowENCText());
2830 if (!m_bMeasure_Active) {
2831 if (event.ShiftDown())
2832 m_bMeasure_DistCircle =
true;
2834 m_bMeasure_DistCircle =
false;
2836 StartMeasureRoute();
2838 CancelMeasureRoute();
2840 SetCursor(*pCursorArrow);
2850 parent_frame->ToggleColorScheme();
2852 TriggerDeferredFocus();
2856 int mod = m_modkeys & wxMOD_SHIFT;
2857 if (mod != m_brightmod) {
2859 m_bbrightdir = !m_bbrightdir;
2862 if (!m_bbrightdir) {
2863 g_nbrightness -= 10;
2864 if (g_nbrightness <= MIN_BRIGHT) {
2865 g_nbrightness = MIN_BRIGHT;
2866 m_bbrightdir =
true;
2869 g_nbrightness += 10;
2870 if (g_nbrightness >= MAX_BRIGHT) {
2871 g_nbrightness = MAX_BRIGHT;
2872 m_bbrightdir =
false;
2876 SetScreenBrightness(g_nbrightness);
2877 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2886 parent_frame->DoStackDown(
this);
2890 parent_frame->DoStackUp(
this);
2895 double t0 = wxGetLocalTimeMillis().ToDouble();
2897 double t1 = wxGetLocalTimeMillis().ToDouble() - t0;
2899 ToggleCanvasQuiltMode();
2905 parent_frame->ToggleFullScreen();
2910 if (m_modkeys == wxMOD_ALT) {
2915 UpdateGPSCompassStatusBox(
true);
2917 ToggleChartOutlines();
2922 parent_frame->ActivateMOB();
2926 case WXK_NUMPAD_ADD:
2931 case WXK_NUMPAD_SUBTRACT:
2932 case WXK_PAGEDOWN: {
2933 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2938 if (m_bMeasure_Active) {
2939 if (m_nMeasureState > 2) {
2940 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2941 m_pMeasureRoute->m_lastMousePointIndex =
2942 m_pMeasureRoute->GetnPoints();
2944 gFrame->RefreshAllCanvas();
2946 CancelMeasureRoute();
2947 StartMeasureRoute();
2955 if (event.GetKeyCode() < 128)
2957 int key_char =
event.GetKeyCode();
2961 if (!g_b_assume_azerty) {
2963 if (g_benable_rotate) {
2995 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3002 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3003 m_modkeys & wxMOD_RAW_CONTROL) {
3004 parent_frame->ToggleFullScreen();
3009 if (event.ControlDown()) key_char -= 64;
3011 if (key_char >=
'0' && key_char <=
'9')
3012 SetGroupIndex(key_char -
'0');
3017 SetShowENCAnchor(!GetShowENCAnchor());
3023 parent_frame->ToggleColorScheme();
3028 event.GetPosition(&x, &y);
3029 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3030 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3032 if (!pPopupDetailSlider) {
3033 if (VPoint.b_quilt) {
3035 if (m_pQuilt->GetChartAtPix(
3040 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3042 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3047 if (m_singleChart) {
3048 ChartType = m_singleChart->GetChartType();
3049 ChartFam = m_singleChart->GetChartFamily();
3053 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3054 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3056 this, -1, ChartType, ChartFam,
3057 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3058 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
3059 if (pPopupDetailSlider) pPopupDetailSlider->Show();
3063 if (pPopupDetailSlider) pPopupDetailSlider->Close();
3064 pPopupDetailSlider = NULL;
3070 if (!wxWindow::FindWindowByName(
"NmeaDebugWindow")) {
3071 auto top_window = wxWindow::FindWindowByName(kTopLevelWindowName);
3072 NMEALogWindow::GetInstance().Create(top_window, 35);
3074 wxWindow::FindWindowByName(
"NmeaDebugWindow")->Show();
3078 SetShowENCLights(!GetShowENCLights());
3084 if (event.ShiftDown())
3085 m_bMeasure_DistCircle =
true;
3087 m_bMeasure_DistCircle =
false;
3089 StartMeasureRoute();
3093 if (g_bInlandEcdis && ps52plib) {
3094 SetENCDisplayCategory((_DisCat)STANDARD);
3099 ToggleChartOutlines();
3103 ToggleCanvasQuiltMode();
3107 parent_frame->ToggleTestPause();
3110 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3111 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3112 g_iNavAidRadarRingsNumberVisible = 1;
3113 else if (!g_bNavAidRadarRingsShown &&
3114 g_iNavAidRadarRingsNumberVisible == 1)
3115 g_iNavAidRadarRingsNumberVisible = 0;
3118 SetShowENCDepth(!m_encShowDepth);
3123 SetShowENCText(!GetShowENCText());
3128 SetShowENCDataQual(!GetShowENCDataQual());
3133 m_bShowNavobjects = !m_bShowNavobjects;
3148 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3153 if (event.ControlDown()) gFrame->DropMarker(
false);
3159 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3160 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3161 if ((indexActive + 1) <= r->GetnPoints()) {
3172 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3178 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3184 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3191 parent_frame->DoSettings();
3195 parent_frame->Close();
3203 if (NULL == pGoToPositionDialog)
3206 pGoToPositionDialog->SetCanvas(
this);
3207 pGoToPositionDialog->Show();
3211 if (undo->AnythingToRedo()) {
3212 undo->RedoNextAction();
3219 if (event.ShiftDown()) {
3220 if (undo->AnythingToRedo()) {
3221 undo->RedoNextAction();
3226 if (undo->AnythingToUndo()) {
3227 undo->UndoLastAction();
3236 if (m_bMeasure_Active) {
3237 CancelMeasureRoute();
3239 SetCursor(*pCursorArrow);
3242 gFrame->RefreshAllCanvas();
3256 switch (gamma_state) {
3276 SetScreenBrightness(g_nbrightness);
3281 if (event.ControlDown()) {
3282 m_bShowCompassWin = !m_bShowCompassWin;
3283 SetShowGPSCompassWindow(m_bShowCompassWin);
3300void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3301 if (SendKeyEventToPlugins(event))
3305 switch (event.GetKeyCode()) {
3307 parent_frame->SwitchKBFocus(
this);
3313 if (!m_pany) m_panspeed = 0;
3319 if (!m_panx) m_panspeed = 0;
3322 case WXK_NUMPAD_ADD:
3323 case WXK_NUMPAD_SUBTRACT:
3326 if (m_mustmove) DoMovement(m_mustmove);
3332 m_modkeys &= ~wxMOD_ALT;
3333#ifdef OCPN_ALT_MENUBAR
3338 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3339 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3340 parent_frame->ApplyGlobalSettings(
false);
3342 m_bMayToggleMenuBar =
true;
3348 m_modkeys &= ~wxMOD_CONTROL;
3352 if (event.GetKeyCode() < 128)
3354 int key_char =
event.GetKeyCode();
3358 if (!g_b_assume_azerty) {
3366 DoMovement(m_mustmove);
3372 DoMovement(m_mustmove);
3373 m_rotation_speed = 0;
3381 DoMovement(m_mustmove);
3391void ChartCanvas::ToggleChartOutlines(
void) {
3392 m_bShowOutlines = !m_bShowOutlines;
3398 if (g_bopengl) InvalidateGL();
3402void ChartCanvas::ToggleLookahead() {
3403 m_bLookAhead = !m_bLookAhead;
3408void ChartCanvas::SetUpMode(
int mode) {
3411 if (mode != NORTH_UP_MODE) {
3414 if (!std::isnan(gCog)) stuff = gCog;
3416 if (g_COGAvgSec > 0) {
3417 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3420 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3422 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3423 SetVPRotation(GetVPSkew());
3428 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3429 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3431 UpdateGPSCompassStatusBox(
true);
3432 gFrame->DoChartUpdate();
3435bool ChartCanvas::DoCanvasCOGSet(
void) {
3436 if (GetUpMode() == NORTH_UP_MODE)
return false;
3437 double cog_use = g_COGAvg;
3438 if (g_btenhertz) cog_use = gCog;
3440 double rotation = 0;
3441 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3442 rotation = -gHdt * PI / 180.;
3443 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3444 rotation = -cog_use * PI / 180.;
3446 SetVPRotation(rotation);
3450double easeOutCubic(
double t) {
3452 return 1.0 - pow(1.0 - t, 3.0);
3455void ChartCanvas::StartChartDragInertia() {
3458 m_bChartDragging =
false;
3461 m_chart_drag_inertia_time = 750;
3462 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3467 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3471 size_t length = m_drag_vec_t.size();
3472 for (
size_t i = 0; i < n_vel; i++) {
3473 xacc += m_drag_vec_x.at(length - 1 - i);
3474 yacc += m_drag_vec_y.at(length - 1 - i);
3475 tacc += m_drag_vec_t.at(length - 1 - i);
3478 m_chart_drag_velocity_x = xacc / tacc;
3479 m_chart_drag_velocity_y = yacc / tacc;
3481 m_chart_drag_inertia_active =
true;
3484 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3490void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3491 if (!m_chart_drag_inertia_active)
return;
3494 wxLongLong now = wxGetLocalTimeMillis();
3495 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3496 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3497 if (t > 1.0) t = 1.0;
3498 double e = 1.0 - easeOutCubic(t);
3501 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3503 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3509 m_last_elapsed = elapsed;
3513 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3514 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3515 double inertia_lat, inertia_lon;
3522 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3523 m_chart_drag_inertia_timer.Stop();
3524 m_chart_drag_inertia_active =
false;
3527 m_target_lat = GetVP().
clat;
3528 m_target_lon = GetVP().
clon;
3529 m_pan_drag.x = m_pan_drag.y = 0;
3530 m_panx = m_pany = 0;
3533 int target_redraw_interval = 40;
3534 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3538void ChartCanvas::StopMovement() {
3539 m_panx = m_pany = 0;
3542 m_rotation_speed = 0;
3545#if !defined(__WXGTK__) && !defined(__WXQT__)
3556bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3558 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3560 if (!pMovementTimer->IsRunning()) {
3562 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3565 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3570 m_last_movement_time = wxDateTime::UNow();
3574void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3577 m_target_lat = target_lat;
3578 m_target_lon = target_lon;
3581 m_start_lat = GetVP().
clat;
3582 m_start_lon = GetVP().
clon;
3584 m_VPMovementTimer.Start(1,
true);
3585 m_timed_move_vp_active =
true;
3587 m_timedVP_step = nstep;
3590void ChartCanvas::DoTimedMovementVP() {
3591 if (!m_timed_move_vp_active)
return;
3592 if (m_stvpc++ > m_timedVP_step * 2) {
3599 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3614 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3615 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3617 m_run_lat = new_lat;
3618 m_run_lon = new_lon;
3624void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3626void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3628void ChartCanvas::StartTimedMovementTarget() {}
3630void ChartCanvas::DoTimedMovementTarget() {}
3632void ChartCanvas::StopMovementTarget() {}
3634void ChartCanvas::DoTimedMovement() {
3635 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3639 wxDateTime now = wxDateTime::UNow();
3641 if (m_last_movement_time.IsValid())
3642 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3644 m_last_movement_time = now;
3652void ChartCanvas::DoMovement(
long dt) {
3654 if (dt == 0) dt = 1;
3657 if (m_mustmove < 0) m_mustmove = 0;
3659 if (m_pan_drag.x || m_pan_drag.y) {
3661 m_pan_drag.x = m_pan_drag.y = 0;
3664 if (m_panx || m_pany) {
3665 const double slowpan = .1, maxpan = 2;
3666 if (m_modkeys == wxMOD_ALT)
3667 m_panspeed = slowpan;
3669 m_panspeed += (double)dt / 500;
3670 m_panspeed = wxMin(maxpan, m_panspeed);
3672 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3675 if (m_zoom_factor != 1) {
3676 double alpha = 400, beta = 1.5;
3677 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3679 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3681 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3686 if (zoom_factor > 1) {
3687 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3691 else if (zoom_factor < 1) {
3692 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3697 if (fabs(zoom_factor - 1) > 1e-4)
3700 if (m_wheelzoom_stop_oneshot > 0) {
3701 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3702 m_wheelzoom_stop_oneshot = 0;
3707 if (zoom_factor > 1) {
3709 m_wheelzoom_stop_oneshot = 0;
3712 }
else if (zoom_factor < 1) {
3714 m_wheelzoom_stop_oneshot = 0;
3721 if (m_rotation_speed) {
3722 double speed = m_rotation_speed;
3723 if (m_modkeys == wxMOD_ALT) speed /= 10;
3724 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3728void ChartCanvas::SetColorScheme(ColorScheme cs) {
3729 SetAlertString(_T(
""));
3733 case GLOBAL_COLOR_SCHEME_DAY:
3734 m_pos_image_red = &m_os_image_red_day;
3735 m_pos_image_grey = &m_os_image_grey_day;
3736 m_pos_image_yellow = &m_os_image_yellow_day;
3737 m_pos_image_user = m_pos_image_user_day;
3738 m_pos_image_user_grey = m_pos_image_user_grey_day;
3739 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3740 m_cTideBitmap = m_bmTideDay;
3741 m_cCurrentBitmap = m_bmCurrentDay;
3744 case GLOBAL_COLOR_SCHEME_DUSK:
3745 m_pos_image_red = &m_os_image_red_dusk;
3746 m_pos_image_grey = &m_os_image_grey_dusk;
3747 m_pos_image_yellow = &m_os_image_yellow_dusk;
3748 m_pos_image_user = m_pos_image_user_dusk;
3749 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3750 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3751 m_cTideBitmap = m_bmTideDusk;
3752 m_cCurrentBitmap = m_bmCurrentDusk;
3754 case GLOBAL_COLOR_SCHEME_NIGHT:
3755 m_pos_image_red = &m_os_image_red_night;
3756 m_pos_image_grey = &m_os_image_grey_night;
3757 m_pos_image_yellow = &m_os_image_yellow_night;
3758 m_pos_image_user = m_pos_image_user_night;
3759 m_pos_image_user_grey = m_pos_image_user_grey_night;
3760 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3761 m_cTideBitmap = m_bmTideNight;
3762 m_cCurrentBitmap = m_bmCurrentNight;
3765 m_pos_image_red = &m_os_image_red_day;
3766 m_pos_image_grey = &m_os_image_grey_day;
3767 m_pos_image_yellow = &m_os_image_yellow_day;
3768 m_pos_image_user = m_pos_image_user_day;
3769 m_pos_image_user_grey = m_pos_image_user_grey_day;
3770 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3771 m_cTideBitmap = m_bmTideDay;
3772 m_cCurrentBitmap = m_bmCurrentDay;
3776 CreateDepthUnitEmbossMaps(cs);
3777 CreateOZEmbossMapData(cs);
3780 m_fog_color = wxColor(
3784 case GLOBAL_COLOR_SCHEME_DUSK:
3787 case GLOBAL_COLOR_SCHEME_NIGHT:
3793 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3794 m_fog_color.Blue() * dim);
3798 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3799 SetBackgroundColour( wxColour(0,0,0) );
3801 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3804 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3806 SetBackgroundColour( wxNullColour );
3813 m_Piano->SetColorScheme(cs);
3815 m_Compass->SetColorScheme(cs);
3817 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3819 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3821 if (g_bopengl && m_glcc) {
3822 m_glcc->SetColorScheme(cs);
3823 g_glTextureManager->ClearAllRasterTextures();
3828 m_brepaint_piano =
true;
3835wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3836 wxImage img = Bitmap.ConvertToImage();
3837 int sx = img.GetWidth();
3838 int sy = img.GetHeight();
3840 wxImage new_img(img);
3842 for (
int i = 0; i < sx; i++) {
3843 for (
int j = 0; j < sy; j++) {
3844 if (!img.IsTransparent(i, j)) {
3845 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3846 (
unsigned char)(img.GetGreen(i, j) * factor),
3847 (
unsigned char)(img.GetBlue(i, j) * factor));
3852 wxBitmap ret = wxBitmap(new_img);
3857void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3860 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3862 if (!m_pBrightPopup) {
3865 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3869 m_pBrightPopup->SetSize(x, y);
3870 m_pBrightPopup->Move(120, 120);
3873 int bmpsx = m_pBrightPopup->GetSize().x;
3874 int bmpsy = m_pBrightPopup->GetSize().y;
3876 wxBitmap bmp(bmpsx, bmpsx);
3877 wxMemoryDC mdc(bmp);
3879 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3880 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3881 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3882 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3885 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3887 mdc.SetFont(*pfont);
3890 if (brightness == max)
3892 else if (brightness == min)
3895 val.Printf(_T(
"%3d"), brightness);
3897 mdc.DrawText(val, 0, 0);
3899 mdc.SelectObject(wxNullBitmap);
3901 m_pBrightPopup->SetBitmap(bmp);
3902 m_pBrightPopup->Show();
3903 m_pBrightPopup->Refresh();
3906void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3907 m_b_rot_hidef =
true;
3911void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3912 if (!g_bRollover)
return;
3914 bool b_need_refresh =
false;
3916 wxSize win_size = GetSize() * m_displayScale;
3917 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3920 bool showAISRollover =
false;
3921 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3923 SelectItem *pFind = pSelectAIS->FindSelection(
3926 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3927 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3930 showAISRollover =
true;
3932 if (NULL == m_pAISRolloverWin) {
3934 m_pAISRolloverWin->IsActive(
false);
3935 b_need_refresh =
true;
3936 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3937 m_AISRollover_MMSI != FoundAIS_MMSI) {
3943 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3944 m_pAISRolloverWin->IsActive(
false);
3945 m_AISRollover_MMSI = 0;
3950 m_AISRollover_MMSI = FoundAIS_MMSI;
3952 if (!m_pAISRolloverWin->IsActive()) {
3953 wxString s = ptarget->GetRolloverString();
3954 m_pAISRolloverWin->SetString(s);
3956 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3957 AIS_ROLLOVER, win_size);
3958 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3959 m_pAISRolloverWin->IsActive(
true);
3960 b_need_refresh =
true;
3964 m_AISRollover_MMSI = 0;
3965 showAISRollover =
false;
3970 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3971 m_pAISRolloverWin->IsActive(
false);
3972 m_AISRollover_MMSI = 0;
3973 b_need_refresh =
true;
3978 bool showRouteRollover =
false;
3980 if (NULL == m_pRolloverRouteSeg) {
3985 SelectableItemList SelList = pSelect->FindSelectionList(
3987 wxSelectableItemListNode *node = SelList.GetFirst();
3993 if (pr && pr->IsVisible()) {
3994 m_pRolloverRouteSeg = pFindSel;
3995 showRouteRollover =
true;
3997 if (NULL == m_pRouteRolloverWin) {
3999 m_pRouteRolloverWin->IsActive(
false);
4002 if (!m_pRouteRolloverWin->IsActive()) {
4010 DistanceBearingMercator(
4011 segShow_point_b->m_lat, segShow_point_b->m_lon,
4012 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4014 if (!pr->m_bIsInLayer)
4015 s.Append(_(
"Route") + _T(
": "));
4017 s.Append(_(
"Layer Route: "));
4019 if (pr->m_RouteNameString.IsEmpty())
4020 s.Append(_(
"(unnamed)"));
4022 s.Append(pr->m_RouteNameString);
4024 s << _T(
"\n") << _(
"Total Length: ")
4025 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
4026 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4027 << segShow_point_b->GetName() << _T(
"\n");
4030 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4031 (
int)floor(brg + 0.5), 0x00B0);
4034 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4036 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4037 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4039 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4040 (
int)floor(varBrg + 0.5), 0x00B0);
4043 s << FormatDistanceAdaptive(dist);
4048 double shiptoEndLeg = 0.;
4049 bool validActive =
false;
4050 if (pr->IsActive() &&
4051 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
4054 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
4055 wxRoutePointListNode *node =
4056 (pr->pRoutePointList)->GetFirst()->GetNext();
4058 float dist_to_endleg = 0;
4062 prp = node->GetData();
4064 shiptoEndLeg += prp->m_seg_len;
4065 else if (prp->m_bIsActive)
4067 dist_to_endleg += prp->m_seg_len;
4068 if (prp->IsSame(segShow_point_a))
break;
4069 node = node->GetNext();
4071 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
4076 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
4077 << segShow_point_b->GetName() << _T(
"\n");
4080 ->GetCurrentRngToActivePoint();
4085 s << FormatDistanceAdaptive(shiptoEndLeg);
4089 if (!std::isnan(gCog) && !std::isnan(gSog))
4091 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
4094 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
4095 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4097 << wxString(ttg_sec > SECONDS_PER_DAY
4098 ? ttg_span.Format(_(
"%Dd %H:%M"))
4099 : ttg_span.Format(_(
"%H:%M")));
4100 wxDateTime dtnow, eta;
4101 eta = dtnow.SetToCurrent().Add(ttg_span);
4102 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
4103 << eta.Format(_T(
" %d %H:%M"));
4105 s << _T(
" ---- ----");
4107 m_pRouteRolloverWin->SetString(s);
4109 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4110 LEG_ROLLOVER, win_size);
4111 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4112 m_pRouteRolloverWin->IsActive(
true);
4113 b_need_refresh =
true;
4114 showRouteRollover =
true;
4118 node = node->GetNext();
4124 m_pRolloverRouteSeg))
4125 showRouteRollover =
false;
4126 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4127 showRouteRollover =
false;
4129 showRouteRollover =
true;
4133 if (m_routeState) showRouteRollover =
false;
4136 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4137 showRouteRollover =
false;
4139 if (m_pRouteRolloverWin &&
4140 !showRouteRollover) {
4141 m_pRouteRolloverWin->IsActive(
false);
4142 m_pRolloverRouteSeg = NULL;
4143 m_pRouteRolloverWin->Destroy();
4144 m_pRouteRolloverWin = NULL;
4145 b_need_refresh =
true;
4146 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4147 m_pRouteRolloverWin->IsActive(
true);
4148 b_need_refresh =
true;
4153 bool showTrackRollover =
false;
4155 if (NULL == m_pRolloverTrackSeg) {
4160 SelectableItemList SelList = pSelect->FindSelectionList(
4162 wxSelectableItemListNode *node = SelList.GetFirst();
4168 if (pt && pt->IsVisible()) {
4169 m_pRolloverTrackSeg = pFindSel;
4170 showTrackRollover =
true;
4172 if (NULL == m_pTrackRolloverWin) {
4174 m_pTrackRolloverWin->IsActive(
false);
4177 if (!m_pTrackRolloverWin->IsActive()) {
4185 DistanceBearingMercator(
4186 segShow_point_b->m_lat, segShow_point_b->m_lon,
4187 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4189 if (!pt->m_bIsInLayer)
4190 s.Append(_(
"Track") + _T(
": "));
4192 s.Append(_(
"Layer Track: "));
4194 if (pt->GetName().IsEmpty())
4195 s.Append(_(
"(unnamed)"));
4197 s.Append(pt->GetName());
4198 double tlenght = pt->Length();
4199 s << _T(
"\n") << _(
"Total Track: ")
4200 << FormatDistanceAdaptive(tlenght);
4201 if (pt->GetLastPoint()->GetTimeString() &&
4202 pt->GetPoint(0)->GetTimeString()) {
4203 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4204 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4205 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4206 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4207 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4208 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4209 << getUsrSpeedUnit();
4210 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4211 : ttime.Format(_T(
" %H:%M")));
4215 if (g_bShowTrackPointTime && strlen(segShow_point_b->GetTimeString()))
4216 s << _T(
"\n") << _(
"Segment Created: ")
4217 << segShow_point_b->GetTimeString();
4221 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4226 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4228 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4229 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4231 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4235 s << FormatDistanceAdaptive(dist);
4237 if (segShow_point_a->GetTimeString() &&
4238 segShow_point_b->GetTimeString()) {
4239 wxDateTime apoint = segShow_point_a->GetCreateTime();
4240 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4241 if (apoint.IsValid() && bpoint.IsValid()) {
4242 double segmentSpeed = toUsrSpeed(
4243 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4244 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4245 << getUsrSpeedUnit();
4249 m_pTrackRolloverWin->SetString(s);
4251 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4252 LEG_ROLLOVER, win_size);
4253 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4254 m_pTrackRolloverWin->IsActive(
true);
4255 b_need_refresh =
true;
4256 showTrackRollover =
true;
4260 node = node->GetNext();
4266 m_pRolloverTrackSeg))
4267 showTrackRollover =
false;
4268 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4269 showTrackRollover =
false;
4271 showTrackRollover =
true;
4275 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4276 showTrackRollover =
false;
4279 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4280 showTrackRollover =
false;
4286 if (m_pTrackRolloverWin &&
4287 !showTrackRollover) {
4288 m_pTrackRolloverWin->IsActive(
false);
4289 m_pRolloverTrackSeg = NULL;
4290 m_pTrackRolloverWin->Destroy();
4291 m_pTrackRolloverWin = NULL;
4292 b_need_refresh =
true;
4293 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4294 m_pTrackRolloverWin->IsActive(
true);
4295 b_need_refresh =
true;
4298 if (b_need_refresh) Refresh();
4301void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4302 if ((GetShowENCLights() || m_bsectors_shown) &&
4303 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4304 extendedSectorLegs)) {
4305 if (!m_bsectors_shown) {
4307 m_bsectors_shown =
true;
4310 if (m_bsectors_shown) {
4312 m_bsectors_shown =
false;
4320#if defined(__WXGTK__) || defined(__WXQT__)
4325 double cursor_lat, cursor_lon;
4328 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4329 while (cursor_lon < -180.) cursor_lon += 360.;
4331 while (cursor_lon > 180.) cursor_lon -= 360.;
4333 SetCursorStatus(cursor_lat, cursor_lon);
4339void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4340 if (!parent_frame->m_pStatusBar)
return;
4344 s1 += toSDMM(1, cursor_lat);
4346 s1 += toSDMM(2, cursor_lon);
4348 if (STAT_FIELD_CURSOR_LL >= 0)
4349 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4351 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4356 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4357 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4358 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4360 wxString s = st + sm;
4361 s << FormatDistanceAdaptive(dist);
4373 if (g_bShowLiveETA) {
4376 float boatSpeedDefault = g_defaultBoatSpeed;
4381 if (!std::isnan(gSog)) {
4383 if (boatSpeed < 0.5) {
4386 realTimeETA = dist / boatSpeed * 60;
4395 s << minutesToHoursDays(realTimeETA);
4400 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4401 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4403 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4408 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4416wxString minutesToHoursDays(
float timeInMinutes) {
4419 if (timeInMinutes == 0) {
4424 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4425 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4430 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4433 hours = (int)timeInMinutes / 60;
4434 min = (int)timeInMinutes % 60;
4437 s << wxString::Format(_T(
"%d"), hours);
4440 s << wxString::Format(_T(
"%d"), hours);
4442 s << wxString::Format(_T(
"%d"), min);
4449 else if (timeInMinutes > 24 * 60) {
4452 days = (int)(timeInMinutes / 60) / 24;
4453 hours = (int)(timeInMinutes / 60) % 24;
4456 s << wxString::Format(_T(
"%d"), days);
4459 s << wxString::Format(_T(
"%d"), days);
4461 s << wxString::Format(_T(
"%d"), hours);
4473void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4481 wxPoint2DDouble *r) {
4486 double rlon, wxPoint2DDouble *r) {
4497 if (!g_bopengl && m_singleChart &&
4498 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4499 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4500 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4501 (m_singleChart->GetChartProjectionType() !=
4502 PROJECTION_TRANSVERSE_MERCATOR) &&
4503 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4504 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4505 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4519 Cur_BSB_Ch->SetVPRasterParms(vp);
4520 double rpixxd, rpixyd;
4521 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4547 if (std::isnan(p.m_x)) {
4548 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4552 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4553 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4555 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4574 if (!g_bopengl && m_singleChart &&
4575 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4576 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4577 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4578 (m_singleChart->GetChartProjectionType() !=
4579 PROJECTION_TRANSVERSE_MERCATOR) &&
4580 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4581 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4582 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4593 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4596 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4601 else if (slon > 180.)
4612 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4618 extendedSectorLegs.clear();
4623 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4625 if (g_bsmoothpanzoom) {
4626 if (StartTimedMovement(stoptimer)) {
4628 m_zoom_factor = factor;
4633 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4638 extendedSectorLegs.clear();
4643 if (!ChartData)
return;
4644 if (!m_pCurrentStack)
return;
4650 if (m_bzooming)
return;
4659 double proposed_scale_onscreen =
4662 bool b_do_zoom =
false;
4671 if (!VPoint.b_quilt) {
4674 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4675 if (new_db_index >= 0)
4676 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4680 int current_ref_stack_index = -1;
4681 if (m_pCurrentStack->nEntry) {
4683 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4684 m_pQuilt->SetReferenceChart(trial_index);
4685 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4686 if (new_db_index >= 0)
4687 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4691 if (m_pCurrentStack)
4692 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4702 double min_allowed_scale =
4705 if (proposed_scale_onscreen < min_allowed_scale) {
4710 proposed_scale_onscreen = min_allowed_scale;
4714 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4717 }
else if (factor < 1) {
4722 bool b_smallest =
false;
4724 if (!VPoint.b_quilt) {
4729 LLBBox viewbox = VPoint.GetBBox();
4731 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4732 double max_allowed_scale;
4746 if (proposed_scale_onscreen > max_allowed_scale) {
4748 proposed_scale_onscreen = max_allowed_scale;
4753 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4754 if (new_db_index >= 0)
4755 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4757 if (m_pCurrentStack)
4758 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4761 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4763 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4764 proposed_scale_onscreen =
4765 wxMin(proposed_scale_onscreen,
4771 m_absolute_min_scale_ppm)
4780 bool b_allow_ztc =
true;
4781 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4782 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4784 double brg, distance;
4785 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4788 meters_to_shift = distance * 1852;
4796 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4799 if (m_bFollow) DoCanvasUpdate();
4806void ChartCanvas::RotateCanvas(
double dir) {
4809 if (g_bsmoothpanzoom) {
4810 if (StartTimedMovement()) {
4812 m_rotation_speed = dir * 60;
4815 double speed = dir * 10;
4816 if (m_modkeys == wxMOD_ALT) speed /= 20;
4817 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4821void ChartCanvas::DoRotateCanvas(
double rotation) {
4822 while (rotation < 0) rotation += 2 * PI;
4823 while (rotation > 2 * PI) rotation -= 2 * PI;
4825 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4827 SetVPRotation(rotation);
4828 parent_frame->UpdateRotationState(VPoint.
rotation);
4831void ChartCanvas::DoTiltCanvas(
double tilt) {
4832 while (tilt < 0) tilt = 0;
4833 while (tilt > .95) tilt = .95;
4835 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4841void ChartCanvas::TogglebFollow(
void) {
4848void ChartCanvas::ClearbFollow(
void) {
4851 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4853 UpdateFollowButtonState();
4857 parent_frame->SetChartUpdatePeriod();
4860void ChartCanvas::SetbFollow(
void) {
4863 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4864 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4872 p.m_x += m_OSoffsetx;
4873 p.m_y -= m_OSoffsety;
4882 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4883 UpdateFollowButtonState();
4885 if (!g_bSmoothRecenter) {
4889 parent_frame->SetChartUpdatePeriod();
4892void ChartCanvas::UpdateFollowButtonState(
void) {
4895 m_muiBar->SetFollowButtonState(0);
4898 m_muiBar->SetFollowButtonState(2);
4900 m_muiBar->SetFollowButtonState(1);
4906 androidSetFollowTool(0);
4909 androidSetFollowTool(2);
4911 androidSetFollowTool(1);
4916void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4917 if (g_bSmoothRecenter && !m_routeState) {
4918 if (StartSmoothJump(lat, lon, scale_ppm))
4922 double gcDist, gcBearingEnd;
4923 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4925 gcBearingEnd += 180;
4926 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4929 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4930 double new_lat = lat + (lat_offset / (1852 * 60));
4931 double new_lon = lon + (lon_offset / (1852 * 60));
4934 StartSmoothJump(lat, lon, scale_ppm);
4939 if (lon > 180.0) lon -= 360.0;
4945 if (!GetQuiltMode()) {
4947 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4948 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4952 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4953 AdjustQuiltRefChart();
4960 UpdateFollowButtonState();
4968bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4973 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4974 double distance_pixels = gcDist *
GetVPScale();
4975 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4981 m_startLat = m_vLat;
4982 m_startLon = m_vLon;
4987 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4988 m_endScale = scale_ppm;
4991 m_animationDuration = 600;
4992 m_animationStart = wxGetLocalTimeMillis();
4999 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5000 m_animationActive =
true;
5005void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5007 wxLongLong now = wxGetLocalTimeMillis();
5008 double elapsed = (now - m_animationStart).ToDouble();
5009 double t = elapsed / m_animationDuration.ToDouble();
5010 if (t > 1.0) t = 1.0;
5013 double e = easeOutCubic(t);
5016 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5017 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5018 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5023 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5029 m_animationActive =
false;
5030 UpdateFollowButtonState();
5037 if (!ChartData)
return false;
5042 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
5043 UpdateFollowButtonState();
5049 extendedSectorLegs.clear();
5059 if (iters++ > 5)
return false;
5060 if (!std::isnan(dlat))
break;
5063 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5069 else if (dlat < -90)
5072 if (dlon > 360.) dlon -= 360.;
5073 if (dlon < -360.) dlon += 360.;
5088 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5092 if (VPoint.b_quilt) {
5093 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5094 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5096 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
5098 double tweak_scale_ppm =
5104 if (new_ref_dbIndex == -1) {
5109 int trial_index = -1;
5110 if (m_pCurrentStack->nEntry) {
5112 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5115 if (trial_index < 0) {
5116 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5117 if (full_screen_array.size())
5118 trial_index = full_screen_array[full_screen_array.size() - 1];
5121 if (trial_index >= 0) {
5122 m_pQuilt->SetReferenceChart(trial_index);
5133 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5135 double offset_angle = atan2(offy, offx);
5136 double offset_distance = sqrt((offy * offy) + (offx * offx));
5137 double chart_angle = GetVPRotation();
5138 double target_angle = chart_angle - offset_angle;
5139 double d_east_mod = offset_distance * cos(target_angle);
5140 double d_north_mod = offset_distance * sin(target_angle);
5145 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5146 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5148 UpdateFollowButtonState();
5154 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5159void ChartCanvas::ReloadVP(
bool b_adjust) {
5160 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5162 LoadVP(VPoint, b_adjust);
5165void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5167 if (g_bopengl && m_glcc) {
5168 m_glcc->Invalidate();
5169 if (m_glcc->GetSize() != GetSize()) {
5170 m_glcc->SetSize(GetSize());
5175 m_cache_vp.Invalidate();
5176 m_bm_cache_vp.Invalidate();
5179 VPoint.Invalidate();
5181 if (m_pQuilt) m_pQuilt->Invalidate();
5190 vp.m_projection_type, b_adjust);
5193void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5194 m_pQuilt->SetReferenceChart(dbIndex);
5195 VPoint.Invalidate();
5196 m_pQuilt->Invalidate();
5199double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5201 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5208int ChartCanvas::AdjustQuiltRefChart() {
5211 wxASSERT(ChartData);
5213 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5215 double min_ref_scale =
5216 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5217 double max_ref_scale =
5218 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5221 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5223 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5225 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5227 int ref_family = pc->GetChartFamily();
5230 unsigned int target_stack_index = 0;
5231 int target_stack_index_check =
5232 m_pQuilt->GetExtendedStackIndexArray()
5233 [m_pQuilt->GetRefChartdbIndex()];
5235 if (wxNOT_FOUND != target_stack_index_check)
5236 target_stack_index = target_stack_index_check;
5238 int extended_array_count =
5239 m_pQuilt->GetExtendedStackIndexArray().size();
5240 while ((!brender_ok) &&
5241 ((
int)target_stack_index < (extended_array_count - 1))) {
5242 target_stack_index++;
5244 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5246 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
5247 IsChartQuiltableRef(test_db_index)) {
5250 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5252 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5259 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5260 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
5261 IsChartQuiltableRef(new_db_index)) {
5262 m_pQuilt->SetReferenceChart(new_db_index);
5265 ret = m_pQuilt->GetRefChartdbIndex();
5267 ret = m_pQuilt->GetRefChartdbIndex();
5270 ret = m_pQuilt->GetRefChartdbIndex();
5279void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5280 delete m_pCurrentStack;
5282 wxASSERT(ChartData);
5283 ChartData->BuildChartStack(m_pCurrentStack, VPoint.
clat, VPoint.
clon,
5292bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5293 double latNE,
double lonNE) {
5295 double latc = (latSW + latNE) / 2.0;
5296 double lonc = (lonSW + lonNE) / 2.0;
5299 double ne_easting, ne_northing;
5300 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5302 double sw_easting, sw_northing;
5303 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5305 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5312 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5315bool ChartCanvas::SetVPProjection(
int projection) {
5321 double prev_true_scale_ppm = m_true_scale_ppm;
5326 m_absolute_min_scale_ppm));
5334bool ChartCanvas::SetVPRotation(
double angle) {
5336 VPoint.
skew, angle);
5339 double skew,
double rotation,
int projection,
5340 bool b_adjust,
bool b_refresh) {
5345 if (VPoint.IsValid()) {
5346 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5347 (fabs(VPoint.
skew - skew) < 1e-9) &&
5348 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5349 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5350 (VPoint.m_projection_type == projection ||
5351 projection == PROJECTION_UNKNOWN))
5354 if (VPoint.m_projection_type != projection)
5355 VPoint.InvalidateTransformCache();
5365 if (projection != PROJECTION_UNKNOWN)
5366 VPoint.SetProjectionType(projection);
5367 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5368 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5371 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5372 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5373 if (VPoint.
clat > 89.5)
5375 else if (VPoint.
clat < -89.5)
5376 VPoint.
clat = -89.5;
5381 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5382 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5394 bool bwasValid = VPoint.IsValid();
5399 m_cache_vp.Invalidate();
5404 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5408 int mouseX = mouse_x;
5409 int mouseY = mouse_y;
5410 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5416 SendCursorLatLonToAllPlugIns(lat, lon);
5419 if (!VPoint.b_quilt && m_singleChart) {
5424 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5428 if ((!m_cache_vp.IsValid()) ||
5433 wxPoint cp_last, cp_this;
5437 if (cp_last != cp_this) {
5443 if (m_pCurrentStack) {
5444 assert(ChartData != 0);
5445 int current_db_index;
5447 m_pCurrentStack->GetCurrentEntrydbIndex();
5449 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5451 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5454 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5458 if (VPoint.b_quilt) {
5460 m_pQuilt->InvalidateAllQuiltPatchs();
5464 if (!m_pCurrentStack)
return false;
5466 int current_db_index;
5468 m_pCurrentStack->GetCurrentEntrydbIndex();
5470 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5471 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5474 int current_ref_stack_index = -1;
5475 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5476 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5477 current_ref_stack_index = i;
5480 if (g_bFullScreenQuilt) {
5481 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5485 bool b_needNewRef =
false;
5488 if ((-1 == current_ref_stack_index) &&
5489 (m_pQuilt->GetRefChartdbIndex() >= 0))
5490 b_needNewRef =
true;
5497 bool renderable =
true;
5499 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5500 if (referenceChart) {
5501 double chartMaxScale = referenceChart->GetNormalScaleMax(
5503 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5505 if (!renderable) b_needNewRef =
true;
5510 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5511 int target_scale = cte_ref.GetScale();
5512 int target_type = cte_ref.GetChartType();
5513 int candidate_stack_index;
5520 candidate_stack_index = 0;
5521 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5523 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5524 int candidate_scale = cte_candidate.GetScale();
5525 int candidate_type = cte_candidate.GetChartType();
5527 if ((candidate_scale >= target_scale) &&
5528 (candidate_type == target_type)) {
5529 bool renderable =
true;
5530 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5531 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5532 if (tentative_referenceChart) {
5533 double chartMaxScale =
5534 tentative_referenceChart->GetNormalScaleMax(
5536 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5539 if (renderable)
break;
5542 candidate_stack_index++;
5547 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5548 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5549 while (candidate_stack_index >= 0) {
5550 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5553 ChartData->GetChartTableEntry(idx);
5554 int candidate_scale = cte_candidate.GetScale();
5555 int candidate_type = cte_candidate.GetChartType();
5557 if ((candidate_scale <= target_scale) &&
5558 (candidate_type == target_type))
5561 candidate_stack_index--;
5566 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5567 (candidate_stack_index < 0))
5568 candidate_stack_index = 0;
5570 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5572 m_pQuilt->SetReferenceChart(new_ref_index);
5578 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5583 bool renderable =
true;
5585 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5586 if (referenceChart) {
5587 double chartMaxScale = referenceChart->GetNormalScaleMax(
5589 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5590 proj = ChartData->GetDBChartProj(ref_db_index);
5592 proj = PROJECTION_MERCATOR;
5594 VPoint.b_MercatorProjectionOverride =
5595 (m_pQuilt->GetnCharts() == 0 || !renderable);
5597 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5599 VPoint.SetProjectionType(proj);
5606 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5611 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5631 m_pQuilt->Invalidate();
5646 ChartData->PurgeCacheUnusedCharts(0.7);
5648 if (b_refresh) Refresh(
false);
5655 }
else if (!g_bopengl) {
5656 OcpnProjType projection = PROJECTION_UNKNOWN;
5659 projection = m_singleChart->GetChartProjectionType();
5660 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5661 VPoint.SetProjectionType(projection);
5665 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5666 m_cache_vp.Invalidate();
5670 UpdateCanvasControlBar();
5676 if (VPoint.GetBBox().GetValid()) {
5679 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5688 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5691 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5698 wxPoint2DDouble r, r1;
5700 double delta_check =
5704 double check_point = wxMin(89., VPoint.
clat);
5706 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5709 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5710 VPoint.
clon, 0, &rhumbDist);
5715 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5716 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5718 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5722 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5728 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5730 if (m_true_scale_ppm)
5731 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5736 double round_factor = 1000.;
5740 round_factor = 100.;
5742 round_factor = 1000.;
5745 double retina_coef = 1;
5749 retina_coef = GetContentScaleFactor();
5760 double true_scale_display =
5761 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5766 if (m_displayed_scale_factor > 10.0)
5767 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5768 m_displayed_scale_factor);
5769 else if (m_displayed_scale_factor > 1.0)
5770 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5771 m_displayed_scale_factor);
5772 else if (m_displayed_scale_factor > 0.1) {
5773 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5774 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5775 }
else if (m_displayed_scale_factor > 0.01) {
5776 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5777 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5780 _T(
"%s %4.0f (---)"), _(
"Scale"),
5781 true_scale_display);
5784 m_scaleValue = true_scale_display;
5786 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5788 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5789 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5791 bool b_noshow =
false;
5795 wxClientDC dc(parent_frame->GetStatusBar());
5797 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5798 dc.SetFont(*templateFont);
5799 dc.GetTextExtent(text, &w, &h);
5804 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5805 if (w && w > rect.width) {
5806 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5807 m_displayed_scale_factor);
5811 dc.GetTextExtent(text, &w, &h);
5813 if (w && w > rect.width) {
5819 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5824 m_vLat = VPoint.
clat;
5825 m_vLon = VPoint.
clon;
5839static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5843static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5844 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5846wxColour ChartCanvas::PredColor() {
5849 if (SHIP_NORMAL == m_ownship_state)
5850 return GetGlobalColor(_T (
"URED" ));
5852 else if (SHIP_LOWACCURACY == m_ownship_state)
5853 return GetGlobalColor(_T (
"YELO1" ));
5855 return GetGlobalColor(_T (
"NODTA" ));
5858wxColour ChartCanvas::ShipColor() {
5862 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5864 if (SHIP_LOWACCURACY == m_ownship_state)
5865 return GetGlobalColor(_T (
"YELO1" ));
5867 return GetGlobalColor(_T (
"URED" ));
5870void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5871 wxPoint2DDouble lShipMidPoint) {
5872 dc.SetPen(wxPen(PredColor(), 2));
5874 if (SHIP_NORMAL == m_ownship_state)
5875 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5877 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5879 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5880 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5882 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5884 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5885 lShipMidPoint.m_y + 12);
5888void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5889 wxPoint GPSOffsetPixels,
5890 wxPoint2DDouble lGPSPoint) {
5891 if (m_animationActive)
return;
5895 float ref_dim = m_display_size_mm / 24;
5896 ref_dim = wxMin(ref_dim, 12);
5897 ref_dim = wxMax(ref_dim, 6);
5900 cPred.Set(g_cog_predictor_color);
5901 if (cPred == wxNullColour) cPred = PredColor();
5908 double nominal_line_width_pix = wxMax(
5910 floor(m_pix_per_mm / 2));
5914 if (nominal_line_width_pix > g_cog_predictor_width)
5915 g_cog_predictor_width = nominal_line_width_pix;
5918 wxPoint lPredPoint, lHeadPoint;
5920 float pCog = std::isnan(gCog) ? 0 : gCog;
5921 float pSog = std::isnan(gSog) ? 0 : gSog;
5923 double pred_lat, pred_lon;
5924 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5925 &pred_lat, &pred_lon);
5936 float ndelta_pix = 10.;
5937 double hdg_pred_lat, hdg_pred_lon;
5938 bool b_render_hdt =
false;
5939 if (!std::isnan(gHdt)) {
5941 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5944 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5945 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5946 if (dist > ndelta_pix ) {
5947 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5948 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5953 wxPoint lShipMidPoint;
5954 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5955 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5956 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5957 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5959 if (lpp >= img_height / 2) {
5960 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5961 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5962 !std::isnan(gSog)) {
5964 float dash_length = ref_dim;
5965 wxDash dash_long[2];
5967 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5968 g_cog_predictor_width);
5969 dash_long[1] = dash_long[0] / 2.0;
5973 if (dash_length > 250.) {
5974 dash_long[0] = 250. / g_cog_predictor_width;
5975 dash_long[1] = dash_long[0] / 2;
5978 wxPen ppPen2(cPred, g_cog_predictor_width,
5979 (wxPenStyle)g_cog_predictor_style);
5980 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5981 ppPen2.SetDashes(2, dash_long);
5984 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5985 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5987 if (g_cog_predictor_width > 1) {
5988 float line_width = g_cog_predictor_width / 3.;
5990 wxDash dash_long3[2];
5991 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5992 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5994 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
5995 (wxPenStyle)g_cog_predictor_style);
5996 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5997 ppPen3.SetDashes(2, dash_long3);
5999 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6000 lGPSPoint.m_y + GPSOffsetPixels.y,
6001 lPredPoint.x + GPSOffsetPixels.x,
6002 lPredPoint.y + GPSOffsetPixels.y);
6005 if (g_cog_predictor_endmarker) {
6007 double png_pred_icon_scale_factor = .4;
6008 if (g_ShipScaleFactorExp > 1.0)
6009 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6010 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6014 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6015 (
float)(lPredPoint.x - lShipMidPoint.x));
6016 cog_rad += (float)PI;
6018 for (
int i = 0; i < 4; i++) {
6020 double pxa = (double)(s_png_pred_icon[j]);
6021 double pya = (double)(s_png_pred_icon[j + 1]);
6023 pya *= png_pred_icon_scale_factor;
6024 pxa *= png_pred_icon_scale_factor;
6026 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6027 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6029 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6030 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6034 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
6037 dc.SetBrush(wxBrush(cPred));
6039 dc.StrokePolygon(4, icon);
6046 float hdt_dash_length = ref_dim * 0.4;
6048 cPred.Set(g_ownship_HDTpredictor_color);
6049 if (cPred == wxNullColour) cPred = PredColor();
6051 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6052 : g_cog_predictor_width * 0.8);
6053 wxDash dash_short[2];
6055 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6058 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6061 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6062 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6063 ppPen2.SetDashes(2, dash_short);
6067 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6068 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6070 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6072 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
6074 if (g_ownship_HDTpredictor_endmarker) {
6075 double nominal_circle_size_pixels = wxMax(
6076 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6079 if (g_ShipScaleFactorExp > 1.0)
6080 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6082 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6083 lHeadPoint.y + GPSOffsetPixels.y,
6084 nominal_circle_size_pixels / 2);
6089 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6090 double factor = 1.00;
6091 if (g_pNavAidRadarRingsStepUnits == 1)
6093 else if (g_pNavAidRadarRingsStepUnits == 2) {
6094 if (std::isnan(gSog))
6099 factor *= g_fNavAidRadarRingsStep;
6103 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
6106 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6107 pow((
double)(lGPSPoint.m_y - r.y), 2));
6108 int pix_radius = (int)lpp;
6110 extern wxColor GetDimColor(wxColor c);
6111 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6113 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6116 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6118 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6119 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6123void ChartCanvas::ComputeShipScaleFactor(
6124 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6125 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6126 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6127 float screenResolution = m_pix_per_mm;
6130 double ship_bow_lat, ship_bow_lon;
6131 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6132 &ship_bow_lat, &ship_bow_lon);
6133 wxPoint lShipBowPoint;
6134 wxPoint2DDouble b_point =
6138 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6139 powf((
float)(b_point.m_y - a_point.m_y), 2));
6142 float shipLength_mm = shipLength_px / screenResolution;
6145 float ownship_min_mm = g_n_ownship_min_mm;
6146 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6149 float hdt_ant = icon_hdt + 180.;
6150 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6151 float dx = g_n_gps_antenna_offset_x / 1852.;
6152 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6160 if (shipLength_mm < ownship_min_mm) {
6161 dy /= shipLength_mm / ownship_min_mm;
6162 dx /= shipLength_mm / ownship_min_mm;
6165 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6167 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6168 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6174 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6175 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6177 float scale_factor = shipLength_px / ownShipLength;
6180 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6183 scale_factor = wxMax(scale_factor, scale_factor_min);
6185 scale_factor_y = scale_factor;
6186 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6187 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6190void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6191 if (!GetVP().IsValid())
return;
6193 wxPoint GPSOffsetPixels(0, 0);
6194 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6197 float pCog = std::isnan(gCog) ? 0 : gCog;
6198 float pSog = std::isnan(gSog) ? 0 : gSog;
6202 lShipMidPoint = lGPSPoint;
6206 float icon_hdt = pCog;
6207 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6210 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6214 double osd_head_lat, osd_head_lon;
6215 wxPoint osd_head_point;
6217 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6222 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6223 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6224 icon_rad += (float)PI;
6226 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6230 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6234 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6235 if (GetVP().chart_scale >
6238 ShipDrawLargeScale(dc, lShipMidPoint);
6244 if (m_pos_image_user)
6245 pos_image = m_pos_image_user->Copy();
6246 else if (SHIP_NORMAL == m_ownship_state)
6247 pos_image = m_pos_image_red->Copy();
6248 if (SHIP_LOWACCURACY == m_ownship_state)
6249 pos_image = m_pos_image_yellow->Copy();
6250 else if (SHIP_NORMAL != m_ownship_state)
6251 pos_image = m_pos_image_grey->Copy();
6254 if (m_pos_image_user) {
6255 pos_image = m_pos_image_user->Copy();
6257 if (SHIP_LOWACCURACY == m_ownship_state)
6258 pos_image = m_pos_image_user_yellow->Copy();
6259 else if (SHIP_NORMAL != m_ownship_state)
6260 pos_image = m_pos_image_user_grey->Copy();
6263 img_height = pos_image.GetHeight();
6265 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6266 g_OwnShipIconType > 0)
6268 int ownShipWidth = 22;
6269 int ownShipLength = 84;
6270 if (g_OwnShipIconType == 1) {
6271 ownShipWidth = pos_image.GetWidth();
6272 ownShipLength = pos_image.GetHeight();
6275 float scale_factor_x, scale_factor_y;
6276 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6277 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6278 scale_factor_x, scale_factor_y);
6280 if (g_OwnShipIconType == 1) {
6281 pos_image.Rescale(ownShipWidth * scale_factor_x,
6282 ownShipLength * scale_factor_y,
6283 wxIMAGE_QUALITY_HIGH);
6284 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6286 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6289 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6290 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6291 if (rot_image.GetAlpha(ip, jp) > 64)
6292 rot_image.SetAlpha(ip, jp, 255);
6294 wxBitmap os_bm(rot_image);
6296 int w = os_bm.GetWidth();
6297 int h = os_bm.GetHeight();
6300 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6301 lShipMidPoint.m_y - h / 2,
true);
6304 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6305 lShipMidPoint.m_y - h / 2);
6306 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6307 lShipMidPoint.m_y - h / 2 + h);
6310 else if (g_OwnShipIconType == 2) {
6311 wxPoint ownship_icon[10];
6313 for (
int i = 0; i < 10; i++) {
6315 float pxa = (float)(s_ownship_icon[j]);
6316 float pya = (float)(s_ownship_icon[j + 1]);
6317 pya *= scale_factor_y;
6318 pxa *= scale_factor_x;
6320 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6321 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6323 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6324 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6327 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6329 dc.SetBrush(wxBrush(ShipColor()));
6331 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6334 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6336 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6340 img_height = ownShipLength * scale_factor_y;
6344 if (m_pos_image_user) circle_rad = 1;
6346 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6347 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6348 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6351 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6353 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6356 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6357 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6358 if (rot_image.GetAlpha(ip, jp) > 64)
6359 rot_image.SetAlpha(ip, jp, 255);
6361 wxBitmap os_bm(rot_image);
6363 if (g_ShipScaleFactorExp > 1) {
6364 wxImage scaled_image = os_bm.ConvertToImage();
6365 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6367 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6368 scaled_image.GetHeight() * factor,
6369 wxIMAGE_QUALITY_HIGH));
6371 int w = os_bm.GetWidth();
6372 int h = os_bm.GetHeight();
6375 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6376 lShipMidPoint.m_y - h / 2,
true);
6380 if (m_pos_image_user) circle_rad = 1;
6382 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6383 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6384 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6387 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6388 lShipMidPoint.m_y - h / 2);
6389 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6390 lShipMidPoint.m_y - h / 2 + h);
6395 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6408void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6409 float &MinorSpacing) {
6414 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6415 {.000001f, 45.0f, 15.0f},
6416 {.0002f, 30.0f, 10.0f},
6417 {.0003f, 10.0f, 2.0f},
6418 {.0008f, 5.0f, 1.0f},
6419 {.001f, 2.0f, 30.0f / 60.0f},
6420 {.003f, 1.0f, 20.0f / 60.0f},
6421 {.006f, 0.5f, 10.0f / 60.0f},
6422 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6423 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6424 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6425 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6426 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6427 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6428 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6429 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6432 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6433 if (view_scale_ppm < lltab[tabi][0])
break;
6434 MajorSpacing = lltab[tabi][1];
6435 MinorSpacing = lltab[tabi][2];
6449wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6450 int deg = (int)fabs(latlon);
6451 float min = fabs((fabs(latlon) - deg) * 60.0);
6461 }
else if (latlon < 0.0) {
6473 if (spacing >= 1.0) {
6474 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6475 }
else if (spacing >= (1.0 / 60.0)) {
6476 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6478 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6495void ChartCanvas::GridDraw(
ocpnDC &dc) {
6496 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6498 double nlat, elon, slat, wlon;
6501 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6503 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6505 dc.SetFont(*m_pgridFont);
6506 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6509 h = m_canvas_height;
6520 dlon = dlon + 360.0;
6523 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6526 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6529 while (lat < nlat) {
6532 CalcGridText(lat, gridlatMajor,
true);
6534 dc.
DrawLine(0, r.y, w, r.y,
false);
6535 dc.DrawText(st, 0, r.y);
6536 lat = lat + gridlatMajor;
6538 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6542 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6545 while (lat < nlat) {
6548 dc.
DrawLine(0, r.y, 10, r.y,
false);
6549 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6550 lat = lat + gridlatMinor;
6554 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6557 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6560 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6562 wxString st = CalcGridText(lon, gridlonMajor,
false);
6564 dc.
DrawLine(r.x, 0, r.x, h,
false);
6565 dc.DrawText(st, r.x, 0);
6566 lon = lon + gridlonMajor;
6571 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6575 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6577 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6580 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6581 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6582 lon = lon + gridlonMinor;
6589void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6591 double blat, blon, tlat, tlon;
6594 int x_origin = m_bDisplayGrid ? 60 : 20;
6595 int y_origin = m_canvas_height - 50;
6601 if (GetVP().chart_scale > 80000)
6605 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6606 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6611 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6612 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6616 double rotation = -VPoint.
rotation;
6618 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6620 int l1 = (y_origin - r.y) / count;
6622 for (
int i = 0; i < count; i++) {
6629 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6632 double blat, blon, tlat, tlon;
6639 int y_origin = m_canvas_height - chartbar_height - 5;
6643 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6650 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6653 int unit = g_iDistanceFormat;
6655 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6656 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6659 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6660 float places = floor(logdist), rem = logdist - places;
6661 dist = pow(10, places);
6668 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6669 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6670 double rotation = -VPoint.
rotation;
6672 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6676 int l1 = r.x - x_origin;
6678 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6683 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6684 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6685 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6687 dc.SetFont(*m_pgridFont);
6688 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6690 dc.GetTextExtent(s, &w, &h);
6691 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6695void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6700 double ra_max = 40.;
6702 wxPen pen_save = dc.GetPen();
6704 wxDateTime now = wxDateTime::Now();
6710 x0 = x1 = x + radius;
6715 while (angle < 360.) {
6716 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6719 if (angle > 360.) angle = 360.;
6721 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6729 x1 = (int)(x + cos(angle * PI / 180.) * r);
6730 y1 = (int)(y + sin(angle * PI / 180.) * r);
6740 dc.
DrawLine(x + radius, y, x1, y1);
6742 dc.SetPen(pen_save);
6745static bool bAnchorSoundPlaying =
false;
6747static void onAnchorSoundFinished(
void *ptr) {
6748 g_anchorwatch_sound->UnLoad();
6749 bAnchorSoundPlaying =
false;
6752void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6754 bool play_sound =
false;
6755 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6756 if (AnchorAlertOn1) {
6757 wxPoint TargetPoint;
6760 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6761 TargetPoint.y, 100);
6765 AnchorAlertOn1 =
false;
6767 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6768 if (AnchorAlertOn2) {
6769 wxPoint TargetPoint;
6772 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6773 TargetPoint.y, 100);
6777 AnchorAlertOn2 =
false;
6780 if (!bAnchorSoundPlaying) {
6781 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6782 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6783 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6784 if (g_anchorwatch_sound->IsOk()) {
6785 bAnchorSoundPlaying =
true;
6786 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6787 g_anchorwatch_sound->Play();
6793void ChartCanvas::UpdateShips() {
6796 wxClientDC dc(
this);
6797 if (!dc.IsOk())
return;
6799 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6800 if (!test_bitmap.IsOk())
return;
6802 wxMemoryDC temp_dc(test_bitmap);
6804 temp_dc.ResetBoundingBox();
6805 temp_dc.DestroyClippingRegion();
6806 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6812 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6813 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6817 ocpndc.CalcBoundingBox(px.x, px.y);
6822 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6823 temp_dc.MaxY() - temp_dc.MinY());
6825 wxRect own_ship_update_rect = ship_draw_rect;
6827 if (!own_ship_update_rect.IsEmpty()) {
6830 own_ship_update_rect.Union(ship_draw_last_rect);
6831 own_ship_update_rect.Inflate(2);
6834 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6836 ship_draw_last_rect = ship_draw_rect;
6838 temp_dc.SelectObject(wxNullBitmap);
6841void ChartCanvas::UpdateAlerts() {
6846 wxClientDC dc(
this);
6850 dc.GetSize(&sx, &sy);
6853 wxBitmap test_bitmap(sx, sy, -1);
6857 temp_dc.SelectObject(test_bitmap);
6859 temp_dc.ResetBoundingBox();
6860 temp_dc.DestroyClippingRegion();
6861 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6868 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6869 temp_dc.MaxX() - temp_dc.MinX(),
6870 temp_dc.MaxY() - temp_dc.MinY());
6872 if (!alert_rect.IsEmpty())
6873 alert_rect.Inflate(2);
6875 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6878 wxRect alert_update_rect = alert_draw_rect;
6879 alert_update_rect.Union(alert_rect);
6882 RefreshRect(alert_update_rect,
false);
6886 alert_draw_rect = alert_rect;
6888 temp_dc.SelectObject(wxNullBitmap);
6891void ChartCanvas::UpdateAIS() {
6892 if (!g_pAIS)
return;
6897 wxClientDC dc(
this);
6901 dc.GetSize(&sx, &sy);
6909 if (g_pAIS->GetTargetList().size() > 10) {
6910 ais_rect = wxRect(0, 0, sx, sy);
6913 wxBitmap test_bitmap(sx, sy, -1);
6917 temp_dc.SelectObject(test_bitmap);
6919 temp_dc.ResetBoundingBox();
6920 temp_dc.DestroyClippingRegion();
6921 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6925 AISDraw(ocpndc, GetVP(),
this);
6926 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6930 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6931 temp_dc.MaxY() - temp_dc.MinY());
6933 if (!ais_rect.IsEmpty())
6934 ais_rect.Inflate(2);
6936 temp_dc.SelectObject(wxNullBitmap);
6939 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6942 wxRect ais_update_rect = ais_draw_rect;
6943 ais_update_rect.Union(ais_rect);
6946 RefreshRect(ais_update_rect,
false);
6950 ais_draw_rect = ais_rect;
6953void ChartCanvas::ToggleCPAWarn() {
6954 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6960 g_bTCPA_Max =
false;
6964 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6965 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6967 if (!g_AisFirstTimeUse) {
6968 OCPNMessageBox(
this,
6969 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
6970 _(
"CPA") + _T(
" ") + mess, 4, 4);
6975void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6977void ChartCanvas::OnSize(wxSizeEvent &event) {
6978 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6980 GetClientSize(&m_canvas_width, &m_canvas_height);
6984 m_displayScale = GetContentScaleFactor();
6988 m_canvas_width *= m_displayScale;
6989 m_canvas_height *= m_displayScale;
7002 m_absolute_min_scale_ppm =
7004 (1.2 * WGS84_semimajor_axis_meters * PI);
7007 gFrame->ProcessCanvasResize();
7017 SetMUIBarPosition();
7018 UpdateFollowButtonState();
7019 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7023 xr_margin = m_canvas_width * 95 / 100;
7024 xl_margin = m_canvas_width * 5 / 100;
7025 yt_margin = m_canvas_height * 5 / 100;
7026 yb_margin = m_canvas_height * 95 / 100;
7029 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7034 m_brepaint_piano =
true;
7037 m_dc_route.SelectObject(wxNullBitmap);
7040 m_dc_route.SelectObject(*proute_bm);
7054 m_glcc->OnSize(event);
7063void ChartCanvas::ProcessNewGUIScale() {
7071void ChartCanvas::CreateMUIBar() {
7072 if (g_useMUI && !m_muiBar) {
7076 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
7078 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7079 m_muiBar->SetColorScheme(m_cs);
7080 m_muiBarHOSize = m_muiBar->m_size;
7084 SetMUIBarPosition();
7085 UpdateFollowButtonState();
7086 m_muiBar->UpdateDynamicValues();
7087 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7091void ChartCanvas::SetMUIBarPosition() {
7095 int pianoWidth = GetClientSize().x * 0.6f;
7100 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7101 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7103 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7104 m_muiBar->SetColorScheme(m_cs);
7108 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7109 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7111 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7112 m_muiBar->SetColorScheme(m_cs);
7116 m_muiBar->SetBestPosition();
7120void ChartCanvas::DestroyMuiBar() {
7127void ChartCanvas::ShowCompositeInfoWindow(
7128 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7130 if (NULL == m_pCIWin) {
7135 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7138 s = _(
"Composite of ");
7141 s1.Printf(
"%d ", n_charts);
7149 s1.Printf(_(
"Chart scale"));
7152 s2.Printf(
"1:%d\n",
scale);
7156 s1 = _(
"Zoom in for more information");
7160 int char_width = s1.Length();
7161 int char_height = 3;
7163 if (g_bChartBarEx) {
7166 for (
int i : index_vector) {
7168 wxString path = cte.GetFullSystemPath();
7172 char_width = wxMax(char_width, path.Length());
7173 if (j++ >= 9)
break;
7176 s +=
" .\n .\n .\n";
7185 m_pCIWin->SetString(s);
7187 m_pCIWin->FitToChars(char_width, char_height);
7190 p.x = x / GetContentScaleFactor();
7191 if ((p.x + m_pCIWin->GetWinSize().x) >
7192 (m_canvas_width / GetContentScaleFactor()))
7193 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7194 m_pCIWin->GetWinSize().x) /
7197 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7198 4 - m_pCIWin->GetWinSize().y;
7200 m_pCIWin->dbIndex = 0;
7201 m_pCIWin->chart_scale = 0;
7202 m_pCIWin->SetPosition(p);
7203 m_pCIWin->SetBitmap();
7204 m_pCIWin->Refresh();
7208 HideChartInfoWindow();
7212void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7214 if (NULL == m_pCIWin) {
7219 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7226 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
7227 pc = ChartData->OpenChartFromDBAndLock(
7228 dbIndex, FULL_INIT);
7230 int char_width, char_height;
7231 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7232 if (pc) ChartData->UnLockCacheChart(dbIndex);
7234 m_pCIWin->SetString(s);
7235 m_pCIWin->FitToChars(char_width, char_height);
7238 p.x = x / GetContentScaleFactor();
7239 if ((p.x + m_pCIWin->GetWinSize().x) >
7240 (m_canvas_width / GetContentScaleFactor()))
7241 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7242 m_pCIWin->GetWinSize().x) /
7245 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7246 4 - m_pCIWin->GetWinSize().y;
7248 m_pCIWin->dbIndex = dbIndex;
7249 m_pCIWin->SetPosition(p);
7250 m_pCIWin->SetBitmap();
7251 m_pCIWin->Refresh();
7255 HideChartInfoWindow();
7259void ChartCanvas::HideChartInfoWindow(
void) {
7262 m_pCIWin->Destroy();
7266 androidForceFullRepaint();
7271void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7272 wxMouseEvent ev(wxEVT_MOTION);
7275 ev.m_leftDown = mouse_leftisdown;
7277 wxEvtHandler *evthp = GetEventHandler();
7279 ::wxPostEvent(evthp, ev);
7282void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7283 if ((m_panx_target_final - m_panx_target_now) ||
7284 (m_pany_target_final - m_pany_target_now)) {
7285 DoTimedMovementTarget();
7290void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7292bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7294 if (m_disable_edge_pan)
return false;
7297 int pan_margin = m_canvas_width * margin / 100;
7298 int pan_timer_set = 200;
7299 double pan_delta = GetVP().
pix_width * delta / 100;
7303 if (x > m_canvas_width - pan_margin) {
7308 else if (x < pan_margin) {
7313 if (y < pan_margin) {
7318 else if (y > m_canvas_height - pan_margin) {
7327 wxMouseState state = ::wxGetMouseState();
7328#if wxCHECK_VERSION(3, 0, 0)
7329 if (!state.LeftIsDown())
7331 if (!state.LeftDown())
7336 if ((bft) && !pPanTimer->IsRunning()) {
7338 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7344 if ((!bft) && pPanTimer->IsRunning()) {
7354void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7355 bool setBeingEdited) {
7356 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7357 m_pRoutePointEditTarget = NULL;
7358 m_pFoundPoint = NULL;
7362 SelectableItemList SelList = pSelect->FindSelectionList(
7364 wxSelectableItemListNode *node = SelList.GetFirst();
7366 pFind = node->GetData();
7371 m_pEditRouteArray = g_pRouteMan->GetRouteArrayContaining(frp);
7374 bool brp_viz =
false;
7375 if (m_pEditRouteArray) {
7376 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7377 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7378 if (pr->IsVisible()) {
7384 brp_viz = frp->IsVisible();
7388 if (m_pEditRouteArray)
7390 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7391 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7392 pr->m_bIsBeingEdited = setBeingEdited;
7394 m_bRouteEditing = setBeingEdited;
7397 frp->m_bRPIsBeingEdited = setBeingEdited;
7398 m_bMarkEditing = setBeingEdited;
7401 m_pRoutePointEditTarget = frp;
7402 m_pFoundPoint = pFind;
7406 node = node->GetNext();
7410void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7411 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7412 singleClickEventIsValid =
false;
7413 m_DoubleClickTimer->Stop();
7418bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7419 if (!m_bChartDragging && !m_bDrawingRoute) {
7425 bool isInCompass = m_Compass && m_Compass->IsShown() &&
7426 logicalRect.Contains(event.GetPosition());
7428 if (m_Compass->MouseEvent(event)) {
7429 cursor_region = CENTER;
7430 if (!g_btouch) SetCanvasCursor(event);
7435 if (MouseEventToolbar(event))
return true;
7437 if (MouseEventChartBar(event))
return true;
7439 if (MouseEventMUIBar(event))
return true;
7441 if (MouseEventIENCBar(event))
return true;
7446bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7447 if (!g_bShowChartBar)
return false;
7449 if (!m_Piano->MouseEvent(event))
return false;
7451 cursor_region = CENTER;
7452 if (!g_btouch) SetCanvasCursor(event);
7456bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7457 if (!IsPrimaryCanvas())
return false;
7459 if (g_MainToolbar) {
7460 if (!g_MainToolbar->MouseEvent(event))
7463 g_MainToolbar->RefreshToolbar();
7466 cursor_region = CENTER;
7467 if (!g_btouch) SetCanvasCursor(event);
7471bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7472 if (!IsPrimaryCanvas())
return false;
7474 if (g_iENCToolbar) {
7475 if (!g_iENCToolbar->MouseEvent(event))
7478 g_iENCToolbar->RefreshToolbar();
7485bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7487 if (!m_muiBar->MouseEvent(event))
return false;
7490 cursor_region = CENTER;
7491 if (!g_btouch) SetCanvasCursor(event);
7503 event.GetPosition(&x, &y);
7505 x *= m_displayScale;
7506 y *= m_displayScale;
7508 m_MouseDragging =
event.Dragging();
7514 if (event.Dragging()) {
7515 if ((x == mouse_x) && (y == mouse_y))
return true;
7521 mouse_leftisdown =
event.LeftDown();
7525 cursor_region = CENTER;
7529 if (m_Compass && m_Compass->IsShown() &&
7530 m_Compass->
GetRect().Contains(event.GetPosition())) {
7531 cursor_region = CENTER;
7532 }
else if (x > xr_margin) {
7533 cursor_region = MID_RIGHT;
7534 }
else if (x < xl_margin) {
7535 cursor_region = MID_LEFT;
7536 }
else if (y > yb_margin - chartbar_height &&
7537 y < m_canvas_height - chartbar_height) {
7538 cursor_region = MID_TOP;
7539 }
else if (y < yt_margin) {
7540 cursor_region = MID_BOT;
7542 cursor_region = CENTER;
7545 if (!g_btouch) SetCanvasCursor(event);
7549 leftIsDown =
event.LeftDown();
7552 if (event.LeftDown()) {
7553 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7556 g_bTempShowMenuBar =
false;
7557 parent_frame->ApplyGlobalSettings(
false);
7565 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7566 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7570 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7571 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7574 event.SetEventObject(
this);
7575 if (SendMouseEventToPlugins(event))
7582 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7583 StartChartDragInertia();
7586 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7588 if (m_DoubleClickTimer->IsRunning()) {
7589 m_DoubleClickTimer->Stop();
7594 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7595 singleClickEvent = event;
7596 singleClickEventIsValid =
true;
7605 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7606 if (g_click_stop > 0) {
7614 if (GetUpMode() == COURSE_UP_MODE) {
7615 m_b_rot_hidef =
false;
7616 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7618 pRotDefTimer->Stop();
7621 bool bRoll = !g_btouch;
7623 bRoll = g_bRollover;
7626 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7627 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7628 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7629 m_RolloverPopupTimer.Start(
7633 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7637 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7646#if !defined(__WXGTK__) && !defined(__WXQT__)
7654 if ((x >= 0) && (y >= 0))
7659 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7660 wxPoint p = ClientToScreen(wxPoint(x, y));
7666 if (m_routeState >= 2) {
7669 m_bDrawingRoute =
true;
7671 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7676 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7679 m_bDrawingRoute =
true;
7681 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7688void ChartCanvas::CallPopupMenu(
int x,
int y) {
7696 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7705#if defined(__WXMAC__) || defined(__ANDROID__)
7709 wxClientDC cdc(GetParent());
7721 if (m_pSelectedRoute) {
7722 m_pSelectedRoute->m_bRtIsSelected =
false;
7723 m_pSelectedRoute->DeSelectRoute();
7725 if (g_bopengl && m_glcc) {
7730 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7733 if (m_pFoundRoutePoint) {
7734 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7736 RefreshRect(m_pFoundRoutePoint->CurrentRect_in_DC);
7741 if (g_btouch && m_pRoutePointEditTarget) {
7742 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7743 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7744 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7749 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7750 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7751 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7752 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7756 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7759 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7765 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7768 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7769 seltype |= SELTYPE_AISTARGET;
7774 m_pFoundRoutePoint = NULL;
7779 Route *pSelectedActiveRoute = NULL;
7780 Route *pSelectedVizRoute = NULL;
7784 SelectableItemList SelList =
7785 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7786 wxSelectableItemListNode *node = SelList.GetFirst();
7793 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(prp);
7796 bool brp_viz =
false;
7798 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7800 if (pr->IsVisible()) {
7805 if (!brp_viz && prp->IsShared())
7807 brp_viz = prp->IsVisible();
7810 brp_viz = prp->IsVisible();
7812 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7817 m_pSelectedRoute = NULL;
7819 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7821 if (pr->m_bRtIsActive) {
7822 pSelectedActiveRoute = pr;
7823 pFoundActiveRoutePoint = prp;
7828 if (NULL == pSelectedVizRoute) {
7829 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7831 if (pr->IsVisible()) {
7832 pSelectedVizRoute = pr;
7833 pFoundVizRoutePoint = prp;
7839 delete proute_array;
7842 node = node->GetNext();
7846 if (pFoundActiveRoutePoint) {
7847 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7848 m_pSelectedRoute = pSelectedActiveRoute;
7849 }
else if (pFoundVizRoutePoint) {
7850 m_pFoundRoutePoint = pFoundVizRoutePoint;
7851 m_pSelectedRoute = pSelectedVizRoute;
7854 m_pFoundRoutePoint = pFirstVizPoint;
7856 if (m_pSelectedRoute) {
7857 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7858 }
else if (m_pFoundRoutePoint)
7859 seltype |= SELTYPE_MARKPOINT;
7863 if (m_pFoundRoutePoint) {
7864 m_pFoundRoutePoint->m_bPtIsSelected =
true;
7867 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7868 RefreshRect(wp_rect,
true);
7877 SelectableItemList SelList =
7878 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7880 if (NULL == m_pSelectedRoute)
7883 wxSelectableItemListNode *node = SelList.GetFirst();
7888 if (pr->IsVisible()) {
7889 m_pSelectedRoute = pr;
7892 node = node->GetNext();
7896 if (m_pSelectedRoute) {
7897 if (NULL == m_pFoundRoutePoint)
7898 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7900 m_pSelectedRoute->m_bRtIsSelected = !(seltype & SELTYPE_ROUTEPOINT);
7901 if (m_pSelectedRoute->m_bRtIsSelected) {
7903 if (g_bopengl && m_glcc) {
7908 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7911 seltype |= SELTYPE_ROUTESEGMENT;
7915 if (pFindTrackSeg) {
7916 m_pSelectedTrack = NULL;
7918 SelectableItemList SelList =
7919 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7922 wxSelectableItemListNode *node = SelList.GetFirst();
7927 if (pt->IsVisible()) {
7928 m_pSelectedTrack = pt;
7931 node = node->GetNext();
7934 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7937 bool bseltc =
false;
7951 SelectableItemList SelList = pSelectTC->FindSelectionList(
7955 wxSelectableItemListNode *node = SelList.GetFirst();
7956 pFind = node->GetData();
7957 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7959 if (SelList.GetCount() > 1) {
7960 node = node->GetNext();
7962 pFind = node->GetData();
7964 if (pIDX_candidate->
IDX_type ==
'c') {
7965 pIDX_best_candidate = pIDX_candidate;
7969 node = node->GetNext();
7972 wxSelectableItemListNode *node = SelList.GetFirst();
7973 pFind = node->GetData();
7974 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7977 m_pIDXCandidate = pIDX_best_candidate;
7980 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
7984 seltype |= SELTYPE_CURRENTPOINT;
7987 else if (pFindTide) {
7988 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7991 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
7995 seltype |= SELTYPE_TIDEPOINT;
7999 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8002 InvokeCanvasMenu(x, y, seltype);
8005 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8006 m_pSelectedRoute->m_bRtIsSelected =
false;
8009 m_pSelectedRoute = NULL;
8011 if (m_pFoundRoutePoint) {
8012 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8013 m_pFoundRoutePoint->m_bPtIsSelected =
false;
8015 m_pFoundRoutePoint = NULL;
8023bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8031 event.GetPosition(&x, &y);
8037 SelectRadius = g_Platform->GetSelectRadiusPix() /
8038 (m_true_scale_ppm * 1852 * 60);
8045 if (event.LeftDClick() && (cursor_region == CENTER)) {
8046 m_DoubleClickTimer->Start();
8047 singleClickEventIsValid =
false;
8051 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8056 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8059 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8060 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8061 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8067 SelectableItemList rpSelList =
8068 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8069 wxSelectableItemListNode *node = rpSelList.GetFirst();
8070 bool b_onRPtarget =
false;
8074 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8075 b_onRPtarget =
true;
8078 node = node->GetNext();
8083 if (m_pRoutePointEditTarget) {
8085 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8088 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8089 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8091 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8094 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8095 m_pRoutePointEditTarget = NULL;
8096 RefreshRect(wp_rect,
true);
8100 node = rpSelList.GetFirst();
8105 wxArrayPtrVoid *proute_array =
8106 g_pRouteMan->GetRouteArrayContaining(frp);
8110 bool brp_viz =
false;
8112 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8114 if (pr->IsVisible()) {
8122 brp_viz = frp->IsVisible();
8124 brp_viz = frp->IsVisible();
8127 ShowMarkPropertiesDialog(frp);
8135 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8139 if (pr->IsVisible()) {
8140 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8145 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8149 if (pt->IsVisible()) {
8150 ShowTrackPropertiesDialog(pt);
8157 ShowObjectQueryWindow(x, y, zlat, zlon);
8162 if (event.LeftDown()) {
8178 bool appending =
false;
8179 bool inserting =
false;
8182 SetCursor(*pCursorPencil);
8186 m_bRouteEditing =
true;
8188 if (m_routeState == 1) {
8189 m_pMouseRoute =
new Route();
8190 pRouteList->Append(m_pMouseRoute);
8199 double nearby_radius_meters =
8200 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8203 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8204 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8205 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8206 wxArrayPtrVoid *proute_array =
8207 g_pRouteMan->GetRouteArrayContaining(pNearbyPoint);
8211 bool brp_viz =
false;
8213 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8215 if (pr->IsVisible()) {
8221 pNearbyPoint->IsShared())
8224 pNearbyPoint->IsVisible();
8226 brp_viz = pNearbyPoint->IsVisible();
8229 wxString msg = _(
"Use nearby waypoint?");
8231 const bool noname(pNearbyPoint->GetName() ==
"");
8234 _(
"Use nearby nameless waypoint and name it M with"
8235 " a unique number?");
8238 m_FinishRouteOnKillFocus =
false;
8240 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8241 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8242 m_FinishRouteOnKillFocus =
true;
8243 if (dlg_return == wxID_YES) {
8245 if (m_pMouseRoute) {
8246 int last_wp_num = m_pMouseRoute->GetnPoints();
8248 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8249 wxString wp_name = wxString::Format(
8250 "M%002i-%s", last_wp_num + 1, guid_short);
8251 pNearbyPoint->SetName(wp_name);
8253 pNearbyPoint->SetName(
"WPXX");
8255 pMousePoint = pNearbyPoint;
8258 if (m_routeState > 1)
8259 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8260 Undo_HasParent, NULL);
8263 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8264 bool procede =
false;
8268 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8274 m_FinishRouteOnKillFocus =
false;
8280 _(
"Insert first part of this route in the new route?");
8281 if (tail->GetIndexOf(pMousePoint) ==
8284 dmsg = _(
"Insert this route in the new route?");
8286 if (tail->GetIndexOf(pMousePoint) != 1) {
8287 dlg_return = OCPNMessageBox(
8288 this, dmsg, _(
"OpenCPN Route Create"),
8289 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8290 m_FinishRouteOnKillFocus =
true;
8292 if (dlg_return == wxID_YES) {
8299 _(
"Append last part of this route to the new route?");
8300 if (tail->GetIndexOf(pMousePoint) == 1)
8302 "Append this route to the new route?");
8307 if (tail->GetLastPoint() != pMousePoint) {
8308 dlg_return = OCPNMessageBox(
8309 this, dmsg, _(
"OpenCPN Route Create"),
8310 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8311 m_FinishRouteOnKillFocus =
true;
8313 if (dlg_return == wxID_YES) {
8324 if (!FindRouteContainingWaypoint(pMousePoint))
8325 pMousePoint->SetShared(
true);
8330 if (NULL == pMousePoint) {
8331 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8332 _T(
""), wxEmptyString);
8333 pMousePoint->SetNameShown(
false);
8335 pConfig->AddNewWayPoint(pMousePoint, -1);
8336 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8338 if (m_routeState > 1)
8339 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8340 Undo_IsOrphanded, NULL);
8343 if (m_pMouseRoute) {
8344 if (m_routeState == 1) {
8346 m_pMouseRoute->AddPoint(pMousePoint);
8348 if (m_pMouseRoute->m_NextLegGreatCircle) {
8349 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8350 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8351 &rhumbBearing, &rhumbDist);
8352 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8353 rlat, &gcDist, &gcBearing, NULL);
8354 double gcDistNM = gcDist / 1852.0;
8357 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8358 pow(rhumbDist - gcDistNM - 1, 0.5);
8361 msg << _(
"For this leg the Great Circle route is ")
8362 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8363 << _(
" shorter than rhumbline.\n\n")
8364 << _(
"Would you like include the Great Circle routing points "
8367 m_FinishRouteOnKillFocus =
false;
8368 m_disable_edge_pan =
true;
8371 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8372 wxYES_NO | wxNO_DEFAULT);
8374 m_disable_edge_pan =
false;
8375 m_FinishRouteOnKillFocus =
true;
8377 if (answer == wxID_YES) {
8379 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8380 wxRealPoint gcCoord;
8382 for (
int i = 1; i <= segmentCount; i++) {
8383 double fraction = (double)i * (1.0 / (
double)segmentCount);
8384 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8385 gcDist * fraction, gcBearing,
8386 &gcCoord.x, &gcCoord.y, NULL);
8388 if (i < segmentCount) {
8389 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8390 _T(
""), wxEmptyString);
8391 gcPoint->SetNameShown(
false);
8392 pConfig->AddNewWayPoint(gcPoint, -1);
8393 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8396 gcPoint = pMousePoint;
8399 m_pMouseRoute->AddPoint(gcPoint);
8400 pSelect->AddSelectableRouteSegment(
8401 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8402 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8403 prevGcPoint = gcPoint;
8406 undo->CancelUndoableAction(
true);
8409 m_pMouseRoute->AddPoint(pMousePoint);
8410 pSelect->AddSelectableRouteSegment(
8411 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8412 pMousePoint, m_pMouseRoute);
8413 undo->AfterUndoableAction(m_pMouseRoute);
8417 m_pMouseRoute->AddPoint(pMousePoint);
8418 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8419 rlon, m_prev_pMousePoint,
8420 pMousePoint, m_pMouseRoute);
8421 undo->AfterUndoableAction(m_pMouseRoute);
8427 m_prev_pMousePoint = pMousePoint;
8429 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
8435 int connect = tail->GetIndexOf(pMousePoint);
8440 int length = tail->GetnPoints();
8445 start = connect + 1;
8450 m_pMouseRoute->RemovePoint(
8454 for (i = start; i <= stop; i++) {
8455 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8457 m_pMouseRoute->m_lastMousePointIndex =
8458 m_pMouseRoute->GetnPoints();
8460 gFrame->RefreshAllCanvas();
8464 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8466 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8467 m_pMouseRoute->FinalizeForRendering();
8469 gFrame->RefreshAllCanvas();
8473 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8475 SetCursor(*pCursorPencil);
8477 if (!m_pMeasureRoute) {
8478 m_pMeasureRoute =
new Route();
8479 pRouteList->Append(m_pMeasureRoute);
8482 if (m_nMeasureState == 1) {
8488 wxString(_T (
"circle" )),
8489 wxEmptyString, wxEmptyString);
8490 pMousePoint->m_bShowName =
false;
8491 pMousePoint->SetShowWaypointRangeRings(
false);
8493 m_pMeasureRoute->AddPoint(pMousePoint);
8497 m_prev_pMousePoint = pMousePoint;
8498 m_pMeasureRoute->m_lastMousePointIndex = m_pMeasureRoute->GetnPoints();
8501 gFrame->RefreshAllCanvas();
8506 FindRoutePointsAtCursor(SelectRadius,
true);
8511 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8519 if (ret)
return true;
8522 if (event.Dragging()) {
8527 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8529 SelectableItemList SelList = pSelect->FindSelectionList(
8531 wxSelectableItemListNode *node = SelList.GetFirst();
8533 pFind = node->GetData();
8535 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8536 node = node->GetNext();
8541 if (m_pRoutePointEditTarget &&
8542 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8544 SelectableItemList SelList = pSelect->FindSelectionList(
8546 wxSelectableItemListNode *node = SelList.GetFirst();
8548 pFind = node->GetData();
8550 if (m_pRoutePointEditTarget == frp) {
8551 m_bIsInRadius =
true;
8554 node = node->GetNext();
8557 if (!m_dragoffsetSet) {
8559 .PresetDragOffset(
this, mouse_x, mouse_y);
8560 m_dragoffsetSet =
true;
8565 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8566 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8568 if (NULL == g_pMarkInfoDialog) {
8569 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8570 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8571 DraggingAllowed =
false;
8573 if (m_pRoutePointEditTarget &&
8574 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8575 DraggingAllowed =
false;
8577 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8579 if (DraggingAllowed) {
8580 if (!undo->InUndoableAction()) {
8581 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8582 Undo_NeedsCopy, m_pFoundPoint);
8588 if (!g_bopengl && m_pEditRouteArray) {
8589 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8590 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8595 if (g_pRouteMan->IsRouteValid(pr)) {
8597 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8598 pre_rect.Union(route_rect);
8606 if (CheckEdgePan(x, y,
true, 5, 2))
8614 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8616 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8617 m_pRoutePointEditTarget,
8618 SELTYPE_DRAGHANDLE);
8619 m_pFoundPoint->m_slat =
8620 m_pRoutePointEditTarget->m_lat;
8621 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8623 m_pRoutePointEditTarget->m_lat =
8625 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8626 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8627 m_pFoundPoint->m_slat =
8629 m_pFoundPoint->m_slon = new_cursor_lon;
8633 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8634 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8635 g_pMarkInfoDialog->UpdateProperties(
true);
8645 if (m_pEditRouteArray) {
8646 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8648 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8649 if (g_pRouteMan->IsRouteValid(pr)) {
8651 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8652 post_rect.Union(route_rect);
8658 pre_rect.Union(post_rect);
8659 RefreshRect(pre_rect,
false);
8661 gFrame->RefreshCanvasOther(
this);
8662 m_bRoutePoinDragging =
true;
8667 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8668 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8670 if (NULL == g_pMarkInfoDialog) {
8671 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8672 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8673 DraggingAllowed =
false;
8675 if (m_pRoutePointEditTarget &&
8676 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8677 DraggingAllowed =
false;
8679 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8681 if (DraggingAllowed) {
8682 if (!undo->InUndoableAction()) {
8683 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8684 Undo_NeedsCopy, m_pFoundPoint);
8692 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8693 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8695 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8696 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8698 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8704 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8705 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8706 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8707 (
int)(lppmax - (pre_rect.height / 2)));
8715 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8718 m_pRoutePointEditTarget,
8719 SELTYPE_DRAGHANDLE);
8720 m_pFoundPoint->m_slat =
8721 m_pRoutePointEditTarget->m_lat;
8722 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8724 m_pRoutePointEditTarget->m_lat =
8727 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8733 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8734 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8735 g_pMarkInfoDialog->UpdateProperties(
true);
8740 if (!g_btouch) InvalidateGL();
8746 .CalculateDCRect(m_dc_route,
this, &post_rect);
8747 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8748 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8749 (
int)(lppmax - (post_rect.height / 2)));
8752 pre_rect.Union(post_rect);
8753 RefreshRect(pre_rect,
false);
8755 gFrame->RefreshCanvasOther(
this);
8756 m_bRoutePoinDragging =
true;
8761 if (ret)
return true;
8764 if (event.LeftUp()) {
8765 bool b_startedit_route =
false;
8766 m_dragoffsetSet =
false;
8769 m_bChartDragging =
false;
8770 m_bIsInRadius =
false;
8775 m_bedge_pan =
false;
8780 bool appending =
false;
8781 bool inserting =
false;
8787 if (m_pRoutePointEditTarget) {
8788 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8789 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8793 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8794 RefreshRect(wp_rect,
true);
8796 m_pRoutePointEditTarget = NULL;
8798 m_bRouteEditing =
true;
8800 if (m_routeState == 1) {
8801 m_pMouseRoute =
new Route();
8802 m_pMouseRoute->SetHiLite(50);
8803 pRouteList->Append(m_pMouseRoute);
8812 double nearby_radius_meters =
8813 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8816 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8817 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8818 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8821 m_FinishRouteOnKillFocus =
8823 dlg_return = OCPNMessageBox(
8824 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8825 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8826 m_FinishRouteOnKillFocus =
true;
8828 dlg_return = wxID_YES;
8830 if (dlg_return == wxID_YES) {
8831 pMousePoint = pNearbyPoint;
8834 if (m_routeState > 1)
8835 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8836 Undo_HasParent, NULL);
8837 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8839 bool procede =
false;
8843 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8849 m_FinishRouteOnKillFocus =
false;
8850 if (m_routeState == 1) {
8854 _(
"Insert first part of this route in the new route?");
8855 if (tail->GetIndexOf(pMousePoint) ==
8858 dmsg = _(
"Insert this route in the new route?");
8860 if (tail->GetIndexOf(pMousePoint) != 1) {
8862 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8863 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8864 m_FinishRouteOnKillFocus =
true;
8866 if (dlg_return == wxID_YES) {
8873 _(
"Append last part of this route to the new route?");
8874 if (tail->GetIndexOf(pMousePoint) == 1)
8876 "Append this route to the new route?");
8880 if (tail->GetLastPoint() != pMousePoint) {
8882 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8883 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8884 m_FinishRouteOnKillFocus =
true;
8886 if (dlg_return == wxID_YES) {
8897 if (!FindRouteContainingWaypoint(pMousePoint))
8898 pMousePoint->SetShared(
true);
8902 if (NULL == pMousePoint) {
8903 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8904 _T(
""), wxEmptyString);
8905 pMousePoint->SetNameShown(
false);
8907 pConfig->AddNewWayPoint(pMousePoint, -1);
8908 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8910 if (m_routeState > 1)
8911 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8912 Undo_IsOrphanded, NULL);
8915 if (m_routeState == 1) {
8917 m_pMouseRoute->AddPoint(pMousePoint);
8919 if (m_pMouseRoute->m_NextLegGreatCircle) {
8920 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8921 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8922 &rhumbBearing, &rhumbDist);
8923 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
8924 &gcDist, &gcBearing, NULL);
8925 double gcDistNM = gcDist / 1852.0;
8928 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8929 pow(rhumbDist - gcDistNM - 1, 0.5);
8932 msg << _(
"For this leg the Great Circle route is ")
8933 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8934 << _(
" shorter than rhumbline.\n\n")
8935 << _(
"Would you like include the Great Circle routing points "
8939 m_FinishRouteOnKillFocus =
false;
8940 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8941 wxYES_NO | wxNO_DEFAULT);
8942 m_FinishRouteOnKillFocus =
true;
8944 int answer = wxID_NO;
8947 if (answer == wxID_YES) {
8949 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8950 wxRealPoint gcCoord;
8952 for (
int i = 1; i <= segmentCount; i++) {
8953 double fraction = (double)i * (1.0 / (
double)segmentCount);
8954 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8955 gcDist * fraction, gcBearing,
8956 &gcCoord.x, &gcCoord.y, NULL);
8958 if (i < segmentCount) {
8959 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8960 _T(
""), wxEmptyString);
8961 gcPoint->SetNameShown(
false);
8962 pConfig->AddNewWayPoint(gcPoint, -1);
8963 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8966 gcPoint = pMousePoint;
8969 m_pMouseRoute->AddPoint(gcPoint);
8970 pSelect->AddSelectableRouteSegment(
8971 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8972 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8973 prevGcPoint = gcPoint;
8976 undo->CancelUndoableAction(
true);
8979 m_pMouseRoute->AddPoint(pMousePoint);
8980 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8981 rlon, m_prev_pMousePoint,
8982 pMousePoint, m_pMouseRoute);
8983 undo->AfterUndoableAction(m_pMouseRoute);
8987 m_pMouseRoute->AddPoint(pMousePoint);
8988 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8989 rlon, m_prev_pMousePoint,
8990 pMousePoint, m_pMouseRoute);
8991 undo->AfterUndoableAction(m_pMouseRoute);
8997 m_prev_pMousePoint = pMousePoint;
8998 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
9004 int connect = tail->GetIndexOf(pMousePoint);
9009 int length = tail->GetnPoints();
9014 start = connect + 1;
9019 m_pMouseRoute->RemovePoint(
9023 for (i = start; i <= stop; i++) {
9024 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9026 m_pMouseRoute->m_lastMousePointIndex =
9027 m_pMouseRoute->GetnPoints();
9029 gFrame->RefreshAllCanvas();
9033 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9035 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9036 m_pMouseRoute->FinalizeForRendering();
9041 }
else if (m_bMeasure_Active && m_nMeasureState)
9044 m_bedge_pan =
false;
9048 if (m_nMeasureState == 1) {
9049 m_pMeasureRoute =
new Route();
9050 pRouteList->Append(m_pMeasureRoute);
9055 if (m_pMeasureRoute) {
9058 wxEmptyString, wxEmptyString);
9059 pMousePoint->m_bShowName =
false;
9061 m_pMeasureRoute->AddPoint(pMousePoint);
9065 m_prev_pMousePoint = pMousePoint;
9066 m_pMeasureRoute->m_lastMousePointIndex =
9067 m_pMeasureRoute->GetnPoints();
9071 CancelMeasureRoute();
9077 bool bSelectAllowed =
true;
9078 if (NULL == g_pMarkInfoDialog) {
9079 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9080 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9081 bSelectAllowed =
false;
9088 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9090 if (bSelectAllowed) {
9091 bool b_was_editing_mark = m_bMarkEditing;
9092 bool b_was_editing_route = m_bRouteEditing;
9093 FindRoutePointsAtCursor(SelectRadius,
9099 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->m_bIsInLayer)
9100 m_pRoutePointEditTarget = NULL;
9102 if (!b_was_editing_route) {
9103 if (m_pEditRouteArray) {
9104 b_startedit_route =
true;
9108 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9109 m_pTrackRolloverWin->IsActive(
false);
9111 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9112 m_pRouteRolloverWin->IsActive(
false);
9116 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9118 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9123 if (g_pRouteMan->IsRouteValid(pr)) {
9126 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9127 pre_rect.Union(route_rect);
9130 RefreshRect(pre_rect,
true);
9133 b_startedit_route =
false;
9137 if (m_pRoutePointEditTarget) {
9138 if (b_was_editing_mark ||
9139 b_was_editing_route) {
9140 if (m_lastRoutePointEditTarget) {
9141 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9142 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9144 .EnableDragHandle(
false);
9145 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9146 SELTYPE_DRAGHANDLE);
9150 if (m_pRoutePointEditTarget) {
9151 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
true;
9152 m_pRoutePointEditTarget->m_bPtIsSelected =
true;
9153 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9154 wxPoint2DDouble dragHandlePoint =
9156 .GetDragHandlePoint(
this);
9157 pSelect->AddSelectablePoint(
9158 dragHandlePoint.m_y, dragHandlePoint.m_x,
9159 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9162 if (m_lastRoutePointEditTarget) {
9163 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9164 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9166 .EnableDragHandle(
false);
9167 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9168 SELTYPE_DRAGHANDLE);
9171 wxArrayPtrVoid *lastEditRouteArray =
9172 g_pRouteMan->GetRouteArrayContaining(
9173 m_lastRoutePointEditTarget);
9174 if (lastEditRouteArray) {
9175 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9177 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9178 if (g_pRouteMan->IsRouteValid(pr)) {
9179 pr->m_bIsBeingEdited =
false;
9192 if (m_lastRoutePointEditTarget) {
9195 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9196 RefreshRect(wp_rect,
true);
9199 if (m_pRoutePointEditTarget) {
9202 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9203 RefreshRect(wp_rect,
true);
9212 bool b_start_rollover =
false;
9213 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9214 SelectItem *pFind = pSelectAIS->FindSelection(
9216 if (pFind) b_start_rollover =
true;
9219 if (!b_start_rollover && !b_startedit_route) {
9220 SelectableItemList SelList = pSelect->FindSelectionList(
9222 wxSelectableItemListNode *node = SelList.GetFirst();
9228 if (pr && pr->IsVisible()) {
9229 b_start_rollover =
true;
9232 node = node->GetNext();
9236 if (!b_start_rollover && !b_startedit_route) {
9237 SelectableItemList SelList = pSelect->FindSelectionList(
9239 wxSelectableItemListNode *node = SelList.GetFirst();
9245 if (tr && tr->IsVisible()) {
9246 b_start_rollover =
true;
9249 node = node->GetNext();
9253 if (b_start_rollover)
9254 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9258 bool appending =
false;
9259 bool inserting =
false;
9261 if (m_bRouteEditing ) {
9263 if (m_pRoutePointEditTarget) {
9269 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9270 double nearby_radius_meters =
9271 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9272 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9273 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9274 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9275 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9276 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9280 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9282 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9283 if (pr && pr->pRoutePointList) {
9284 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
9297 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9302 OCPNMessageBox(
this,
9303 _(
"Replace this RoutePoint by the nearby "
9305 _(
"OpenCPN RoutePoint change"),
9306 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9307 if (dlg_return == wxID_YES) {
9312 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9315 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9317 if (tail && current && (tail != current)) {
9319 connect = tail->GetIndexOf(pNearbyPoint);
9320 int index_current_route =
9321 current->GetIndexOf(m_pRoutePointEditTarget);
9322 index_last = current->GetIndexOf(current->GetLastPoint());
9323 dlg_return1 = wxID_NO;
9325 index_current_route) {
9327 if (connect != tail->GetnPoints()) {
9330 _(
"Last part of route to be appended to dragged "
9334 _(
"Full route to be appended to dragged route?");
9336 dlg_return1 = OCPNMessageBox(
9337 this, dmsg, _(
"OpenCPN Route Create"),
9338 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9339 if (dlg_return1 == wxID_YES) {
9343 }
else if (index_current_route ==
9348 _(
"First part of route to be inserted into dragged "
9350 if (connect == tail->GetnPoints())
9352 "Full route to be inserted into dragged route?");
9354 dlg_return1 = OCPNMessageBox(
9355 this, dmsg, _(
"OpenCPN Route Create"),
9356 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9357 if (dlg_return1 == wxID_YES) {
9364 if (m_pRoutePointEditTarget->IsShared()) {
9366 dlg_return = OCPNMessageBox(
9368 _(
"Do you really want to delete and replace this "
9370 _T(
"\n") + _(
"which has been created manually?"),
9371 (
"OpenCPN RoutePoint warning"),
9372 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9375 if (dlg_return == wxID_YES) {
9376 pMousePoint = pNearbyPoint;
9378 pMousePoint->SetShared(
true);
9382 pMousePoint->m_bIsInRoute =
true;
9388 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9390 if (m_pEditRouteArray) {
9391 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9393 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9394 if (g_pRouteMan->IsRouteValid(pr)) {
9398 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9400 pSelect->DeleteAllSelectableRoutePoints(pr);
9401 pSelect->DeleteAllSelectableRouteSegments(pr);
9403 pr->pRoutePointList->Insert(nRP, pMousePoint);
9404 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9406 pSelect->AddAllSelectableRouteSegments(pr);
9407 pSelect->AddAllSelectableRoutePoints(pr);
9409 pr->FinalizeForRendering();
9410 pr->UpdateSegmentDistances();
9411 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9417 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9418 if (m_pEditRouteArray) {
9419 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9421 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9422 if (g_pRouteMan->IsRouteValid(pr)) {
9423 if (pRoutePropDialog->GetRoute() == pr) {
9424 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9439 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9442 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9443 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9444 g_pMarkInfoDialog->Hide();
9446 delete m_pRoutePointEditTarget;
9447 m_lastRoutePointEditTarget = NULL;
9448 m_pRoutePointEditTarget = NULL;
9449 undo->AfterUndoableAction(pMousePoint);
9450 undo->InvalidateUndo();
9455 else if (m_bMarkEditing) {
9456 if (m_pRoutePointEditTarget)
9457 if (m_bRoutePoinDragging)
9458 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9461 if (m_pRoutePointEditTarget)
9462 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9464 if (!m_pRoutePointEditTarget) {
9465 delete m_pEditRouteArray;
9466 m_pEditRouteArray = NULL;
9467 m_bRouteEditing =
false;
9469 m_bRoutePoinDragging =
false;
9476 int length = tail->GetnPoints();
9477 for (
int i = connect + 1; i <= length; i++) {
9478 current->AddPointAndSegment(tail->GetPoint(i),
false);
9479 if (current) current->m_lastMousePointIndex = current->GetnPoints();
9481 gFrame->RefreshAllCanvas();
9484 current->FinalizeForRendering();
9485 current->m_bIsBeingEdited =
false;
9487 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9490 pSelect->DeleteAllSelectableRoutePoints(current);
9491 pSelect->DeleteAllSelectableRouteSegments(current);
9492 for (
int i = 1; i < connect; i++) {
9493 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9495 pSelect->AddAllSelectableRouteSegments(current);
9496 pSelect->AddAllSelectableRoutePoints(current);
9497 current->FinalizeForRendering();
9498 current->m_bIsBeingEdited =
false;
9499 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9503 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9504 if (m_pEditRouteArray) {
9505 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9506 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9507 if (g_pRouteMan->IsRouteValid(pr)) {
9508 if (pRoutePropDialog->GetRoute() == pr) {
9509 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9519 if (m_bRouteEditing) {
9522 bool appending =
false;
9523 bool inserting =
false;
9526 if (m_pRoutePointEditTarget) {
9527 m_pRoutePointEditTarget->m_bBlink =
false;
9531 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9532 double nearby_radius_meters =
9533 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9534 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9535 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9536 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9537 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9538 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9539 bool duplicate =
false;
9541 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9543 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9544 if (pr && pr->pRoutePointList) {
9545 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
9558 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9563 OCPNMessageBox(
this,
9564 _(
"Replace this RoutePoint by the nearby "
9566 _(
"OpenCPN RoutePoint change"),
9567 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9568 if (dlg_return == wxID_YES) {
9572 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9575 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9577 if (tail && current && (tail != current)) {
9579 connect = tail->GetIndexOf(pNearbyPoint);
9580 int index_current_route =
9581 current->GetIndexOf(m_pRoutePointEditTarget);
9582 index_last = current->GetIndexOf(current->GetLastPoint());
9583 dlg_return1 = wxID_NO;
9585 index_current_route) {
9587 if (connect != tail->GetnPoints()) {
9590 _(
"Last part of route to be appended to dragged "
9594 _(
"Full route to be appended to dragged route?");
9596 dlg_return1 = OCPNMessageBox(
9597 this, dmsg, _(
"OpenCPN Route Create"),
9598 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9599 if (dlg_return1 == wxID_YES) {
9603 }
else if (index_current_route ==
9608 _(
"First part of route to be inserted into dragged "
9610 if (connect == tail->GetnPoints())
9612 "Full route to be inserted into dragged route?");
9614 dlg_return1 = OCPNMessageBox(
9615 this, dmsg, _(
"OpenCPN Route Create"),
9616 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9617 if (dlg_return1 == wxID_YES) {
9624 if (m_pRoutePointEditTarget->IsShared()) {
9625 dlg_return = wxID_NO;
9626 dlg_return = OCPNMessageBox(
9628 _(
"Do you really want to delete and replace this "
9630 _T(
"\n") + _(
"which has been created manually?"),
9631 (
"OpenCPN RoutePoint warning"),
9632 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9635 if (dlg_return == wxID_YES) {
9636 pMousePoint = pNearbyPoint;
9638 pMousePoint->SetShared(
true);
9642 pMousePoint->m_bIsInRoute =
true;
9648 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9650 if (m_pEditRouteArray) {
9651 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9653 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9654 if (g_pRouteMan->IsRouteValid(pr)) {
9657 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9659 pSelect->DeleteAllSelectableRoutePoints(pr);
9660 pSelect->DeleteAllSelectableRouteSegments(pr);
9662 pr->pRoutePointList->Insert(nRP, pMousePoint);
9663 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9665 pSelect->AddAllSelectableRouteSegments(pr);
9666 pSelect->AddAllSelectableRoutePoints(pr);
9668 pr->FinalizeForRendering();
9669 pr->UpdateSegmentDistances();
9670 pr->m_bIsBeingEdited =
false;
9672 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9684 int length = tail->GetnPoints();
9685 for (
int i = connect + 1; i <= length; i++) {
9686 current->AddPointAndSegment(tail->GetPoint(i),
false);
9688 current->m_lastMousePointIndex = current->GetnPoints();
9690 gFrame->RefreshAllCanvas();
9693 current->FinalizeForRendering();
9694 current->m_bIsBeingEdited =
false;
9696 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9699 pSelect->DeleteAllSelectableRoutePoints(current);
9700 pSelect->DeleteAllSelectableRouteSegments(current);
9701 for (
int i = 1; i < connect; i++) {
9702 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9704 pSelect->AddAllSelectableRouteSegments(current);
9705 pSelect->AddAllSelectableRoutePoints(current);
9706 current->FinalizeForRendering();
9707 current->m_bIsBeingEdited =
false;
9708 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9712 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9713 if (m_pEditRouteArray) {
9714 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9716 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9717 if (g_pRouteMan->IsRouteValid(pr)) {
9718 if (pRoutePropDialog->GetRoute() == pr) {
9719 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9727 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9730 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9731 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9732 g_pMarkInfoDialog->Hide();
9734 delete m_pRoutePointEditTarget;
9735 m_lastRoutePointEditTarget = NULL;
9736 undo->AfterUndoableAction(pMousePoint);
9737 undo->InvalidateUndo();
9739 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9740 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9742 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9745 delete m_pEditRouteArray;
9746 m_pEditRouteArray = NULL;
9750 m_bRouteEditing =
false;
9751 m_pRoutePointEditTarget = NULL;
9757 else if (m_bMarkEditing) {
9758 if (m_pRoutePointEditTarget) {
9759 if (m_bRoutePoinDragging)
9760 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9761 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9762 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9766 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9767 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9768 RefreshRect(wp_rect,
true);
9771 m_pRoutePointEditTarget = NULL;
9772 m_bMarkEditing =
false;
9777 else if (leftIsDown) {
9782 if (!m_bChartDragging && !m_bMeasure_Active) {
9784 m_bChartDragging =
false;
9788 m_bRoutePoinDragging =
false;
9791 if (ret)
return true;
9794 if (event.RightDown()) {
9805 m_FinishRouteOnKillFocus =
false;
9806 CallPopupMenu(mx, my);
9807 m_FinishRouteOnKillFocus =
true;
9818 if (event.ShiftDown()) {
9822 event.GetPosition(&x, &y);
9824 x *= m_displayScale;
9825 y *= m_displayScale;
9831 int wheel_dir =
event.GetWheelRotation();
9834 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9835 wheel_dir = wheel_dir > 0 ? 1 : -1;
9837 double factor = g_mouse_zoom_sensitivity;
9838 if (wheel_dir < 0) factor = 1 / factor;
9840 if (g_bsmoothpanzoom) {
9841 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9842 if (wheel_dir == m_last_wheel_dir) {
9843 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9848 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9849 m_wheelstopwatch.Start(0);
9854 m_last_wheel_dir = wheel_dir;
9859 if (event.LeftDown()) {
9866 last_drag.x = x, last_drag.y = y;
9867 panleftIsDown =
true;
9870 if (event.LeftUp()) {
9871 if (panleftIsDown) {
9873 panleftIsDown =
false;
9876 if (!m_bChartDragging && !m_bMeasure_Active) {
9877 switch (cursor_region) {
9899 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
9904 m_bChartDragging =
false;
9910 if (event.Dragging() && event.LeftIsDown()) {
9928 struct timespec now;
9929 clock_gettime(CLOCK_MONOTONIC, &now);
9930 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
9932 if (
false == m_bChartDragging) {
9934 last_drag.x = x, last_drag.y = y;
9935 m_bChartDragging =
true;
9936 m_chart_drag_total_time = 0;
9937 m_chart_drag_total_x = 0;
9938 m_chart_drag_total_y = 0;
9939 m_inertia_last_drag_x = x;
9940 m_inertia_last_drag_y = y;
9941 m_drag_vec_x.clear();
9942 m_drag_vec_y.clear();
9943 m_drag_vec_t.clear();
9944 m_last_drag_time = tnow;
9948 uint64_t delta_t = tnow - m_last_drag_time;
9949 double delta_tf = delta_t / 1e9;
9951 m_chart_drag_total_time += delta_tf;
9952 m_chart_drag_total_x += m_inertia_last_drag_x - x;
9953 m_chart_drag_total_y += m_inertia_last_drag_y - y;
9955 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
9956 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
9957 m_drag_vec_t.push_back(delta_tf);
9959 m_inertia_last_drag_x = x;
9960 m_inertia_last_drag_y = y;
9961 m_last_drag_time = tnow;
9963 if ((last_drag.x != x) || (last_drag.y != y)) {
9964 if (!m_routeState) {
9967 m_bChartDragging =
true;
9968 StartTimedMovement();
9969 m_pan_drag.x += last_drag.x - x;
9970 m_pan_drag.y += last_drag.y - y;
9971 last_drag.x = x, last_drag.y = y;
9975 if ((last_drag.x != x) || (last_drag.y != y)) {
9976 if (!m_routeState) {
9979 m_bChartDragging =
true;
9980 StartTimedMovement();
9981 m_pan_drag.x += last_drag.x - x;
9982 m_pan_drag.y += last_drag.y - y;
9983 last_drag.x = x, last_drag.y = y;
9990 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
9992 m_DoubleClickTimer->Start();
9993 singleClickEventIsValid =
false;
10001void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10002 if (MouseEventOverlayWindows(event))
return;
10009void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10012 wxCursor *ptarget_cursor = pCursorArrow;
10013 if (!pPlugIn_Cursor) {
10014 ptarget_cursor = pCursorArrow;
10015 if ((!m_routeState) &&
10016 (!m_bMeasure_Active) ) {
10017 if (cursor_region == MID_RIGHT) {
10018 ptarget_cursor = pCursorRight;
10019 }
else if (cursor_region == MID_LEFT) {
10020 ptarget_cursor = pCursorLeft;
10021 }
else if (cursor_region == MID_TOP) {
10022 ptarget_cursor = pCursorDown;
10023 }
else if (cursor_region == MID_BOT) {
10024 ptarget_cursor = pCursorUp;
10026 ptarget_cursor = pCursorArrow;
10028 }
else if (m_bMeasure_Active ||
10030 ptarget_cursor = pCursorPencil;
10032 ptarget_cursor = pPlugIn_Cursor;
10035 SetCursor(*ptarget_cursor);
10038void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10039 SetCursor(*pCursorArrow);
10042void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10046 wxArrayString files;
10048 ChartBase *target_chart = GetChartAtCursor();
10049 if (target_chart) {
10050 file.Assign(target_chart->GetFullPath());
10051 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10052 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10055 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10057 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10058 unsigned int im = stackIndexArray.size();
10059 int scale = 2147483647;
10060 if (VPoint.b_quilt && im > 0) {
10061 for (
unsigned int is = 0; is < im; is++) {
10062 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
10063 CHART_TYPE_MBTILES) {
10064 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10066 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10067 if (ChartData->GetChartTableEntry(stackIndexArray[is])
10069 .Contains(lat, lon)) {
10070 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10073 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10074 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
10082 std::vector<Ais8_001_22 *> area_notices;
10084 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10087 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10088 auto target_data = target.second;
10089 if (!target_data->area_notices.empty()) {
10090 for (
auto &ani : target_data->area_notices) {
10095 for (Ais8_001_22_SubAreaList::iterator sa =
10096 area_notice.sub_areas.begin();
10097 sa != area_notice.sub_areas.end(); ++sa) {
10098 switch (sa->shape) {
10099 case AIS8_001_22_SHAPE_CIRCLE: {
10100 wxPoint target_point;
10102 bbox.Expand(target_point);
10103 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10106 case AIS8_001_22_SHAPE_RECT: {
10107 wxPoint target_point;
10109 bbox.Expand(target_point);
10110 if (sa->e_dim_m > sa->n_dim_m)
10111 bbox.EnLarge(sa->e_dim_m * vp_scale);
10113 bbox.EnLarge(sa->n_dim_m * vp_scale);
10116 case AIS8_001_22_SHAPE_POLYGON:
10117 case AIS8_001_22_SHAPE_POLYLINE: {
10118 for (
int i = 0; i < 4; ++i) {
10119 double lat = sa->latitude;
10120 double lon = sa->longitude;
10121 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10123 wxPoint target_point;
10125 bbox.Expand(target_point);
10129 case AIS8_001_22_SHAPE_SECTOR: {
10130 double lat1 = sa->latitude;
10131 double lon1 = sa->longitude;
10133 wxPoint target_point;
10135 bbox.Expand(target_point);
10136 for (
int i = 0; i < 18; ++i) {
10139 sa->left_bound_deg +
10140 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10141 sa->radius_m / 1852.0, &lat, &lon);
10143 bbox.Expand(target_point);
10145 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10148 bbox.Expand(target_point);
10154 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10155 area_notices.push_back(&area_notice);
10162 if (target_chart || !area_notices.empty() || file.HasName()) {
10164 int sel_rad_pix = 5;
10165 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10170 SetCursor(wxCURSOR_WAIT);
10171 bool lightsVis = m_encShowLights;
10172 if (!lightsVis) SetShowENCLights(
true);
10175 ListOfObjRazRules *rule_list = NULL;
10176 ListOfPI_S57Obj *pi_rule_list = NULL;
10179 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10180 else if (target_plugin_chart)
10181 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10182 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10184 ListOfObjRazRules *overlay_rule_list = NULL;
10185 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10188 if (CHs57_Overlay) {
10189 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10190 zlat, zlon, SelectRadius, &GetVP());
10193 if (!lightsVis) SetShowENCLights(
false);
10196 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10197 wxString face = dFont->GetFaceName();
10199 if (NULL == g_pObjectQueryDialog) {
10200 g_pObjectQueryDialog =
10201 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10202 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10205 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10206 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10210 fg = g_pObjectQueryDialog->GetForegroundColour();
10214 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
10215 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10218 int points = dFont->GetPointSize();
10220 int points = dFont->GetPointSize() + 1;
10224 for (
int i = -2; i < 5; i++) {
10225 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10227 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10229 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
10231 if (overlay_rule_list && CHs57_Overlay) {
10232 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10233 objText << _T(
"<hr noshade>");
10236 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10237 an != area_notices.end(); ++an) {
10238 objText << _T(
"<b>AIS Area Notice:</b> " );
10239 objText << ais8_001_22_notice_names[(*an)->notice_type];
10240 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10241 (*an)->sub_areas.begin();
10242 sa != (*an)->sub_areas.end(); ++sa)
10243 if (!sa->text.empty()) objText << sa->text;
10244 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10245 objText << _T(
"<hr noshade>" );
10249 objText << Chs57->CreateObjDescriptions(rule_list);
10250 else if (target_plugin_chart)
10251 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10254 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
10257 wxString AddFiles, filenameOK;
10259 if (!target_plugin_chart) {
10262 AddFiles = wxString::Format(
10263 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
10265 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
10266 _T(
"cellpadding=3>"),
10267 file.GetFullName());
10269 file.Assign(file.GetPath(), wxT(
""));
10270 wxDir dir(file.GetFullPath());
10272 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10274 file.Assign(dir.GetNameWithSep().append(filename));
10275 wxString FormatString =
10276 _T(
"<td valign=top><font size=-2><a ")
10277 _T("href=\"%s\">%s</a></font></td>");
10278 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10279 filenameOK = file.GetFullPath();
10281 if (3 * ((
int)filecount / 3) == filecount)
10282 FormatString.Prepend(_T(
"<tr>"));
10284 FormatString.Prepend(
10285 _T(
"<td>  </td>"));
10288 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10289 file.GetFullName());
10292 cont = dir.GetNext(&filename);
10294 objText << AddFiles << _T(
"</table>");
10296 objText << _T(
"</font>");
10297 objText << _T(
"</body></html>");
10299 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10300 g_pObjectQueryDialog->SetHTMLPage(objText);
10301 g_pObjectQueryDialog->Show();
10303 if ((!Chs57 && filecount == 1)) {
10305 wxHtmlLinkInfo hli(filenameOK);
10306 wxHtmlLinkEvent hle(1, hli);
10307 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10310 if (rule_list) rule_list->Clear();
10313 if (overlay_rule_list) overlay_rule_list->Clear();
10314 delete overlay_rule_list;
10316 if (pi_rule_list) pi_rule_list->Clear();
10317 delete pi_rule_list;
10319 SetCursor(wxCURSOR_ARROW);
10323void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10325 if (!g_pMarkInfoDialog) {
10332 wxSize canvas_size = GetSize();
10335 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10337 g_pMarkInfoDialog->Layout();
10339 wxPoint canvas_pos = GetPosition();
10340 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10342 bool newFit =
false;
10343 if (canvas_size.x < fitted_size.x) {
10344 fitted_size.x = canvas_size.x - 40;
10345 if (canvas_size.y < fitted_size.y)
10346 fitted_size.y -= 40;
10348 if (canvas_size.y < fitted_size.y) {
10349 fitted_size.y = canvas_size.y - 40;
10350 if (canvas_size.x < fitted_size.x)
10351 fitted_size.x -= 40;
10355 g_pMarkInfoDialog->SetSize(fitted_size);
10356 g_pMarkInfoDialog->Centre();
10360 markPoint->m_bRPIsBeingEdited =
false;
10362 wxString title_base = _(
"Mark Properties");
10363 if (markPoint->m_bIsInRoute) {
10364 title_base = _(
"Waypoint Properties");
10366 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10367 g_pMarkInfoDialog->UpdateProperties();
10368 if (markPoint->m_bIsInLayer) {
10369 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title_base, _(
"Layer"),
10370 GetLayerName(markPoint->m_LayerID)));
10371 g_pMarkInfoDialog->SetDialogTitle(caption);
10373 g_pMarkInfoDialog->SetDialogTitle(title_base);
10375 g_pMarkInfoDialog->Show();
10376 g_pMarkInfoDialog->Raise();
10377 g_pMarkInfoDialog->InitialFocus();
10378 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10381void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10382 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10383 pRoutePropDialog->SetRouteAndUpdate(selected);
10385 pRoutePropDialog->Show();
10386 pRoutePropDialog->Raise();
10388 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10391 if (g_bresponsive) {
10392 wxSize canvas_size = GetSize();
10393 wxPoint canvas_pos = GetPosition();
10394 wxSize fitted_size = pRoutePropDialog->GetSize();
10397 if (canvas_size.x < fitted_size.x) {
10398 fitted_size.x = canvas_size.x;
10399 if (canvas_size.y < fitted_size.y)
10400 fitted_size.y -= 20;
10402 if (canvas_size.y < fitted_size.y) {
10403 fitted_size.y = canvas_size.y;
10404 if (canvas_size.x < fitted_size.x)
10405 fitted_size.x -= 20;
10408 pRoutePropDialog->SetSize(fitted_size);
10409 pRoutePropDialog->Centre();
10414 wxPoint xxp = ClientToScreen(canvas_pos);
10418 pRoutePropDialog->SetRouteAndUpdate(selected);
10420 pRoutePropDialog->Show();
10425void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10426 pTrackPropDialog = TrackPropDlg::getInstance(
10429 pTrackPropDialog->SetTrackAndUpdate(selected);
10432 pTrackPropDialog->Show();
10437void pupHandler_PasteWaypoint() {
10440 int pasteBuffer = kml.ParsePasteBuffer();
10441 RoutePoint *pasted = kml.GetParsedRoutePoint();
10442 if (!pasted)
return;
10444 double nearby_radius_meters =
10445 g_Platform->GetSelectRadiusPix() /
10446 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10448 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10449 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10451 int answer = wxID_NO;
10452 if (nearPoint && !nearPoint->m_bIsInLayer) {
10455 "There is an existing waypoint at the same location as the one you are "
10456 "pasting. Would you like to merge the pasted data with it?\n\n");
10457 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10458 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10459 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10462 if (answer == wxID_YES) {
10463 nearPoint->SetName(pasted->GetName());
10464 nearPoint->m_MarkDescription = pasted->m_MarkDescription;
10465 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10466 pRouteManagerDialog->UpdateWptListCtrl();
10469 if (answer == wxID_NO) {
10472 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10474 pConfig->AddNewWayPoint(newPoint, -1);
10476 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10477 pRouteManagerDialog->UpdateWptListCtrl();
10478 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10479 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10482 gFrame->InvalidateAllGL();
10483 gFrame->RefreshAllCanvas(
false);
10486void pupHandler_PasteRoute() {
10489 int pasteBuffer = kml.ParsePasteBuffer();
10490 Route *pasted = kml.GetParsedRoute();
10491 if (!pasted)
return;
10493 double nearby_radius_meters =
10494 g_Platform->GetSelectRadiusPix() /
10495 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10501 bool mergepoints =
false;
10502 bool createNewRoute =
true;
10503 int existingWaypointCounter = 0;
10505 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10506 curPoint = pasted->GetPoint(i);
10507 nearPoint = pWayPointMan->GetNearbyWaypoint(
10508 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10510 mergepoints =
true;
10511 existingWaypointCounter++;
10515 curPoint->m_bPtIsSelected =
true;
10519 int answer = wxID_NO;
10523 "There are existing waypoints at the same location as some of the ones "
10524 "you are pasting. Would you like to just merge the pasted data into "
10526 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10527 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10528 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10530 if (answer == wxID_CANCEL) {
10537 if (mergepoints && answer == wxID_YES &&
10538 existingWaypointCounter == pasted->GetnPoints()) {
10539 wxRouteListNode *route_node = pRouteList->GetFirst();
10540 while (route_node) {
10541 Route *proute = route_node->GetData();
10543 if (pasted->m_RouteNameString == proute->m_RouteNameString) {
10544 createNewRoute =
false;
10547 route_node = route_node->GetNext();
10551 Route *newRoute = 0;
10554 if (createNewRoute) {
10555 newRoute =
new Route();
10556 newRoute->m_RouteNameString = pasted->m_RouteNameString;
10559 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10560 curPoint = pasted->GetPoint(i);
10561 if (answer == wxID_YES && curPoint->m_bPtIsSelected) {
10562 curPoint->m_bPtIsSelected =
false;
10563 newPoint = pWayPointMan->GetNearbyWaypoint(
10564 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10565 newPoint->SetName(curPoint->GetName());
10566 newPoint->m_MarkDescription = curPoint->m_MarkDescription;
10568 if (createNewRoute) newRoute->AddPoint(newPoint);
10570 curPoint->m_bPtIsSelected =
false;
10574 newPoint->SetIconName(_T(
"circle"));
10575 newPoint->m_bIsVisible =
true;
10576 newPoint->m_bShowName =
false;
10577 newPoint->SetShared(
false);
10579 newRoute->AddPoint(newPoint);
10580 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10582 pConfig->AddNewWayPoint(newPoint, -1);
10585 if (i > 1 && createNewRoute)
10586 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10587 curPoint->m_lat, curPoint->m_lon,
10588 prevPoint, newPoint, newRoute);
10589 prevPoint = newPoint;
10592 if (createNewRoute) {
10593 pRouteList->Append(newRoute);
10594 pConfig->AddNewRoute(newRoute);
10596 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10597 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10600 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10601 pRouteManagerDialog->UpdateRouteListCtrl();
10602 pRouteManagerDialog->UpdateWptListCtrl();
10604 gFrame->InvalidateAllGL();
10605 gFrame->RefreshAllCanvas(
false);
10607 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10608 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10611void pupHandler_PasteTrack() {
10614 int pasteBuffer = kml.ParsePasteBuffer();
10615 Track *pasted = kml.GetParsedTrack();
10616 if (!pasted)
return;
10624 newTrack->SetName(pasted->GetName());
10626 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10627 curPoint = pasted->GetPoint(i);
10631 wxDateTime now = wxDateTime::Now();
10632 newPoint->SetCreateTime(curPoint->GetCreateTime());
10634 newTrack->AddPoint(newPoint);
10637 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10638 newPoint->m_lat, newPoint->m_lon,
10639 prevPoint, newPoint, newTrack);
10641 prevPoint = newPoint;
10644 g_TrackList.push_back(newTrack);
10645 pConfig->AddNewTrack(newTrack);
10647 gFrame->InvalidateAllGL();
10648 gFrame->RefreshAllCanvas(
false);
10651bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10653 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10657 wxEVT_COMMAND_MENU_SELECTED,
10658 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10660 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10663 wxEVT_COMMAND_MENU_SELECTED,
10664 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10666 delete m_canvasMenu;
10667 m_canvasMenu = NULL;
10677void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10680 if (m_canvasMenu) {
10681 m_canvasMenu->PopupMenuHandler(event);
10686void ChartCanvas::StartRoute(
void) {
10688 if (g_brouteCreating)
return;
10690 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10692 g_brouteCreating =
true;
10694 m_bDrawingRoute =
false;
10695 SetCursor(*pCursorPencil);
10697 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10699 HideGlobalToolbar();
10702 androidSetRouteAnnunciator(
true);
10706void ChartCanvas::FinishRoute(
void) {
10708 m_prev_pMousePoint = NULL;
10709 m_bDrawingRoute =
false;
10712 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10714 androidSetRouteAnnunciator(
false);
10717 SetCursor(*pCursorArrow);
10719 if (m_pMouseRoute) {
10720 if (m_bAppendingRoute)
10721 pConfig->UpdateRoute(m_pMouseRoute);
10723 if (m_pMouseRoute->GetnPoints() > 1) {
10724 pConfig->AddNewRoute(m_pMouseRoute);
10727 NavObjectChanges::getInstance());
10728 m_pMouseRoute = NULL;
10731 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10733 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10734 (pRoutePropDialog->IsShown())) {
10735 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10738 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10739 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10740 pRouteManagerDialog->UpdateRouteListCtrl();
10743 m_bAppendingRoute =
false;
10744 m_pMouseRoute = NULL;
10746 m_pSelectedRoute = NULL;
10748 undo->InvalidateUndo();
10749 gFrame->RefreshAllCanvas(
true);
10751 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10753 ShowGlobalToolbar();
10755 g_brouteCreating =
false;
10758void ChartCanvas::HideGlobalToolbar() {
10759 if (m_canvasIndex == 0) {
10760 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10764void ChartCanvas::ShowGlobalToolbar() {
10765 if (m_canvasIndex == 0) {
10766 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10770void ChartCanvas::ShowAISTargetList(
void) {
10771 if (NULL == g_pAISTargetList) {
10775 g_pAISTargetList->UpdateAISTargetList();
10778void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10779 if (!m_bShowOutlines)
return;
10781 if (!ChartData)
return;
10783 int nEntry = ChartData->GetChartTableEntries();
10785 for (
int i = 0; i < nEntry; i++) {
10789 bool b_group_draw =
false;
10790 if (m_groupIndex > 0) {
10791 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10792 int index = pt->GetGroupArray()[ig];
10793 if (m_groupIndex == index) {
10794 b_group_draw =
true;
10799 b_group_draw =
true;
10801 if (b_group_draw) RenderChartOutline(dc, i, vp);
10807 if (VPoint.b_quilt) {
10808 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10809 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10813 }
else if (m_singleChart &&
10814 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10818 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10821 if (zoom_factor > 8.0) {
10822 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10825 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10829 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
10833void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10835 if (g_bopengl && m_glcc) {
10837 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10842 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10843 if (!ChartData->IsChartAvailable(dbIndex))
return;
10846 float plylat, plylon;
10847 float plylat1, plylon1;
10849 int pixx, pixy, pixx1, pixy1;
10852 ChartData->GetDBBoundingBox(dbIndex, box);
10856 if (box.GetLonRange() == 360)
return;
10858 double lon_bias = 0;
10860 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10862 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10864 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10865 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10867 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10868 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10871 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10874 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10875 if (0 == nAuxPlyEntries)
10879 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10880 plylon += lon_bias;
10886 for (
int i = 0; i < nPly - 1; i++) {
10887 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
10888 plylon1 += lon_bias;
10894 int pixxs1 = pixx1;
10895 int pixys1 = pixy1;
10897 bool b_skip =
false;
10901 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
10902 pow((
double)(pixy1 - pixy), 2)) /
10908 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10913 if (fabs(dist - distgc) > 10000. * 1852.)
10919 ClipResult res = cohen_sutherland_line_clip_i(
10921 if (res != Invisible && !b_skip)
10922 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
10930 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
10931 plylon1 += lon_bias;
10937 ClipResult res = cohen_sutherland_line_clip_i(
10939 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
10946 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10947 for (
int j = 0; j < nAuxPlyEntries; j++) {
10949 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
10954 for (
int i = 0; i < nAuxPly - 1; i++) {
10955 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
10961 int pixxs1 = pixx1;
10962 int pixys1 = pixy1;
10964 bool b_skip =
false;
10968 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
10969 ((pixy1 - pixy) * (pixy1 - pixy))) /
10974 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10979 if (fabs(dist - distgc) > 10000. * 1852.)
10985 ClipResult res = cohen_sutherland_line_clip_i(
10987 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
10995 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11000 ClipResult res = cohen_sutherland_line_clip_i(
11002 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11007static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11008 const wxString &second) {
11009 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11011 int pointsize = dFont->GetPointSize();
11015 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11016 false, dFont->GetFaceName());
11018 dc.SetFont(*psRLI_font);
11026 int hilite_offset = 3;
11029 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11030 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11032 dc.GetTextExtent(first, &w1, &h1);
11033 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11039 w = wxMax(w1, w2) + (h1 / 2);
11044 xp = ref_point.x - w;
11046 yp += hilite_offset;
11048 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11050 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11051 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11053 dc.DrawText(first, xp, yp);
11054 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11057void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11058 if (!g_bAllowShipToActive)
return;
11060 Route *rt = g_pRouteMan->GetpActiveRoute();
11063 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11064 wxPoint2DDouble pa, pb;
11070 g_pRouteMan->GetRoutePen()->GetWidth();
11071 if (rt->m_width != wxPENSTYLE_INVALID)
11072 width = rt->m_width;
11073 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11074 g_shipToActiveStyle, 5)];
11075 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11077 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11079 g_pRouteMan->GetActiveRoutePen()->GetColour();
11080 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11083 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11086 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11087 (
int)pb.m_y, GetVP(),
true);
11091#ifdef USE_ANDROID_GLES2
11092 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11094 if (style != wxPENSTYLE_SOLID) {
11095 if (glChartCanvas::dash_map.find(style) !=
11096 glChartCanvas::dash_map.end()) {
11097 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11101 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11104 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11105 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11111void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11113 if (m_routeState >= 2) route = m_pMouseRoute;
11114 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11115 route = m_pMeasureRoute;
11117 if (!route)
return;
11120 if (!g_pRouteMan->IsRouteValid(route))
return;
11125 int np = route->GetnPoints();
11127 if (g_btouch && (np > 1)) np--;
11129 render_lat = rp.m_lat;
11130 render_lon = rp.m_lon;
11133 double rhumbBearing, rhumbDist;
11135 &rhumbBearing, &rhumbDist);
11136 double brg = rhumbBearing;
11137 double dist = rhumbDist;
11141 double gcBearing, gcBearing2, gcDist;
11142 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11145 double gcDistm = gcDist / 1852.0;
11148 rhumbBearing = 90.;
11150 wxPoint destPoint, lastPoint;
11152 route->m_NextLegGreatCircle =
false;
11153 int milesDiff = rhumbDist - gcDistm;
11154 if (milesDiff > 1) {
11157 route->m_NextLegGreatCircle =
true;
11161 RouteGui(*route).DrawPointWhich(dc,
this, route->m_lastMousePointIndex,
11164 if (route->m_NextLegGreatCircle) {
11165 for (
int i = 1; i <= milesDiff; i++) {
11166 double p = (double)i * (1.0 / (
double)milesDiff);
11168 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11169 &pLon, &pLat, &gcBearing2);
11171 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11173 lastPoint = destPoint;
11176 if (r_rband.x && r_rband.y) {
11177 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11179 if (m_bMeasure_DistCircle) {
11180 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11181 powf((
float)(r_rband.y - lastPoint.y), 2));
11183 dc.SetPen(*g_pRouteMan->GetRoutePen());
11184 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11185 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11191 wxString routeInfo;
11193 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11199 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11201 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11202 (
int)varBrg, 0x00B0);
11205 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
11208 if (!route->m_bIsInLayer)
11209 s0.Append(_(
"Route") + _T(
": "));
11211 s0.Append(_(
"Layer Route: "));
11213 double disp_length = route->m_route_length;
11214 if (!g_btouch) disp_length += dist;
11215 s0 += FormatDistanceAdaptive(disp_length);
11217 RouteLegInfo(dc, r_rband, routeInfo, s0);
11219 m_brepaint_piano =
true;
11222void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11223 if (!m_bShowVisibleSectors)
return;
11225 if (g_bDeferredInitDone) {
11227 double rhumbBearing, rhumbDist;
11228 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11229 &rhumbBearing, &rhumbDist);
11231 if (rhumbDist > 0.05)
11233 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11234 m_sectorlegsVisible);
11235 m_sector_glat = gLat;
11236 m_sector_glon = gLon;
11238 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11242void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11250void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11251 if (!ps52plib)
return;
11253 if (VPoint.b_quilt) {
11254 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11256 if (m_pQuilt->IsQuiltVector()) {
11257 if (ps52plib->GetStateHash() != m_s52StateHash) {
11259 m_s52StateHash = ps52plib->GetStateHash();
11263 if (ps52plib->GetStateHash() != m_s52StateHash) {
11265 m_s52StateHash = ps52plib->GetStateHash();
11270 bool bSendPlibState =
true;
11271 if (VPoint.b_quilt) {
11272 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11275 if (bSendPlibState) {
11277 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
11278 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
11279 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
11280 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
11281 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
11284 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
11285 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
11286 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
11287 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] = m_encShowAnchor;
11288 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] = GetShowENCDataQual();
11289 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
11290 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
11294 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
11295 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
11299 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
11300 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
11301 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
11302 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] =
11303 ps52plib->m_bShowS57ImportantTextOnly;
11304 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
11305 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
11306 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
11307 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
11308 v[_T(
"OpenCPN S52PLIB ColorShades")] =
11309 S52_getMarinerParam(S52_MAR_TWO_SHADES);
11312 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
11313 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
11314 v[_T(
"OpenCPN Scale Factor Exp")] =
11315 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11316 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
11322 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11323 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11324 g_lastS52PLIBPluginMessage = out;
11330void ChartCanvas::OnPaint(wxPaintEvent &event) {
11331 wxPaintDC dc(
this);
11341 if (!m_b_paint_enable) {
11346 UpdateCanvasS52PLIBConfig();
11349 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11351 if (m_glcc && g_bopengl) {
11352 if (!s_in_update) {
11362 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11364 wxRegion ru = GetUpdateRegion();
11366 int rx, ry, rwidth, rheight;
11367 ru.GetBox(rx, ry, rwidth, rheight);
11371#ifdef ocpnUSE_DIBSECTION
11374 wxMemoryDC temp_dc;
11382 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11383 height += m_Piano->GetHeight();
11385 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11389 int thumbx, thumby, thumbsx, thumbsy;
11390 pthumbwin->GetPosition(&thumbx, &thumby);
11391 pthumbwin->GetSize(&thumbsx, &thumbsy);
11392 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11394 if (pthumbwin->IsShown()) {
11395 rgn_chart.Subtract(rgn_thumbwin);
11396 ru.Subtract(rgn_thumbwin);
11402 wxRegion rgn_blit = ru;
11403 if (g_bShowChartBar) {
11404 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11405 GetClientSize().x, m_Piano->GetHeight());
11408 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11409 if (style->chartStatusWindowTransparent)
11410 m_brepaint_piano =
true;
11412 ru.Subtract(chart_bar_rect);
11416 if (m_Compass && m_Compass->IsShown()) {
11417 wxRect compassRect = m_Compass->
GetRect();
11418 if (ru.Contains(compassRect) != wxOutRegion) {
11419 ru.Subtract(compassRect);
11424 bool b_newview =
true;
11429 m_cache_vp.IsValid()) {
11435 bool b_rcache_ok =
false;
11436 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11437 b_rcache_ok = !b_newview;
11440 if (VPoint.b_MercatorProjectionOverride)
11441 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11455 if (b_rcache_ok) chart_get_region.Clear();
11458 if (VPoint.b_quilt)
11460 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11462 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11467 AbstractPlatform::ShowBusySpinner();
11471 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11472 (m_working_bm.GetHeight() != svp.
pix_height))
11476 if (fabs(VPoint.
rotation) < 0.01) {
11477 bool b_save =
true;
11479 if (g_SencThreadManager) {
11480 if (g_SencThreadManager->GetJobCount()) {
11482 m_cache_vp.Invalidate();
11496 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11501 int dy = c_new.y - c_old.y;
11502 int dx = c_new.x - c_old.x;
11507 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11511 temp_dc.SelectObject(m_working_bm);
11513 wxMemoryDC cache_dc;
11514 cache_dc.SelectObject(m_cached_chart_bm);
11518 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11521 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11527 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11530 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11538 update_region.Union(
11541 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11546 update_region.Union(
11549 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11553 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11555 cache_dc.SelectObject(wxNullBitmap);
11559 temp_dc.SelectObject(m_cached_chart_bm);
11562 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11566 temp_dc.SelectObject(m_working_bm);
11567 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11572 temp_dc.SelectObject(m_cached_chart_bm);
11577 temp_dc.SelectObject(m_working_bm);
11578 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11591 wxMemoryDC scratch_dc_0;
11592 scratch_dc_0.SelectObject(m_cached_chart_bm);
11595 scratch_dc_0.SelectObject(wxNullBitmap);
11604 temp_dc.SelectObject(m_working_bm);
11607 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11608 chart_get_all_region);
11611 AbstractPlatform::HideBusySpinner();
11617 if (!m_singleChart) {
11618 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11623 if (!chart_get_region.IsEmpty()) {
11624 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11628 if (temp_dc.IsOk()) {
11633 if (!VPoint.b_quilt) {
11636 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11637 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11644 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11645 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11648 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11650 temp_dc.DestroyClippingRegion();
11655 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11657 if (!backgroundRegion.IsEmpty()) {
11663 wxColour water = pWorldBackgroundChart->water;
11664 if (water.IsOk()) {
11665 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11666 temp_dc.SetBrush(wxBrush(water));
11668 while (upd.HaveRects()) {
11669 wxRect rect = upd.GetRect();
11670 temp_dc.DrawRectangle(rect);
11675 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11676 temp_dc.SetDeviceClippingRegion(*clip_region);
11677 delete clip_region;
11681 SetVPRotation(VPoint.
skew);
11684 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11690 wxMemoryDC *pChartDC = &temp_dc;
11691 wxMemoryDC rotd_dc;
11693 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11695 if (!b_rcache_ok) {
11697 wxMemoryDC tbase_dc;
11699 tbase_dc.SelectObject(bm_base);
11701 tbase_dc.SelectObject(wxNullBitmap);
11703 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11706 wxImage base_image;
11707 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11715 bool b_rot_ok =
false;
11716 if (base_image.IsOk()) {
11719 m_b_rot_hidef =
false;
11723 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11724 m_b_rot_hidef, &m_roffset);
11729 rot_vp.IsValid() && (ri.IsOk())) {
11736 m_prot_bm =
new wxBitmap(ri);
11739 m_roffset.x += VPoint.rv_rect.x;
11740 m_roffset.y += VPoint.rv_rect.y;
11743 if (m_prot_bm && m_prot_bm->IsOk()) {
11744 rotd_dc.SelectObject(*m_prot_bm);
11745 pChartDC = &rotd_dc;
11747 pChartDC = &temp_dc;
11748 m_roffset = wxPoint(0, 0);
11751 pChartDC = &temp_dc;
11752 m_roffset = wxPoint(0, 0);
11755 wxPoint offset = m_roffset;
11758 m_cache_vp = VPoint;
11761 wxMemoryDC mscratch_dc;
11762 mscratch_dc.SelectObject(*pscratch_bm);
11764 mscratch_dc.ResetBoundingBox();
11765 mscratch_dc.DestroyClippingRegion();
11766 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11769 wxRegionIterator upd(rgn_blit);
11771 wxRect rect = upd.GetRect();
11773 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11774 rect.x - offset.x, rect.y - offset.y);
11780 if (m_show_focus_bar && (g_canvasConfig != 0)) {
11781 if (
this == wxWindow::FindFocus()) {
11782 g_focusCanvas =
this;
11784 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11785 mscratch_dc.SetPen(wxPen(colour));
11786 mscratch_dc.SetBrush(wxBrush(colour));
11788 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11789 mscratch_dc.DrawRectangle(activeRect);
11794 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11795 unsigned int im = stackIndexArray.size();
11796 if (VPoint.b_quilt && im > 0) {
11797 std::vector<int> tiles_to_show;
11798 for (
unsigned int is = 0; is < im; is++) {
11800 ChartData->GetChartTableEntry(stackIndexArray[is]);
11801 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11804 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11805 tiles_to_show.push_back(stackIndexArray[is]);
11809 if (tiles_to_show.size())
11810 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11817 ocpnDC scratch_dc(mscratch_dc);
11818 DrawOverlayObjects(scratch_dc, ru);
11821 RebuildTideSelectList(GetVP().GetBBox());
11822 DrawAllTidesInBBox(scratch_dc, GetVP().GetBBox());
11825 if (m_bShowCurrent) {
11826 RebuildCurrentSelectList(GetVP().GetBBox());
11827 DrawAllCurrentsInBBox(scratch_dc, GetVP().GetBBox());
11830 if (m_brepaint_piano && g_bShowChartBar) {
11831 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), mscratch_dc);
11834 if (m_Compass) m_Compass->Paint(scratch_dc);
11836 RenderAlertMessage(mscratch_dc, GetVP());
11841#ifdef ocpnUSE_DIBSECTION
11846 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11847 q_dc.SelectObject(qbm);
11850 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11853 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11854 q_dc.SetBrush(qbr);
11855 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11858 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11861 q_dc.SelectObject(wxNullBitmap);
11868 if( VPoint.b_quilt ) {
11869 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11870 ChartBase *chart = m_pQuilt->GetRefChart();
11871 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11876 ChPI->ClearPLIBTextList();
11879 ps52plib->ClearTextList();
11883 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11885 wxColor maskBackground = wxColour(1,0,0);
11886 t_dc.SelectObject( qbm );
11887 t_dc.SetBackground(wxBrush(maskBackground));
11891 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
11894 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
11895 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
11898 wxRegionIterator upd_final( ru );
11899 while( upd_final ) {
11900 wxRect rect = upd_final.GetRect();
11901 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
11905 t_dc.SelectObject( wxNullBitmap );
11911 if (VPoint.b_quilt) {
11912 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
11913 ChartBase *chart = m_pQuilt->GetRefChart();
11914 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
11918 ChPI->ClearPLIBTextList();
11920 if (ps52plib) ps52plib->ClearTextList();
11925 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
11927 if (g_bShowChartBar && m_Piano) {
11928 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
11929 GetVP().pix_width, m_Piano->GetHeight());
11932 if (!style->chartStatusWindowTransparent)
11933 chart_all_text_region.Subtract(chart_bar_rect);
11936 if (m_Compass && m_Compass->IsShown()) {
11937 wxRect compassRect = m_Compass->
GetRect();
11938 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
11939 chart_all_text_region.Subtract(compassRect);
11943 mscratch_dc.DestroyClippingRegion();
11945 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
11946 chart_all_text_region);
11952 wxRegionIterator upd_final(rgn_blit);
11953 while (upd_final) {
11954 wxRect rect = upd_final.GetRect();
11955 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
11976 temp_dc.SelectObject(wxNullBitmap);
11978 mscratch_dc.SelectObject(wxNullBitmap);
11980 dc.DestroyClippingRegion();
11985void ChartCanvas::PaintCleanup() {
11997 m_bTCupdate =
false;
12001 WarpPointer(warp_x, warp_y);
12008 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12009 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12013wxColour GetErrorGraphicColor(
double val)
12032 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
12033 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
12034 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
12035 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
12036 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
12037 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
12038 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
12039 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
12040 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
12041 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
12042 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
12043 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
12044 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
12045 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
12046 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
12047 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
12048 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
12049 else if( val >= 48) c.Set(_T(
"#410000"));
12054void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12057 gr_image.InitAlpha();
12059 double maxval = -10000;
12060 double minval = 10000;
12077 maxval = wxMax(maxval, (glat - rlat));
12078 minval = wxMin(minval, (glat - rlat));
12095 double f = ((glat - rlat)-minval)/(maxval - minval);
12097 double dy = (f * 40);
12099 wxColour c = GetErrorGraphicColor(dy);
12100 unsigned char r = c.Red();
12101 unsigned char g = c.Green();
12102 unsigned char b = c.Blue();
12104 gr_image.SetRGB(j, i, r,g,b);
12105 if((glat - rlat )!= 0)
12106 gr_image.SetAlpha(j, i, 128);
12108 gr_image.SetAlpha(j, i, 255);
12115 wxBitmap *pbm =
new wxBitmap(gr_image);
12116 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12117 pbm->SetMask(gr_mask);
12119 pmdc->DrawBitmap(*pbm, 0,0);
12127void ChartCanvas::CancelMouseRoute() {
12129 m_pMouseRoute = NULL;
12130 m_bDrawingRoute =
false;
12133int ChartCanvas::GetNextContextMenuId() {
12134 return CanvasMenuHandler::GetNextContextMenuId();
12137bool ChartCanvas::SetCursor(
const wxCursor &c) {
12139 if (g_bopengl && m_glcc)
12140 return m_glcc->SetCursor(c);
12143 return wxWindow::SetCursor(c);
12146void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12147 if (g_bquiting)
return;
12157 if (!m_RolloverPopupTimer.IsRunning() &&
12158 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12159 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12160 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12161 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12164 if (m_glcc && g_bopengl) {
12167 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12169 m_glcc->Refresh(eraseBackground,
12180 if (pthumbwin && pthumbwin->IsShown()) {
12181 pthumbwin->Raise();
12182 pthumbwin->Refresh(
false);
12186 if (m_pCIWin && m_pCIWin->IsShown()) {
12188 m_pCIWin->Refresh(
false);
12196 wxWindow::Refresh(eraseBackground, rect);
12199void ChartCanvas::Update() {
12200 if (m_glcc && g_bopengl) {
12205 wxWindow::Update();
12209 if (!pemboss)
return;
12210 int x = pemboss->x, y = pemboss->y;
12211 const double factor = 200;
12213 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
12214 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12215 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
12218 wxMemoryDC snip_dc;
12219 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12220 snip_dc.SelectObject(snip_bmp);
12222 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12223 snip_dc.SelectObject(wxNullBitmap);
12225 wxImage snip_img = snip_bmp.ConvertToImage();
12228 unsigned char *pdata = snip_img.GetData();
12230 for (
int y = 0; y < pemboss->height; y++) {
12231 int map_index = (y * pemboss->width);
12232 for (
int x = 0; x < pemboss->width; x++) {
12233 double val = (pemboss->pmap[map_index] * factor) / 256.;
12235 int nred = (int)((*pdata) + val);
12236 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12237 *pdata++ = (
unsigned char)nred;
12239 int ngreen = (int)((*pdata) + val);
12240 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12241 *pdata++ = (
unsigned char)ngreen;
12243 int nblue = (int)((*pdata) + val);
12244 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12245 *pdata++ = (
unsigned char)nblue;
12253 wxBitmap emb_bmp(snip_img);
12256 wxMemoryDC result_dc;
12257 result_dc.SelectObject(emb_bmp);
12260 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12262 result_dc.SelectObject(wxNullBitmap);
12268 if (GetQuiltMode()) {
12270 int refIndex = GetQuiltRefChartdbIndex();
12271 if (refIndex >= 0) {
12272 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
12273 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12274 if (current_type == CHART_TYPE_MBTILES) {
12275 ChartBase *pChart = m_pQuilt->GetRefChart();
12278 zoom_factor = ptc->GetZoomFactor();
12283 if (zoom_factor <= 3.9)
return NULL;
12285 if (m_singleChart) {
12286 if (zoom_factor <= 3.9)
return NULL;
12291 if (m_pEM_OverZoom) {
12292 m_pEM_OverZoom->x = 4;
12293 m_pEM_OverZoom->y = 0;
12294 if (g_MainToolbar && IsPrimaryCanvas()) {
12295 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12296 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12299 return m_pEM_OverZoom;
12302void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12312 g_overlayCanvas =
this;
12314 if (g_pi_manager) {
12315 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12316 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12320 AISDrawAreaNotices(dc, GetVP(),
this);
12322 wxDC *pdc = dc.GetDC();
12324 pdc->DestroyClippingRegion();
12325 wxDCClipper(*pdc, ru);
12328 if (m_bShowNavobjects) {
12329 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12330 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12331 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12332 DrawAnchorWatchPoints(dc);
12334 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12335 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12338 AISDraw(dc, GetVP(),
this);
12342 RenderVisibleSectorLights(dc);
12344 RenderAllChartOutlines(dc, GetVP());
12345 RenderRouteLegs(dc);
12346 RenderShipToActive(dc,
false);
12348 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12349 if (g_pi_manager) {
12350 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12351 OVERLAY_OVER_SHIPS);
12354 DrawEmboss(dc, EmbossDepthScale());
12355 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12356 if (g_pi_manager) {
12357 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12358 OVERLAY_OVER_EMBOSS);
12360 if (!g_PrintingInProgress) {
12361 if (IsPrimaryCanvas()) {
12362 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12365 if (IsPrimaryCanvas()) {
12366 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12369 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12371 if (m_pTrackRolloverWin) {
12372 m_pTrackRolloverWin->Draw(dc);
12373 m_brepaint_piano =
true;
12376 if (m_pRouteRolloverWin) {
12377 m_pRouteRolloverWin->Draw(dc);
12378 m_brepaint_piano =
true;
12381 if (m_pAISRolloverWin) {
12382 m_pAISRolloverWin->Draw(dc);
12383 m_brepaint_piano =
true;
12386 if (g_pi_manager) {
12387 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12393 if (!m_bShowDepthUnits)
return NULL;
12395 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12397 if (GetQuiltMode()) {
12398 wxString s = m_pQuilt->GetQuiltDepthUnit();
12400 if (s == _T(
"FEET"))
12401 depth_unit_type = DEPTH_UNIT_FEET;
12402 else if (s.StartsWith(_T(
"FATHOMS")))
12403 depth_unit_type = DEPTH_UNIT_FATHOMS;
12404 else if (s.StartsWith(_T(
"METERS")))
12405 depth_unit_type = DEPTH_UNIT_METERS;
12406 else if (s.StartsWith(_T(
"METRES")))
12407 depth_unit_type = DEPTH_UNIT_METERS;
12408 else if (s.StartsWith(_T(
"METRIC")))
12409 depth_unit_type = DEPTH_UNIT_METERS;
12410 else if (s.StartsWith(_T(
"METER")))
12411 depth_unit_type = DEPTH_UNIT_METERS;
12414 if (m_singleChart) {
12415 depth_unit_type = m_singleChart->GetDepthUnitType();
12416 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12417 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12422 switch (depth_unit_type) {
12423 case DEPTH_UNIT_FEET:
12426 case DEPTH_UNIT_METERS:
12427 ped = m_pEM_Meters;
12429 case DEPTH_UNIT_FATHOMS:
12430 ped = m_pEM_Fathoms;
12436 ped->x = (GetVP().
pix_width - ped->width);
12438 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12439 wxRect r = m_Compass->
GetRect();
12440 ped->y = r.y + r.height;
12447void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12450 if (style->embossFont == wxEmptyString) {
12451 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12453 font.SetPointSize(60);
12454 font.SetWeight(wxFONTWEIGHT_BOLD);
12456 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12457 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12459 int emboss_width = 500;
12460 int emboss_height = 200;
12464 delete m_pEM_Meters;
12465 delete m_pEM_Fathoms;
12469 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12471 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12473 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12476#define OVERZOOM_TEXT _("OverZoom")
12478void ChartCanvas::SetOverzoomFont() {
12483 if (style->embossFont == wxEmptyString) {
12484 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12486 font.SetPointSize(40);
12487 font.SetWeight(wxFONTWEIGHT_BOLD);
12489 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12490 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12492 wxClientDC dc(
this);
12494 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12496 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12497 font.SetPointSize(font.GetPointSize() - 1);
12499 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12501 m_overzoomFont = font;
12502 m_overzoomTextWidth = w;
12503 m_overzoomTextHeight = h;
12506void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12507 delete m_pEM_OverZoom;
12509 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12511 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12512 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12515emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12516 int height,
const wxString &str,
12521 wxBitmap bmp(width, height, -1);
12524 wxMemoryDC temp_dc;
12525 temp_dc.SelectObject(bmp);
12528 temp_dc.SetBackground(*wxWHITE_BRUSH);
12529 temp_dc.SetTextBackground(*wxWHITE);
12530 temp_dc.SetTextForeground(*wxBLACK);
12534 temp_dc.SetFont(font);
12537 temp_dc.GetTextExtent(str, &str_w, &str_h);
12539 temp_dc.DrawText(str, 1, 1);
12542 temp_dc.SelectObject(wxNullBitmap);
12545 wxImage img = bmp.ConvertToImage();
12547 int image_width = str_w * 105 / 100;
12548 int image_height = str_h * 105 / 100;
12549 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12550 wxMin(image_height, img.GetHeight()));
12551 wxImage imgs = img.GetSubImage(r);
12555 case GLOBAL_COLOR_SCHEME_DAY:
12559 case GLOBAL_COLOR_SCHEME_DUSK:
12562 case GLOBAL_COLOR_SCHEME_NIGHT:
12569 const int w = imgs.GetWidth();
12570 const int h = imgs.GetHeight();
12571 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12576 for (
int y = 1; y < h - 1; y++) {
12577 for (
int x = 1; x < w - 1; x++) {
12579 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12580 val = (int)(val * val_factor);
12581 index = (y * w) + x;
12594void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12595 Track *active_track = NULL;
12596 for (
Track *pTrackDraw : g_TrackList) {
12597 if (g_pActiveTrack == pTrackDraw) {
12598 active_track = pTrackDraw;
12602 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12605 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12608void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12609 Track *active_track = NULL;
12610 for (
Track *pTrackDraw : g_TrackList) {
12611 if (g_pActiveTrack == pTrackDraw) {
12612 active_track = pTrackDraw;
12616 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12619void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12620 Route *active_route = NULL;
12622 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12623 node = node->GetNext()) {
12624 Route *pRouteDraw = node->GetData();
12625 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12626 active_route = pRouteDraw;
12631 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12636 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12639void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12640 Route *active_route = NULL;
12642 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12643 node = node->GetNext()) {
12644 Route *pRouteDraw = node->GetData();
12645 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12646 active_route = pRouteDraw;
12650 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12653void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12654 if (!pWayPointMan)
return;
12656 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12661 if (pWP->m_bIsInRoute) {
12662 node = node->GetNext();
12667 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12671 if (pWP->GetShowWaypointRangeRings() &&
12672 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12673 double factor = 1.00;
12674 if (pWP->GetWaypointRangeRingsStepUnits() ==
12676 factor = 1 / 1.852;
12678 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12679 pWP->GetWaypointRangeRingsStep() / 60.;
12683 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12684 pWP->m_lat + radius, pWP->m_lon + radius);
12685 if (!BltBBox.IntersectOut(radar_box)) {
12692 node = node->GetNext();
12696void ChartCanvas::DrawBlinkObjects(
void) {
12698 wxRect update_rect;
12700 if (!pWayPointMan)
return;
12702 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12707 if (pWP->m_bBlink) {
12708 update_rect.Union(pWP->CurrentRect_in_DC);
12712 node = node->GetNext();
12714 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12717void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12720 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12722 wxPoint lAnchorPoint1, lAnchorPoint2;
12725 if (pAnchorWatchPoint1) {
12726 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12730 if (pAnchorWatchPoint2) {
12731 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12736 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12737 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12739 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12740 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12741 dc.SetBrush(*ppBrush);
12745 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12750 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12755 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12760 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12765double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12768 wxPoint lAnchorPoint;
12771 double tlat1, tlon1;
12773 if (pAnchorWatchPoint) {
12774 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12775 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12776 dabs = fabs(d1 / 1852.);
12777 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12782 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12783 pow((
double)(lAnchorPoint.y - r1.y), 2));
12786 if (d1 < 0) lpp = -lpp;
12794void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12795 if (!ptcmgr)
return;
12797 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12799 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12800 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12805 if ((type ==
't') || (type ==
'T')) {
12806 if (BBox.Contains(lat, lon)) {
12808 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12814extern wxDateTime gTimeSource;
12816void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12817 if (!ptcmgr)
return;
12819 wxDateTime this_now = gTimeSource;
12820 bool cur_time = !gTimeSource.IsValid();
12821 if (cur_time) this_now = wxDateTime::Now();
12822 time_t t_this_now = this_now.GetTicks();
12824 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12825 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12826 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12827 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12829 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12830 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12833 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12834 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12837 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12838 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12839 wxBRUSHSTYLE_SOLID);
12840 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12841 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12842 wxBRUSHSTYLE_SOLID);
12844 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
12845 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12846 int font_size = wxMax(10, dFont->GetPointSize());
12849 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
12850 false, dFont->GetFaceName());
12852 dc.SetPen(*pblack_pen);
12853 dc.SetBrush(*pgreen_brush);
12857 case GLOBAL_COLOR_SCHEME_DAY:
12860 case GLOBAL_COLOR_SCHEME_DUSK:
12863 case GLOBAL_COLOR_SCHEME_NIGHT:
12864 bm = m_bmTideNight;
12871 int bmw = bm.GetWidth();
12872 int bmh = bm.GetHeight();
12874 float scale_factor = 1.0;
12878 float icon_pixelRefDim = 45;
12882 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
12883 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
12884 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12898 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
12900 float nominal_icon_size_pixels = 48;
12901 float pix_factor = (2 * height) / nominal_icon_size_pixels;
12911 double targetHeight0 = 16.0;
12914 double displaySize = m_display_size_mm;
12915 displaySize = wxMax(displaySize, 100);
12917 float targetHeight = wxMin(targetHeight0, displaySize / 15);
12919 double pix_factor = targetHeight / symHeight;
12922 scale_factor *= pix_factor;
12924 float user_scale_factor = g_ChartScaleFactorExp;
12925 if (g_ChartScaleFactorExp > 1.0)
12926 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
12929 scale_factor *= user_scale_factor;
12930 scale_factor *= GetContentScaleFactor();
12933 double marge = 0.05;
12934 std::vector<LLBBox> drawn_boxes;
12935 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12936 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12939 if ((type ==
't') || (type ==
'T'))
12944 if (BBox.ContainsMarge(lat, lon, marge)) {
12946 if (GetVP().chart_scale < 500000) {
12947 bool bdrawn =
false;
12948 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
12949 if (drawn_boxes[i].Contains(lat, lon)) {
12954 if (bdrawn)
continue;
12957 this_box.Set(lat, lon, lat, lon);
12958 this_box.EnLarge(.005);
12959 drawn_boxes.push_back(this_box);
12965 if (GetVP().chart_scale > 500000) {
12966 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
12970 dc.SetFont(*plabelFont);
12982 if (ptcmgr->GetTideFlowSens(
12983 t_this_now, BACKWARD_TEN_MINUTES_STEP,
12987 ptcmgr->GetHightOrLowTide(
12988 t_this_now + BACKWARD_TEN_MINUTES_STEP,
12989 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13001 if (tctime > t_this_now)
13002 ptcmgr->GetHightOrLowTide(
13003 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13004 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13008 ptcmgr->GetHightOrLowTide(
13009 t_this_now, FORWARD_TEN_MINUTES_STEP,
13010 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13024 int width = (int)(12 * scale_factor + 0.5);
13025 int height = (int)(45 * scale_factor + 0.5);
13026 int linew = wxMax(1, (
int)(scale_factor));
13027 int xDraw = r.x - (width / 2);
13028 int yDraw = r.y - (height / 2);
13031 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13032 int hs = (httime > lttime) ? -4 : 4;
13033 hs *= (int)(scale_factor + 0.5);
13034 if (ts > 0.995 || ts < 0.005) hs = 0;
13035 int ht_y = (int)(height * ts);
13038 pblack_pen->SetWidth(linew);
13039 dc.SetPen(*pblack_pen);
13040 dc.SetBrush(*pyelo_brush);
13041 dc.DrawRectangle(xDraw, yDraw, width, height);
13045 dc.SetPen(*pblue_pen);
13046 dc.SetBrush(*pblue_brush);
13047 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13048 (width - (4 * linew)), height - ht_y);
13054 arrow[0].x = xDraw + 2 * linew;
13055 arrow[1].x = xDraw + width / 2;
13056 arrow[2].x = xDraw + width - 2 * linew;
13057 pyelo_pen->SetWidth(linew);
13058 pblue_pen->SetWidth(linew);
13059 if (ts > 0.35 || ts < 0.15)
13061 hl = (int)(height * 0.25) + yDraw;
13063 arrow[1].y = hl + hs;
13066 dc.SetPen(*pyelo_pen);
13068 dc.SetPen(*pblue_pen);
13069 dc.DrawLines(3, arrow);
13071 if (ts > 0.60 || ts < 0.40)
13073 hl = (int)(height * 0.5) + yDraw;
13075 arrow[1].y = hl + hs;
13078 dc.SetPen(*pyelo_pen);
13080 dc.SetPen(*pblue_pen);
13081 dc.DrawLines(3, arrow);
13083 if (ts < 0.65 || ts > 0.85)
13085 hl = (int)(height * 0.75) + yDraw;
13087 arrow[1].y = hl + hs;
13090 dc.SetPen(*pyelo_pen);
13092 dc.SetPen(*pblue_pen);
13093 dc.DrawLines(3, arrow);
13097 s.Printf(_T(
"%3.1f"), nowlev);
13099 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13101 dc.GetTextExtent(s, &wx1, NULL);
13103 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13118void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13119 if (!ptcmgr)
return;
13121 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13123 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13124 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13129 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13130 if ((BBox.Contains(lat, lon))) {
13132 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13138void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13139 if (!ptcmgr)
return;
13141 float tcvalue, dir;
13145 double lon_last = 0.;
13146 double lat_last = 0.;
13148 double marge = 0.2;
13149 bool cur_time = !gTimeSource.IsValid();
13151 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13152 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13154 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13155 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13156 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13157 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13159 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13160 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13161 wxBRUSHSTYLE_SOLID);
13162 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13163 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13164 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13165 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13167 double skew_angle = GetVPRotation();
13169 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13170 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13171 int font_size = wxMax(10, dFont->GetPointSize());
13174 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13175 false, dFont->GetFaceName());
13177 float scale_factor = 1.0;
13184 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
13185 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
13186 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13192 float nominal_icon_size_pixels = 6;
13193 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
13200 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13202 float nominal_icon_size_pixels = 15;
13203 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13210 float icon_pixelRefDim = 5;
13215 double targetHeight0 = 2.0;
13218 double displaySize = m_display_size_mm;
13219 displaySize = wxMax(displaySize, 100);
13221 float targetHeight = wxMin(targetHeight0, displaySize / 50);
13222 double pix_factor = targetHeight / symHeight;
13225 scale_factor *= pix_factor;
13227 float user_scale_factor = g_ChartScaleFactorExp;
13228 if (g_ChartScaleFactorExp > 1.0)
13229 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13232 scale_factor *= user_scale_factor;
13234 scale_factor *= GetContentScaleFactor();
13237 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13238 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13243 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13244 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13249 int dd = (int)(5.0 * scale_factor + 0.5);
13260 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13261 dc.SetPen(*pblack_pen);
13262 dc.SetBrush(*porange_brush);
13263 dc.DrawPolygon(4, d);
13266 dc.SetBrush(*pblack_brush);
13267 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13271 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13285 double a1 = fabs(tcvalue) * 10.;
13287 a1 = wxMax(1.0, a1);
13288 double a2 = log10(a1);
13290 float cscale = scale_factor * a2 * 0.4;
13292 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13293 dc.SetPen(*porange_pen);
13294 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13298 if (bDrawCurrentValues) {
13299 dc.SetFont(*pTCFont);
13300 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13301 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13322void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
13323 pCwin =
new TCWin(
this, x, y, pvIDX);
13326#define NUM_CURRENT_ARROW_POINTS 9
13327static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13328 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13329 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13330 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13332void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13334 if (
scale > 1e-2) {
13335 float sin_rot = sin(rot_angle * PI / 180.);
13336 float cos_rot = cos(rot_angle * PI / 180.);
13340 float xt = CurrentArrowArray[0].x;
13341 float yt = CurrentArrowArray[0].y;
13343 float xp = (xt * cos_rot) - (yt * sin_rot);
13344 float yp = (xt * sin_rot) + (yt * cos_rot);
13345 int x1 = (int)(xp *
scale);
13346 int y1 = (int)(yp *
scale);
13349 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13350 xt = CurrentArrowArray[ip].x;
13351 yt = CurrentArrowArray[ip].y;
13353 float xp = (xt * cos_rot) - (yt * sin_rot);
13354 float yp = (xt * sin_rot) + (yt * cos_rot);
13355 int x2 = (int)(xp *
scale);
13356 int y2 = (int)(yp *
scale);
13358 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13366wxString ChartCanvas::FindValidUploadPort() {
13369 if (!g_uploadConnection.IsEmpty() &&
13370 g_uploadConnection.StartsWith(_T(
"Serial"))) {
13371 port = g_uploadConnection;
13377 for (
auto *cp : TheConnectionParams()) {
13378 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13379 port << _T(
"Serial:") << cp->Port;
13385void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13388 if (NULL == g_pais_query_dialog_active) {
13389 int pos_x = g_ais_query_dialog_x;
13390 int pos_y = g_ais_query_dialog_y;
13392 if (g_pais_query_dialog_active) {
13393 g_pais_query_dialog_active->Destroy();
13399 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13400 wxPoint(pos_x, pos_y));
13402 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13403 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13404 g_pais_query_dialog_active->SetMMSI(mmsi);
13405 g_pais_query_dialog_active->UpdateText();
13406 wxSize sz = g_pais_query_dialog_active->GetSize();
13408 bool b_reset_pos =
false;
13413 RECT frame_title_rect;
13414 frame_title_rect.left = pos_x;
13415 frame_title_rect.top = pos_y;
13416 frame_title_rect.right = pos_x + sz.x;
13417 frame_title_rect.bottom = pos_y + 30;
13419 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13420 b_reset_pos =
true;
13425 wxRect window_title_rect;
13426 window_title_rect.x = pos_x;
13427 window_title_rect.y = pos_y;
13428 window_title_rect.width = sz.x;
13429 window_title_rect.height = 30;
13431 wxRect ClientRect = wxGetClientDisplayRect();
13432 ClientRect.Deflate(
13434 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13438 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13441 g_pais_query_dialog_active->SetMMSI(mmsi);
13442 g_pais_query_dialog_active->UpdateText();
13445 g_pais_query_dialog_active->Show();
13448void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13449 bool cur_mode = GetQuiltMode();
13451 if (!GetQuiltMode())
13452 SetQuiltMode(
true);
13453 else if (GetQuiltMode()) {
13454 SetQuiltMode(
false);
13455 g_sticky_chart = GetQuiltReferenceChartIndex();
13458 if (cur_mode != GetQuiltMode()) {
13459 SetupCanvasQuiltMode();
13468 if (ps52plib) ps52plib->GenerateStateHash();
13470 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13471 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13474void ChartCanvas::DoCanvasStackDelta(
int direction) {
13475 if (!GetQuiltMode()) {
13476 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13477 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13478 if ((current_stack_index + direction) < 0)
return;
13480 if (m_bpersistent_quilt ) {
13482 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13484 if (IsChartQuiltableRef(new_dbIndex)) {
13485 ToggleCanvasQuiltMode();
13486 SelectQuiltRefdbChart(new_dbIndex);
13487 m_bpersistent_quilt =
false;
13490 SelectChartFromStack(current_stack_index + direction);
13493 std::vector<int> piano_chart_index_array =
13494 GetQuiltExtendedStackdbIndexArray();
13495 int refdb = GetQuiltRefChartdbIndex();
13498 int current_index = -1;
13499 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13500 if (refdb == piano_chart_index_array[i]) {
13505 if (current_index == -1)
return;
13508 int target_family = ctet.GetChartFamily();
13510 int new_index = -1;
13511 int check_index = current_index + direction;
13512 bool found =
false;
13513 int check_dbIndex = -1;
13514 int new_dbIndex = -1;
13518 (
unsigned int)check_index < piano_chart_index_array.size() &&
13519 (check_index >= 0)) {
13520 check_dbIndex = piano_chart_index_array[check_index];
13521 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13522 if (target_family == cte.GetChartFamily()) {
13524 new_index = check_index;
13525 new_dbIndex = check_dbIndex;
13529 check_index += direction;
13532 if (!found)
return;
13534 if (!IsChartQuiltableRef(new_dbIndex)) {
13535 ToggleCanvasQuiltMode();
13536 SelectdbChart(new_dbIndex);
13537 m_bpersistent_quilt =
true;
13539 SelectQuiltRefChart(new_index);
13543 gFrame->UpdateGlobalMenuItems();
13545 SetQuiltChartHiLiteIndex(-1);
13556void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13559 switch (event.GetId()) {
13573 DoCanvasStackDelta(1);
13578 DoCanvasStackDelta(-1);
13588 ShowCurrents(!GetbShowCurrent());
13595 ShowTides(!GetbShowTide());
13602 if (0 == m_routeState) {
13609 androidSetRouteAnnunciator(m_routeState == 1);
13615 SetAISCanvasDisplayStyle(-1);
13627void ChartCanvas::SetShowAIS(
bool show) {
13629 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13630 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13633void ChartCanvas::SetAttenAIS(
bool show) {
13634 m_bShowAISScaled = show;
13635 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13636 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13639void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13642 bool bShowAIS_Array[3] = {
true,
true,
false};
13643 bool bShowScaled_Array[3] = {
false,
true,
true};
13644 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13645 _(
"Attenuate less critical AIS targets"),
13646 _(
"Hide AIS Targets")};
13647 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13648 _T(
"AIS_Disabled")};
13650 int AIS_Toolbar_Switch = 0;
13651 if (StyleIndx == -1) {
13653 for (
int i = 1; i < ArraySize; i++) {
13654 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13655 (bShowScaled_Array[i] == m_bShowAISScaled))
13656 AIS_Toolbar_Switch = i;
13658 AIS_Toolbar_Switch++;
13659 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13660 AIS_Toolbar_Switch++;
13663 AIS_Toolbar_Switch = StyleIndx;
13666 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13668 int AIS_Toolbar_Switch_Next =
13669 AIS_Toolbar_Switch + 1;
13670 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13671 AIS_Toolbar_Switch_Next++;
13672 if (AIS_Toolbar_Switch_Next >= ArraySize)
13673 AIS_Toolbar_Switch_Next = 0;
13676 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13677 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13680void ChartCanvas::TouchAISToolActive(
void) {}
13682void ChartCanvas::UpdateAISTBTool(
void) {}
13690void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13692 bool b_update =
false;
13693 int cc1_edge_comp = 2;
13694 wxRect rect = m_Compass->
GetRect();
13695 wxSize parent_size = GetSize();
13697 parent_size *= m_displayScale;
13701 wxPoint tentative_pt(parent_size.x - rect.width - cc1_edge_comp,
13702 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13703 wxRect tentative_rect(tentative_pt, rect.GetSize());
13705 m_Compass->Move(tentative_pt);
13707 if (m_Compass && m_Compass->IsShown())
13708 m_Compass->UpdateStatus(b_force_new | b_update);
13710 if (b_force_new | b_update) Refresh();
13713void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13714 ChartTypeEnum New_Type,
13715 ChartFamilyEnum New_Family) {
13716 if (!GetpCurrentStack())
return;
13717 if (!ChartData)
return;
13719 if (index < GetpCurrentStack()->nEntry) {
13722 pTentative_Chart = ChartData->OpenStackChartConditional(
13723 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13725 if (pTentative_Chart) {
13726 if (m_singleChart) m_singleChart->Deactivate();
13728 m_singleChart = pTentative_Chart;
13729 m_singleChart->Activate();
13731 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13732 GetpCurrentStack(), m_singleChart->GetFullPath());
13745 double best_scale_ppm = GetBestVPScale(m_singleChart);
13746 double rotation = GetVPRotation();
13747 double oldskew = GetVPSkew();
13748 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13750 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13751 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13752 if (fabs(newskew) > 0.0001) rotation = newskew;
13755 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13757 UpdateGPSCompassStatusBox(
true);
13761 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13762 if (idx < 0)
return;
13764 std::vector<int> piano_active_chart_index_array;
13765 piano_active_chart_index_array.push_back(
13766 GetpCurrentStack()->GetCurrentEntrydbIndex());
13767 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13770void ChartCanvas::SelectdbChart(
int dbindex) {
13771 if (!GetpCurrentStack())
return;
13772 if (!ChartData)
return;
13774 if (dbindex >= 0) {
13777 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13779 if (pTentative_Chart) {
13780 if (m_singleChart) m_singleChart->Deactivate();
13782 m_singleChart = pTentative_Chart;
13783 m_singleChart->Activate();
13785 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13786 GetpCurrentStack(), m_singleChart->GetFullPath());
13799 double best_scale_ppm = GetBestVPScale(m_singleChart);
13803 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13813void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13816 if (!GetQuiltMode()) {
13817 if (GetpCurrentStack()) {
13818 int stack_index = -1;
13819 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13820 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13821 if (check_dbIndex < 0)
continue;
13823 ChartData->GetChartTableEntry(check_dbIndex);
13824 if (type == cte.GetChartType()) {
13827 }
else if (family == cte.GetChartFamily()) {
13833 if (stack_index >= 0) {
13834 SelectChartFromStack(stack_index);
13838 int sel_dbIndex = -1;
13839 std::vector<int> piano_chart_index_array =
13840 GetQuiltExtendedStackdbIndexArray();
13841 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13842 int check_dbIndex = piano_chart_index_array[i];
13843 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13844 if (type == cte.GetChartType()) {
13845 if (IsChartQuiltableRef(check_dbIndex)) {
13846 sel_dbIndex = check_dbIndex;
13849 }
else if (family == cte.GetChartFamily()) {
13850 if (IsChartQuiltableRef(check_dbIndex)) {
13851 sel_dbIndex = check_dbIndex;
13857 if (sel_dbIndex >= 0) {
13858 SelectQuiltRefdbChart(sel_dbIndex,
false);
13860 AdjustQuiltRefChart();
13867 SetQuiltChartHiLiteIndex(-1);
13872bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
13873 return std::find(m_tile_yesshow_index_array.begin(),
13874 m_tile_yesshow_index_array.end(),
13875 index) != m_tile_yesshow_index_array.end();
13878bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
13879 return std::find(m_tile_noshow_index_array.begin(),
13880 m_tile_noshow_index_array.end(),
13881 index) != m_tile_noshow_index_array.end();
13884void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
13885 if (std::find(m_tile_noshow_index_array.begin(),
13886 m_tile_noshow_index_array.end(),
13887 index) == m_tile_noshow_index_array.end()) {
13888 m_tile_noshow_index_array.push_back(index);
13898void ChartCanvas::HandlePianoClick(
13899 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
13900 if (g_options && g_options->IsShown())
13902 if (!m_pCurrentStack)
return;
13903 if (!ChartData)
return;
13918 double distance = 25000;
13919 int closest_index = -1;
13920 for (
int chart_index : selected_dbIndex_array) {
13921 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
13922 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
13923 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
13926 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
13927 if (test_distance < distance) {
13928 distance = test_distance;
13929 closest_index = chart_index;
13933 int selected_dbIndex = selected_dbIndex_array[0];
13934 if (closest_index >= 0) selected_dbIndex = closest_index;
13936 if (!GetQuiltMode()) {
13937 if (m_bpersistent_quilt ) {
13938 if (IsChartQuiltableRef(selected_dbIndex)) {
13939 ToggleCanvasQuiltMode();
13940 SelectQuiltRefdbChart(selected_dbIndex);
13941 m_bpersistent_quilt =
false;
13943 SelectChartFromStack(selected_index);
13946 SelectChartFromStack(selected_index);
13947 g_sticky_chart = selected_dbIndex;
13951 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
13955 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
13956 bool bfound =
false;
13957 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
13958 if (m_tile_noshow_index_array[i] ==
13959 selected_dbIndex) {
13960 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
13967 m_tile_noshow_index_array.push_back(selected_dbIndex);
13971 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
13972 m_tile_yesshow_index_array.push_back(selected_dbIndex);
13976 if (IsChartQuiltableRef(selected_dbIndex)) {
13982 bool set_scale =
false;
13983 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
13984 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
13990 SelectQuiltRefdbChart(selected_dbIndex,
true);
13992 SelectQuiltRefdbChart(selected_dbIndex,
false);
13997 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
13999 double proposed_scale_onscreen =
14002 if (g_bPreserveScaleOnX) {
14003 proposed_scale_onscreen =
14004 wxMin(proposed_scale_onscreen,
14006 GetCanvasWidth()));
14008 proposed_scale_onscreen =
14009 wxMin(proposed_scale_onscreen,
14011 GetCanvasWidth()));
14013 proposed_scale_onscreen =
14014 wxMax(proposed_scale_onscreen,
14023 ToggleCanvasQuiltMode();
14024 SelectdbChart(selected_dbIndex);
14025 m_bpersistent_quilt =
true;
14030 SetQuiltChartHiLiteIndex(-1);
14031 gFrame->UpdateGlobalMenuItems();
14033 HideChartInfoWindow();
14038void ChartCanvas::HandlePianoRClick(
14039 int x,
int y,
int selected_index,
14040 const std::vector<int> &selected_dbIndex_array) {
14041 if (g_options && g_options->IsShown())
14043 if (!GetpCurrentStack())
return;
14045 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14046 UpdateCanvasControlBar();
14048 SetQuiltChartHiLiteIndex(-1);
14051void ChartCanvas::HandlePianoRollover(
14052 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14053 int n_charts,
int scale) {
14054 if (g_options && g_options->IsShown())
14056 if (!GetpCurrentStack())
return;
14057 if (!ChartData)
return;
14059 if (ChartData->IsBusy())
return;
14061 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14063 if (!GetQuiltMode()) {
14064 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14067 std::vector<int> piano_chart_index_array;
14068 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14069 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14070 if ((GetpCurrentStack()->nEntry > 1) ||
14071 (piano_chart_index_array.size() >= 1)) {
14072 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14074 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14076 }
else if (GetpCurrentStack()->nEntry == 1) {
14078 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14079 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14080 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14082 }
else if ((-1 == selected_index) &&
14083 (0 == selected_dbIndex_array.size())) {
14084 ShowChartInfoWindow(key_location.x, -1);
14088 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14090 if ((GetpCurrentStack()->nEntry > 1) ||
14091 (piano_chart_index_array.size() >= 1)) {
14093 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14094 selected_dbIndex_array);
14095 else if (n_charts == 1)
14096 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14098 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14105void ChartCanvas::ClearPianoRollover() {
14106 ClearQuiltChartHiLiteIndexArray();
14107 ShowChartInfoWindow(0, -1);
14108 std::vector<int> vec;
14109 ShowCompositeInfoWindow(0, 0, 0, vec);
14113void ChartCanvas::UpdateCanvasControlBar(
void) {
14114 if (m_pianoFrozen)
return;
14116 if (!GetpCurrentStack())
return;
14117 if (!ChartData)
return;
14118 if (!g_bShowChartBar)
return;
14121 int sel_family = -1;
14123 std::vector<int> piano_chart_index_array;
14124 std::vector<int> empty_piano_chart_index_array;
14126 wxString old_hash = m_Piano->GetStoredHash();
14128 if (GetQuiltMode()) {
14129 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14130 GetQuiltFullScreendbIndexArray());
14132 std::vector<int> piano_active_chart_index_array =
14133 GetQuiltCandidatedbIndexArray();
14134 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14136 std::vector<int> piano_eclipsed_chart_index_array =
14137 GetQuiltEclipsedStackdbIndexArray();
14138 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14140 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14141 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14143 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14144 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14146 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
14147 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14150 if (m_singleChart) {
14151 sel_type = m_singleChart->GetChartType();
14152 sel_family = m_singleChart->GetChartFamily();
14157 std::vector<int> piano_skew_chart_index_array;
14158 std::vector<int> piano_tmerc_chart_index_array;
14159 std::vector<int> piano_poly_chart_index_array;
14161 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14163 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14164 double skew_norm = ctei.GetChartSkew();
14165 if (skew_norm > 180.) skew_norm -= 360.;
14167 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14168 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14171 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14172 if (fabs(skew_norm) > 1.)
14173 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14175 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14176 }
else if (fabs(skew_norm) > 1.)
14177 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14179 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14180 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14181 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14183 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14184 if (new_hash != old_hash) {
14185 m_Piano->FormatKeys();
14186 HideChartInfoWindow();
14187 m_Piano->ResetRollover();
14188 SetQuiltChartHiLiteIndex(-1);
14189 m_brepaint_piano =
true;
14195 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14197 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14198 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14199 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14200 if (e == CHART_FAMILY_RASTER) mask |= 1;
14201 if (e == CHART_FAMILY_VECTOR) {
14202 if (t == CHART_TYPE_CM93COMP)
14209 wxString s_indicated;
14210 if (sel_type == CHART_TYPE_CM93COMP)
14211 s_indicated = _T(
"cm93");
14213 if (sel_family == CHART_FAMILY_RASTER)
14214 s_indicated = _T(
"raster");
14215 else if (sel_family == CHART_FAMILY_VECTOR)
14216 s_indicated = _T(
"vector");
14219 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14222void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14224void ChartCanvas::PianoPopupMenu(
14225 int x,
int y,
int selected_index,
14226 const std::vector<int> &selected_dbIndex_array) {
14227 if (!GetpCurrentStack())
return;
14230 if (!GetQuiltMode())
return;
14232 m_piano_ctx_menu =
new wxMenu();
14234 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14244 menu_selected_dbIndex = selected_dbIndex_array[0];
14245 menu_selected_index = selected_index;
14248 bool b_is_in_noshow =
false;
14249 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14250 if (m_quilt_noshow_index_array[i] ==
14251 menu_selected_dbIndex)
14253 b_is_in_noshow =
true;
14258 if (b_is_in_noshow) {
14259 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14260 _(
"Show This Chart"));
14261 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14262 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14263 }
else if (GetpCurrentStack()->nEntry > 1) {
14264 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14265 _(
"Hide This Chart"));
14266 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14267 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14271 wxPoint pos = wxPoint(x, y - 30);
14274 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14275 PopupMenu(m_piano_ctx_menu, pos);
14277 delete m_piano_ctx_menu;
14278 m_piano_ctx_menu = NULL;
14280 HideChartInfoWindow();
14281 m_Piano->ResetRollover();
14283 SetQuiltChartHiLiteIndex(-1);
14284 ClearQuiltChartHiLiteIndexArray();
14289void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14290 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14291 if (m_quilt_noshow_index_array[i] ==
14292 menu_selected_dbIndex)
14294 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14300void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14301 if (!GetpCurrentStack())
return;
14302 if (!ChartData)
return;
14304 RemoveChartFromQuilt(menu_selected_dbIndex);
14308 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14309 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
14311 int i = menu_selected_index + 1;
14312 bool b_success =
false;
14313 while (i < GetpCurrentStack()->nEntry - 1) {
14314 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14315 if (type == ChartData->GetDBChartType(dbIndex)) {
14316 SelectQuiltRefChart(i);
14326 i = menu_selected_index - 1;
14328 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14329 if (type == ChartData->GetDBChartType(dbIndex)) {
14330 SelectQuiltRefChart(i);
14340void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14342 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14343 if (m_quilt_noshow_index_array[i] ==
14346 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14351 m_quilt_noshow_index_array.push_back(dbIndex);
14354bool ChartCanvas::UpdateS52State() {
14355 bool retval =
false;
14359 ps52plib->SetShowS57Text(m_encShowText);
14360 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14361 ps52plib->m_bShowSoundg = m_encShowDepth;
14362 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14363 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14366 if (!m_encShowLights)
14367 ps52plib->AddObjNoshow(
"LIGHTS");
14369 ps52plib->RemoveObjNoshow(
"LIGHTS");
14370 ps52plib->SetLightsOff(!m_encShowLights);
14371 ps52plib->m_bExtendLightSectors =
true;
14374 ps52plib->SetAnchorOn(m_encShowAnchor);
14375 ps52plib->SetQualityOfData(m_encShowDataQual);
14381void ChartCanvas::SetShowENCDataQual(
bool show) {
14382 m_encShowDataQual = show;
14383 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14384 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14386 m_s52StateHash = 0;
14389void ChartCanvas::SetShowENCText(
bool show) {
14390 m_encShowText = show;
14391 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14392 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14394 m_s52StateHash = 0;
14397void ChartCanvas::SetENCDisplayCategory(
int category) {
14398 m_encDisplayCategory = category;
14399 m_s52StateHash = 0;
14402void ChartCanvas::SetShowENCDepth(
bool show) {
14403 m_encShowDepth = show;
14404 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14405 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14407 m_s52StateHash = 0;
14410void ChartCanvas::SetShowENCLightDesc(
bool show) {
14411 m_encShowLightDesc = show;
14412 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14413 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14415 m_s52StateHash = 0;
14418void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14419 m_encShowBuoyLabels = show;
14420 m_s52StateHash = 0;
14423void ChartCanvas::SetShowENCLights(
bool show) {
14424 m_encShowLights = show;
14425 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14426 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14428 m_s52StateHash = 0;
14431void ChartCanvas::SetShowENCAnchor(
bool show) {
14432 m_encShowAnchor = show;
14433 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14434 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14436 m_s52StateHash = 0;
14439wxRect ChartCanvas::GetMUIBarRect() {
14442 rv = m_muiBar->GetRect();
14448void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14449 if (!GetAlertString().IsEmpty()) {
14450 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14451 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14453 dc.SetFont(*pfont);
14454 dc.SetPen(*wxTRANSPARENT_PEN);
14456 dc.SetBrush(wxColour(243, 229, 47));
14458 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14462 wxRect sbr = GetScaleBarRect();
14463 int xp = sbr.x + sbr.width + 10;
14464 int yp = (sbr.y + sbr.height) - h;
14466 int wdraw = w + 10;
14467 dc.DrawRectangle(xp, yp, wdraw, h);
14468 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14469 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14479#define BRIGHT_XCALIB
14480#define __OPCPN_USEICC__
14483#ifdef __OPCPN_USEICC__
14484int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14485 double co_green,
double co_blue);
14487wxString temp_file_name;
14491class ocpnCurtain:
public wxDialog
14493 DECLARE_CLASS( ocpnCurtain )
14494 DECLARE_EVENT_TABLE()
14497 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14499 bool ProcessEvent(wxEvent& event);
14503IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14505BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14508ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14510 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14513ocpnCurtain::~ocpnCurtain()
14517bool ocpnCurtain::ProcessEvent(wxEvent& event)
14519 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14520 return GetParent()->GetEventHandler()->ProcessEvent(event);
14525#include <windows.h>
14528typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14529typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14530SetDeviceGammaRamp_ptr_type
14531 g_pSetDeviceGammaRamp;
14532GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14534WORD *g_pSavedGammaMap;
14538int InitScreenBrightness(
void) {
14541 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14545 if (NULL == hGDI32DLL) {
14546 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14548 if (NULL != hGDI32DLL) {
14550 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14551 hGDI32DLL,
"SetDeviceGammaRamp");
14552 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14553 hGDI32DLL,
"GetDeviceGammaRamp");
14556 if ((NULL == g_pSetDeviceGammaRamp) ||
14557 (NULL == g_pGetDeviceGammaRamp)) {
14558 FreeLibrary(hGDI32DLL);
14567 if (!g_pSavedGammaMap) {
14568 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14571 bbr = g_pGetDeviceGammaRamp(
14572 hDC, g_pSavedGammaMap);
14573 ReleaseDC(NULL, hDC);
14578 wxRegKey *pRegKey =
new wxRegKey(
14579 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14580 _T(
"NT\\CurrentVersion\\ICM"));
14581 if (!pRegKey->Exists()) pRegKey->Create();
14582 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14584 g_brightness_init =
true;
14590 if (NULL == g_pcurtain) {
14591 if (gFrame->CanSetTransparent()) {
14593 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14594 wxPoint(0, 0), ::wxGetDisplaySize(),
14595 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14596 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14603 g_pcurtain->Hide();
14605 HWND hWnd = GetHwndOf(g_pcurtain);
14606 SetWindowLong(hWnd, GWL_EXSTYLE,
14607 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14608 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14609 g_pcurtain->SetTransparent(0);
14611 g_pcurtain->Maximize();
14612 g_pcurtain->Show();
14615 g_pcurtain->Enable();
14616 g_pcurtain->Disable();
14623 g_brightness_init =
true;
14629 wxString cmd(_T (
"xcalib -version" ));
14631 wxArrayString output;
14632 long r = wxExecute(cmd, output);
14635 _T(
" External application \"xcalib\" not found. Screen brightness ")
14636 _T(
"not changed."));
14638 g_brightness_init =
true;
14643int RestoreScreenBrightness(
void) {
14646 if (g_pSavedGammaMap) {
14647 HDC hDC = GetDC(NULL);
14648 g_pSetDeviceGammaRamp(hDC,
14650 ReleaseDC(NULL, hDC);
14652 free(g_pSavedGammaMap);
14653 g_pSavedGammaMap = NULL;
14657 g_pcurtain->Close();
14658 g_pcurtain->Destroy();
14662 g_brightness_init =
false;
14667#ifdef BRIGHT_XCALIB
14668 if (g_brightness_init) {
14670 cmd = _T(
"xcalib -clear");
14671 wxExecute(cmd, wxEXEC_ASYNC);
14672 g_brightness_init =
false;
14682int SetScreenBrightness(
int brightness) {
14689 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14691 g_pcurtain->Close();
14692 g_pcurtain->Destroy();
14696 InitScreenBrightness();
14698 if (NULL == hGDI32DLL) {
14700 wchar_t wdll_name[80];
14701 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14702 LPCWSTR cstr = wdll_name;
14704 hGDI32DLL = LoadLibrary(cstr);
14706 if (NULL != hGDI32DLL) {
14708 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14709 hGDI32DLL,
"SetDeviceGammaRamp");
14710 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14711 hGDI32DLL,
"GetDeviceGammaRamp");
14714 if ((NULL == g_pSetDeviceGammaRamp) ||
14715 (NULL == g_pGetDeviceGammaRamp)) {
14716 FreeLibrary(hGDI32DLL);
14723 HDC hDC = GetDC(NULL);
14734 int increment = brightness * 256 / 100;
14737 WORD GammaTable[3][256];
14740 for (
int i = 0; i < 256; i++) {
14741 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14742 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14743 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14745 table_val += increment;
14747 if (table_val > 65535) table_val = 65535;
14750 g_pSetDeviceGammaRamp(hDC, GammaTable);
14751 ReleaseDC(NULL, hDC);
14758 if (g_pSavedGammaMap) {
14759 HDC hDC = GetDC(NULL);
14760 g_pSetDeviceGammaRamp(hDC,
14762 ReleaseDC(NULL, hDC);
14765 if (brightness < 100) {
14766 if (NULL == g_pcurtain) InitScreenBrightness();
14769 int sbrite = wxMax(1, brightness);
14770 sbrite = wxMin(100, sbrite);
14772 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14776 g_pcurtain->Close();
14777 g_pcurtain->Destroy();
14787#ifdef BRIGHT_XCALIB
14789 if (!g_brightness_init) {
14790 last_brightness = 100;
14791 g_brightness_init =
true;
14792 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14793 InitScreenBrightness();
14796#ifdef __OPCPN_USEICC__
14799 if (!CreateSimpleICCProfileFile(
14800 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14801 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14802 wxString cmd(_T (
"xcalib " ));
14803 cmd += temp_file_name;
14805 wxExecute(cmd, wxEXEC_ASYNC);
14814 if (brightness > last_brightness) {
14816 cmd = _T(
"xcalib -clear");
14817 wxExecute(cmd, wxEXEC_ASYNC);
14819 ::wxMilliSleep(10);
14821 int brite_adj = wxMax(1, brightness);
14822 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14823 wxExecute(cmd, wxEXEC_ASYNC);
14825 int brite_adj = wxMax(1, brightness);
14826 int factor = (brite_adj * 100) / last_brightness;
14827 factor = wxMax(1, factor);
14829 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14830 wxExecute(cmd, wxEXEC_ASYNC);
14835 last_brightness = brightness;
14842#ifdef __OPCPN_USEICC__
14844#define MLUT_TAG 0x6d4c5554L
14845#define VCGT_TAG 0x76636774L
14847int GetIntEndian(
unsigned char *s) {
14852 p = (
unsigned char *)&ret;
14855 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14857 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14862unsigned short GetShortEndian(
unsigned char *s) {
14863 unsigned short ret;
14867 p = (
unsigned char *)&ret;
14870 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
14872 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
14878int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14879 double co_green,
double co_blue) {
14883 fp = fopen(file_name,
"wb");
14884 if (!fp)
return -1;
14890 for (
int i = 0; i < 128; i++) header[i] = 0;
14892 fwrite(header, 128, 1, fp);
14896 int numTags = GetIntEndian((
unsigned char *)&numTags0);
14897 fwrite(&numTags, 1, 4, fp);
14899 int tagName0 = VCGT_TAG;
14900 int tagName = GetIntEndian((
unsigned char *)&tagName0);
14901 fwrite(&tagName, 1, 4, fp);
14903 int tagOffset0 = 128 + 4 *
sizeof(int);
14904 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
14905 fwrite(&tagOffset, 1, 4, fp);
14908 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
14909 fwrite(&tagSize, 1, 4, fp);
14911 fwrite(&tagName, 1, 4, fp);
14913 fwrite(&tagName, 1, 4, fp);
14918 int gammatype0 = 0;
14919 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
14920 fwrite(&gammatype, 1, 4, fp);
14922 int numChannels0 = 3;
14923 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
14924 fwrite(&numChannels, 1, 2, fp);
14926 int numEntries0 = 256;
14927 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
14928 fwrite(&numEntries, 1, 2, fp);
14930 int entrySize0 = 1;
14931 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
14932 fwrite(&entrySize, 1, 2, fp);
14934 unsigned char ramp[256];
14937 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
14938 fwrite(ramp, 256, 1, fp);
14941 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
14942 fwrite(ramp, 256, 1, fp);
14945 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
14946 fwrite(ramp, 256, 1, fp);
Global state for AIS decoder.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Represents an active track that is currently being recorded.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
void DoZoomCanvas(double factor, bool can_zoom_to_cursor=true)
Internal function that implements the actual zoom operation.
double GetCanvasTrueScale()
Return the physical pixels per meter at chart center, accounting for latitude distortion.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Set the viewport center point.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Manages the chart database and provides access to chart data.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
Primary navigation console display for route and vessel tracking.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
Represents a navigational route in the navigation system.
bool ActivateNextPoint(Route *pr, bool skipped)
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
Dialog for displaying query results of S57 objects.
Manager for S57 chart SENC creation threads.
Manages a set of ShapeBaseChart objects at different resolutions.
Window for displaying chart thumbnails.
Represents a single point in a track.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
void SetBoxes(void)
Computes the bounding box coordinates for the current viewport.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Global variables reflecting command line options and arguments.
Hooks into gui available in model.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
void EnableTenHertzUpdate(bool enable)
Enable or disable 10 Hz update rate.
bool GetEnableTenHertzUpdate()
Check if 10 Hz update rate is enabled.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Tools to send data to plugins.
Route validators for dialog validation.
Represents an entry in the chart table, containing information about a single chart.