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;
319static bool mouse_leftisdown;
321bool g_brouteCreating;
323bool g_bShowTrackPointTime;
329bool g_brightness_init;
332int g_cog_predictor_width;
333extern double g_display_size_mm;
337extern wxColour g_colourOwnshipRangeRingsColour;
341extern double g_defaultBoatSpeed;
342double g_defaultBoatSpeedUserUnit;
344extern int g_nAIS_activity_timer;
345extern bool g_bskew_comp;
346extern float g_compass_scalefactor;
347extern int g_COGAvgSec;
348extern bool g_btenhertz;
350wxGLContext *g_pGLcontext;
353extern unsigned int g_canvasConfig;
358extern float g_toolbar_scalefactor;
361wxString g_ObjQFileExt;
366extern int g_GUIScaleFactor;
369wxString g_lastS52PLIBPluginMessage;
370extern bool g_bChartBarEx;
371bool g_PrintingInProgress;
374#define MAX_BRIGHT 100
380EVT_PAINT(ChartCanvas::OnPaint)
381EVT_ACTIVATE(ChartCanvas::OnActivate)
382EVT_SIZE(ChartCanvas::OnSize)
383#ifndef HAVE_WX_GESTURE_EVENTS
384EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
386EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
387EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
388EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
389EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
390EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
391EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
392EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
393EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
394EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
395EVT_KEY_UP(ChartCanvas::OnKeyUp)
396EVT_CHAR(ChartCanvas::OnKeyChar)
397EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
398EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
399EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
400EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
401EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
402EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
403EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
404EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
410 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER) {
411 parent_frame = (
MyFrame *)frame;
412 m_canvasIndex = canvasIndex;
416 SetBackgroundColour(wxColour(0, 0, 0));
417 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
421 m_bDrawingRoute =
false;
422 m_bRouteEditing =
false;
423 m_bMarkEditing =
false;
424 m_bRoutePoinDragging =
false;
425 m_bIsInRadius =
false;
426 m_bMayToggleMenuBar =
true;
429 m_bShowNavobjects =
true;
431 m_bAppendingRoute =
false;
432 pThumbDIBShow = NULL;
433 m_bShowCurrent =
false;
435 bShowingCurrent =
false;
439 m_b_paint_enable =
true;
442 pss_overlay_bmp = NULL;
443 pss_overlay_mask = NULL;
444 m_bChartDragging =
false;
445 m_bMeasure_Active =
false;
446 m_bMeasure_DistCircle =
false;
447 m_pMeasureRoute = NULL;
448 m_pTrackRolloverWin = NULL;
449 m_pRouteRolloverWin = NULL;
450 m_pAISRolloverWin = NULL;
452 m_disable_edge_pan =
false;
453 m_dragoffsetSet =
false;
457 m_singleChart = NULL;
458 m_upMode = NORTH_UP_MODE;
460 m_bShowAISScaled =
false;
461 m_timed_move_vp_active =
false;
468 m_pSelectedRoute = NULL;
469 m_pSelectedTrack = NULL;
470 m_pRoutePointEditTarget = NULL;
471 m_pFoundPoint = NULL;
472 m_pMouseRoute = NULL;
473 m_prev_pMousePoint = NULL;
474 m_pEditRouteArray = NULL;
475 m_pFoundRoutePoint = NULL;
476 m_FinishRouteOnKillFocus =
true;
478 m_pRolloverRouteSeg = NULL;
479 m_pRolloverTrackSeg = NULL;
480 m_bsectors_shown =
false;
482 m_bbrightdir =
false;
487 m_pos_image_user_day = NULL;
488 m_pos_image_user_dusk = NULL;
489 m_pos_image_user_night = NULL;
490 m_pos_image_user_grey_day = NULL;
491 m_pos_image_user_grey_dusk = NULL;
492 m_pos_image_user_grey_night = NULL;
495 m_rotation_speed = 0;
501 m_pos_image_user_yellow_day = NULL;
502 m_pos_image_user_yellow_dusk = NULL;
503 m_pos_image_user_yellow_night = NULL;
505 SetOwnShipState(SHIP_INVALID);
507 undo =
new Undo(
this);
513 m_focus_indicator_pix = 1;
515 m_pCurrentStack = NULL;
516 m_bpersistent_quilt =
false;
517 m_piano_ctx_menu = NULL;
520 g_ChartNotRenderScaleFactor = 2.0;
521 m_bShowScaleInStatusBar =
true;
524 m_bShowScaleInStatusBar =
false;
525 m_show_focus_bar =
true;
527 m_bShowOutlines =
false;
528 m_bDisplayGrid =
false;
529 m_bShowDepthUnits =
true;
530 m_encDisplayCategory = (int)STANDARD;
532 m_encShowLights =
true;
533 m_encShowAnchor =
true;
534 m_encShowDataQual =
false;
536 m_pQuilt =
new Quilt(
this);
538 SetAlertString(_T(
""));
541 g_PrintingInProgress =
false;
543#ifdef HAVE_WX_GESTURE_EVENTS
544 m_oldVPSScale = -1.0;
545 m_popupWanted =
false;
551 singleClickEventIsValid =
false;
560 pCursorPencil = NULL;
565 SetCursor(*pCursorArrow);
567 pPanTimer =
new wxTimer(
this, m_MouseDragging);
570 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
571 pMovementTimer->Stop();
573 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
574 pMovementStopTimer->Stop();
576 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
577 pRotDefTimer->Stop();
579 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
580 m_DoubleClickTimer->Stop();
582 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
583 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
584 m_chart_drag_inertia_active =
false;
586 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
587 m_animationActive =
false;
591 m_panx_target_final = m_pany_target_final = 0;
592 m_panx_target_now = m_pany_target_now = 0;
594 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
595 pCurTrackTimer->Stop();
596 m_curtrack_timer_msec = 10;
598 m_wheelzoom_stop_oneshot = 0;
599 m_last_wheel_dir = 0;
601 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
603 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
605 m_rollover_popup_timer_msec = 20;
607 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
609 m_b_rot_hidef =
true;
614 m_upMode = NORTH_UP_MODE;
615 m_bLookAhead =
false;
619 m_cs = GLOBAL_COLOR_SCHEME_DAY;
622 VPoint.view_scale_ppm = 1;
626 m_canvas_scale_factor = 1.;
628 m_canvas_width = 1000;
630 m_overzoomTextWidth = 0;
631 m_overzoomTextHeight = 0;
635 gShapeBasemap.Reset();
640 m_pEM_Fathoms = NULL;
642 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
644 m_pEM_OverZoom = NULL;
646 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
650 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"),
654 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
657 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
660 double factor_dusk = 0.5;
661 double factor_night = 0.25;
664 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
666 int rimg_width = m_os_image_red_day.GetWidth();
667 int rimg_height = m_os_image_red_day.GetHeight();
669 m_os_image_red_dusk = m_os_image_red_day.Copy();
670 m_os_image_red_night = m_os_image_red_day.Copy();
672 for (
int iy = 0; iy < rimg_height; iy++) {
673 for (
int ix = 0; ix < rimg_width; ix++) {
674 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
675 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
676 m_os_image_red_day.GetGreen(ix, iy),
677 m_os_image_red_day.GetBlue(ix, iy));
678 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
679 hsv.value = hsv.value * factor_dusk;
680 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
681 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
683 hsv = wxImage::RGBtoHSV(rgb);
684 hsv.value = hsv.value * factor_night;
685 nrgb = wxImage::HSVtoRGB(hsv);
686 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
692 m_os_image_grey_day =
693 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
695 int gimg_width = m_os_image_grey_day.GetWidth();
696 int gimg_height = m_os_image_grey_day.GetHeight();
698 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
699 m_os_image_grey_night = m_os_image_grey_day.Copy();
701 for (
int iy = 0; iy < gimg_height; iy++) {
702 for (
int ix = 0; ix < gimg_width; ix++) {
703 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
704 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
705 m_os_image_grey_day.GetGreen(ix, iy),
706 m_os_image_grey_day.GetBlue(ix, iy));
707 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
708 hsv.value = hsv.value * factor_dusk;
709 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
710 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
712 hsv = wxImage::RGBtoHSV(rgb);
713 hsv.value = hsv.value * factor_night;
714 nrgb = wxImage::HSVtoRGB(hsv);
715 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
721 m_os_image_yellow_day = m_os_image_red_day.Copy();
723 gimg_width = m_os_image_yellow_day.GetWidth();
724 gimg_height = m_os_image_yellow_day.GetHeight();
726 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
727 m_os_image_yellow_night = m_os_image_red_day.Copy();
729 for (
int iy = 0; iy < gimg_height; iy++) {
730 for (
int ix = 0; ix < gimg_width; ix++) {
731 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
732 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
733 m_os_image_yellow_day.GetGreen(ix, iy),
734 m_os_image_yellow_day.GetBlue(ix, iy));
735 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
736 hsv.hue += 60. / 360.;
737 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
738 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
740 hsv = wxImage::RGBtoHSV(rgb);
741 hsv.value = hsv.value * factor_dusk;
742 hsv.hue += 60. / 360.;
743 nrgb = wxImage::HSVtoRGB(hsv);
744 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
746 hsv = wxImage::RGBtoHSV(rgb);
747 hsv.hue += 60. / 360.;
748 hsv.value = hsv.value * factor_night;
749 nrgb = wxImage::HSVtoRGB(hsv);
750 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
756 m_pos_image_red = &m_os_image_red_day;
757 m_pos_image_yellow = &m_os_image_yellow_day;
758 m_pos_image_grey = &m_os_image_grey_day;
762 m_pBrightPopup = NULL;
765 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
768 int gridFontSize = 8;
769#if defined(__WXOSX__) || defined(__WXGTK3__)
771 gridFontSize *= GetContentScaleFactor();
775 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
776 FALSE, wxString(_T (
"Arial" )));
778 m_Piano =
new Piano(
this);
780 m_bShowCompassWin =
true;
783 m_Compass->SetScaleFactor(g_compass_scalefactor);
784 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
786 m_pianoFrozen =
false;
788 SetMinSize(wxSize(200, 200));
790 m_displayScale = 1.0;
791#if defined(__WXOSX__) || defined(__WXGTK3__)
793 m_displayScale = GetContentScaleFactor();
795 VPoint.SetPixelScale(m_displayScale);
797#ifdef HAVE_WX_GESTURE_EVENTS
800 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
801 wxLogError(
"Failed to enable touch events");
806 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
807 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
809 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
810 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
812 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
813 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
815 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
816 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
821ChartCanvas::~ChartCanvas() {
822 delete pThumbDIBShow;
830 delete pCursorPencil;
834 delete pMovementTimer;
835 delete pMovementStopTimer;
836 delete pCurTrackTimer;
838 delete m_DoubleClickTimer;
840 delete m_pTrackRolloverWin;
841 delete m_pRouteRolloverWin;
842 delete m_pAISRolloverWin;
843 delete m_pBrightPopup;
849 m_dc_route.SelectObject(wxNullBitmap);
852 delete pWorldBackgroundChart;
853 delete pss_overlay_bmp;
857 delete m_pEM_Fathoms;
859 delete m_pEM_OverZoom;
864 delete m_pos_image_user_day;
865 delete m_pos_image_user_dusk;
866 delete m_pos_image_user_night;
867 delete m_pos_image_user_grey_day;
868 delete m_pos_image_user_grey_dusk;
869 delete m_pos_image_user_grey_night;
870 delete m_pos_image_user_yellow_day;
871 delete m_pos_image_user_yellow_dusk;
872 delete m_pos_image_user_yellow_night;
876 if (!g_bdisable_opengl) {
879#if wxCHECK_VERSION(2, 9, 0)
880 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
887 MUIBar *muiBar = m_muiBar;
891 delete m_pCurrentStack;
896void ChartCanvas::RebuildCursors() {
902 delete pCursorPencil;
906 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
910 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
911 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
912 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
913 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
914 wxImage ICursorPencil =
915 style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
916 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
918#if !defined(__WXMSW__) && !defined(__WXQT__)
919 ICursorLeft.ConvertAlphaToMask(128);
920 ICursorRight.ConvertAlphaToMask(128);
921 ICursorUp.ConvertAlphaToMask(128);
922 ICursorDown.ConvertAlphaToMask(128);
923 ICursorPencil.ConvertAlphaToMask(10);
924 ICursorCross.ConvertAlphaToMask(10);
927 if (ICursorLeft.Ok()) {
928 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
929 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
930 pCursorLeft =
new wxCursor(ICursorLeft);
932 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
934 if (ICursorRight.Ok()) {
935 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
936 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
937 pCursorRight =
new wxCursor(ICursorRight);
939 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
941 if (ICursorUp.Ok()) {
942 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
943 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
944 pCursorUp =
new wxCursor(ICursorUp);
946 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
948 if (ICursorDown.Ok()) {
949 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
950 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
951 pCursorDown =
new wxCursor(ICursorDown);
953 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
955 if (ICursorPencil.Ok()) {
956 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
957 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
958 pCursorPencil =
new wxCursor(ICursorPencil);
960 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
962 if (ICursorCross.Ok()) {
963 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
964 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
965 pCursorCross =
new wxCursor(ICursorCross);
967 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
969 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
970 pPlugIn_Cursor = NULL;
973void ChartCanvas::CanvasApplyLocale() {
974 CreateDepthUnitEmbossMaps(m_cs);
975 CreateOZEmbossMapData(m_cs);
978void ChartCanvas::SetupGlCanvas() {
981 if (!g_bdisable_opengl) {
983 wxLogMessage(_T(
"Creating glChartCanvas"));
988 if (IsPrimaryCanvas()) {
995 wxGLContext *pctx =
new wxGLContext(m_glcc);
996 m_glcc->SetContext(pctx);
1000 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
1002 m_glcc->SetContext(g_pGLcontext);
1012 if (!g_bdisable_opengl) {
1015 wxLogMessage(_T(
"Creating glChartCanvas"));
1019 if (IsPrimaryCanvas()) {
1020 qDebug() <<
"Creating Primary glChartCanvas";
1028 wxGLContext *pctx =
new wxGLContext(m_glcc);
1029 m_glcc->SetContext(pctx);
1030 g_pGLcontext = pctx;
1031 m_glcc->m_pParentCanvas =
this;
1034 qDebug() <<
"Creating Secondary glChartCanvas";
1040 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1043 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1044 m_glcc->SetContext(pwxctx);
1045 m_glcc->m_pParentCanvas =
this;
1053void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1054 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1069 if (m_routeState && m_FinishRouteOnKillFocus)
1070 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1072 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1076void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1077 m_routeFinishTimer.Stop();
1081 gFrame->UpdateGlobalMenuItems(
this);
1083 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1086void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1087 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1090#ifdef HAVE_WX_GESTURE_EVENTS
1091void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1097 m_popupWanted =
true;
1100void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1104void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1106void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1108void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1109 wxPoint pos =
event.GetPosition();
1113 if (!m_popupWanted) {
1114 wxMouseEvent ev(wxEVT_LEFT_UP);
1121 m_popupWanted =
false;
1123 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1130void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1133 wxPoint pos =
event.GetPosition();
1137void ChartCanvas::OnMotion(wxMouseEvent &event) {
1142 event.m_leftDown = m_leftdown;
1146void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1148 if (event.IsGestureEnd())
return;
1150 double factor =
event.GetZoomFactor();
1152 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1157 double wanted_factor = m_oldVPSScale / current_vps * factor;
1162 if (event.IsGestureStart()) {
1163 m_zoomStartPoint =
event.GetPosition();
1165 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1167 m_zoomStartPoint =
event.GetPosition();
1171void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1173void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1174 DoRotateCanvas(0.0);
1178void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1183 m_restore_dbindex = pcc->DBindex;
1185 if (pcc->GroupID < 0) pcc->GroupID = 0;
1187 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1190 m_groupIndex = pcc->GroupID;
1192 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1206 m_encDisplayCategory = pcc->nENCDisplayCategory;
1207 m_encShowDepth = pcc->bShowENCDepths;
1208 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1209 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1210 m_encShowLights = pcc->bShowENCLights;
1211 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1212 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1213 m_encShowDataQual = pcc->bShowENCDataQuality;
1217 m_upMode = NORTH_UP_MODE;
1219 m_upMode = COURSE_UP_MODE;
1221 m_upMode = HEAD_UP_MODE;
1225 m_singleChart = NULL;
1228void ChartCanvas::ApplyGlobalSettings() {
1231 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1232 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1236void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1237 bool groupOK = CheckGroup(m_groupIndex);
1240 SetGroupIndex(m_groupIndex,
true);
1244void ChartCanvas::SetShowGPS(
bool bshow) {
1245 if (m_bShowGPS != bshow) {
1248 m_Compass->SetScaleFactor(g_compass_scalefactor);
1249 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1254void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1255 m_bShowCompassWin = bshow;
1257 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1258 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1262int ChartCanvas::GetPianoHeight() {
1264 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1269void ChartCanvas::ConfigureChartBar() {
1272 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1273 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1275 if (GetQuiltMode()) {
1276 m_Piano->SetRoundedRectangles(
true);
1278 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1279 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1280 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1283void ChartCanvas::ShowTides(
bool bShow) {
1284 gFrame->LoadHarmonics();
1286 if (ptcmgr->IsReady()) {
1287 SetbShowTide(bShow);
1289 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1291 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1292 SetbShowTide(
false);
1293 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1296 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1297 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1308void ChartCanvas::ShowCurrents(
bool bShow) {
1309 gFrame->LoadHarmonics();
1311 if (ptcmgr->IsReady()) {
1312 SetbShowCurrent(bShow);
1313 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1315 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1316 SetbShowCurrent(
false);
1317 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1320 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1321 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1333extern bool g_bPreserveScaleOnX;
1335extern int g_sticky_chart;
1337void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1339void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1340 SetAlertString(_T(
""));
1342 int new_index = index;
1343 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1345 bool bgroup_override =
false;
1346 int old_group_index = new_index;
1348 if (!CheckGroup(new_index)) {
1350 bgroup_override =
true;
1353 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1357 int current_chart_native_scale = GetCanvasChartNativeScale();
1360 m_groupIndex = new_index;
1363 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1366 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1370 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1374 g_sticky_chart = -1;
1378 UpdateCanvasOnGroupChange();
1381 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1383 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1386 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1387 double best_scale = GetBestStartScale(dbi_hint, vp);
1391 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1395 canvasChartsRefresh(dbi_hint);
1397 UpdateCanvasControlBar();
1399 if (!autoSwitch && bgroup_override) {
1401 wxString msg(_(
"Group \""));
1403 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1404 msg += pGroup->m_group_name;
1406 msg += _(
"\" is empty.");
1408 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1415 if (bgroup_override) {
1416 wxString msg(_(
"Group \""));
1418 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1419 msg += pGroup->m_group_name;
1421 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1423 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1427bool ChartCanvas::CheckGroup(
int igroup) {
1428 if (!ChartData)
return true;
1430 if (igroup == 0)
return true;
1435 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1437 if (pGroup->m_element_array.empty())
1441 for (
const auto &elem : pGroup->m_element_array) {
1442 for (
unsigned int ic = 0;
1443 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1445 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1447 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1452 for (
const auto &elem : pGroup->m_element_array) {
1453 const wxString &element_root = elem.m_element_name;
1454 wxString test_string = _T(
"GSHH");
1455 if (element_root.Upper().Contains(test_string))
return true;
1461void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1462 if (!ChartData)
return;
1464 AbstractPlatform::ShowBusySpinner();
1468 SetQuiltRefChart(-1);
1470 m_singleChart = NULL;
1476 if (!m_pCurrentStack) {
1478 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1481 if (-1 != dbi_hint) {
1482 if (GetQuiltMode()) {
1483 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1484 SetQuiltRefChart(dbi_hint);
1488 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1490 if (pTentative_Chart) {
1493 if (m_singleChart) m_singleChart->Deactivate();
1495 m_singleChart = pTentative_Chart;
1496 m_singleChart->Activate();
1498 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1499 GetpCurrentStack(), m_singleChart->GetFullPath());
1507 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1508 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1509 SetQuiltRefChart(selected_index);
1513 SetupCanvasQuiltMode();
1514 if (!GetQuiltMode() && m_singleChart == 0) {
1516 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1517 m_singleChart = pDummyChart;
1523 UpdateCanvasControlBar();
1524 UpdateGPSCompassStatusBox(
true);
1526 SetCursor(wxCURSOR_ARROW);
1528 AbstractPlatform::HideBusySpinner();
1531bool ChartCanvas::DoCanvasUpdate(
void) {
1533 double vpLat, vpLon;
1534 bool blong_jump =
false;
1535 meters_to_shift = 0;
1538 bool bNewChart =
false;
1539 bool bNewView =
false;
1540 bool bCanvasChartAutoOpen =
true;
1542 bool bNewPiano =
false;
1543 bool bOpenSpecified;
1549 if (bDBUpdateInProgress)
return false;
1550 if (!ChartData)
return false;
1552 if (ChartData->IsBusy())
return false;
1578 double dx = m_OSoffsetx;
1579 double dy = m_OSoffsety;
1583 if (GetUpMode() == NORTH_UP_MODE) {
1584 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1586 double offset_angle = atan2(d_north, d_east);
1587 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1588 double chart_angle = GetVPRotation();
1589 double target_angle = chart_angle + offset_angle;
1590 double d_east_mod = offset_distance * cos(target_angle);
1591 double d_north_mod = offset_distance * sin(target_angle);
1592 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1595 extern double gCog_gt;
1598 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1599 double cog_to_use = gCog;
1601 (fabs(gCog - gCog_gt) > 20)) {
1602 cog_to_use = gCog_gt;
1605 if (!g_btenhertz) cog_to_use = g_COGAvg;
1607 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1609 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1610 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1612 double pixel_delta_tent =
1613 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1615 double pixel_delta = 0;
1620 if (!std::isnan(gSog)) {
1624 pixel_delta = pixel_delta_tent;
1627 meters_to_shift = 0;
1629 if (!std::isnan(gCog)) {
1630 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1631 dir_to_shift = cog_to_use;
1632 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1638 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1652 if (GetQuiltMode()) {
1653 int current_db_index = -1;
1654 if (m_pCurrentStack)
1657 ->GetCurrentEntrydbIndex();
1665 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1667 if (m_pCurrentStack->nEntry) {
1668 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1670 SelectQuiltRefdbChart(new_dbIndex,
true);
1671 m_bautofind =
false;
1675 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1676 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1681 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1687 double proposed_scale_onscreen =
1690 int initial_db_index = m_restore_dbindex;
1691 if (initial_db_index < 0) {
1692 if (m_pCurrentStack->nEntry) {
1694 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1699 if (m_pCurrentStack->nEntry) {
1700 int initial_type = ChartData->GetDBChartType(initial_db_index);
1705 if (!IsChartQuiltableRef(initial_db_index)) {
1709 int stack_index = 0;
1711 if (stack_index >= 0) {
1712 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1713 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1714 if (IsChartQuiltableRef(test_db_index) &&
1716 ChartData->GetDBChartType(initial_db_index))) {
1717 initial_db_index = test_db_index;
1725 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1727 SetQuiltRefChart(initial_db_index);
1728 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1736 0, GetVPRotation());
1741 bool super_jump =
false;
1743 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1744 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1745 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1747 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead) {
1749 if (blong_jump) nstep = 20;
1750 StartTimedMovementVP(vpLat, vpLon, nstep);
1759 pLast_Ch = m_singleChart;
1760 ChartTypeEnum new_open_type;
1761 ChartFamilyEnum new_open_family;
1763 new_open_type = pLast_Ch->GetChartType();
1764 new_open_family = pLast_Ch->GetChartFamily();
1766 new_open_type = CHART_TYPE_KAP;
1767 new_open_family = CHART_FAMILY_RASTER;
1770 bOpenSpecified = m_bFirstAuto;
1773 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1776 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1778 if (NULL == pDummyChart) {
1784 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1786 m_singleChart = pDummyChart;
1791 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1793 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1796 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1797 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1804 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1810 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1815 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1818 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1823 if (NULL != m_singleChart)
1824 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1825 m_singleChart->GetFullPath());
1828 m_pCurrentStack->CurrentStackEntry = tEntry;
1838 if (bCanvasChartAutoOpen) {
1839 bool search_direction =
1841 int start_index = 0;
1845 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1846 (LastStack.nEntry == 0)) {
1847 search_direction =
true;
1848 start_index = m_pCurrentStack->nEntry - 1;
1852 if (bOpenSpecified) {
1853 search_direction =
false;
1855 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1858 new_open_type = CHART_TYPE_DONTCARE;
1861 pProposed = ChartData->OpenStackChartConditional(
1862 m_pCurrentStack, start_index, search_direction, new_open_type,
1866 if (NULL == pProposed)
1867 pProposed = ChartData->OpenStackChartConditional(
1868 m_pCurrentStack, start_index, search_direction,
1869 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1871 if (NULL == pProposed)
1872 pProposed = ChartData->OpenStackChartConditional(
1873 m_pCurrentStack, start_index, search_direction,
1874 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1885 if (NULL == pProposed) {
1886 if (NULL == pDummyChart) {
1892 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1894 pProposed = pDummyChart;
1898 if (m_singleChart) m_singleChart->Deactivate();
1899 m_singleChart = pProposed;
1901 if (m_singleChart) {
1902 m_singleChart->Activate();
1903 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1904 m_pCurrentStack, m_singleChart->GetFullPath());
1909 if (NULL != m_singleChart) {
1915 if (!GetVP().IsValid())
1916 set_scale = 1. / 20000.;
1918 double proposed_scale_onscreen;
1921 double new_scale_ppm =
1922 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1930 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1931 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1932 double equivalent_vp_scale =
1934 double new_scale_ppm =
1935 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1940 proposed_scale_onscreen =
1941 wxMin(proposed_scale_onscreen,
1944 proposed_scale_onscreen =
1945 wxMax(proposed_scale_onscreen,
1954 m_singleChart->GetChartSkew() * PI / 180.,
1961 if ((m_bFollow) && m_singleChart)
1963 m_singleChart->GetChartSkew() * PI / 180.,
1972 m_bFirstAuto =
false;
1976 if (bNewChart && !bNewView) Refresh(
false);
1981 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1984 return bNewChart | bNewView;
1987void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1988 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1990 SetQuiltRefChart(db_index);
1992 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
1995 double best_scale_ppm = GetBestVPScale(pc);
1999 SetQuiltRefChart(-1);
2001 SetQuiltRefChart(-1);
2004void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
2005 std::vector<int> piano_chart_index_array =
2006 GetQuiltExtendedStackdbIndexArray();
2007 int current_db_index = piano_chart_index_array[selected_index];
2009 SelectQuiltRefdbChart(current_db_index);
2012double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2016 if ((g_bPreserveScaleOnX) ||
2017 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2023 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2024 double equivalent_vp_scale =
2026 double new_scale_ppm =
2027 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2034 double max_underzoom_multiplier = 2.0;
2035 if (GetVP().b_quilt) {
2036 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2037 pchart->GetChartType(),
2038 pchart->GetChartFamily());
2039 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2042 proposed_scale_onscreen = wxMin(
2043 proposed_scale_onscreen,
2045 max_underzoom_multiplier);
2048 proposed_scale_onscreen =
2049 wxMax(proposed_scale_onscreen,
2057void ChartCanvas::SetupCanvasQuiltMode(
void) {
2060 ChartData->LockCache();
2062 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2066 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2067 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2068 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2069 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2071 m_Piano->SetRoundedRectangles(
true);
2074 int target_new_dbindex = -1;
2075 if (m_pCurrentStack) {
2076 target_new_dbindex =
2077 GetQuiltReferenceChartIndex();
2079 if (-1 != target_new_dbindex) {
2080 if (!IsChartQuiltableRef(target_new_dbindex)) {
2081 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2082 int type = ChartData->GetDBChartType(target_new_dbindex);
2085 int stack_index = m_pCurrentStack->CurrentStackEntry;
2087 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2088 (stack_index >= 0)) {
2089 int proj_tent = ChartData->GetDBChartProj(
2090 m_pCurrentStack->GetDBIndex(stack_index));
2091 int type_tent = ChartData->GetDBChartType(
2092 m_pCurrentStack->GetDBIndex(stack_index));
2094 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2095 if ((proj == proj_tent) && (type_tent == type)) {
2096 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2106 if (IsChartQuiltableRef(target_new_dbindex))
2107 SelectQuiltRefdbChart(target_new_dbindex,
2110 SelectQuiltRefdbChart(-1,
false);
2112 m_singleChart = NULL;
2115 AdjustQuiltRefChart();
2123 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2127 std::vector<int> empty_array;
2128 m_Piano->SetActiveKeyArray(empty_array);
2129 m_Piano->SetNoshowIndexArray(empty_array);
2130 m_Piano->SetEclipsedIndexArray(empty_array);
2133 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2134 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2135 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2136 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2138 m_Piano->SetRoundedRectangles(
false);
2144 if (!GetQuiltMode()) {
2145 if (ChartData && ChartData->IsValid()) {
2149 if (m_bFollow ==
true) {
2157 if (!m_singleChart) {
2160 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2168 int cur_max_scale = (int)1e8;
2170 ChartBase *pChart = GetFirstQuiltChart();
2174 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2176 if (pChart->GetNativeScale() < cur_max_scale) {
2177 Candidate_Chart = pChart;
2178 cur_max_scale = pChart->GetNativeScale();
2181 pChart = GetNextQuiltChart();
2184 m_singleChart = Candidate_Chart;
2188 if (NULL == m_singleChart) {
2189 m_singleChart = ChartData->OpenStackChartConditional(
2190 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2191 CHART_FAMILY_DONTCARE);
2197 InvalidateAllQuiltPatchs();
2199 if (m_singleChart) {
2200 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2201 std::vector<int> one_array;
2202 one_array.push_back(dbi);
2203 m_Piano->SetActiveKeyArray(one_array);
2206 if (m_singleChart) {
2207 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2211 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2215bool ChartCanvas::IsTempMenuBarEnabled() {
2218 wxGetOsVersion(&major);
2226double ChartCanvas::GetCanvasRangeMeters() {
2228 GetSize(&width, &height);
2229 int minDimension = wxMin(width, height);
2232 range *= cos(GetVP().clat * PI / 180.);
2236void ChartCanvas::SetCanvasRangeMeters(
double range) {
2238 GetSize(&width, &height);
2239 int minDimension = wxMin(width, height);
2241 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2245bool ChartCanvas::SetUserOwnship() {
2249 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2250 double factor_dusk = 0.5;
2251 double factor_night = 0.25;
2253 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2254 m_pos_image_user_day =
new wxImage;
2255 *m_pos_image_user_day = pbmp->ConvertToImage();
2256 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2258 int gimg_width = m_pos_image_user_day->GetWidth();
2259 int gimg_height = m_pos_image_user_day->GetHeight();
2262 m_pos_image_user_dusk =
new wxImage;
2263 m_pos_image_user_night =
new wxImage;
2265 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2266 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2268 for (
int iy = 0; iy < gimg_height; iy++) {
2269 for (
int ix = 0; ix < gimg_width; ix++) {
2270 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2271 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2272 m_pos_image_user_day->GetGreen(ix, iy),
2273 m_pos_image_user_day->GetBlue(ix, iy));
2274 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2275 hsv.value = hsv.value * factor_dusk;
2276 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2277 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2280 hsv = wxImage::RGBtoHSV(rgb);
2281 hsv.value = hsv.value * factor_night;
2282 nrgb = wxImage::HSVtoRGB(hsv);
2283 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2290 m_pos_image_user_grey_day =
new wxImage;
2291 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2293 m_pos_image_user_grey_dusk =
new wxImage;
2294 m_pos_image_user_grey_night =
new wxImage;
2296 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2297 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2299 for (
int iy = 0; iy < gimg_height; iy++) {
2300 for (
int ix = 0; ix < gimg_width; ix++) {
2301 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2302 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2303 m_pos_image_user_grey_day->GetGreen(ix, iy),
2304 m_pos_image_user_grey_day->GetBlue(ix, iy));
2305 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2306 hsv.value = hsv.value * factor_dusk;
2307 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2308 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2311 hsv = wxImage::RGBtoHSV(rgb);
2312 hsv.value = hsv.value * factor_night;
2313 nrgb = wxImage::HSVtoRGB(hsv);
2314 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2321 m_pos_image_user_yellow_day =
new wxImage;
2322 m_pos_image_user_yellow_dusk =
new wxImage;
2323 m_pos_image_user_yellow_night =
new wxImage;
2325 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2326 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2327 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2329 for (
int iy = 0; iy < gimg_height; iy++) {
2330 for (
int ix = 0; ix < gimg_width; ix++) {
2331 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2332 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2333 m_pos_image_user_grey_day->GetGreen(ix, iy),
2334 m_pos_image_user_grey_day->GetBlue(ix, iy));
2338 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2339 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2340 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2342 hsv = wxImage::RGBtoHSV(rgb);
2343 hsv.value = hsv.value * factor_dusk;
2344 nrgb = wxImage::HSVtoRGB(hsv);
2345 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2347 hsv = wxImage::RGBtoHSV(rgb);
2348 hsv.value = hsv.value * factor_night;
2349 nrgb = wxImage::HSVtoRGB(hsv);
2350 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2362 m_display_size_mm = size;
2369 double horizontal = sd.x;
2373 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2374 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2377 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2378 ps52plib->SetPPMM(m_pix_per_mm);
2383 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2385 m_display_size_mm, sd.x, sd.y);
2389 ssx = g_monitor_info[g_current_monitor].width;
2390 ssy = g_monitor_info[g_current_monitor].height;
2391 msg.Printf(_T(
"monitor size: %d %d"), ssx, ssy);
2394 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2397void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2399 wxString msg(event.m_string.c_str(), wxConvUTF8);
2401 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2402 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2405 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2407 compress_msg_array.RemoveAt(event.thread);
2408 compress_msg_array.Insert( msg, event.thread);
2411 compress_msg_array.Add(msg);
2414 wxString combined_msg;
2415 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2416 combined_msg += compress_msg_array[i];
2417 combined_msg += _T(
"\n");
2421 pprog->Update(pprog_count, combined_msg, &skip );
2422 pprog->SetSize(pprog_size);
2427void ChartCanvas::InvalidateGL() {
2428 if (!m_glcc)
return;
2430 if (g_bopengl) m_glcc->Invalidate();
2432 if (m_Compass) m_Compass->UpdateStatus(
true);
2435int ChartCanvas::GetCanvasChartNativeScale() {
2437 if (!VPoint.b_quilt) {
2438 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2440 ret = (int)m_pQuilt->GetRefNativeScale();
2445ChartBase *ChartCanvas::GetChartAtCursor() {
2447 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2448 target_chart = m_singleChart;
2449 else if (VPoint.b_quilt)
2450 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2452 target_chart = NULL;
2453 return target_chart;
2456ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2460 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2462 target_chart = NULL;
2463 return target_chart;
2466int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2467 int new_dbIndex = -1;
2468 if (!VPoint.b_quilt) {
2469 if (m_pCurrentStack) {
2470 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2471 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2473 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2483 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2485 for (
unsigned int is = 0; is < im; is++) {
2487 m_pQuilt->GetExtendedStackIndexArray()[is]);
2490 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2500void ChartCanvas::EnablePaint(
bool b_enable) {
2501 m_b_paint_enable = b_enable;
2503 if (m_glcc) m_glcc->EnablePaint(b_enable);
2507bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2509void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2511std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2512 return m_pQuilt->GetQuiltIndexArray();
2516void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2517 VPoint.b_quilt = b_quilt;
2518 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2521bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2523int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2524 return m_pQuilt->GetRefChartdbIndex();
2527void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2528 m_pQuilt->InvalidateAllQuiltPatchs();
2531ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2532 return m_pQuilt->GetLargestScaleChart();
2535ChartBase *ChartCanvas::GetFirstQuiltChart() {
2536 return m_pQuilt->GetFirstChart();
2539ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2541int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2543void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2544 m_pQuilt->SetHiliteIndex(dbIndex);
2547void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2548 m_pQuilt->SetHiliteIndexArray(hilite_array);
2551void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2552 m_pQuilt->ClearHiliteIndexArray();
2555std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2557 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2560int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2561 return m_pQuilt->GetRefChartdbIndex();
2564std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2565 return m_pQuilt->GetExtendedStackIndexArray();
2568std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2569 return m_pQuilt->GetFullscreenIndexArray();
2572std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2573 return m_pQuilt->GetEclipsedStackIndexArray();
2576void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2578double ChartCanvas::GetQuiltMaxErrorFactor() {
2579 return m_pQuilt->GetMaxErrorFactor();
2582bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2583 return m_pQuilt->IsChartQuiltableRef(db_index);
2587 double chartMaxScale =
2589 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2592void ChartCanvas::StartMeasureRoute() {
2593 if (!m_routeState) {
2594 if (m_bMeasure_Active) {
2596 NavObjectChanges::getInstance());
2597 m_pMeasureRoute = NULL;
2600 m_bMeasure_Active =
true;
2601 m_nMeasureState = 1;
2602 m_bDrawingRoute =
false;
2604 SetCursor(*pCursorPencil);
2609void ChartCanvas::CancelMeasureRoute() {
2610 m_bMeasure_Active =
false;
2611 m_nMeasureState = 0;
2612 m_bDrawingRoute =
false;
2614 g_pRouteMan->
DeleteRoute(m_pMeasureRoute, NavObjectChanges::getInstance());
2615 m_pMeasureRoute = NULL;
2617 SetCursor(*pCursorArrow);
2620ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2622void ChartCanvas::SetVP(
ViewPort &vp) {
2633void ChartCanvas::TriggerDeferredFocus() {
2636 m_deferredFocusTimer.Start(20,
true);
2638#if defined(__WXGTK__) || defined(__WXOSX__)
2649void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2654void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2655 if (SendKeyEventToPlugins(event))
2659 int key_char =
event.GetKeyCode();
2662 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2668 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2673 if (g_benable_rotate) {
2694void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2695 if (SendKeyEventToPlugins(event))
2699 bool b_handled =
false;
2701 m_modkeys =
event.GetModifiers();
2703 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2705#ifdef OCPN_ALT_MENUBAR
2711 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2713 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2714 if (!g_bTempShowMenuBar) {
2715 g_bTempShowMenuBar =
true;
2716 parent_frame->ApplyGlobalSettings(
false);
2718 m_bMayToggleMenuBar =
false;
2724 if (event.GetKeyCode() != WXK_ALT) {
2725 m_bMayToggleMenuBar =
false;
2732 switch (event.GetKeyCode()) {
2739 event.GetPosition(&x, &y);
2740 m_FinishRouteOnKillFocus =
false;
2741 CallPopupMenu(x, y);
2742 m_FinishRouteOnKillFocus =
true;
2746 m_modkeys |= wxMOD_ALT;
2750 m_modkeys |= wxMOD_CONTROL;
2755 case WXK_RAW_CONTROL:
2756 m_modkeys |= wxMOD_RAW_CONTROL;
2761 if (m_modkeys == wxMOD_CONTROL)
2762 parent_frame->DoStackDown(
this);
2763 else if (g_bsmoothpanzoom) {
2764 StartTimedMovement();
2773 if (g_bsmoothpanzoom) {
2774 StartTimedMovement();
2782 if (m_modkeys == wxMOD_CONTROL)
2783 parent_frame->DoStackUp(
this);
2784 else if (g_bsmoothpanzoom) {
2785 StartTimedMovement();
2794 if (g_bsmoothpanzoom) {
2795 StartTimedMovement();
2807 SetShowENCText(!GetShowENCText());
2813 if (!m_bMeasure_Active) {
2814 if (event.ShiftDown())
2815 m_bMeasure_DistCircle =
true;
2817 m_bMeasure_DistCircle =
false;
2819 StartMeasureRoute();
2821 CancelMeasureRoute();
2823 SetCursor(*pCursorArrow);
2833 parent_frame->ToggleColorScheme();
2835 TriggerDeferredFocus();
2839 int mod = m_modkeys & wxMOD_SHIFT;
2840 if (mod != m_brightmod) {
2842 m_bbrightdir = !m_bbrightdir;
2845 if (!m_bbrightdir) {
2846 g_nbrightness -= 10;
2847 if (g_nbrightness <= MIN_BRIGHT) {
2848 g_nbrightness = MIN_BRIGHT;
2849 m_bbrightdir =
true;
2852 g_nbrightness += 10;
2853 if (g_nbrightness >= MAX_BRIGHT) {
2854 g_nbrightness = MAX_BRIGHT;
2855 m_bbrightdir =
false;
2859 SetScreenBrightness(g_nbrightness);
2860 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2869 parent_frame->DoStackDown(
this);
2873 parent_frame->DoStackUp(
this);
2878 double t0 = wxGetLocalTimeMillis().ToDouble();
2880 double t1 = wxGetLocalTimeMillis().ToDouble() - t0;
2882 ToggleCanvasQuiltMode();
2888 parent_frame->ToggleFullScreen();
2893 if (m_modkeys == wxMOD_ALT) {
2896 bool b = GetEnableTenHertzUpdate();
2897 EnableTenHertzUpdate(!b);
2898 UpdateGPSCompassStatusBox(
true);
2900 ToggleChartOutlines();
2905 parent_frame->ActivateMOB();
2909 case WXK_NUMPAD_ADD:
2914 case WXK_NUMPAD_SUBTRACT:
2915 case WXK_PAGEDOWN: {
2916 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2921 if (m_bMeasure_Active) {
2922 if (m_nMeasureState > 2) {
2923 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2924 m_pMeasureRoute->m_lastMousePointIndex =
2925 m_pMeasureRoute->GetnPoints();
2927 gFrame->RefreshAllCanvas();
2929 CancelMeasureRoute();
2930 StartMeasureRoute();
2938 if (event.GetKeyCode() < 128)
2940 int key_char =
event.GetKeyCode();
2944 if (!g_b_assume_azerty) {
2946 if (g_benable_rotate) {
2978 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2985 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2986 m_modkeys & wxMOD_RAW_CONTROL) {
2987 parent_frame->ToggleFullScreen();
2992 if (event.ControlDown()) key_char -= 64;
2994 if (key_char >=
'0' && key_char <=
'9')
2995 SetGroupIndex(key_char -
'0');
3000 SetShowENCAnchor(!GetShowENCAnchor());
3006 parent_frame->ToggleColorScheme();
3011 event.GetPosition(&x, &y);
3012 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3013 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3015 if (!pPopupDetailSlider) {
3016 if (VPoint.b_quilt) {
3018 if (m_pQuilt->GetChartAtPix(
3023 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3025 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3030 if (m_singleChart) {
3031 ChartType = m_singleChart->GetChartType();
3032 ChartFam = m_singleChart->GetChartFamily();
3036 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3037 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3039 this, -1, ChartType, ChartFam,
3040 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3041 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
3042 if (pPopupDetailSlider) pPopupDetailSlider->Show();
3046 if (pPopupDetailSlider) pPopupDetailSlider->Close();
3047 pPopupDetailSlider = NULL;
3053 if (!wxWindow::FindWindowByName(
"NmeaDebugWindow")) {
3054 auto top_window = wxWindow::FindWindowByName(kTopLevelWindowName);
3055 NMEALogWindow::GetInstance().Create(top_window, 35);
3057 wxWindow::FindWindowByName(
"NmeaDebugWindow")->Show();
3061 SetShowENCLights(!GetShowENCLights());
3067 if (event.ShiftDown())
3068 m_bMeasure_DistCircle =
true;
3070 m_bMeasure_DistCircle =
false;
3072 StartMeasureRoute();
3076 if (g_bInlandEcdis && ps52plib) {
3077 SetENCDisplayCategory((_DisCat)STANDARD);
3082 ToggleChartOutlines();
3086 ToggleCanvasQuiltMode();
3090 parent_frame->ToggleTestPause();
3093 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3094 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3095 g_iNavAidRadarRingsNumberVisible = 1;
3096 else if (!g_bNavAidRadarRingsShown &&
3097 g_iNavAidRadarRingsNumberVisible == 1)
3098 g_iNavAidRadarRingsNumberVisible = 0;
3101 SetShowENCDepth(!m_encShowDepth);
3106 SetShowENCText(!GetShowENCText());
3111 SetShowENCDataQual(!GetShowENCDataQual());
3116 m_bShowNavobjects = !m_bShowNavobjects;
3131 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3136 if (event.ControlDown()) gFrame->DropMarker(
false);
3142 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3143 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3144 if ((indexActive + 1) <= r->GetnPoints()) {
3155 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3161 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3167 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3174 parent_frame->DoSettings();
3178 parent_frame->Close();
3186 if (NULL == pGoToPositionDialog)
3189 pGoToPositionDialog->SetCanvas(
this);
3190 pGoToPositionDialog->Show();
3194 if (undo->AnythingToRedo()) {
3195 undo->RedoNextAction();
3202 if (event.ShiftDown()) {
3203 if (undo->AnythingToRedo()) {
3204 undo->RedoNextAction();
3209 if (undo->AnythingToUndo()) {
3210 undo->UndoLastAction();
3219 if (m_bMeasure_Active) {
3220 CancelMeasureRoute();
3222 SetCursor(*pCursorArrow);
3225 gFrame->RefreshAllCanvas();
3239 switch (gamma_state) {
3259 SetScreenBrightness(g_nbrightness);
3264 if (event.ControlDown()) {
3265 m_bShowCompassWin = !m_bShowCompassWin;
3266 SetShowGPSCompassWindow(m_bShowCompassWin);
3283void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3284 if (SendKeyEventToPlugins(event))
3288 switch (event.GetKeyCode()) {
3290 parent_frame->SwitchKBFocus(
this);
3296 if (!m_pany) m_panspeed = 0;
3302 if (!m_panx) m_panspeed = 0;
3305 case WXK_NUMPAD_ADD:
3306 case WXK_NUMPAD_SUBTRACT:
3309 if (m_mustmove) DoMovement(m_mustmove);
3315 m_modkeys &= ~wxMOD_ALT;
3316#ifdef OCPN_ALT_MENUBAR
3321 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3322 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3323 parent_frame->ApplyGlobalSettings(
false);
3325 m_bMayToggleMenuBar =
true;
3331 m_modkeys &= ~wxMOD_CONTROL;
3335 if (event.GetKeyCode() < 128)
3337 int key_char =
event.GetKeyCode();
3341 if (!g_b_assume_azerty) {
3349 DoMovement(m_mustmove);
3355 DoMovement(m_mustmove);
3356 m_rotation_speed = 0;
3364 DoMovement(m_mustmove);
3374void ChartCanvas::ToggleChartOutlines(
void) {
3375 m_bShowOutlines = !m_bShowOutlines;
3381 if (g_bopengl) InvalidateGL();
3385void ChartCanvas::ToggleLookahead() {
3386 m_bLookAhead = !m_bLookAhead;
3391void ChartCanvas::SetUpMode(
int mode) {
3394 if (mode != NORTH_UP_MODE) {
3397 if (!std::isnan(gCog)) stuff = gCog;
3399 if (g_COGAvgSec > 0) {
3400 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3403 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3405 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3406 SetVPRotation(GetVPSkew());
3411 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3412 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3414 UpdateGPSCompassStatusBox(
true);
3415 gFrame->DoChartUpdate();
3418bool ChartCanvas::DoCanvasCOGSet(
void) {
3419 if (GetUpMode() == NORTH_UP_MODE)
return false;
3420 double cog_use = g_COGAvg;
3421 if (g_btenhertz) cog_use = gCog;
3423 double rotation = 0;
3424 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3425 rotation = -gHdt * PI / 180.;
3426 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3427 rotation = -cog_use * PI / 180.;
3429 SetVPRotation(rotation);
3433double easeOutCubic(
double t) {
3435 return 1.0 - pow(1.0 - t, 3.0);
3438void ChartCanvas::StartChartDragInertia() {
3441 m_bChartDragging =
false;
3444 m_chart_drag_inertia_time = 750;
3445 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3450 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3454 size_t length = m_drag_vec_t.size();
3455 for (
size_t i = 0; i < n_vel; i++) {
3456 xacc += m_drag_vec_x.at(length - 1 - i);
3457 yacc += m_drag_vec_y.at(length - 1 - i);
3458 tacc += m_drag_vec_t.at(length - 1 - i);
3461 m_chart_drag_velocity_x = xacc / tacc;
3462 m_chart_drag_velocity_y = yacc / tacc;
3464 m_chart_drag_inertia_active =
true;
3467 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3473void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3474 if (!m_chart_drag_inertia_active)
return;
3477 wxLongLong now = wxGetLocalTimeMillis();
3478 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3479 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3480 if (t > 1.0) t = 1.0;
3481 double e = 1.0 - easeOutCubic(t);
3484 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3486 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3492 m_last_elapsed = elapsed;
3496 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3497 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3498 double inertia_lat, inertia_lon;
3505 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3506 m_chart_drag_inertia_timer.Stop();
3507 m_chart_drag_inertia_active =
false;
3510 m_target_lat = GetVP().
clat;
3511 m_target_lon = GetVP().
clon;
3512 m_pan_drag.x = m_pan_drag.y = 0;
3513 m_panx = m_pany = 0;
3516 int target_redraw_interval = 40;
3517 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3521void ChartCanvas::StopMovement() {
3522 m_panx = m_pany = 0;
3525 m_rotation_speed = 0;
3528#if !defined(__WXGTK__) && !defined(__WXQT__)
3539bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3541 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3543 if (!pMovementTimer->IsRunning()) {
3545 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3548 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3553 m_last_movement_time = wxDateTime::UNow();
3557void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3560 m_target_lat = target_lat;
3561 m_target_lon = target_lon;
3564 m_start_lat = GetVP().
clat;
3565 m_start_lon = GetVP().
clon;
3567 m_VPMovementTimer.Start(1,
true);
3568 m_timed_move_vp_active =
true;
3570 m_timedVP_step = nstep;
3573void ChartCanvas::DoTimedMovementVP() {
3574 if (!m_timed_move_vp_active)
return;
3575 if (m_stvpc++ > m_timedVP_step * 2) {
3582 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3597 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3598 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3600 m_run_lat = new_lat;
3601 m_run_lon = new_lon;
3607void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3609void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3611void ChartCanvas::StartTimedMovementTarget() {}
3613void ChartCanvas::DoTimedMovementTarget() {}
3615void ChartCanvas::StopMovementTarget() {}
3617void ChartCanvas::DoTimedMovement() {
3618 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3622 wxDateTime now = wxDateTime::UNow();
3624 if (m_last_movement_time.IsValid())
3625 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3627 m_last_movement_time = now;
3635void ChartCanvas::DoMovement(
long dt) {
3637 if (dt == 0) dt = 1;
3640 if (m_mustmove < 0) m_mustmove = 0;
3642 if (m_pan_drag.x || m_pan_drag.y) {
3644 m_pan_drag.x = m_pan_drag.y = 0;
3647 if (m_panx || m_pany) {
3648 const double slowpan = .1, maxpan = 2;
3649 if (m_modkeys == wxMOD_ALT)
3650 m_panspeed = slowpan;
3652 m_panspeed += (double)dt / 500;
3653 m_panspeed = wxMin(maxpan, m_panspeed);
3655 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3658 if (m_zoom_factor != 1) {
3659 double alpha = 400, beta = 1.5;
3660 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3662 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3664 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3669 if (zoom_factor > 1) {
3670 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3674 else if (zoom_factor < 1) {
3675 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3680 if (fabs(zoom_factor - 1) > 1e-4)
3683 if (m_wheelzoom_stop_oneshot > 0) {
3684 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3685 m_wheelzoom_stop_oneshot = 0;
3690 if (zoom_factor > 1) {
3692 m_wheelzoom_stop_oneshot = 0;
3695 }
else if (zoom_factor < 1) {
3697 m_wheelzoom_stop_oneshot = 0;
3704 if (m_rotation_speed) {
3705 double speed = m_rotation_speed;
3706 if (m_modkeys == wxMOD_ALT) speed /= 10;
3707 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3711void ChartCanvas::SetColorScheme(ColorScheme cs) {
3712 SetAlertString(_T(
""));
3716 case GLOBAL_COLOR_SCHEME_DAY:
3717 m_pos_image_red = &m_os_image_red_day;
3718 m_pos_image_grey = &m_os_image_grey_day;
3719 m_pos_image_yellow = &m_os_image_yellow_day;
3720 m_pos_image_user = m_pos_image_user_day;
3721 m_pos_image_user_grey = m_pos_image_user_grey_day;
3722 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3723 m_cTideBitmap = m_bmTideDay;
3724 m_cCurrentBitmap = m_bmCurrentDay;
3727 case GLOBAL_COLOR_SCHEME_DUSK:
3728 m_pos_image_red = &m_os_image_red_dusk;
3729 m_pos_image_grey = &m_os_image_grey_dusk;
3730 m_pos_image_yellow = &m_os_image_yellow_dusk;
3731 m_pos_image_user = m_pos_image_user_dusk;
3732 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3733 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3734 m_cTideBitmap = m_bmTideDusk;
3735 m_cCurrentBitmap = m_bmCurrentDusk;
3737 case GLOBAL_COLOR_SCHEME_NIGHT:
3738 m_pos_image_red = &m_os_image_red_night;
3739 m_pos_image_grey = &m_os_image_grey_night;
3740 m_pos_image_yellow = &m_os_image_yellow_night;
3741 m_pos_image_user = m_pos_image_user_night;
3742 m_pos_image_user_grey = m_pos_image_user_grey_night;
3743 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3744 m_cTideBitmap = m_bmTideNight;
3745 m_cCurrentBitmap = m_bmCurrentNight;
3748 m_pos_image_red = &m_os_image_red_day;
3749 m_pos_image_grey = &m_os_image_grey_day;
3750 m_pos_image_yellow = &m_os_image_yellow_day;
3751 m_pos_image_user = m_pos_image_user_day;
3752 m_pos_image_user_grey = m_pos_image_user_grey_day;
3753 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3754 m_cTideBitmap = m_bmTideDay;
3755 m_cCurrentBitmap = m_bmCurrentDay;
3759 CreateDepthUnitEmbossMaps(cs);
3760 CreateOZEmbossMapData(cs);
3763 m_fog_color = wxColor(
3767 case GLOBAL_COLOR_SCHEME_DUSK:
3770 case GLOBAL_COLOR_SCHEME_NIGHT:
3776 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3777 m_fog_color.Blue() * dim);
3781 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3782 SetBackgroundColour( wxColour(0,0,0) );
3784 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3787 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3789 SetBackgroundColour( wxNullColour );
3796 m_Piano->SetColorScheme(cs);
3798 m_Compass->SetColorScheme(cs);
3800 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3802 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3804 if (g_bopengl && m_glcc) {
3805 m_glcc->SetColorScheme(cs);
3806 g_glTextureManager->ClearAllRasterTextures();
3811 m_brepaint_piano =
true;
3818wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3819 wxImage img = Bitmap.ConvertToImage();
3820 int sx = img.GetWidth();
3821 int sy = img.GetHeight();
3823 wxImage new_img(img);
3825 for (
int i = 0; i < sx; i++) {
3826 for (
int j = 0; j < sy; j++) {
3827 if (!img.IsTransparent(i, j)) {
3828 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3829 (
unsigned char)(img.GetGreen(i, j) * factor),
3830 (
unsigned char)(img.GetBlue(i, j) * factor));
3835 wxBitmap ret = wxBitmap(new_img);
3840void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3843 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3845 if (!m_pBrightPopup) {
3848 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3852 m_pBrightPopup->SetSize(x, y);
3853 m_pBrightPopup->Move(120, 120);
3856 int bmpsx = m_pBrightPopup->GetSize().x;
3857 int bmpsy = m_pBrightPopup->GetSize().y;
3859 wxBitmap bmp(bmpsx, bmpsx);
3860 wxMemoryDC mdc(bmp);
3862 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3863 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3864 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3865 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3868 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3870 mdc.SetFont(*pfont);
3873 if (brightness == max)
3875 else if (brightness == min)
3878 val.Printf(_T(
"%3d"), brightness);
3880 mdc.DrawText(val, 0, 0);
3882 mdc.SelectObject(wxNullBitmap);
3884 m_pBrightPopup->SetBitmap(bmp);
3885 m_pBrightPopup->Show();
3886 m_pBrightPopup->Refresh();
3889void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3890 m_b_rot_hidef =
true;
3894void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3895 if (!g_bRollover)
return;
3897 bool b_need_refresh =
false;
3899 wxSize win_size = GetSize() * m_displayScale;
3900 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3903 bool showAISRollover =
false;
3904 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3906 SelectItem *pFind = pSelectAIS->FindSelection(
3909 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3910 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3913 showAISRollover =
true;
3915 if (NULL == m_pAISRolloverWin) {
3917 m_pAISRolloverWin->IsActive(
false);
3918 b_need_refresh =
true;
3919 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3920 m_AISRollover_MMSI != FoundAIS_MMSI) {
3926 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3927 m_pAISRolloverWin->IsActive(
false);
3928 m_AISRollover_MMSI = 0;
3933 m_AISRollover_MMSI = FoundAIS_MMSI;
3935 if (!m_pAISRolloverWin->IsActive()) {
3936 wxString s = ptarget->GetRolloverString();
3937 m_pAISRolloverWin->SetString(s);
3939 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3940 AIS_ROLLOVER, win_size);
3941 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3942 m_pAISRolloverWin->IsActive(
true);
3943 b_need_refresh =
true;
3947 m_AISRollover_MMSI = 0;
3948 showAISRollover =
false;
3953 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3954 m_pAISRolloverWin->IsActive(
false);
3955 m_AISRollover_MMSI = 0;
3956 b_need_refresh =
true;
3961 bool showRouteRollover =
false;
3963 if (NULL == m_pRolloverRouteSeg) {
3968 SelectableItemList SelList = pSelect->FindSelectionList(
3970 wxSelectableItemListNode *node = SelList.GetFirst();
3976 if (pr && pr->IsVisible()) {
3977 m_pRolloverRouteSeg = pFindSel;
3978 showRouteRollover =
true;
3980 if (NULL == m_pRouteRolloverWin) {
3982 m_pRouteRolloverWin->IsActive(
false);
3985 if (!m_pRouteRolloverWin->IsActive()) {
3993 DistanceBearingMercator(
3994 segShow_point_b->m_lat, segShow_point_b->m_lon,
3995 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3997 if (!pr->m_bIsInLayer)
3998 s.Append(_(
"Route") + _T(
": "));
4000 s.Append(_(
"Layer Route: "));
4002 if (pr->m_RouteNameString.IsEmpty())
4003 s.Append(_(
"(unnamed)"));
4005 s.Append(pr->m_RouteNameString);
4007 s << _T(
"\n") << _(
"Total Length: ")
4008 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
4009 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4010 << segShow_point_b->GetName() << _T(
"\n");
4013 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4014 (
int)floor(brg + 0.5), 0x00B0);
4017 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4019 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4020 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4022 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4023 (
int)floor(varBrg + 0.5), 0x00B0);
4026 s << FormatDistanceAdaptive(dist);
4031 double shiptoEndLeg = 0.;
4032 bool validActive =
false;
4033 if (pr->IsActive() &&
4034 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
4037 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
4038 wxRoutePointListNode *node =
4039 (pr->pRoutePointList)->GetFirst()->GetNext();
4041 float dist_to_endleg = 0;
4045 prp = node->GetData();
4047 shiptoEndLeg += prp->m_seg_len;
4048 else if (prp->m_bIsActive)
4050 dist_to_endleg += prp->m_seg_len;
4051 if (prp->IsSame(segShow_point_a))
break;
4052 node = node->GetNext();
4054 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
4059 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
4060 << segShow_point_b->GetName() << _T(
"\n");
4063 ->GetCurrentRngToActivePoint();
4068 s << FormatDistanceAdaptive(shiptoEndLeg);
4072 if (!std::isnan(gCog) && !std::isnan(gSog))
4074 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
4077 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
4078 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4080 << wxString(ttg_sec > SECONDS_PER_DAY
4081 ? ttg_span.Format(_(
"%Dd %H:%M"))
4082 : ttg_span.Format(_(
"%H:%M")));
4083 wxDateTime dtnow, eta;
4084 eta = dtnow.SetToCurrent().Add(ttg_span);
4085 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
4086 << eta.Format(_T(
" %d %H:%M"));
4088 s << _T(
" ---- ----");
4090 m_pRouteRolloverWin->SetString(s);
4092 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4093 LEG_ROLLOVER, win_size);
4094 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4095 m_pRouteRolloverWin->IsActive(
true);
4096 b_need_refresh =
true;
4097 showRouteRollover =
true;
4101 node = node->GetNext();
4107 m_pRolloverRouteSeg))
4108 showRouteRollover =
false;
4109 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4110 showRouteRollover =
false;
4112 showRouteRollover =
true;
4116 if (m_routeState) showRouteRollover =
false;
4119 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4120 showRouteRollover =
false;
4122 if (m_pRouteRolloverWin &&
4123 !showRouteRollover) {
4124 m_pRouteRolloverWin->IsActive(
false);
4125 m_pRolloverRouteSeg = NULL;
4126 m_pRouteRolloverWin->Destroy();
4127 m_pRouteRolloverWin = NULL;
4128 b_need_refresh =
true;
4129 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4130 m_pRouteRolloverWin->IsActive(
true);
4131 b_need_refresh =
true;
4136 bool showTrackRollover =
false;
4138 if (NULL == m_pRolloverTrackSeg) {
4143 SelectableItemList SelList = pSelect->FindSelectionList(
4145 wxSelectableItemListNode *node = SelList.GetFirst();
4151 if (pt && pt->IsVisible()) {
4152 m_pRolloverTrackSeg = pFindSel;
4153 showTrackRollover =
true;
4155 if (NULL == m_pTrackRolloverWin) {
4157 m_pTrackRolloverWin->IsActive(
false);
4160 if (!m_pTrackRolloverWin->IsActive()) {
4168 DistanceBearingMercator(
4169 segShow_point_b->m_lat, segShow_point_b->m_lon,
4170 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4172 if (!pt->m_bIsInLayer)
4173 s.Append(_(
"Track") + _T(
": "));
4175 s.Append(_(
"Layer Track: "));
4177 if (pt->GetName().IsEmpty())
4178 s.Append(_(
"(unnamed)"));
4180 s.Append(pt->GetName());
4181 double tlenght = pt->Length();
4182 s << _T(
"\n") << _(
"Total Track: ")
4183 << FormatDistanceAdaptive(tlenght);
4184 if (pt->GetLastPoint()->GetTimeString() &&
4185 pt->GetPoint(0)->GetTimeString()) {
4186 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4187 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4188 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4189 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4190 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4191 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4192 << getUsrSpeedUnit();
4193 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4194 : ttime.Format(_T(
" %H:%M")));
4198 if (g_bShowTrackPointTime && strlen(segShow_point_b->GetTimeString()))
4199 s << _T(
"\n") << _(
"Segment Created: ")
4200 << segShow_point_b->GetTimeString();
4204 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4209 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4211 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4212 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4214 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4218 s << FormatDistanceAdaptive(dist);
4220 if (segShow_point_a->GetTimeString() &&
4221 segShow_point_b->GetTimeString()) {
4222 wxDateTime apoint = segShow_point_a->GetCreateTime();
4223 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4224 if (apoint.IsValid() && bpoint.IsValid()) {
4225 double segmentSpeed = toUsrSpeed(
4226 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4227 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4228 << getUsrSpeedUnit();
4232 m_pTrackRolloverWin->SetString(s);
4234 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4235 LEG_ROLLOVER, win_size);
4236 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4237 m_pTrackRolloverWin->IsActive(
true);
4238 b_need_refresh =
true;
4239 showTrackRollover =
true;
4243 node = node->GetNext();
4249 m_pRolloverTrackSeg))
4250 showTrackRollover =
false;
4251 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4252 showTrackRollover =
false;
4254 showTrackRollover =
true;
4258 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4259 showTrackRollover =
false;
4262 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4263 showTrackRollover =
false;
4269 if (m_pTrackRolloverWin &&
4270 !showTrackRollover) {
4271 m_pTrackRolloverWin->IsActive(
false);
4272 m_pRolloverTrackSeg = NULL;
4273 m_pTrackRolloverWin->Destroy();
4274 m_pTrackRolloverWin = NULL;
4275 b_need_refresh =
true;
4276 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4277 m_pTrackRolloverWin->IsActive(
true);
4278 b_need_refresh =
true;
4281 if (b_need_refresh) Refresh();
4284void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4285 if ((GetShowENCLights() || m_bsectors_shown) &&
4286 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4287 extendedSectorLegs)) {
4288 if (!m_bsectors_shown) {
4290 m_bsectors_shown =
true;
4293 if (m_bsectors_shown) {
4295 m_bsectors_shown =
false;
4303#if defined(__WXGTK__) || defined(__WXQT__)
4308 double cursor_lat, cursor_lon;
4311 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4312 while (cursor_lon < -180.) cursor_lon += 360.;
4314 while (cursor_lon > 180.) cursor_lon -= 360.;
4316 SetCursorStatus(cursor_lat, cursor_lon);
4322void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4323 if (!parent_frame->m_pStatusBar)
return;
4327 s1 += toSDMM(1, cursor_lat);
4329 s1 += toSDMM(2, cursor_lon);
4331 if (STAT_FIELD_CURSOR_LL >= 0)
4332 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4334 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4339 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4340 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4341 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4343 wxString s = st + sm;
4344 s << FormatDistanceAdaptive(dist);
4356 if (g_bShowLiveETA) {
4359 float boatSpeedDefault = g_defaultBoatSpeed;
4364 if (!std::isnan(gSog)) {
4366 if (boatSpeed < 0.5) {
4369 realTimeETA = dist / boatSpeed * 60;
4378 s << minutesToHoursDays(realTimeETA);
4383 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4384 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4386 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4391 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4399wxString minutesToHoursDays(
float timeInMinutes) {
4402 if (timeInMinutes == 0) {
4407 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4408 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4413 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4416 hours = (int)timeInMinutes / 60;
4417 min = (int)timeInMinutes % 60;
4420 s << wxString::Format(_T(
"%d"), hours);
4423 s << wxString::Format(_T(
"%d"), hours);
4425 s << wxString::Format(_T(
"%d"), min);
4432 else if (timeInMinutes > 24 * 60) {
4435 days = (int)(timeInMinutes / 60) / 24;
4436 hours = (int)(timeInMinutes / 60) % 24;
4439 s << wxString::Format(_T(
"%d"), days);
4442 s << wxString::Format(_T(
"%d"), days);
4444 s << wxString::Format(_T(
"%d"), hours);
4456void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4464 wxPoint2DDouble *r) {
4469 double rlon, wxPoint2DDouble *r) {
4480 if (!g_bopengl && m_singleChart &&
4481 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4482 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4483 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4484 (m_singleChart->GetChartProjectionType() !=
4485 PROJECTION_TRANSVERSE_MERCATOR) &&
4486 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4487 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4488 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4502 Cur_BSB_Ch->SetVPRasterParms(vp);
4503 double rpixxd, rpixyd;
4504 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4530 if (std::isnan(p.m_x)) {
4531 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4535 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4536 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4538 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4557 if (!g_bopengl && m_singleChart &&
4558 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4559 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4560 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4561 (m_singleChart->GetChartProjectionType() !=
4562 PROJECTION_TRANSVERSE_MERCATOR) &&
4563 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4564 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4565 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4576 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4579 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4584 else if (slon > 180.)
4595 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4601 extendedSectorLegs.clear();
4606 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4608 if (g_bsmoothpanzoom) {
4609 if (StartTimedMovement(stoptimer)) {
4611 m_zoom_factor = factor;
4616 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4621 extendedSectorLegs.clear();
4626 if (!ChartData)
return;
4627 if (!m_pCurrentStack)
return;
4633 if (m_bzooming)
return;
4642 double proposed_scale_onscreen =
4645 bool b_do_zoom =
false;
4654 if (!VPoint.b_quilt) {
4657 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4658 if (new_db_index >= 0)
4659 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4663 int current_ref_stack_index = -1;
4664 if (m_pCurrentStack->nEntry) {
4666 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4667 m_pQuilt->SetReferenceChart(trial_index);
4668 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4669 if (new_db_index >= 0)
4670 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4674 if (m_pCurrentStack)
4675 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4685 double min_allowed_scale =
4688 if (proposed_scale_onscreen < min_allowed_scale) {
4693 proposed_scale_onscreen = min_allowed_scale;
4697 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4700 }
else if (factor < 1) {
4705 bool b_smallest =
false;
4707 if (!VPoint.b_quilt) {
4712 LLBBox viewbox = VPoint.GetBBox();
4714 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4715 double max_allowed_scale;
4729 if (proposed_scale_onscreen > max_allowed_scale) {
4731 proposed_scale_onscreen = max_allowed_scale;
4736 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4737 if (new_db_index >= 0)
4738 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4740 if (m_pCurrentStack)
4741 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4744 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4746 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4747 proposed_scale_onscreen =
4748 wxMin(proposed_scale_onscreen,
4754 m_absolute_min_scale_ppm)
4763 bool b_allow_ztc =
true;
4764 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4765 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4767 double brg, distance;
4768 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4771 meters_to_shift = distance * 1852;
4779 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4782 if (m_bFollow) DoCanvasUpdate();
4789void ChartCanvas::RotateCanvas(
double dir) {
4792 if (g_bsmoothpanzoom) {
4793 if (StartTimedMovement()) {
4795 m_rotation_speed = dir * 60;
4798 double speed = dir * 10;
4799 if (m_modkeys == wxMOD_ALT) speed /= 20;
4800 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4804void ChartCanvas::DoRotateCanvas(
double rotation) {
4805 while (rotation < 0) rotation += 2 * PI;
4806 while (rotation > 2 * PI) rotation -= 2 * PI;
4808 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4810 SetVPRotation(rotation);
4811 parent_frame->UpdateRotationState(VPoint.
rotation);
4814void ChartCanvas::DoTiltCanvas(
double tilt) {
4815 while (tilt < 0) tilt = 0;
4816 while (tilt > .95) tilt = .95;
4818 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4824void ChartCanvas::TogglebFollow(
void) {
4831void ChartCanvas::ClearbFollow(
void) {
4834 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4836 UpdateFollowButtonState();
4840 parent_frame->SetChartUpdatePeriod();
4843void ChartCanvas::SetbFollow(
void) {
4846 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4847 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4855 p.m_x += m_OSoffsetx;
4856 p.m_y -= m_OSoffsety;
4865 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4866 UpdateFollowButtonState();
4868 if (!g_bSmoothRecenter) {
4872 parent_frame->SetChartUpdatePeriod();
4875void ChartCanvas::UpdateFollowButtonState(
void) {
4878 m_muiBar->SetFollowButtonState(0);
4881 m_muiBar->SetFollowButtonState(2);
4883 m_muiBar->SetFollowButtonState(1);
4889 androidSetFollowTool(0);
4892 androidSetFollowTool(2);
4894 androidSetFollowTool(1);
4899void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4900 if (g_bSmoothRecenter && !m_routeState) {
4901 if (StartSmoothJump(lat, lon, scale_ppm))
4905 double gcDist, gcBearingEnd;
4906 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4908 gcBearingEnd += 180;
4909 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4912 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4913 double new_lat = lat + (lat_offset / (1852 * 60));
4914 double new_lon = lon + (lon_offset / (1852 * 60));
4917 StartSmoothJump(lat, lon, scale_ppm);
4922 if (lon > 180.0) lon -= 360.0;
4928 if (!GetQuiltMode()) {
4930 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4931 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4935 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4936 AdjustQuiltRefChart();
4943 UpdateFollowButtonState();
4951bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4956 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4957 double distance_pixels = gcDist *
GetVPScale();
4958 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4964 m_startLat = m_vLat;
4965 m_startLon = m_vLon;
4970 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4971 m_endScale = scale_ppm;
4974 m_animationDuration = 600;
4975 m_animationStart = wxGetLocalTimeMillis();
4982 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
4983 m_animationActive =
true;
4988void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
4990 wxLongLong now = wxGetLocalTimeMillis();
4991 double elapsed = (now - m_animationStart).ToDouble();
4992 double t = elapsed / m_animationDuration.ToDouble();
4993 if (t > 1.0) t = 1.0;
4996 double e = easeOutCubic(t);
4999 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5000 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5001 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5006 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5012 m_animationActive =
false;
5013 UpdateFollowButtonState();
5020 if (!ChartData)
return false;
5025 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
5026 UpdateFollowButtonState();
5032 extendedSectorLegs.clear();
5042 if (iters++ > 5)
return false;
5043 if (!std::isnan(dlat))
break;
5046 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5052 else if (dlat < -90)
5055 if (dlon > 360.) dlon -= 360.;
5056 if (dlon < -360.) dlon += 360.;
5071 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5075 if (VPoint.b_quilt) {
5076 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5077 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5079 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
5081 double tweak_scale_ppm =
5087 if (new_ref_dbIndex == -1) {
5092 int trial_index = -1;
5093 if (m_pCurrentStack->nEntry) {
5095 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5098 if (trial_index < 0) {
5099 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5100 if (full_screen_array.size())
5101 trial_index = full_screen_array[full_screen_array.size() - 1];
5104 if (trial_index >= 0) {
5105 m_pQuilt->SetReferenceChart(trial_index);
5116 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5118 double offset_angle = atan2(offy, offx);
5119 double offset_distance = sqrt((offy * offy) + (offx * offx));
5120 double chart_angle = GetVPRotation();
5121 double target_angle = chart_angle - offset_angle;
5122 double d_east_mod = offset_distance * cos(target_angle);
5123 double d_north_mod = offset_distance * sin(target_angle);
5128 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5129 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5131 UpdateFollowButtonState();
5137 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5142void ChartCanvas::ReloadVP(
bool b_adjust) {
5143 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5145 LoadVP(VPoint, b_adjust);
5148void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5150 if (g_bopengl && m_glcc) {
5151 m_glcc->Invalidate();
5152 if (m_glcc->GetSize() != GetSize()) {
5153 m_glcc->SetSize(GetSize());
5158 m_cache_vp.Invalidate();
5159 m_bm_cache_vp.Invalidate();
5162 VPoint.Invalidate();
5164 if (m_pQuilt) m_pQuilt->Invalidate();
5173 vp.m_projection_type, b_adjust);
5176void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5177 m_pQuilt->SetReferenceChart(dbIndex);
5178 VPoint.Invalidate();
5179 m_pQuilt->Invalidate();
5182double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5184 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5191int ChartCanvas::AdjustQuiltRefChart() {
5194 wxASSERT(ChartData);
5196 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5198 double min_ref_scale =
5199 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5200 double max_ref_scale =
5201 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5204 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5206 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5208 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5210 int ref_family = pc->GetChartFamily();
5213 unsigned int target_stack_index = 0;
5214 int target_stack_index_check =
5215 m_pQuilt->GetExtendedStackIndexArray()
5216 [m_pQuilt->GetRefChartdbIndex()];
5218 if (wxNOT_FOUND != target_stack_index_check)
5219 target_stack_index = target_stack_index_check;
5221 int extended_array_count =
5222 m_pQuilt->GetExtendedStackIndexArray().size();
5223 while ((!brender_ok) &&
5224 ((
int)target_stack_index < (extended_array_count - 1))) {
5225 target_stack_index++;
5227 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5229 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
5230 IsChartQuiltableRef(test_db_index)) {
5233 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5235 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5242 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5243 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
5244 IsChartQuiltableRef(new_db_index)) {
5245 m_pQuilt->SetReferenceChart(new_db_index);
5248 ret = m_pQuilt->GetRefChartdbIndex();
5250 ret = m_pQuilt->GetRefChartdbIndex();
5253 ret = m_pQuilt->GetRefChartdbIndex();
5262void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5263 delete m_pCurrentStack;
5265 wxASSERT(ChartData);
5266 ChartData->BuildChartStack(m_pCurrentStack, VPoint.
clat, VPoint.
clon,
5275bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5276 double latNE,
double lonNE) {
5278 double latc = (latSW + latNE) / 2.0;
5279 double lonc = (lonSW + lonNE) / 2.0;
5282 double ne_easting, ne_northing;
5283 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5285 double sw_easting, sw_northing;
5286 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5288 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5295 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5298bool ChartCanvas::SetVPProjection(
int projection) {
5304 double prev_true_scale_ppm = m_true_scale_ppm;
5309 m_absolute_min_scale_ppm));
5317bool ChartCanvas::SetVPRotation(
double angle) {
5319 VPoint.
skew, angle);
5322 double skew,
double rotation,
int projection,
5323 bool b_adjust,
bool b_refresh) {
5328 if (VPoint.IsValid()) {
5329 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5330 (fabs(VPoint.
skew - skew) < 1e-9) &&
5331 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5332 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5333 (VPoint.m_projection_type == projection ||
5334 projection == PROJECTION_UNKNOWN))
5337 if (VPoint.m_projection_type != projection)
5338 VPoint.InvalidateTransformCache();
5348 if (projection != PROJECTION_UNKNOWN)
5349 VPoint.SetProjectionType(projection);
5350 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5351 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5354 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5355 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5356 if (VPoint.
clat > 89.5)
5358 else if (VPoint.
clat < -89.5)
5359 VPoint.
clat = -89.5;
5364 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5365 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5377 bool bwasValid = VPoint.IsValid();
5382 m_cache_vp.Invalidate();
5387 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5392 const wxPoint pt = wxGetMousePosition();
5393 int mouseX = pt.x - GetScreenPosition().x;
5394 int mouseY = pt.y - GetScreenPosition().y;
5395 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5401 SendCursorLatLonToAllPlugIns(lat, lon);
5404 if (!VPoint.b_quilt && m_singleChart) {
5409 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5413 if ((!m_cache_vp.IsValid()) ||
5418 wxPoint cp_last, cp_this;
5422 if (cp_last != cp_this) {
5428 if (m_pCurrentStack) {
5429 assert(ChartData != 0);
5430 int current_db_index;
5432 m_pCurrentStack->GetCurrentEntrydbIndex();
5434 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5436 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5439 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5443 if (VPoint.b_quilt) {
5445 m_pQuilt->InvalidateAllQuiltPatchs();
5449 if (!m_pCurrentStack)
return false;
5451 int current_db_index;
5453 m_pCurrentStack->GetCurrentEntrydbIndex();
5455 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5456 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5459 int current_ref_stack_index = -1;
5460 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5461 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5462 current_ref_stack_index = i;
5465 if (g_bFullScreenQuilt) {
5466 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5470 bool b_needNewRef =
false;
5473 if ((-1 == current_ref_stack_index) &&
5474 (m_pQuilt->GetRefChartdbIndex() >= 0))
5475 b_needNewRef =
true;
5482 bool renderable =
true;
5484 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5485 if (referenceChart) {
5486 double chartMaxScale = referenceChart->GetNormalScaleMax(
5488 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5490 if (!renderable) b_needNewRef =
true;
5495 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5496 int target_scale = cte_ref.GetScale();
5497 int target_type = cte_ref.GetChartType();
5498 int candidate_stack_index;
5505 candidate_stack_index = 0;
5506 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5508 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5509 int candidate_scale = cte_candidate.GetScale();
5510 int candidate_type = cte_candidate.GetChartType();
5512 if ((candidate_scale >= target_scale) &&
5513 (candidate_type == target_type)) {
5514 bool renderable =
true;
5515 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5516 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5517 if (tentative_referenceChart) {
5518 double chartMaxScale =
5519 tentative_referenceChart->GetNormalScaleMax(
5521 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5524 if (renderable)
break;
5527 candidate_stack_index++;
5532 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5533 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5534 while (candidate_stack_index >= 0) {
5535 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5538 ChartData->GetChartTableEntry(idx);
5539 int candidate_scale = cte_candidate.GetScale();
5540 int candidate_type = cte_candidate.GetChartType();
5542 if ((candidate_scale <= target_scale) &&
5543 (candidate_type == target_type))
5546 candidate_stack_index--;
5551 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5552 (candidate_stack_index < 0))
5553 candidate_stack_index = 0;
5555 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5557 m_pQuilt->SetReferenceChart(new_ref_index);
5563 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5568 bool renderable =
true;
5570 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5571 if (referenceChart) {
5572 double chartMaxScale = referenceChart->GetNormalScaleMax(
5574 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5575 proj = ChartData->GetDBChartProj(ref_db_index);
5577 proj = PROJECTION_MERCATOR;
5579 VPoint.b_MercatorProjectionOverride =
5580 (m_pQuilt->GetnCharts() == 0 || !renderable);
5582 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5584 VPoint.SetProjectionType(proj);
5591 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5595 if (b_adjust) m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5614 m_pQuilt->Invalidate();
5629 ChartData->PurgeCacheUnusedCharts(0.7);
5631 if (b_refresh) Refresh(
false);
5638 }
else if (!g_bopengl) {
5639 OcpnProjType projection = PROJECTION_UNKNOWN;
5642 projection = m_singleChart->GetChartProjectionType();
5643 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5644 VPoint.SetProjectionType(projection);
5648 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5649 m_cache_vp.Invalidate();
5653 UpdateCanvasControlBar();
5659 if (VPoint.GetBBox().GetValid()) {
5662 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5671 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5674 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5681 wxPoint2DDouble r, r1;
5683 double delta_check =
5687 double check_point = wxMin(89., VPoint.
clat);
5689 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5692 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5693 VPoint.
clon, 0, &rhumbDist);
5698 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5699 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5701 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5705 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5711 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5713 if (m_true_scale_ppm)
5714 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5719 double round_factor = 1000.;
5723 round_factor = 100.;
5725 round_factor = 1000.;
5728 double retina_coef = 1;
5732 retina_coef = GetContentScaleFactor();
5743 double true_scale_display =
5744 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5749 if (m_displayed_scale_factor > 10.0)
5750 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5751 m_displayed_scale_factor);
5752 else if (m_displayed_scale_factor > 1.0)
5753 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5754 m_displayed_scale_factor);
5755 else if (m_displayed_scale_factor > 0.1) {
5756 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5757 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5758 }
else if (m_displayed_scale_factor > 0.01) {
5759 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5760 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5763 _T(
"%s %4.0f (---)"), _(
"Scale"),
5764 true_scale_display);
5767 m_scaleValue = true_scale_display;
5769 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5771 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5772 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5774 bool b_noshow =
false;
5778 wxClientDC dc(parent_frame->GetStatusBar());
5780 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5781 dc.SetFont(*templateFont);
5782 dc.GetTextExtent(text, &w, &h);
5787 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5788 if (w && w > rect.width) {
5789 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5790 m_displayed_scale_factor);
5794 dc.GetTextExtent(text, &w, &h);
5796 if (w && w > rect.width) {
5802 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5807 m_vLat = VPoint.
clat;
5808 m_vLon = VPoint.
clon;
5822static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5826static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5827 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5829wxColour ChartCanvas::PredColor() {
5832 if (SHIP_NORMAL == m_ownship_state)
5833 return GetGlobalColor(_T (
"URED" ));
5835 else if (SHIP_LOWACCURACY == m_ownship_state)
5836 return GetGlobalColor(_T (
"YELO1" ));
5838 return GetGlobalColor(_T (
"NODTA" ));
5841wxColour ChartCanvas::ShipColor() {
5845 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5847 if (SHIP_LOWACCURACY == m_ownship_state)
5848 return GetGlobalColor(_T (
"YELO1" ));
5850 return GetGlobalColor(_T (
"URED" ));
5853void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5854 wxPoint2DDouble lShipMidPoint) {
5855 dc.SetPen(wxPen(PredColor(), 2));
5857 if (SHIP_NORMAL == m_ownship_state)
5858 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5860 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5862 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5863 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5865 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5867 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5868 lShipMidPoint.m_y + 12);
5871void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5872 wxPoint GPSOffsetPixels,
5873 wxPoint2DDouble lGPSPoint) {
5874 if (m_animationActive)
return;
5878 float ref_dim = m_display_size_mm / 24;
5879 ref_dim = wxMin(ref_dim, 12);
5880 ref_dim = wxMax(ref_dim, 6);
5883 cPred.Set(g_cog_predictor_color);
5884 if (cPred == wxNullColour) cPred = PredColor();
5891 double nominal_line_width_pix = wxMax(
5893 floor(m_pix_per_mm / 2));
5897 if (nominal_line_width_pix > g_cog_predictor_width)
5898 g_cog_predictor_width = nominal_line_width_pix;
5901 wxPoint lPredPoint, lHeadPoint;
5903 float pCog = std::isnan(gCog) ? 0 : gCog;
5904 float pSog = std::isnan(gSog) ? 0 : gSog;
5906 double pred_lat, pred_lon;
5907 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5908 &pred_lat, &pred_lon);
5919 float ndelta_pix = 10.;
5920 double hdg_pred_lat, hdg_pred_lon;
5921 bool b_render_hdt =
false;
5922 if (!std::isnan(gHdt)) {
5924 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5927 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5928 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5929 if (dist > ndelta_pix ) {
5930 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5931 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5936 wxPoint lShipMidPoint;
5937 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5938 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5939 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5940 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5942 if (lpp >= img_height / 2) {
5943 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5944 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5945 !std::isnan(gSog)) {
5947 float dash_length = ref_dim;
5948 wxDash dash_long[2];
5950 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5951 g_cog_predictor_width);
5952 dash_long[1] = dash_long[0] / 2.0;
5956 if (dash_length > 250.) {
5957 dash_long[0] = 250. / g_cog_predictor_width;
5958 dash_long[1] = dash_long[0] / 2;
5961 wxPen ppPen2(cPred, g_cog_predictor_width,
5962 (wxPenStyle)g_cog_predictor_style);
5963 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5964 ppPen2.SetDashes(2, dash_long);
5967 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5968 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5970 if (g_cog_predictor_width > 1) {
5971 float line_width = g_cog_predictor_width / 3.;
5973 wxDash dash_long3[2];
5974 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5975 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5977 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
5978 (wxPenStyle)g_cog_predictor_style);
5979 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5980 ppPen3.SetDashes(2, dash_long3);
5982 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
5983 lGPSPoint.m_y + GPSOffsetPixels.y,
5984 lPredPoint.x + GPSOffsetPixels.x,
5985 lPredPoint.y + GPSOffsetPixels.y);
5988 if (g_cog_predictor_endmarker) {
5990 double png_pred_icon_scale_factor = .4;
5991 if (g_ShipScaleFactorExp > 1.0)
5992 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5993 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
5997 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
5998 (
float)(lPredPoint.x - lShipMidPoint.x));
5999 cog_rad += (float)PI;
6001 for (
int i = 0; i < 4; i++) {
6003 double pxa = (double)(s_png_pred_icon[j]);
6004 double pya = (double)(s_png_pred_icon[j + 1]);
6006 pya *= png_pred_icon_scale_factor;
6007 pxa *= png_pred_icon_scale_factor;
6009 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6010 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6012 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6013 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6017 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
6020 dc.SetBrush(wxBrush(cPred));
6022 dc.StrokePolygon(4, icon);
6029 float hdt_dash_length = ref_dim * 0.4;
6031 cPred.Set(g_ownship_HDTpredictor_color);
6032 if (cPred == wxNullColour) cPred = PredColor();
6034 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6035 : g_cog_predictor_width * 0.8);
6036 wxDash dash_short[2];
6038 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6041 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6044 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6045 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6046 ppPen2.SetDashes(2, dash_short);
6050 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6051 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6053 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6055 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
6057 if (g_ownship_HDTpredictor_endmarker) {
6058 double nominal_circle_size_pixels = wxMax(
6059 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6062 if (g_ShipScaleFactorExp > 1.0)
6063 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6065 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6066 lHeadPoint.y + GPSOffsetPixels.y,
6067 nominal_circle_size_pixels / 2);
6072 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6073 double factor = 1.00;
6074 if (g_pNavAidRadarRingsStepUnits == 1)
6076 else if (g_pNavAidRadarRingsStepUnits == 2) {
6077 if (std::isnan(gSog))
6082 factor *= g_fNavAidRadarRingsStep;
6086 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
6089 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6090 pow((
double)(lGPSPoint.m_y - r.y), 2));
6091 int pix_radius = (int)lpp;
6093 extern wxColor GetDimColor(wxColor c);
6094 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6096 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6099 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6101 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6102 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6106void ChartCanvas::ComputeShipScaleFactor(
6107 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6108 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6109 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6110 float screenResolution = m_pix_per_mm;
6113 double ship_bow_lat, ship_bow_lon;
6114 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6115 &ship_bow_lat, &ship_bow_lon);
6116 wxPoint lShipBowPoint;
6117 wxPoint2DDouble b_point =
6121 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6122 powf((
float)(b_point.m_y - a_point.m_y), 2));
6125 float shipLength_mm = shipLength_px / screenResolution;
6128 float ownship_min_mm = g_n_ownship_min_mm;
6129 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6132 float hdt_ant = icon_hdt + 180.;
6133 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6134 float dx = g_n_gps_antenna_offset_x / 1852.;
6135 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6143 if (shipLength_mm < ownship_min_mm) {
6144 dy /= shipLength_mm / ownship_min_mm;
6145 dx /= shipLength_mm / ownship_min_mm;
6148 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6150 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6151 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6157 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6158 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6160 float scale_factor = shipLength_px / ownShipLength;
6163 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6166 scale_factor = wxMax(scale_factor, scale_factor_min);
6168 scale_factor_y = scale_factor;
6169 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6170 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6173void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6174 if (!GetVP().IsValid())
return;
6176 wxPoint GPSOffsetPixels(0, 0);
6177 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6180 float pCog = std::isnan(gCog) ? 0 : gCog;
6181 float pSog = std::isnan(gSog) ? 0 : gSog;
6185 lShipMidPoint = lGPSPoint;
6189 float icon_hdt = pCog;
6190 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6193 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6197 double osd_head_lat, osd_head_lon;
6198 wxPoint osd_head_point;
6200 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6205 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6206 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6207 icon_rad += (float)PI;
6209 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6213 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6217 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6218 if (GetVP().chart_scale >
6221 ShipDrawLargeScale(dc, lShipMidPoint);
6227 if (m_pos_image_user)
6228 pos_image = m_pos_image_user->Copy();
6229 else if (SHIP_NORMAL == m_ownship_state)
6230 pos_image = m_pos_image_red->Copy();
6231 if (SHIP_LOWACCURACY == m_ownship_state)
6232 pos_image = m_pos_image_yellow->Copy();
6233 else if (SHIP_NORMAL != m_ownship_state)
6234 pos_image = m_pos_image_grey->Copy();
6237 if (m_pos_image_user) {
6238 pos_image = m_pos_image_user->Copy();
6240 if (SHIP_LOWACCURACY == m_ownship_state)
6241 pos_image = m_pos_image_user_yellow->Copy();
6242 else if (SHIP_NORMAL != m_ownship_state)
6243 pos_image = m_pos_image_user_grey->Copy();
6246 img_height = pos_image.GetHeight();
6248 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6249 g_OwnShipIconType > 0)
6251 int ownShipWidth = 22;
6252 int ownShipLength = 84;
6253 if (g_OwnShipIconType == 1) {
6254 ownShipWidth = pos_image.GetWidth();
6255 ownShipLength = pos_image.GetHeight();
6258 float scale_factor_x, scale_factor_y;
6259 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6260 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6261 scale_factor_x, scale_factor_y);
6263 if (g_OwnShipIconType == 1) {
6264 pos_image.Rescale(ownShipWidth * scale_factor_x,
6265 ownShipLength * scale_factor_y,
6266 wxIMAGE_QUALITY_HIGH);
6267 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6269 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6272 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6273 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6274 if (rot_image.GetAlpha(ip, jp) > 64)
6275 rot_image.SetAlpha(ip, jp, 255);
6277 wxBitmap os_bm(rot_image);
6279 int w = os_bm.GetWidth();
6280 int h = os_bm.GetHeight();
6283 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6284 lShipMidPoint.m_y - h / 2,
true);
6287 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6288 lShipMidPoint.m_y - h / 2);
6289 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6290 lShipMidPoint.m_y - h / 2 + h);
6293 else if (g_OwnShipIconType == 2) {
6294 wxPoint ownship_icon[10];
6296 for (
int i = 0; i < 10; i++) {
6298 float pxa = (float)(s_ownship_icon[j]);
6299 float pya = (float)(s_ownship_icon[j + 1]);
6300 pya *= scale_factor_y;
6301 pxa *= scale_factor_x;
6303 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6304 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6306 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6307 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6310 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6312 dc.SetBrush(wxBrush(ShipColor()));
6314 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6317 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6319 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6323 img_height = ownShipLength * scale_factor_y;
6327 if (m_pos_image_user) circle_rad = 1;
6329 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6330 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6331 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6334 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6336 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6339 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6340 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6341 if (rot_image.GetAlpha(ip, jp) > 64)
6342 rot_image.SetAlpha(ip, jp, 255);
6344 wxBitmap os_bm(rot_image);
6346 if (g_ShipScaleFactorExp > 1) {
6347 wxImage scaled_image = os_bm.ConvertToImage();
6348 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6350 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6351 scaled_image.GetHeight() * factor,
6352 wxIMAGE_QUALITY_HIGH));
6354 int w = os_bm.GetWidth();
6355 int h = os_bm.GetHeight();
6358 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6359 lShipMidPoint.m_y - h / 2,
true);
6363 if (m_pos_image_user) circle_rad = 1;
6365 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6366 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6367 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6370 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6371 lShipMidPoint.m_y - h / 2);
6372 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6373 lShipMidPoint.m_y - h / 2 + h);
6378 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6391void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6392 float &MinorSpacing) {
6397 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6398 {.000001f, 45.0f, 15.0f},
6399 {.0002f, 30.0f, 10.0f},
6400 {.0003f, 10.0f, 2.0f},
6401 {.0008f, 5.0f, 1.0f},
6402 {.001f, 2.0f, 30.0f / 60.0f},
6403 {.003f, 1.0f, 20.0f / 60.0f},
6404 {.006f, 0.5f, 10.0f / 60.0f},
6405 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6406 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6407 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6408 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6409 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6410 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6411 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6412 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6415 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6416 if (view_scale_ppm < lltab[tabi][0])
break;
6417 MajorSpacing = lltab[tabi][1];
6418 MinorSpacing = lltab[tabi][2];
6432wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6433 int deg = (int)fabs(latlon);
6434 float min = fabs((fabs(latlon) - deg) * 60.0);
6444 }
else if (latlon < 0.0) {
6456 if (spacing >= 1.0) {
6457 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6458 }
else if (spacing >= (1.0 / 60.0)) {
6459 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6461 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6478void ChartCanvas::GridDraw(
ocpnDC &dc) {
6479 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6481 double nlat, elon, slat, wlon;
6484 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6486 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6488 dc.SetFont(*m_pgridFont);
6489 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6492 h = m_canvas_height;
6503 dlon = dlon + 360.0;
6506 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6509 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6512 while (lat < nlat) {
6515 CalcGridText(lat, gridlatMajor,
true);
6517 dc.
DrawLine(0, r.y, w, r.y,
false);
6518 dc.DrawText(st, 0, r.y);
6519 lat = lat + gridlatMajor;
6521 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6525 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6528 while (lat < nlat) {
6531 dc.
DrawLine(0, r.y, 10, r.y,
false);
6532 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6533 lat = lat + gridlatMinor;
6537 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6540 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6543 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6545 wxString st = CalcGridText(lon, gridlonMajor,
false);
6547 dc.
DrawLine(r.x, 0, r.x, h,
false);
6548 dc.DrawText(st, r.x, 0);
6549 lon = lon + gridlonMajor;
6554 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6558 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6560 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6563 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6564 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6565 lon = lon + gridlonMinor;
6572void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6574 double blat, blon, tlat, tlon;
6577 int x_origin = m_bDisplayGrid ? 60 : 20;
6578 int y_origin = m_canvas_height - 50;
6584 if (GetVP().chart_scale > 80000)
6588 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6589 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6594 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6595 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6599 double rotation = -VPoint.
rotation;
6601 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6603 int l1 = (y_origin - r.y) / count;
6605 for (
int i = 0; i < count; i++) {
6612 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6615 double blat, blon, tlat, tlon;
6618 int chartbar_height = GetChartbarHeight();
6622 int y_origin = m_canvas_height - chartbar_height - 5;
6626 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6633 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6636 int unit = g_iDistanceFormat;
6638 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6639 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6642 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6643 float places = floor(logdist), rem = logdist - places;
6644 dist = pow(10, places);
6651 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6652 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6653 double rotation = -VPoint.
rotation;
6655 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6659 int l1 = r.x - x_origin;
6661 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6666 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6667 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6668 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6670 dc.SetFont(*m_pgridFont);
6671 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6673 dc.GetTextExtent(s, &w, &h);
6674 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6678void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6683 double ra_max = 40.;
6685 wxPen pen_save = dc.GetPen();
6687 wxDateTime now = wxDateTime::Now();
6693 x0 = x1 = x + radius;
6698 while (angle < 360.) {
6699 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6702 if (angle > 360.) angle = 360.;
6704 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6712 x1 = (int)(x + cos(angle * PI / 180.) * r);
6713 y1 = (int)(y + sin(angle * PI / 180.) * r);
6723 dc.
DrawLine(x + radius, y, x1, y1);
6725 dc.SetPen(pen_save);
6728static bool bAnchorSoundPlaying =
false;
6730static void onAnchorSoundFinished(
void *ptr) {
6731 g_anchorwatch_sound->UnLoad();
6732 bAnchorSoundPlaying =
false;
6735void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6737 bool play_sound =
false;
6738 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6739 if (AnchorAlertOn1) {
6740 wxPoint TargetPoint;
6743 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6744 TargetPoint.y, 100);
6748 AnchorAlertOn1 =
false;
6750 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6751 if (AnchorAlertOn2) {
6752 wxPoint TargetPoint;
6755 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6756 TargetPoint.y, 100);
6760 AnchorAlertOn2 =
false;
6763 if (!bAnchorSoundPlaying) {
6764 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6765 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6766 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6767 if (g_anchorwatch_sound->IsOk()) {
6768 bAnchorSoundPlaying =
true;
6769 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6770 g_anchorwatch_sound->Play();
6776void ChartCanvas::UpdateShips() {
6779 wxClientDC dc(
this);
6780 if (!dc.IsOk())
return;
6782 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6783 if (!test_bitmap.IsOk())
return;
6785 wxMemoryDC temp_dc(test_bitmap);
6787 temp_dc.ResetBoundingBox();
6788 temp_dc.DestroyClippingRegion();
6789 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6795 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6796 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6800 ocpndc.CalcBoundingBox(px.x, px.y);
6805 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6806 temp_dc.MaxY() - temp_dc.MinY());
6808 wxRect own_ship_update_rect = ship_draw_rect;
6810 if (!own_ship_update_rect.IsEmpty()) {
6813 own_ship_update_rect.Union(ship_draw_last_rect);
6814 own_ship_update_rect.Inflate(2);
6817 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6819 ship_draw_last_rect = ship_draw_rect;
6821 temp_dc.SelectObject(wxNullBitmap);
6824void ChartCanvas::UpdateAlerts() {
6829 wxClientDC dc(
this);
6833 dc.GetSize(&sx, &sy);
6836 wxBitmap test_bitmap(sx, sy, -1);
6840 temp_dc.SelectObject(test_bitmap);
6842 temp_dc.ResetBoundingBox();
6843 temp_dc.DestroyClippingRegion();
6844 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6851 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6852 temp_dc.MaxX() - temp_dc.MinX(),
6853 temp_dc.MaxY() - temp_dc.MinY());
6855 if (!alert_rect.IsEmpty())
6856 alert_rect.Inflate(2);
6858 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6861 wxRect alert_update_rect = alert_draw_rect;
6862 alert_update_rect.Union(alert_rect);
6865 RefreshRect(alert_update_rect,
false);
6869 alert_draw_rect = alert_rect;
6871 temp_dc.SelectObject(wxNullBitmap);
6874void ChartCanvas::UpdateAIS() {
6875 if (!g_pAIS)
return;
6880 wxClientDC dc(
this);
6884 dc.GetSize(&sx, &sy);
6892 if (g_pAIS->GetTargetList().size() > 10) {
6893 ais_rect = wxRect(0, 0, sx, sy);
6896 wxBitmap test_bitmap(sx, sy, -1);
6900 temp_dc.SelectObject(test_bitmap);
6902 temp_dc.ResetBoundingBox();
6903 temp_dc.DestroyClippingRegion();
6904 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6908 AISDraw(ocpndc, GetVP(),
this);
6909 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6913 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6914 temp_dc.MaxY() - temp_dc.MinY());
6916 if (!ais_rect.IsEmpty())
6917 ais_rect.Inflate(2);
6919 temp_dc.SelectObject(wxNullBitmap);
6922 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6925 wxRect ais_update_rect = ais_draw_rect;
6926 ais_update_rect.Union(ais_rect);
6929 RefreshRect(ais_update_rect,
false);
6933 ais_draw_rect = ais_rect;
6936void ChartCanvas::ToggleCPAWarn() {
6937 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6943 g_bTCPA_Max =
false;
6947 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6948 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6950 if (!g_AisFirstTimeUse) {
6951 OCPNMessageBox(
this,
6952 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
6953 _(
"CPA") + _T(
" ") + mess, 4, 4);
6958void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6960void ChartCanvas::OnSize(wxSizeEvent &event) {
6961 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6963 GetClientSize(&m_canvas_width, &m_canvas_height);
6967 m_displayScale = GetContentScaleFactor();
6971 m_canvas_width *= m_displayScale;
6972 m_canvas_height *= m_displayScale;
6985 m_absolute_min_scale_ppm =
6987 (1.2 * WGS84_semimajor_axis_meters * PI);
6990 gFrame->ProcessCanvasResize();
7000 SetMUIBarPosition();
7001 UpdateFollowButtonState();
7002 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7006 xr_margin = m_canvas_width * 95 / 100;
7007 xl_margin = m_canvas_width * 5 / 100;
7008 yt_margin = m_canvas_height * 5 / 100;
7009 yb_margin = m_canvas_height * 95 / 100;
7012 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7017 m_brepaint_piano =
true;
7020 m_dc_route.SelectObject(wxNullBitmap);
7023 m_dc_route.SelectObject(*proute_bm);
7037 m_glcc->OnSize(event);
7046void ChartCanvas::ProcessNewGUIScale() {
7054void ChartCanvas::CreateMUIBar() {
7055 if (g_useMUI && !m_muiBar) {
7059 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
7061 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7062 m_muiBar->SetColorScheme(m_cs);
7063 m_muiBarHOSize = m_muiBar->m_size;
7067 SetMUIBarPosition();
7068 UpdateFollowButtonState();
7069 m_muiBar->UpdateDynamicValues();
7070 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7074void ChartCanvas::SetMUIBarPosition() {
7078 int pianoWidth = GetClientSize().x * 0.6f;
7083 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7084 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7086 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7087 m_muiBar->SetColorScheme(m_cs);
7091 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7092 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7094 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7095 m_muiBar->SetColorScheme(m_cs);
7099 m_muiBar->SetBestPosition();
7103void ChartCanvas::DestroyMuiBar() {
7110void ChartCanvas::ShowCompositeInfoWindow(
7111 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7113 if (NULL == m_pCIWin) {
7118 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7121 s = _(
"Composite of ");
7124 s1.Printf(
"%d ", n_charts);
7132 s1.Printf(_(
"Chart scale"));
7135 s2.Printf(
"1:%d\n",
scale);
7139 s1 = _(
"Zoom in for more information");
7143 int char_width = s1.Length();
7144 int char_height = 3;
7146 if (g_bChartBarEx) {
7149 for (
int i : index_vector) {
7151 wxString path = cte.GetFullSystemPath();
7155 char_width = wxMax(char_width, path.Length());
7156 if (j++ >= 9)
break;
7159 s +=
" .\n .\n .\n";
7168 m_pCIWin->SetString(s);
7170 m_pCIWin->FitToChars(char_width, char_height);
7173 p.x = x / GetContentScaleFactor();
7174 if ((p.x + m_pCIWin->GetWinSize().x) >
7175 (m_canvas_width / GetContentScaleFactor()))
7176 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7177 m_pCIWin->GetWinSize().x) /
7180 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7181 4 - m_pCIWin->GetWinSize().y;
7183 m_pCIWin->dbIndex = 0;
7184 m_pCIWin->chart_scale = 0;
7185 m_pCIWin->SetPosition(p);
7186 m_pCIWin->SetBitmap();
7187 m_pCIWin->Refresh();
7191 HideChartInfoWindow();
7195void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7197 if (NULL == m_pCIWin) {
7202 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7209 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
7210 pc = ChartData->OpenChartFromDBAndLock(
7211 dbIndex, FULL_INIT);
7213 int char_width, char_height;
7214 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7215 if (pc) ChartData->UnLockCacheChart(dbIndex);
7217 m_pCIWin->SetString(s);
7218 m_pCIWin->FitToChars(char_width, char_height);
7221 p.x = x / GetContentScaleFactor();
7222 if ((p.x + m_pCIWin->GetWinSize().x) >
7223 (m_canvas_width / GetContentScaleFactor()))
7224 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7225 m_pCIWin->GetWinSize().x) /
7228 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7229 4 - m_pCIWin->GetWinSize().y;
7231 m_pCIWin->dbIndex = dbIndex;
7232 m_pCIWin->SetPosition(p);
7233 m_pCIWin->SetBitmap();
7234 m_pCIWin->Refresh();
7238 HideChartInfoWindow();
7242void ChartCanvas::HideChartInfoWindow(
void) {
7245 m_pCIWin->Destroy();
7249 androidForceFullRepaint();
7254void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7255 wxMouseEvent ev(wxEVT_MOTION);
7258 ev.m_leftDown = mouse_leftisdown;
7260 wxEvtHandler *evthp = GetEventHandler();
7262 ::wxPostEvent(evthp, ev);
7265void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7266 if ((m_panx_target_final - m_panx_target_now) ||
7267 (m_pany_target_final - m_pany_target_now)) {
7268 DoTimedMovementTarget();
7273void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7275bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7277 if (m_disable_edge_pan)
return false;
7280 int pan_margin = m_canvas_width * margin / 100;
7281 int pan_timer_set = 200;
7282 double pan_delta = GetVP().
pix_width * delta / 100;
7286 if (x > m_canvas_width - pan_margin) {
7291 else if (x < pan_margin) {
7296 if (y < pan_margin) {
7301 else if (y > m_canvas_height - pan_margin) {
7310 wxMouseState state = ::wxGetMouseState();
7311#if wxCHECK_VERSION(3, 0, 0)
7312 if (!state.LeftIsDown())
7314 if (!state.LeftDown())
7319 if ((bft) && !pPanTimer->IsRunning()) {
7321 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7327 if ((!bft) && pPanTimer->IsRunning()) {
7337void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7338 bool setBeingEdited) {
7339 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7340 m_pRoutePointEditTarget = NULL;
7341 m_pFoundPoint = NULL;
7345 SelectableItemList SelList = pSelect->FindSelectionList(
7347 wxSelectableItemListNode *node = SelList.GetFirst();
7349 pFind = node->GetData();
7354 m_pEditRouteArray = g_pRouteMan->GetRouteArrayContaining(frp);
7357 bool brp_viz =
false;
7358 if (m_pEditRouteArray) {
7359 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7360 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7361 if (pr->IsVisible()) {
7367 brp_viz = frp->IsVisible();
7371 if (m_pEditRouteArray)
7373 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7374 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7375 pr->m_bIsBeingEdited = setBeingEdited;
7377 m_bRouteEditing = setBeingEdited;
7380 frp->m_bRPIsBeingEdited = setBeingEdited;
7381 m_bMarkEditing = setBeingEdited;
7384 m_pRoutePointEditTarget = frp;
7385 m_pFoundPoint = pFind;
7389 node = node->GetNext();
7393void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7394 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7395 singleClickEventIsValid =
false;
7396 m_DoubleClickTimer->Stop();
7401bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7402 if (!m_bChartDragging && !m_bDrawingRoute) {
7408 bool isInCompass = m_Compass && m_Compass->IsShown() &&
7409 logicalRect.Contains(event.GetPosition());
7411 if (m_Compass->MouseEvent(event)) {
7412 cursor_region = CENTER;
7413 if (!g_btouch) SetCanvasCursor(event);
7418 if (MouseEventToolbar(event))
return true;
7420 if (MouseEventChartBar(event))
return true;
7422 if (MouseEventMUIBar(event))
return true;
7424 if (MouseEventIENCBar(event))
return true;
7429bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7430 if (!g_bShowChartBar)
return false;
7432 if (!m_Piano->MouseEvent(event))
return false;
7434 cursor_region = CENTER;
7435 if (!g_btouch) SetCanvasCursor(event);
7439bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7440 if (!IsPrimaryCanvas())
return false;
7442 if (g_MainToolbar) {
7443 if (!g_MainToolbar->MouseEvent(event))
7446 g_MainToolbar->RefreshToolbar();
7449 cursor_region = CENTER;
7450 if (!g_btouch) SetCanvasCursor(event);
7454bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7455 if (!IsPrimaryCanvas())
return false;
7457 if (g_iENCToolbar) {
7458 if (!g_iENCToolbar->MouseEvent(event))
7461 g_iENCToolbar->RefreshToolbar();
7468bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7470 if (!m_muiBar->MouseEvent(event))
return false;
7473 cursor_region = CENTER;
7474 if (!g_btouch) SetCanvasCursor(event);
7486 event.GetPosition(&x, &y);
7488 x *= m_displayScale;
7489 y *= m_displayScale;
7491 m_MouseDragging =
event.Dragging();
7497 if (event.Dragging()) {
7498 if ((x == mouse_x) && (y == mouse_y))
return true;
7504 mouse_leftisdown =
event.LeftDown();
7508 cursor_region = CENTER;
7510 int chartbar_height = GetChartbarHeight();
7512 if (m_Compass && m_Compass->IsShown() &&
7513 m_Compass->
GetRect().Contains(event.GetPosition())) {
7514 cursor_region = CENTER;
7515 }
else if (x > xr_margin) {
7516 cursor_region = MID_RIGHT;
7517 }
else if (x < xl_margin) {
7518 cursor_region = MID_LEFT;
7519 }
else if (y > yb_margin - chartbar_height &&
7520 y < m_canvas_height - chartbar_height) {
7521 cursor_region = MID_TOP;
7522 }
else if (y < yt_margin) {
7523 cursor_region = MID_BOT;
7525 cursor_region = CENTER;
7528 if (!g_btouch) SetCanvasCursor(event);
7532 leftIsDown =
event.LeftDown();
7535 if (event.LeftDown()) {
7536 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7539 g_bTempShowMenuBar =
false;
7540 parent_frame->ApplyGlobalSettings(
false);
7548 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7549 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7553 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7554 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7557 event.SetEventObject(
this);
7558 if (SendMouseEventToPlugins(event))
7565 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7566 StartChartDragInertia();
7569 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7571 if (m_DoubleClickTimer->IsRunning()) {
7572 m_DoubleClickTimer->Stop();
7577 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7578 singleClickEvent = event;
7579 singleClickEventIsValid =
true;
7588 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7589 if (g_click_stop > 0) {
7597 if (GetUpMode() == COURSE_UP_MODE) {
7598 m_b_rot_hidef =
false;
7599 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7601 pRotDefTimer->Stop();
7604 bool bRoll = !g_btouch;
7606 bRoll = g_bRollover;
7609 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7610 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7611 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7612 m_RolloverPopupTimer.Start(
7616 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7620 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7629#if !defined(__WXGTK__) && !defined(__WXQT__)
7637 if ((x >= 0) && (y >= 0))
7642 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7643 wxPoint p = ClientToScreen(wxPoint(x, y));
7649 if (m_routeState >= 2) {
7652 m_bDrawingRoute =
true;
7654 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7659 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7662 m_bDrawingRoute =
true;
7664 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7671void ChartCanvas::CallPopupMenu(
int x,
int y) {
7679 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7688#if defined(__WXMAC__) || defined(__ANDROID__)
7692 wxClientDC cdc(GetParent());
7704 if (m_pSelectedRoute) {
7705 m_pSelectedRoute->m_bRtIsSelected =
false;
7706 m_pSelectedRoute->DeSelectRoute();
7708 if (g_bopengl && m_glcc) {
7713 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7716 if (m_pFoundRoutePoint) {
7717 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7719 RefreshRect(m_pFoundRoutePoint->CurrentRect_in_DC);
7724 if (g_btouch && m_pRoutePointEditTarget) {
7725 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7726 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7727 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7732 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7733 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7734 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7735 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7739 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7742 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7748 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7751 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7752 seltype |= SELTYPE_AISTARGET;
7757 m_pFoundRoutePoint = NULL;
7762 Route *pSelectedActiveRoute = NULL;
7763 Route *pSelectedVizRoute = NULL;
7767 SelectableItemList SelList =
7768 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7769 wxSelectableItemListNode *node = SelList.GetFirst();
7776 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(prp);
7779 bool brp_viz =
false;
7781 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7783 if (pr->IsVisible()) {
7788 if (!brp_viz && prp->IsShared())
7790 brp_viz = prp->IsVisible();
7793 brp_viz = prp->IsVisible();
7795 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7800 m_pSelectedRoute = NULL;
7802 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7804 if (pr->m_bRtIsActive) {
7805 pSelectedActiveRoute = pr;
7806 pFoundActiveRoutePoint = prp;
7811 if (NULL == pSelectedVizRoute) {
7812 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7814 if (pr->IsVisible()) {
7815 pSelectedVizRoute = pr;
7816 pFoundVizRoutePoint = prp;
7822 delete proute_array;
7825 node = node->GetNext();
7829 if (pFoundActiveRoutePoint) {
7830 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7831 m_pSelectedRoute = pSelectedActiveRoute;
7832 }
else if (pFoundVizRoutePoint) {
7833 m_pFoundRoutePoint = pFoundVizRoutePoint;
7834 m_pSelectedRoute = pSelectedVizRoute;
7837 m_pFoundRoutePoint = pFirstVizPoint;
7839 if (m_pSelectedRoute) {
7840 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7841 }
else if (m_pFoundRoutePoint)
7842 seltype |= SELTYPE_MARKPOINT;
7846 if (m_pFoundRoutePoint) {
7847 m_pFoundRoutePoint->m_bPtIsSelected =
true;
7850 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7851 RefreshRect(wp_rect,
true);
7860 SelectableItemList SelList =
7861 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7863 if (NULL == m_pSelectedRoute)
7866 wxSelectableItemListNode *node = SelList.GetFirst();
7871 if (pr->IsVisible()) {
7872 m_pSelectedRoute = pr;
7875 node = node->GetNext();
7879 if (m_pSelectedRoute) {
7880 if (NULL == m_pFoundRoutePoint)
7881 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7883 m_pSelectedRoute->m_bRtIsSelected = !(seltype & SELTYPE_ROUTEPOINT);
7884 if (m_pSelectedRoute->m_bRtIsSelected) {
7886 if (g_bopengl && m_glcc) {
7891 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7894 seltype |= SELTYPE_ROUTESEGMENT;
7898 if (pFindTrackSeg) {
7899 m_pSelectedTrack = NULL;
7901 SelectableItemList SelList =
7902 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7905 wxSelectableItemListNode *node = SelList.GetFirst();
7910 if (pt->IsVisible()) {
7911 m_pSelectedTrack = pt;
7914 node = node->GetNext();
7917 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7920 bool bseltc =
false;
7934 SelectableItemList SelList = pSelectTC->FindSelectionList(
7938 wxSelectableItemListNode *node = SelList.GetFirst();
7939 pFind = node->GetData();
7940 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7942 if (SelList.GetCount() > 1) {
7943 node = node->GetNext();
7945 pFind = node->GetData();
7947 if (pIDX_candidate->
IDX_type ==
'c') {
7948 pIDX_best_candidate = pIDX_candidate;
7952 node = node->GetNext();
7955 wxSelectableItemListNode *node = SelList.GetFirst();
7956 pFind = node->GetData();
7957 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7960 m_pIDXCandidate = pIDX_best_candidate;
7963 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
7967 seltype |= SELTYPE_CURRENTPOINT;
7970 else if (pFindTide) {
7971 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7974 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
7978 seltype |= SELTYPE_TIDEPOINT;
7982 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7985 InvokeCanvasMenu(x, y, seltype);
7988 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
7989 m_pSelectedRoute->m_bRtIsSelected =
false;
7992 m_pSelectedRoute = NULL;
7994 if (m_pFoundRoutePoint) {
7995 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
7996 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7998 m_pFoundRoutePoint = NULL;
8006bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8014 event.GetPosition(&x, &y);
8020 SelectRadius = g_Platform->GetSelectRadiusPix() /
8021 (m_true_scale_ppm * 1852 * 60);
8028 if (event.LeftDClick() && (cursor_region == CENTER)) {
8029 m_DoubleClickTimer->Start();
8030 singleClickEventIsValid =
false;
8034 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8039 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8042 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8043 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8044 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8050 SelectableItemList rpSelList =
8051 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8052 wxSelectableItemListNode *node = rpSelList.GetFirst();
8053 bool b_onRPtarget =
false;
8057 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8058 b_onRPtarget =
true;
8061 node = node->GetNext();
8066 if (m_pRoutePointEditTarget) {
8068 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8071 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8072 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8074 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8077 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8078 m_pRoutePointEditTarget = NULL;
8079 RefreshRect(wp_rect,
true);
8083 node = rpSelList.GetFirst();
8088 wxArrayPtrVoid *proute_array =
8089 g_pRouteMan->GetRouteArrayContaining(frp);
8093 bool brp_viz =
false;
8095 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8097 if (pr->IsVisible()) {
8105 brp_viz = frp->IsVisible();
8107 brp_viz = frp->IsVisible();
8110 ShowMarkPropertiesDialog(frp);
8118 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8122 if (pr->IsVisible()) {
8123 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8128 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8132 if (pt->IsVisible()) {
8133 ShowTrackPropertiesDialog(pt);
8140 ShowObjectQueryWindow(x, y, zlat, zlon);
8145 if (event.LeftDown()) {
8161 bool appending =
false;
8162 bool inserting =
false;
8165 SetCursor(*pCursorPencil);
8169 m_bRouteEditing =
true;
8171 if (m_routeState == 1) {
8172 m_pMouseRoute =
new Route();
8173 pRouteList->Append(m_pMouseRoute);
8182 double nearby_radius_meters =
8183 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8186 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8187 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8188 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8189 wxArrayPtrVoid *proute_array =
8190 g_pRouteMan->GetRouteArrayContaining(pNearbyPoint);
8194 bool brp_viz =
false;
8196 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8198 if (pr->IsVisible()) {
8204 pNearbyPoint->IsShared())
8207 pNearbyPoint->IsVisible();
8209 brp_viz = pNearbyPoint->IsVisible();
8212 wxString msg = _(
"Use nearby waypoint?");
8214 const bool noname(pNearbyPoint->GetName() ==
"");
8217 _(
"Use nearby nameless waypoint and name it M with"
8218 " a unique number?");
8221 m_FinishRouteOnKillFocus =
false;
8223 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8224 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8225 m_FinishRouteOnKillFocus =
true;
8226 if (dlg_return == wxID_YES) {
8228 if (m_pMouseRoute) {
8229 int last_wp_num = m_pMouseRoute->GetnPoints();
8231 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8232 wxString wp_name = wxString::Format(
8233 "M%002i-%s", last_wp_num + 1, guid_short);
8234 pNearbyPoint->SetName(wp_name);
8236 pNearbyPoint->SetName(
"WPXX");
8238 pMousePoint = pNearbyPoint;
8241 if (m_routeState > 1)
8242 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8243 Undo_HasParent, NULL);
8246 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8247 bool procede =
false;
8251 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8257 m_FinishRouteOnKillFocus =
false;
8263 _(
"Insert first part of this route in the new route?");
8264 if (tail->GetIndexOf(pMousePoint) ==
8267 dmsg = _(
"Insert this route in the new route?");
8269 if (tail->GetIndexOf(pMousePoint) != 1) {
8270 dlg_return = OCPNMessageBox(
8271 this, dmsg, _(
"OpenCPN Route Create"),
8272 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8273 m_FinishRouteOnKillFocus =
true;
8275 if (dlg_return == wxID_YES) {
8282 _(
"Append last part of this route to the new route?");
8283 if (tail->GetIndexOf(pMousePoint) == 1)
8285 "Append this route to the new route?");
8290 if (tail->GetLastPoint() != pMousePoint) {
8291 dlg_return = OCPNMessageBox(
8292 this, dmsg, _(
"OpenCPN Route Create"),
8293 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8294 m_FinishRouteOnKillFocus =
true;
8296 if (dlg_return == wxID_YES) {
8307 if (!FindRouteContainingWaypoint(pMousePoint))
8308 pMousePoint->SetShared(
true);
8313 if (NULL == pMousePoint) {
8314 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8315 _T(
""), wxEmptyString);
8316 pMousePoint->SetNameShown(
false);
8318 pConfig->AddNewWayPoint(pMousePoint, -1);
8319 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8321 if (m_routeState > 1)
8322 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8323 Undo_IsOrphanded, NULL);
8326 if (m_pMouseRoute) {
8327 if (m_routeState == 1) {
8329 m_pMouseRoute->AddPoint(pMousePoint);
8331 if (m_pMouseRoute->m_NextLegGreatCircle) {
8332 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8333 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8334 &rhumbBearing, &rhumbDist);
8335 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8336 rlat, &gcDist, &gcBearing, NULL);
8337 double gcDistNM = gcDist / 1852.0;
8340 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8341 pow(rhumbDist - gcDistNM - 1, 0.5);
8344 msg << _(
"For this leg the Great Circle route is ")
8345 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8346 << _(
" shorter than rhumbline.\n\n")
8347 << _(
"Would you like include the Great Circle routing points "
8350 m_FinishRouteOnKillFocus =
false;
8351 m_disable_edge_pan =
true;
8354 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8355 wxYES_NO | wxNO_DEFAULT);
8357 m_disable_edge_pan =
false;
8358 m_FinishRouteOnKillFocus =
true;
8360 if (answer == wxID_YES) {
8362 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8363 wxRealPoint gcCoord;
8365 for (
int i = 1; i <= segmentCount; i++) {
8366 double fraction = (double)i * (1.0 / (
double)segmentCount);
8367 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8368 gcDist * fraction, gcBearing,
8369 &gcCoord.x, &gcCoord.y, NULL);
8371 if (i < segmentCount) {
8372 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8373 _T(
""), wxEmptyString);
8374 gcPoint->SetNameShown(
false);
8375 pConfig->AddNewWayPoint(gcPoint, -1);
8376 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8379 gcPoint = pMousePoint;
8382 m_pMouseRoute->AddPoint(gcPoint);
8383 pSelect->AddSelectableRouteSegment(
8384 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8385 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8386 prevGcPoint = gcPoint;
8389 undo->CancelUndoableAction(
true);
8392 m_pMouseRoute->AddPoint(pMousePoint);
8393 pSelect->AddSelectableRouteSegment(
8394 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8395 pMousePoint, m_pMouseRoute);
8396 undo->AfterUndoableAction(m_pMouseRoute);
8400 m_pMouseRoute->AddPoint(pMousePoint);
8401 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8402 rlon, m_prev_pMousePoint,
8403 pMousePoint, m_pMouseRoute);
8404 undo->AfterUndoableAction(m_pMouseRoute);
8410 m_prev_pMousePoint = pMousePoint;
8412 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
8418 int connect = tail->GetIndexOf(pMousePoint);
8423 int length = tail->GetnPoints();
8428 start = connect + 1;
8433 m_pMouseRoute->RemovePoint(
8437 for (i = start; i <= stop; i++) {
8438 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8440 m_pMouseRoute->m_lastMousePointIndex =
8441 m_pMouseRoute->GetnPoints();
8443 gFrame->RefreshAllCanvas();
8447 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8449 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8450 m_pMouseRoute->FinalizeForRendering();
8452 gFrame->RefreshAllCanvas();
8456 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8458 SetCursor(*pCursorPencil);
8460 if (!m_pMeasureRoute) {
8461 m_pMeasureRoute =
new Route();
8462 pRouteList->Append(m_pMeasureRoute);
8465 if (m_nMeasureState == 1) {
8471 wxString(_T (
"circle" )),
8472 wxEmptyString, wxEmptyString);
8473 pMousePoint->m_bShowName =
false;
8474 pMousePoint->SetShowWaypointRangeRings(
false);
8476 m_pMeasureRoute->AddPoint(pMousePoint);
8480 m_prev_pMousePoint = pMousePoint;
8481 m_pMeasureRoute->m_lastMousePointIndex = m_pMeasureRoute->GetnPoints();
8484 gFrame->RefreshAllCanvas();
8489 FindRoutePointsAtCursor(SelectRadius,
true);
8494 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8502 if (ret)
return true;
8505 if (event.Dragging()) {
8510 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8512 SelectableItemList SelList = pSelect->FindSelectionList(
8514 wxSelectableItemListNode *node = SelList.GetFirst();
8516 pFind = node->GetData();
8518 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8519 node = node->GetNext();
8524 if (m_pRoutePointEditTarget &&
8525 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8527 SelectableItemList SelList = pSelect->FindSelectionList(
8529 wxSelectableItemListNode *node = SelList.GetFirst();
8531 pFind = node->GetData();
8533 if (m_pRoutePointEditTarget == frp) {
8534 m_bIsInRadius =
true;
8537 node = node->GetNext();
8540 if (!m_dragoffsetSet) {
8542 .PresetDragOffset(
this, mouse_x, mouse_y);
8543 m_dragoffsetSet =
true;
8548 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8549 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8551 if (NULL == g_pMarkInfoDialog) {
8552 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8553 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8554 DraggingAllowed =
false;
8556 if (m_pRoutePointEditTarget &&
8557 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8558 DraggingAllowed =
false;
8560 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8562 if (DraggingAllowed) {
8563 if (!undo->InUndoableAction()) {
8564 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8565 Undo_NeedsCopy, m_pFoundPoint);
8571 if (!g_bopengl && m_pEditRouteArray) {
8572 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8573 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8578 if (g_pRouteMan->IsRouteValid(pr)) {
8580 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8581 pre_rect.Union(route_rect);
8589 if (CheckEdgePan(x, y,
true, 5, 2))
8597 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8599 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8600 m_pRoutePointEditTarget,
8601 SELTYPE_DRAGHANDLE);
8602 m_pFoundPoint->m_slat =
8603 m_pRoutePointEditTarget->m_lat;
8604 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8606 m_pRoutePointEditTarget->m_lat =
8608 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8609 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8610 m_pFoundPoint->m_slat =
8612 m_pFoundPoint->m_slon = new_cursor_lon;
8616 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8617 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8618 g_pMarkInfoDialog->UpdateProperties(
true);
8628 if (m_pEditRouteArray) {
8629 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8631 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8632 if (g_pRouteMan->IsRouteValid(pr)) {
8634 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8635 post_rect.Union(route_rect);
8641 pre_rect.Union(post_rect);
8642 RefreshRect(pre_rect,
false);
8644 gFrame->RefreshCanvasOther(
this);
8645 m_bRoutePoinDragging =
true;
8650 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8651 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8653 if (NULL == g_pMarkInfoDialog) {
8654 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8655 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8656 DraggingAllowed =
false;
8658 if (m_pRoutePointEditTarget &&
8659 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8660 DraggingAllowed =
false;
8662 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8664 if (DraggingAllowed) {
8665 if (!undo->InUndoableAction()) {
8666 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8667 Undo_NeedsCopy, m_pFoundPoint);
8675 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8676 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8678 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8679 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8681 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8687 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8688 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8689 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8690 (
int)(lppmax - (pre_rect.height / 2)));
8698 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8701 m_pRoutePointEditTarget,
8702 SELTYPE_DRAGHANDLE);
8703 m_pFoundPoint->m_slat =
8704 m_pRoutePointEditTarget->m_lat;
8705 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8707 m_pRoutePointEditTarget->m_lat =
8710 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8716 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8717 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8718 g_pMarkInfoDialog->UpdateProperties(
true);
8723 if (!g_btouch) InvalidateGL();
8729 .CalculateDCRect(m_dc_route,
this, &post_rect);
8730 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8731 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8732 (
int)(lppmax - (post_rect.height / 2)));
8735 pre_rect.Union(post_rect);
8736 RefreshRect(pre_rect,
false);
8738 gFrame->RefreshCanvasOther(
this);
8739 m_bRoutePoinDragging =
true;
8744 if (ret)
return true;
8747 if (event.LeftUp()) {
8748 bool b_startedit_route =
false;
8749 m_dragoffsetSet =
false;
8752 m_bChartDragging =
false;
8753 m_bIsInRadius =
false;
8758 m_bedge_pan =
false;
8763 bool appending =
false;
8764 bool inserting =
false;
8770 if (m_pRoutePointEditTarget) {
8771 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8772 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8776 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8777 RefreshRect(wp_rect,
true);
8779 m_pRoutePointEditTarget = NULL;
8781 m_bRouteEditing =
true;
8783 if (m_routeState == 1) {
8784 m_pMouseRoute =
new Route();
8785 m_pMouseRoute->SetHiLite(50);
8786 pRouteList->Append(m_pMouseRoute);
8795 double nearby_radius_meters =
8796 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8799 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8800 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8801 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8804 m_FinishRouteOnKillFocus =
8806 dlg_return = OCPNMessageBox(
8807 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8808 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8809 m_FinishRouteOnKillFocus =
true;
8811 dlg_return = wxID_YES;
8813 if (dlg_return == wxID_YES) {
8814 pMousePoint = pNearbyPoint;
8817 if (m_routeState > 1)
8818 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8819 Undo_HasParent, NULL);
8820 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8822 bool procede =
false;
8826 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8832 m_FinishRouteOnKillFocus =
false;
8833 if (m_routeState == 1) {
8837 _(
"Insert first part of this route in the new route?");
8838 if (tail->GetIndexOf(pMousePoint) ==
8841 dmsg = _(
"Insert this route in the new route?");
8843 if (tail->GetIndexOf(pMousePoint) != 1) {
8845 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8846 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8847 m_FinishRouteOnKillFocus =
true;
8849 if (dlg_return == wxID_YES) {
8856 _(
"Append last part of this route to the new route?");
8857 if (tail->GetIndexOf(pMousePoint) == 1)
8859 "Append this route to the new route?");
8863 if (tail->GetLastPoint() != pMousePoint) {
8865 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8866 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8867 m_FinishRouteOnKillFocus =
true;
8869 if (dlg_return == wxID_YES) {
8880 if (!FindRouteContainingWaypoint(pMousePoint))
8881 pMousePoint->SetShared(
true);
8885 if (NULL == pMousePoint) {
8886 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8887 _T(
""), wxEmptyString);
8888 pMousePoint->SetNameShown(
false);
8890 pConfig->AddNewWayPoint(pMousePoint, -1);
8891 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8893 if (m_routeState > 1)
8894 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8895 Undo_IsOrphanded, NULL);
8898 if (m_routeState == 1) {
8900 m_pMouseRoute->AddPoint(pMousePoint);
8902 if (m_pMouseRoute->m_NextLegGreatCircle) {
8903 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8904 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8905 &rhumbBearing, &rhumbDist);
8906 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
8907 &gcDist, &gcBearing, NULL);
8908 double gcDistNM = gcDist / 1852.0;
8911 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8912 pow(rhumbDist - gcDistNM - 1, 0.5);
8915 msg << _(
"For this leg the Great Circle route is ")
8916 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8917 << _(
" shorter than rhumbline.\n\n")
8918 << _(
"Would you like include the Great Circle routing points "
8922 m_FinishRouteOnKillFocus =
false;
8923 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8924 wxYES_NO | wxNO_DEFAULT);
8925 m_FinishRouteOnKillFocus =
true;
8927 int answer = wxID_NO;
8930 if (answer == wxID_YES) {
8932 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8933 wxRealPoint gcCoord;
8935 for (
int i = 1; i <= segmentCount; i++) {
8936 double fraction = (double)i * (1.0 / (
double)segmentCount);
8937 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8938 gcDist * fraction, gcBearing,
8939 &gcCoord.x, &gcCoord.y, NULL);
8941 if (i < segmentCount) {
8942 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8943 _T(
""), wxEmptyString);
8944 gcPoint->SetNameShown(
false);
8945 pConfig->AddNewWayPoint(gcPoint, -1);
8946 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8949 gcPoint = pMousePoint;
8952 m_pMouseRoute->AddPoint(gcPoint);
8953 pSelect->AddSelectableRouteSegment(
8954 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8955 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8956 prevGcPoint = gcPoint;
8959 undo->CancelUndoableAction(
true);
8962 m_pMouseRoute->AddPoint(pMousePoint);
8963 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8964 rlon, m_prev_pMousePoint,
8965 pMousePoint, m_pMouseRoute);
8966 undo->AfterUndoableAction(m_pMouseRoute);
8970 m_pMouseRoute->AddPoint(pMousePoint);
8971 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8972 rlon, m_prev_pMousePoint,
8973 pMousePoint, m_pMouseRoute);
8974 undo->AfterUndoableAction(m_pMouseRoute);
8980 m_prev_pMousePoint = pMousePoint;
8981 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
8987 int connect = tail->GetIndexOf(pMousePoint);
8992 int length = tail->GetnPoints();
8997 start = connect + 1;
9002 m_pMouseRoute->RemovePoint(
9006 for (i = start; i <= stop; i++) {
9007 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9009 m_pMouseRoute->m_lastMousePointIndex =
9010 m_pMouseRoute->GetnPoints();
9012 gFrame->RefreshAllCanvas();
9016 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9018 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9019 m_pMouseRoute->FinalizeForRendering();
9024 }
else if (m_bMeasure_Active && m_nMeasureState)
9027 m_bedge_pan =
false;
9031 if (m_nMeasureState == 1) {
9032 m_pMeasureRoute =
new Route();
9033 pRouteList->Append(m_pMeasureRoute);
9038 if (m_pMeasureRoute) {
9041 wxEmptyString, wxEmptyString);
9042 pMousePoint->m_bShowName =
false;
9044 m_pMeasureRoute->AddPoint(pMousePoint);
9048 m_prev_pMousePoint = pMousePoint;
9049 m_pMeasureRoute->m_lastMousePointIndex =
9050 m_pMeasureRoute->GetnPoints();
9054 CancelMeasureRoute();
9060 bool bSelectAllowed =
true;
9061 if (NULL == g_pMarkInfoDialog) {
9062 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9063 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9064 bSelectAllowed =
false;
9071 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9073 if (bSelectAllowed) {
9074 bool b_was_editing_mark = m_bMarkEditing;
9075 bool b_was_editing_route = m_bRouteEditing;
9076 FindRoutePointsAtCursor(SelectRadius,
9082 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->m_bIsInLayer)
9083 m_pRoutePointEditTarget = NULL;
9085 if (!b_was_editing_route) {
9086 if (m_pEditRouteArray) {
9087 b_startedit_route =
true;
9091 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9092 m_pTrackRolloverWin->IsActive(
false);
9094 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9095 m_pRouteRolloverWin->IsActive(
false);
9099 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9101 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9106 if (g_pRouteMan->IsRouteValid(pr)) {
9109 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9110 pre_rect.Union(route_rect);
9113 RefreshRect(pre_rect,
true);
9116 b_startedit_route =
false;
9120 if (m_pRoutePointEditTarget) {
9121 if (b_was_editing_mark ||
9122 b_was_editing_route) {
9123 if (m_lastRoutePointEditTarget) {
9124 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9125 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9127 .EnableDragHandle(
false);
9128 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9129 SELTYPE_DRAGHANDLE);
9133 if (m_pRoutePointEditTarget) {
9134 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
true;
9135 m_pRoutePointEditTarget->m_bPtIsSelected =
true;
9136 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9137 wxPoint2DDouble dragHandlePoint =
9139 .GetDragHandlePoint(
this);
9140 pSelect->AddSelectablePoint(
9141 dragHandlePoint.m_y, dragHandlePoint.m_x,
9142 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9145 if (m_lastRoutePointEditTarget) {
9146 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9147 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9149 .EnableDragHandle(
false);
9150 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9151 SELTYPE_DRAGHANDLE);
9154 wxArrayPtrVoid *lastEditRouteArray =
9155 g_pRouteMan->GetRouteArrayContaining(
9156 m_lastRoutePointEditTarget);
9157 if (lastEditRouteArray) {
9158 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9160 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9161 if (g_pRouteMan->IsRouteValid(pr)) {
9162 pr->m_bIsBeingEdited =
false;
9175 if (m_lastRoutePointEditTarget) {
9178 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9179 RefreshRect(wp_rect,
true);
9182 if (m_pRoutePointEditTarget) {
9185 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9186 RefreshRect(wp_rect,
true);
9195 bool b_start_rollover =
false;
9196 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9197 SelectItem *pFind = pSelectAIS->FindSelection(
9199 if (pFind) b_start_rollover =
true;
9202 if (!b_start_rollover && !b_startedit_route) {
9203 SelectableItemList SelList = pSelect->FindSelectionList(
9205 wxSelectableItemListNode *node = SelList.GetFirst();
9211 if (pr && pr->IsVisible()) {
9212 b_start_rollover =
true;
9215 node = node->GetNext();
9219 if (!b_start_rollover && !b_startedit_route) {
9220 SelectableItemList SelList = pSelect->FindSelectionList(
9222 wxSelectableItemListNode *node = SelList.GetFirst();
9228 if (tr && tr->IsVisible()) {
9229 b_start_rollover =
true;
9232 node = node->GetNext();
9236 if (b_start_rollover)
9237 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9241 bool appending =
false;
9242 bool inserting =
false;
9244 if (m_bRouteEditing ) {
9246 if (m_pRoutePointEditTarget) {
9252 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9253 double nearby_radius_meters =
9254 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9255 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9256 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9257 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9258 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9259 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9262 if (m_pEditRouteArray && !pNearbyPoint->m_bIsolatedMark) {
9263 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9265 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9266 if (pr && pr->pRoutePointList) {
9267 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
9280 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9285 OCPNMessageBox(
this,
9286 _(
"Replace this RoutePoint by the nearby "
9288 _(
"OpenCPN RoutePoint change"),
9289 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9290 if (dlg_return == wxID_YES) {
9295 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9298 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9300 if (tail && current && (tail != current)) {
9302 connect = tail->GetIndexOf(pNearbyPoint);
9303 int index_current_route =
9304 current->GetIndexOf(m_pRoutePointEditTarget);
9305 index_last = current->GetIndexOf(current->GetLastPoint());
9306 dlg_return1 = wxID_NO;
9308 index_current_route) {
9310 if (connect != tail->GetnPoints()) {
9313 _(
"Last part of route to be appended to dragged "
9317 _(
"Full route to be appended to dragged route?");
9319 dlg_return1 = OCPNMessageBox(
9320 this, dmsg, _(
"OpenCPN Route Create"),
9321 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9322 if (dlg_return1 == wxID_YES) {
9326 }
else if (index_current_route ==
9331 _(
"First part of route to be inserted into dragged "
9333 if (connect == tail->GetnPoints())
9335 "Full route to be inserted into dragged route?");
9337 dlg_return1 = OCPNMessageBox(
9338 this, dmsg, _(
"OpenCPN Route Create"),
9339 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9340 if (dlg_return1 == wxID_YES) {
9347 if (m_pRoutePointEditTarget->IsShared()) {
9349 dlg_return = OCPNMessageBox(
9351 _(
"Do you really want to delete and replace this "
9353 _T(
"\n") + _(
"which has been created manually?"),
9354 (
"OpenCPN RoutePoint warning"),
9355 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9358 if (dlg_return == wxID_YES) {
9359 pMousePoint = pNearbyPoint;
9360 if (pMousePoint->m_bIsolatedMark) {
9361 pMousePoint->SetShared(
true);
9363 pMousePoint->m_bIsolatedMark =
9365 pMousePoint->m_bIsInRoute =
true;
9371 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9373 if (m_pEditRouteArray) {
9374 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9376 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9377 if (g_pRouteMan->IsRouteValid(pr)) {
9381 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9383 pSelect->DeleteAllSelectableRoutePoints(pr);
9384 pSelect->DeleteAllSelectableRouteSegments(pr);
9386 pr->pRoutePointList->Insert(nRP, pMousePoint);
9387 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9389 pSelect->AddAllSelectableRouteSegments(pr);
9390 pSelect->AddAllSelectableRoutePoints(pr);
9392 pr->FinalizeForRendering();
9393 pr->UpdateSegmentDistances();
9394 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9400 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9401 if (m_pEditRouteArray) {
9402 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9404 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9405 if (g_pRouteMan->IsRouteValid(pr)) {
9406 if (pRoutePropDialog->GetRoute() == pr) {
9407 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9422 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9425 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9426 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9427 g_pMarkInfoDialog->Hide();
9429 delete m_pRoutePointEditTarget;
9430 m_lastRoutePointEditTarget = NULL;
9431 m_pRoutePointEditTarget = NULL;
9432 undo->AfterUndoableAction(pMousePoint);
9433 undo->InvalidateUndo();
9438 else if (m_bMarkEditing) {
9439 if (m_pRoutePointEditTarget)
9440 if (m_bRoutePoinDragging)
9441 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9444 if (m_pRoutePointEditTarget)
9445 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9447 if (!m_pRoutePointEditTarget) {
9448 delete m_pEditRouteArray;
9449 m_pEditRouteArray = NULL;
9450 m_bRouteEditing =
false;
9452 m_bRoutePoinDragging =
false;
9459 int length = tail->GetnPoints();
9460 for (
int i = connect + 1; i <= length; i++) {
9461 current->AddPointAndSegment(tail->GetPoint(i),
false);
9462 if (current) current->m_lastMousePointIndex = current->GetnPoints();
9464 gFrame->RefreshAllCanvas();
9467 current->FinalizeForRendering();
9468 current->m_bIsBeingEdited =
false;
9470 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9473 pSelect->DeleteAllSelectableRoutePoints(current);
9474 pSelect->DeleteAllSelectableRouteSegments(current);
9475 for (
int i = 1; i < connect; i++) {
9476 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9478 pSelect->AddAllSelectableRouteSegments(current);
9479 pSelect->AddAllSelectableRoutePoints(current);
9480 current->FinalizeForRendering();
9481 current->m_bIsBeingEdited =
false;
9482 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9486 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9487 if (m_pEditRouteArray) {
9488 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9489 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9490 if (g_pRouteMan->IsRouteValid(pr)) {
9491 if (pRoutePropDialog->GetRoute() == pr) {
9492 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9502 if (m_bRouteEditing) {
9505 bool appending =
false;
9506 bool inserting =
false;
9509 if (m_pRoutePointEditTarget) {
9510 m_pRoutePointEditTarget->m_bBlink =
false;
9514 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9515 double nearby_radius_meters =
9516 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9517 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9518 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9519 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9520 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9521 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9522 bool duplicate =
false;
9523 if (m_pEditRouteArray && !pNearbyPoint->m_bIsolatedMark) {
9524 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9526 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9527 if (pr && pr->pRoutePointList) {
9528 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
9541 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9546 OCPNMessageBox(
this,
9547 _(
"Replace this RoutePoint by the nearby "
9549 _(
"OpenCPN RoutePoint change"),
9550 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9551 if (dlg_return == wxID_YES) {
9555 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9558 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9560 if (tail && current && (tail != current)) {
9562 connect = tail->GetIndexOf(pNearbyPoint);
9563 int index_current_route =
9564 current->GetIndexOf(m_pRoutePointEditTarget);
9565 index_last = current->GetIndexOf(current->GetLastPoint());
9566 dlg_return1 = wxID_NO;
9568 index_current_route) {
9570 if (connect != tail->GetnPoints()) {
9573 _(
"Last part of route to be appended to dragged "
9577 _(
"Full route to be appended to dragged route?");
9579 dlg_return1 = OCPNMessageBox(
9580 this, dmsg, _(
"OpenCPN Route Create"),
9581 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9582 if (dlg_return1 == wxID_YES) {
9586 }
else if (index_current_route ==
9591 _(
"First part of route to be inserted into dragged "
9593 if (connect == tail->GetnPoints())
9595 "Full route to be inserted into dragged route?");
9597 dlg_return1 = OCPNMessageBox(
9598 this, dmsg, _(
"OpenCPN Route Create"),
9599 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9600 if (dlg_return1 == wxID_YES) {
9607 if (m_pRoutePointEditTarget->IsShared()) {
9608 dlg_return = wxID_NO;
9609 dlg_return = OCPNMessageBox(
9611 _(
"Do you really want to delete and replace this "
9613 _T(
"\n") + _(
"which has been created manually?"),
9614 (
"OpenCPN RoutePoint warning"),
9615 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9618 if (dlg_return == wxID_YES) {
9619 pMousePoint = pNearbyPoint;
9620 if (pMousePoint->m_bIsolatedMark) {
9621 pMousePoint->SetShared(
true);
9623 pMousePoint->m_bIsolatedMark =
9625 pMousePoint->m_bIsInRoute =
true;
9631 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9633 if (m_pEditRouteArray) {
9634 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9636 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9637 if (g_pRouteMan->IsRouteValid(pr)) {
9640 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9642 pSelect->DeleteAllSelectableRoutePoints(pr);
9643 pSelect->DeleteAllSelectableRouteSegments(pr);
9645 pr->pRoutePointList->Insert(nRP, pMousePoint);
9646 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9648 pSelect->AddAllSelectableRouteSegments(pr);
9649 pSelect->AddAllSelectableRoutePoints(pr);
9651 pr->FinalizeForRendering();
9652 pr->UpdateSegmentDistances();
9653 pr->m_bIsBeingEdited =
false;
9655 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9667 int length = tail->GetnPoints();
9668 for (
int i = connect + 1; i <= length; i++) {
9669 current->AddPointAndSegment(tail->GetPoint(i),
false);
9671 current->m_lastMousePointIndex = current->GetnPoints();
9673 gFrame->RefreshAllCanvas();
9676 current->FinalizeForRendering();
9677 current->m_bIsBeingEdited =
false;
9679 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9682 pSelect->DeleteAllSelectableRoutePoints(current);
9683 pSelect->DeleteAllSelectableRouteSegments(current);
9684 for (
int i = 1; i < connect; i++) {
9685 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9687 pSelect->AddAllSelectableRouteSegments(current);
9688 pSelect->AddAllSelectableRoutePoints(current);
9689 current->FinalizeForRendering();
9690 current->m_bIsBeingEdited =
false;
9691 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9695 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9696 if (m_pEditRouteArray) {
9697 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9699 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9700 if (g_pRouteMan->IsRouteValid(pr)) {
9701 if (pRoutePropDialog->GetRoute() == pr) {
9702 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9710 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9713 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9714 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9715 g_pMarkInfoDialog->Hide();
9717 delete m_pRoutePointEditTarget;
9718 m_lastRoutePointEditTarget = NULL;
9719 undo->AfterUndoableAction(pMousePoint);
9720 undo->InvalidateUndo();
9722 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9723 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9725 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9728 delete m_pEditRouteArray;
9729 m_pEditRouteArray = NULL;
9733 m_bRouteEditing =
false;
9734 m_pRoutePointEditTarget = NULL;
9740 else if (m_bMarkEditing) {
9741 if (m_pRoutePointEditTarget) {
9742 if (m_bRoutePoinDragging)
9743 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9744 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9745 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9749 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9750 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9751 RefreshRect(wp_rect,
true);
9754 m_pRoutePointEditTarget = NULL;
9755 m_bMarkEditing =
false;
9760 else if (leftIsDown) {
9765 if (!m_bChartDragging && !m_bMeasure_Active) {
9767 m_bChartDragging =
false;
9771 m_bRoutePoinDragging =
false;
9774 if (ret)
return true;
9777 if (event.RightDown()) {
9788 m_FinishRouteOnKillFocus =
false;
9789 CallPopupMenu(mx, my);
9790 m_FinishRouteOnKillFocus =
true;
9800 event.GetPosition(&x, &y);
9802 x *= m_displayScale;
9803 y *= m_displayScale;
9809 int wheel_dir =
event.GetWheelRotation();
9812 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9813 wheel_dir = wheel_dir > 0 ? 1 : -1;
9815 double factor = g_mouse_zoom_sensitivity;
9816 if (wheel_dir < 0) factor = 1 / factor;
9818 if (g_bsmoothpanzoom) {
9819 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9820 if (wheel_dir == m_last_wheel_dir) {
9821 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9826 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9827 m_wheelstopwatch.Start(0);
9832 m_last_wheel_dir = wheel_dir;
9837 if (event.LeftDown()) {
9839 if ((GetCanvasCount() > 1) && (
this != g_focusCanvas)) {
9844 last_drag.x = x, last_drag.y = y;
9845 panleftIsDown =
true;
9848 if (event.LeftUp()) {
9849 if (panleftIsDown) {
9851 panleftIsDown =
false;
9854 if (!m_bChartDragging && !m_bMeasure_Active) {
9855 switch (cursor_region) {
9877 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
9882 m_bChartDragging =
false;
9888 if (event.Dragging() && event.LeftIsDown()) {
9906 struct timespec now;
9907 clock_gettime(CLOCK_MONOTONIC, &now);
9908 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
9910 if (
false == m_bChartDragging) {
9912 last_drag.x = x, last_drag.y = y;
9913 m_bChartDragging =
true;
9914 m_chart_drag_total_time = 0;
9915 m_chart_drag_total_x = 0;
9916 m_chart_drag_total_y = 0;
9917 m_inertia_last_drag_x = x;
9918 m_inertia_last_drag_y = y;
9919 m_drag_vec_x.clear();
9920 m_drag_vec_y.clear();
9921 m_drag_vec_t.clear();
9922 m_last_drag_time = tnow;
9926 uint64_t delta_t = tnow - m_last_drag_time;
9927 double delta_tf = delta_t / 1e9;
9929 m_chart_drag_total_time += delta_tf;
9930 m_chart_drag_total_x += m_inertia_last_drag_x - x;
9931 m_chart_drag_total_y += m_inertia_last_drag_y - y;
9933 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
9934 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
9935 m_drag_vec_t.push_back(delta_tf);
9937 m_inertia_last_drag_x = x;
9938 m_inertia_last_drag_y = y;
9939 m_last_drag_time = tnow;
9941 if ((last_drag.x != x) || (last_drag.y != y)) {
9942 if (!m_routeState) {
9945 m_bChartDragging =
true;
9946 StartTimedMovement();
9947 m_pan_drag.x += last_drag.x - x;
9948 m_pan_drag.y += last_drag.y - y;
9949 last_drag.x = x, last_drag.y = y;
9953 if ((last_drag.x != x) || (last_drag.y != y)) {
9954 if (!m_routeState) {
9957 m_bChartDragging =
true;
9958 StartTimedMovement();
9959 m_pan_drag.x += last_drag.x - x;
9960 m_pan_drag.y += last_drag.y - y;
9961 last_drag.x = x, last_drag.y = y;
9968 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
9970 m_DoubleClickTimer->Start();
9971 singleClickEventIsValid =
false;
9979void ChartCanvas::MouseEvent(wxMouseEvent &event) {
9980 if (MouseEventOverlayWindows(event))
return;
9987void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
9990 wxCursor *ptarget_cursor = pCursorArrow;
9991 if (!pPlugIn_Cursor) {
9992 ptarget_cursor = pCursorArrow;
9993 if ((!m_routeState) &&
9994 (!m_bMeasure_Active) ) {
9995 if (cursor_region == MID_RIGHT) {
9996 ptarget_cursor = pCursorRight;
9997 }
else if (cursor_region == MID_LEFT) {
9998 ptarget_cursor = pCursorLeft;
9999 }
else if (cursor_region == MID_TOP) {
10000 ptarget_cursor = pCursorDown;
10001 }
else if (cursor_region == MID_BOT) {
10002 ptarget_cursor = pCursorUp;
10004 ptarget_cursor = pCursorArrow;
10006 }
else if (m_bMeasure_Active ||
10008 ptarget_cursor = pCursorPencil;
10010 ptarget_cursor = pPlugIn_Cursor;
10013 SetCursor(*ptarget_cursor);
10016void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10017 SetCursor(*pCursorArrow);
10020void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10024 wxArrayString files;
10026 ChartBase *target_chart = GetChartAtCursor();
10027 if (target_chart) {
10028 file.Assign(target_chart->GetFullPath());
10029 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10030 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10033 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10035 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10036 unsigned int im = stackIndexArray.size();
10037 int scale = 2147483647;
10038 if (VPoint.b_quilt && im > 0) {
10039 for (
unsigned int is = 0; is < im; is++) {
10040 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
10041 CHART_TYPE_MBTILES) {
10042 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10044 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10045 if (ChartData->GetChartTableEntry(stackIndexArray[is])
10047 .Contains(lat, lon)) {
10048 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10051 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10052 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
10060 std::vector<Ais8_001_22 *> area_notices;
10062 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10065 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10066 auto target_data = target.second;
10067 if (!target_data->area_notices.empty()) {
10068 for (
auto &ani : target_data->area_notices) {
10073 for (Ais8_001_22_SubAreaList::iterator sa =
10074 area_notice.sub_areas.begin();
10075 sa != area_notice.sub_areas.end(); ++sa) {
10076 switch (sa->shape) {
10077 case AIS8_001_22_SHAPE_CIRCLE: {
10078 wxPoint target_point;
10080 bbox.Expand(target_point);
10081 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10084 case AIS8_001_22_SHAPE_RECT: {
10085 wxPoint target_point;
10087 bbox.Expand(target_point);
10088 if (sa->e_dim_m > sa->n_dim_m)
10089 bbox.EnLarge(sa->e_dim_m * vp_scale);
10091 bbox.EnLarge(sa->n_dim_m * vp_scale);
10094 case AIS8_001_22_SHAPE_POLYGON:
10095 case AIS8_001_22_SHAPE_POLYLINE: {
10096 for (
int i = 0; i < 4; ++i) {
10097 double lat = sa->latitude;
10098 double lon = sa->longitude;
10099 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10101 wxPoint target_point;
10103 bbox.Expand(target_point);
10107 case AIS8_001_22_SHAPE_SECTOR: {
10108 double lat1 = sa->latitude;
10109 double lon1 = sa->longitude;
10111 wxPoint target_point;
10113 bbox.Expand(target_point);
10114 for (
int i = 0; i < 18; ++i) {
10117 sa->left_bound_deg +
10118 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10119 sa->radius_m / 1852.0, &lat, &lon);
10121 bbox.Expand(target_point);
10123 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10126 bbox.Expand(target_point);
10132 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10133 area_notices.push_back(&area_notice);
10140 if (target_chart || !area_notices.empty() || file.HasName()) {
10142 int sel_rad_pix = 5;
10143 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10148 SetCursor(wxCURSOR_WAIT);
10149 bool lightsVis = m_encShowLights;
10150 if (!lightsVis) SetShowENCLights(
true);
10153 ListOfObjRazRules *rule_list = NULL;
10154 ListOfPI_S57Obj *pi_rule_list = NULL;
10157 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10158 else if (target_plugin_chart)
10159 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10160 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10162 ListOfObjRazRules *overlay_rule_list = NULL;
10163 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10166 if (CHs57_Overlay) {
10167 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10168 zlat, zlon, SelectRadius, &GetVP());
10171 if (!lightsVis) SetShowENCLights(
false);
10174 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10175 wxString face = dFont->GetFaceName();
10177 if (NULL == g_pObjectQueryDialog) {
10178 g_pObjectQueryDialog =
10179 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10180 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10183 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10184 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10188 fg = g_pObjectQueryDialog->GetForegroundColour();
10192 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
10193 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10196 int points = dFont->GetPointSize();
10198 int points = dFont->GetPointSize() + 1;
10202 for (
int i = -2; i < 5; i++) {
10203 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10205 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10207 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
10209 if (overlay_rule_list && CHs57_Overlay) {
10210 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10211 objText << _T(
"<hr noshade>");
10214 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10215 an != area_notices.end(); ++an) {
10216 objText << _T(
"<b>AIS Area Notice:</b> " );
10217 objText << ais8_001_22_notice_names[(*an)->notice_type];
10218 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10219 (*an)->sub_areas.begin();
10220 sa != (*an)->sub_areas.end(); ++sa)
10221 if (!sa->text.empty()) objText << sa->text;
10222 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10223 objText << _T(
"<hr noshade>" );
10227 objText << Chs57->CreateObjDescriptions(rule_list);
10228 else if (target_plugin_chart)
10229 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10232 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
10235 wxString AddFiles, filenameOK;
10237 if (!target_plugin_chart) {
10240 AddFiles = wxString::Format(
10241 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
10243 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
10244 _T(
"cellpadding=3>"),
10245 file.GetFullName());
10247 file.Assign(file.GetPath(), wxT(
""));
10248 wxDir dir(file.GetFullPath());
10250 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10252 file.Assign(dir.GetNameWithSep().append(filename));
10253 wxString FormatString =
10254 _T(
"<td valign=top><font size=-2><a ")
10255 _T("href=\"%s\">%s</a></font></td>");
10256 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10257 filenameOK = file.GetFullPath();
10259 if (3 * ((
int)filecount / 3) == filecount)
10260 FormatString.Prepend(_T(
"<tr>"));
10262 FormatString.Prepend(
10263 _T(
"<td>  </td>"));
10266 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10267 file.GetFullName());
10270 cont = dir.GetNext(&filename);
10272 objText << AddFiles << _T(
"</table>");
10274 objText << _T(
"</font>");
10275 objText << _T(
"</body></html>");
10277 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10278 g_pObjectQueryDialog->SetHTMLPage(objText);
10279 g_pObjectQueryDialog->Show();
10281 if ((!Chs57 && filecount == 1)) {
10283 wxHtmlLinkInfo hli(filenameOK);
10284 wxHtmlLinkEvent hle(1, hli);
10285 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10288 if (rule_list) rule_list->Clear();
10291 if (overlay_rule_list) overlay_rule_list->Clear();
10292 delete overlay_rule_list;
10294 if (pi_rule_list) pi_rule_list->Clear();
10295 delete pi_rule_list;
10297 SetCursor(wxCURSOR_ARROW);
10301void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10303 if (!g_pMarkInfoDialog) {
10310 wxSize canvas_size = GetSize();
10312 int best_size_y = wxMin(400 / OCPN_GetWinDIPScaleFactor(), canvas_size.y);
10313 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10315 g_pMarkInfoDialog->Layout();
10317 wxPoint canvas_pos = GetPosition();
10318 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10320 bool newFit =
false;
10321 if (canvas_size.x < fitted_size.x) {
10322 fitted_size.x = canvas_size.x - 40;
10323 if (canvas_size.y < fitted_size.y)
10324 fitted_size.y -= 40;
10326 if (canvas_size.y < fitted_size.y) {
10327 fitted_size.y = canvas_size.y - 40;
10328 if (canvas_size.x < fitted_size.x)
10329 fitted_size.x -= 40;
10333 g_pMarkInfoDialog->SetSize(fitted_size);
10334 g_pMarkInfoDialog->Centre();
10338 markPoint->m_bRPIsBeingEdited =
false;
10340 wxString title_base = _(
"Mark Properties");
10341 if (markPoint->m_bIsInRoute) {
10342 title_base = _(
"Waypoint Properties");
10344 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10345 g_pMarkInfoDialog->UpdateProperties();
10346 if (markPoint->m_bIsInLayer) {
10347 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title_base, _(
"Layer"),
10348 GetLayerName(markPoint->m_LayerID)));
10349 g_pMarkInfoDialog->SetDialogTitle(caption);
10351 g_pMarkInfoDialog->SetDialogTitle(title_base);
10353 g_pMarkInfoDialog->Show();
10354 g_pMarkInfoDialog->Raise();
10355 g_pMarkInfoDialog->InitialFocus();
10356 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10359void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10360 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10361 pRoutePropDialog->SetRouteAndUpdate(selected);
10363 pRoutePropDialog->Show();
10364 pRoutePropDialog->Raise();
10366 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10369 if (g_bresponsive) {
10370 wxSize canvas_size = GetSize();
10371 wxPoint canvas_pos = GetPosition();
10372 wxSize fitted_size = pRoutePropDialog->GetSize();
10375 if (canvas_size.x < fitted_size.x) {
10376 fitted_size.x = canvas_size.x;
10377 if (canvas_size.y < fitted_size.y)
10378 fitted_size.y -= 20;
10380 if (canvas_size.y < fitted_size.y) {
10381 fitted_size.y = canvas_size.y;
10382 if (canvas_size.x < fitted_size.x)
10383 fitted_size.x -= 20;
10386 pRoutePropDialog->SetSize(fitted_size);
10387 pRoutePropDialog->Centre();
10392 wxPoint xxp = ClientToScreen(canvas_pos);
10396 pRoutePropDialog->SetRouteAndUpdate(selected);
10398 pRoutePropDialog->Show();
10403void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10404 pTrackPropDialog = TrackPropDlg::getInstance(
10407 pTrackPropDialog->SetTrackAndUpdate(selected);
10410 pTrackPropDialog->Show();
10415void pupHandler_PasteWaypoint() {
10418 int pasteBuffer = kml.ParsePasteBuffer();
10419 RoutePoint *pasted = kml.GetParsedRoutePoint();
10420 if (!pasted)
return;
10422 double nearby_radius_meters =
10423 g_Platform->GetSelectRadiusPix() /
10424 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10426 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10427 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10429 int answer = wxID_NO;
10430 if (nearPoint && !nearPoint->m_bIsInLayer) {
10433 "There is an existing waypoint at the same location as the one you are "
10434 "pasting. Would you like to merge the pasted data with it?\n\n");
10435 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10436 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10437 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10440 if (answer == wxID_YES) {
10441 nearPoint->SetName(pasted->GetName());
10442 nearPoint->m_MarkDescription = pasted->m_MarkDescription;
10443 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10444 pRouteManagerDialog->UpdateWptListCtrl();
10447 if (answer == wxID_NO) {
10449 newPoint->m_bIsolatedMark =
true;
10450 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10452 pConfig->AddNewWayPoint(newPoint, -1);
10454 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10455 pRouteManagerDialog->UpdateWptListCtrl();
10456 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10457 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10460 gFrame->InvalidateAllGL();
10461 gFrame->RefreshAllCanvas(
false);
10464void pupHandler_PasteRoute() {
10467 int pasteBuffer = kml.ParsePasteBuffer();
10468 Route *pasted = kml.GetParsedRoute();
10469 if (!pasted)
return;
10471 double nearby_radius_meters =
10472 g_Platform->GetSelectRadiusPix() /
10473 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10479 bool mergepoints =
false;
10480 bool createNewRoute =
true;
10481 int existingWaypointCounter = 0;
10483 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10484 curPoint = pasted->GetPoint(i);
10485 nearPoint = pWayPointMan->GetNearbyWaypoint(
10486 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10488 mergepoints =
true;
10489 existingWaypointCounter++;
10493 curPoint->m_bPtIsSelected =
true;
10497 int answer = wxID_NO;
10501 "There are existing waypoints at the same location as some of the ones "
10502 "you are pasting. Would you like to just merge the pasted data into "
10504 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10505 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10506 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10508 if (answer == wxID_CANCEL) {
10515 if (mergepoints && answer == wxID_YES &&
10516 existingWaypointCounter == pasted->GetnPoints()) {
10517 wxRouteListNode *route_node = pRouteList->GetFirst();
10518 while (route_node) {
10519 Route *proute = route_node->GetData();
10521 if (pasted->m_RouteNameString == proute->m_RouteNameString) {
10522 createNewRoute =
false;
10525 route_node = route_node->GetNext();
10529 Route *newRoute = 0;
10532 if (createNewRoute) {
10533 newRoute =
new Route();
10534 newRoute->m_RouteNameString = pasted->m_RouteNameString;
10537 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10538 curPoint = pasted->GetPoint(i);
10539 if (answer == wxID_YES && curPoint->m_bPtIsSelected) {
10540 curPoint->m_bPtIsSelected =
false;
10541 newPoint = pWayPointMan->GetNearbyWaypoint(
10542 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10543 newPoint->SetName(curPoint->GetName());
10544 newPoint->m_MarkDescription = curPoint->m_MarkDescription;
10546 if (createNewRoute) newRoute->AddPoint(newPoint);
10548 curPoint->m_bPtIsSelected =
false;
10551 newPoint->m_bIsolatedMark =
false;
10552 newPoint->SetIconName(_T(
"circle"));
10553 newPoint->m_bIsVisible =
true;
10554 newPoint->m_bShowName =
false;
10555 newPoint->SetShared(
false);
10557 newRoute->AddPoint(newPoint);
10558 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10560 pConfig->AddNewWayPoint(newPoint, -1);
10563 if (i > 1 && createNewRoute)
10564 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10565 curPoint->m_lat, curPoint->m_lon,
10566 prevPoint, newPoint, newRoute);
10567 prevPoint = newPoint;
10570 if (createNewRoute) {
10571 pRouteList->Append(newRoute);
10572 pConfig->AddNewRoute(newRoute);
10574 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10575 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10578 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10579 pRouteManagerDialog->UpdateRouteListCtrl();
10580 pRouteManagerDialog->UpdateWptListCtrl();
10582 gFrame->InvalidateAllGL();
10583 gFrame->RefreshAllCanvas(
false);
10585 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10586 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10589void pupHandler_PasteTrack() {
10592 int pasteBuffer = kml.ParsePasteBuffer();
10593 Track *pasted = kml.GetParsedTrack();
10594 if (!pasted)
return;
10602 newTrack->SetName(pasted->GetName());
10604 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10605 curPoint = pasted->GetPoint(i);
10609 wxDateTime now = wxDateTime::Now();
10610 newPoint->SetCreateTime(curPoint->GetCreateTime());
10612 newTrack->AddPoint(newPoint);
10615 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10616 newPoint->m_lat, newPoint->m_lon,
10617 prevPoint, newPoint, newTrack);
10619 prevPoint = newPoint;
10622 g_TrackList.push_back(newTrack);
10623 pConfig->AddNewTrack(newTrack);
10625 gFrame->InvalidateAllGL();
10626 gFrame->RefreshAllCanvas(
false);
10629bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10631 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10635 wxEVT_COMMAND_MENU_SELECTED,
10636 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10638 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10641 wxEVT_COMMAND_MENU_SELECTED,
10642 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10644 delete m_canvasMenu;
10645 m_canvasMenu = NULL;
10655void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10658 if (m_canvasMenu) {
10659 m_canvasMenu->PopupMenuHandler(event);
10664void ChartCanvas::StartRoute(
void) {
10666 if (g_brouteCreating)
return;
10668 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10670 g_brouteCreating =
true;
10672 m_bDrawingRoute =
false;
10673 SetCursor(*pCursorPencil);
10675 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10677 HideGlobalToolbar();
10680 androidSetRouteAnnunciator(
true);
10684void ChartCanvas::FinishRoute(
void) {
10686 m_prev_pMousePoint = NULL;
10687 m_bDrawingRoute =
false;
10690 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10692 androidSetRouteAnnunciator(
false);
10695 SetCursor(*pCursorArrow);
10697 if (m_pMouseRoute) {
10698 if (m_bAppendingRoute)
10699 pConfig->UpdateRoute(m_pMouseRoute);
10701 if (m_pMouseRoute->GetnPoints() > 1) {
10702 pConfig->AddNewRoute(m_pMouseRoute);
10705 NavObjectChanges::getInstance());
10706 m_pMouseRoute = NULL;
10709 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10711 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10712 (pRoutePropDialog->IsShown())) {
10713 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10716 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10717 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10718 pRouteManagerDialog->UpdateRouteListCtrl();
10721 m_bAppendingRoute =
false;
10722 m_pMouseRoute = NULL;
10724 m_pSelectedRoute = NULL;
10726 undo->InvalidateUndo();
10727 gFrame->RefreshAllCanvas(
true);
10729 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10731 ShowGlobalToolbar();
10733 g_brouteCreating =
false;
10736void ChartCanvas::HideGlobalToolbar() {
10737 if (m_canvasIndex == 0) {
10738 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10742void ChartCanvas::ShowGlobalToolbar() {
10743 if (m_canvasIndex == 0) {
10744 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10748void ChartCanvas::ShowAISTargetList(
void) {
10749 if (NULL == g_pAISTargetList) {
10753 g_pAISTargetList->UpdateAISTargetList();
10756void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10757 if (!m_bShowOutlines)
return;
10759 if (!ChartData)
return;
10761 int nEntry = ChartData->GetChartTableEntries();
10763 for (
int i = 0; i < nEntry; i++) {
10767 bool b_group_draw =
false;
10768 if (m_groupIndex > 0) {
10769 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10770 int index = pt->GetGroupArray()[ig];
10771 if (m_groupIndex == index) {
10772 b_group_draw =
true;
10777 b_group_draw =
true;
10779 if (b_group_draw) RenderChartOutline(dc, i, vp);
10785 if (VPoint.b_quilt) {
10786 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10787 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10791 }
else if (m_singleChart &&
10792 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10796 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10799 if (zoom_factor > 8.0) {
10800 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10803 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10807 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
10811void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10813 if (g_bopengl && m_glcc) {
10815 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10820 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10821 if (!ChartData->IsChartAvailable(dbIndex))
return;
10824 float plylat, plylon;
10825 float plylat1, plylon1;
10827 int pixx, pixy, pixx1, pixy1;
10830 ChartData->GetDBBoundingBox(dbIndex, box);
10834 if (box.GetLonRange() == 360)
return;
10836 double lon_bias = 0;
10838 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10840 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10842 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10843 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10845 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10846 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10849 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10852 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10853 if (0 == nAuxPlyEntries)
10857 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10858 plylon += lon_bias;
10864 for (
int i = 0; i < nPly - 1; i++) {
10865 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
10866 plylon1 += lon_bias;
10872 int pixxs1 = pixx1;
10873 int pixys1 = pixy1;
10875 bool b_skip =
false;
10879 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
10880 pow((
double)(pixy1 - pixy), 2)) /
10886 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10891 if (fabs(dist - distgc) > 10000. * 1852.)
10897 ClipResult res = cohen_sutherland_line_clip_i(
10899 if (res != Invisible && !b_skip)
10900 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
10908 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
10909 plylon1 += lon_bias;
10915 ClipResult res = cohen_sutherland_line_clip_i(
10917 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
10924 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10925 for (
int j = 0; j < nAuxPlyEntries; j++) {
10927 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
10932 for (
int i = 0; i < nAuxPly - 1; i++) {
10933 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
10939 int pixxs1 = pixx1;
10940 int pixys1 = pixy1;
10942 bool b_skip =
false;
10946 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
10947 ((pixy1 - pixy) * (pixy1 - pixy))) /
10952 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10957 if (fabs(dist - distgc) > 10000. * 1852.)
10963 ClipResult res = cohen_sutherland_line_clip_i(
10965 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
10973 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
10978 ClipResult res = cohen_sutherland_line_clip_i(
10980 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
10985static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
10986 const wxString &second) {
10987 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
10989 int pointsize = dFont->GetPointSize();
10990 pointsize /= OCPN_GetWinDIPScaleFactor();
10993 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
10994 false, dFont->GetFaceName());
10996 dc.SetFont(*psRLI_font);
11004 int hilite_offset = 3;
11007 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11008 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11010 dc.GetTextExtent(first, &w1, &h1);
11011 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11014 h1 *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
11015 h2 *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
11017 w = wxMax(w1, w2) + (h1 / 2);
11018 w *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
11022 xp = ref_point.x - w;
11024 yp += hilite_offset;
11026 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11028 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11029 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11031 dc.DrawText(first, xp, yp);
11032 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11035void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11036 if (!g_bAllowShipToActive)
return;
11038 Route *rt = g_pRouteMan->GetpActiveRoute();
11041 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11042 wxPoint2DDouble pa, pb;
11048 g_pRouteMan->GetRoutePen()->GetWidth();
11049 if (rt->m_width != wxPENSTYLE_INVALID)
11050 width = rt->m_width;
11051 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11052 g_shipToActiveStyle, 5)];
11053 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11055 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11057 g_pRouteMan->GetActiveRoutePen()->GetColour();
11058 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11061 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11064 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11065 (
int)pb.m_y, GetVP(),
true);
11069#ifdef USE_ANDROID_GLES2
11070 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11072 if (style != wxPENSTYLE_SOLID) {
11073 if (glChartCanvas::dash_map.find(style) !=
11074 glChartCanvas::dash_map.end()) {
11075 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11079 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11082 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11083 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11089void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11091 if (m_routeState >= 2) route = m_pMouseRoute;
11092 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11093 route = m_pMeasureRoute;
11095 if (!route)
return;
11098 if (!g_pRouteMan->IsRouteValid(route))
return;
11103 int np = route->GetnPoints();
11105 if (g_btouch && (np > 1)) np--;
11107 render_lat = rp.m_lat;
11108 render_lon = rp.m_lon;
11111 double rhumbBearing, rhumbDist;
11113 &rhumbBearing, &rhumbDist);
11114 double brg = rhumbBearing;
11115 double dist = rhumbDist;
11119 double gcBearing, gcBearing2, gcDist;
11120 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11123 double gcDistm = gcDist / 1852.0;
11126 rhumbBearing = 90.;
11128 wxPoint destPoint, lastPoint;
11130 route->m_NextLegGreatCircle =
false;
11131 int milesDiff = rhumbDist - gcDistm;
11132 if (milesDiff > 1) {
11135 route->m_NextLegGreatCircle =
true;
11139 RouteGui(*route).DrawPointWhich(dc,
this, route->m_lastMousePointIndex,
11142 if (route->m_NextLegGreatCircle) {
11143 for (
int i = 1; i <= milesDiff; i++) {
11144 double p = (double)i * (1.0 / (
double)milesDiff);
11146 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11147 &pLon, &pLat, &gcBearing2);
11149 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11151 lastPoint = destPoint;
11154 if (r_rband.x && r_rband.y) {
11155 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11157 if (m_bMeasure_DistCircle) {
11158 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11159 powf((
float)(r_rband.y - lastPoint.y), 2));
11161 dc.SetPen(*g_pRouteMan->GetRoutePen());
11162 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11163 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11169 wxString routeInfo;
11171 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11177 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11179 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11180 (
int)varBrg, 0x00B0);
11183 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
11186 if (!route->m_bIsInLayer)
11187 s0.Append(_(
"Route") + _T(
": "));
11189 s0.Append(_(
"Layer Route: "));
11191 double disp_length = route->m_route_length;
11192 if (!g_btouch) disp_length += dist;
11193 s0 += FormatDistanceAdaptive(disp_length);
11195 RouteLegInfo(dc, r_rband, routeInfo, s0);
11197 m_brepaint_piano =
true;
11200void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11201 if (!m_bShowVisibleSectors)
return;
11203 if (g_bDeferredInitDone) {
11205 double rhumbBearing, rhumbDist;
11206 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11207 &rhumbBearing, &rhumbDist);
11209 if (rhumbDist > 0.05)
11211 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11212 m_sectorlegsVisible);
11213 m_sector_glat = gLat;
11214 m_sector_glon = gLon;
11216 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11220void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11228void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11229 if (!ps52plib)
return;
11231 if (VPoint.b_quilt) {
11232 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11234 if (m_pQuilt->IsQuiltVector()) {
11235 if (ps52plib->GetStateHash() != m_s52StateHash) {
11237 m_s52StateHash = ps52plib->GetStateHash();
11241 if (ps52plib->GetStateHash() != m_s52StateHash) {
11243 m_s52StateHash = ps52plib->GetStateHash();
11248 bool bSendPlibState =
true;
11249 if (VPoint.b_quilt) {
11250 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11253 if (bSendPlibState) {
11255 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
11256 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
11257 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
11258 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
11259 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
11262 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
11263 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
11264 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
11265 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] = m_encShowAnchor;
11266 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] = GetShowENCDataQual();
11267 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
11268 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
11270 v[_T(
"OpenCPN S52PLIB DisplayCategory")] = GetENCDisplayCategory();
11272 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
11273 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
11277 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
11278 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
11279 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
11280 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] =
11281 ps52plib->m_bShowS57ImportantTextOnly;
11282 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
11283 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
11284 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
11285 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
11286 v[_T(
"OpenCPN S52PLIB ColorShades")] =
11287 S52_getMarinerParam(S52_MAR_TWO_SHADES);
11290 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
11291 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
11292 v[_T(
"OpenCPN Scale Factor Exp")] =
11293 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11294 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
11300 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11301 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11302 g_lastS52PLIBPluginMessage = out;
11308void ChartCanvas::OnPaint(wxPaintEvent &event) {
11309 wxPaintDC dc(
this);
11319 if (!m_b_paint_enable) {
11324 UpdateCanvasS52PLIBConfig();
11327 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11329 if (m_glcc && g_bopengl) {
11330 if (!s_in_update) {
11340 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11342 wxRegion ru = GetUpdateRegion();
11344 int rx, ry, rwidth, rheight;
11345 ru.GetBox(rx, ry, rwidth, rheight);
11349#ifdef ocpnUSE_DIBSECTION
11352 wxMemoryDC temp_dc;
11360 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11361 height += m_Piano->GetHeight();
11363 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11367 int thumbx, thumby, thumbsx, thumbsy;
11368 pthumbwin->GetPosition(&thumbx, &thumby);
11369 pthumbwin->GetSize(&thumbsx, &thumbsy);
11370 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11372 if (pthumbwin->IsShown()) {
11373 rgn_chart.Subtract(rgn_thumbwin);
11374 ru.Subtract(rgn_thumbwin);
11380 wxRegion rgn_blit = ru;
11381 if (g_bShowChartBar) {
11382 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11383 GetClientSize().x, m_Piano->GetHeight());
11386 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11387 if (style->chartStatusWindowTransparent)
11388 m_brepaint_piano =
true;
11390 ru.Subtract(chart_bar_rect);
11394 if (m_Compass && m_Compass->IsShown()) {
11395 wxRect compassRect = m_Compass->
GetRect();
11396 if (ru.Contains(compassRect) != wxOutRegion) {
11397 ru.Subtract(compassRect);
11402 bool b_newview =
true;
11407 m_cache_vp.IsValid()) {
11413 bool b_rcache_ok =
false;
11414 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11415 b_rcache_ok = !b_newview;
11418 if (VPoint.b_MercatorProjectionOverride)
11419 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11433 if (b_rcache_ok) chart_get_region.Clear();
11436 if (VPoint.b_quilt)
11438 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11440 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11445 AbstractPlatform::ShowBusySpinner();
11449 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11450 (m_working_bm.GetHeight() != svp.
pix_height))
11454 if (fabs(VPoint.
rotation) < 0.01) {
11455 bool b_save =
true;
11457 if (g_SencThreadManager) {
11458 if (g_SencThreadManager->GetJobCount()) {
11460 m_cache_vp.Invalidate();
11474 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11479 int dy = c_new.y - c_old.y;
11480 int dx = c_new.x - c_old.x;
11485 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11489 temp_dc.SelectObject(m_working_bm);
11491 wxMemoryDC cache_dc;
11492 cache_dc.SelectObject(m_cached_chart_bm);
11496 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11499 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11505 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11508 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11516 update_region.Union(
11519 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11524 update_region.Union(
11527 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11531 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11533 cache_dc.SelectObject(wxNullBitmap);
11537 temp_dc.SelectObject(m_cached_chart_bm);
11540 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11544 temp_dc.SelectObject(m_working_bm);
11545 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11550 temp_dc.SelectObject(m_cached_chart_bm);
11555 temp_dc.SelectObject(m_working_bm);
11556 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11569 wxMemoryDC scratch_dc_0;
11570 scratch_dc_0.SelectObject(m_cached_chart_bm);
11573 scratch_dc_0.SelectObject(wxNullBitmap);
11582 temp_dc.SelectObject(m_working_bm);
11585 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11586 chart_get_all_region);
11589 AbstractPlatform::HideBusySpinner();
11595 if (!m_singleChart) {
11596 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11601 if (!chart_get_region.IsEmpty()) {
11602 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11606 if (temp_dc.IsOk()) {
11611 if (!VPoint.b_quilt) {
11614 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11615 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11622 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11623 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11626 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11628 temp_dc.DestroyClippingRegion();
11633 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11635 if (!backgroundRegion.IsEmpty()) {
11641 wxColour water = pWorldBackgroundChart->water;
11642 if (water.IsOk()) {
11643 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11644 temp_dc.SetBrush(wxBrush(water));
11646 while (upd.HaveRects()) {
11647 wxRect rect = upd.GetRect();
11648 temp_dc.DrawRectangle(rect);
11653 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11654 temp_dc.SetDeviceClippingRegion(*clip_region);
11655 delete clip_region;
11659 SetVPRotation(VPoint.
skew);
11662 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11668 wxMemoryDC *pChartDC = &temp_dc;
11669 wxMemoryDC rotd_dc;
11671 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11673 if (!b_rcache_ok) {
11675 wxMemoryDC tbase_dc;
11677 tbase_dc.SelectObject(bm_base);
11679 tbase_dc.SelectObject(wxNullBitmap);
11681 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11684 wxImage base_image;
11685 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11693 bool b_rot_ok =
false;
11694 if (base_image.IsOk()) {
11697 m_b_rot_hidef =
false;
11701 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11702 m_b_rot_hidef, &m_roffset);
11707 rot_vp.IsValid() && (ri.IsOk())) {
11714 m_prot_bm =
new wxBitmap(ri);
11717 m_roffset.x += VPoint.rv_rect.x;
11718 m_roffset.y += VPoint.rv_rect.y;
11721 if (m_prot_bm && m_prot_bm->IsOk()) {
11722 rotd_dc.SelectObject(*m_prot_bm);
11723 pChartDC = &rotd_dc;
11725 pChartDC = &temp_dc;
11726 m_roffset = wxPoint(0, 0);
11729 pChartDC = &temp_dc;
11730 m_roffset = wxPoint(0, 0);
11733 wxPoint offset = m_roffset;
11736 m_cache_vp = VPoint;
11739 wxMemoryDC mscratch_dc;
11740 mscratch_dc.SelectObject(*pscratch_bm);
11742 mscratch_dc.ResetBoundingBox();
11743 mscratch_dc.DestroyClippingRegion();
11744 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11747 wxRegionIterator upd(rgn_blit);
11749 wxRect rect = upd.GetRect();
11751 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11752 rect.x - offset.x, rect.y - offset.y);
11758 if (m_show_focus_bar && (g_canvasConfig != 0)) {
11759 if (
this == wxWindow::FindFocus()) {
11760 g_focusCanvas =
this;
11762 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11763 mscratch_dc.SetPen(wxPen(colour));
11764 mscratch_dc.SetBrush(wxBrush(colour));
11766 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11767 mscratch_dc.DrawRectangle(activeRect);
11772 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11773 unsigned int im = stackIndexArray.size();
11774 if (VPoint.b_quilt && im > 0) {
11775 std::vector<int> tiles_to_show;
11776 for (
unsigned int is = 0; is < im; is++) {
11778 ChartData->GetChartTableEntry(stackIndexArray[is]);
11779 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11782 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11783 tiles_to_show.push_back(stackIndexArray[is]);
11787 if (tiles_to_show.size())
11788 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11795 ocpnDC scratch_dc(mscratch_dc);
11796 DrawOverlayObjects(scratch_dc, ru);
11799 RebuildTideSelectList(GetVP().GetBBox());
11800 DrawAllTidesInBBox(scratch_dc, GetVP().GetBBox());
11803 if (m_bShowCurrent) {
11804 RebuildCurrentSelectList(GetVP().GetBBox());
11805 DrawAllCurrentsInBBox(scratch_dc, GetVP().GetBBox());
11808 if (m_brepaint_piano && g_bShowChartBar) {
11809 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), mscratch_dc);
11812 if (m_Compass) m_Compass->Paint(scratch_dc);
11814 RenderAlertMessage(mscratch_dc, GetVP());
11819#ifdef ocpnUSE_DIBSECTION
11824 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11825 q_dc.SelectObject(qbm);
11828 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11831 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11832 q_dc.SetBrush(qbr);
11833 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11836 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11839 q_dc.SelectObject(wxNullBitmap);
11846 if( VPoint.b_quilt ) {
11847 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11848 ChartBase *chart = m_pQuilt->GetRefChart();
11849 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11854 ChPI->ClearPLIBTextList();
11857 ps52plib->ClearTextList();
11861 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11863 wxColor maskBackground = wxColour(1,0,0);
11864 t_dc.SelectObject( qbm );
11865 t_dc.SetBackground(wxBrush(maskBackground));
11869 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
11872 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
11873 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
11876 wxRegionIterator upd_final( ru );
11877 while( upd_final ) {
11878 wxRect rect = upd_final.GetRect();
11879 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
11883 t_dc.SelectObject( wxNullBitmap );
11889 if (VPoint.b_quilt) {
11890 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
11891 ChartBase *chart = m_pQuilt->GetRefChart();
11892 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
11896 ChPI->ClearPLIBTextList();
11898 if (ps52plib) ps52plib->ClearTextList();
11903 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
11905 if (g_bShowChartBar && m_Piano) {
11906 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
11907 GetVP().pix_width, m_Piano->GetHeight());
11910 if (!style->chartStatusWindowTransparent)
11911 chart_all_text_region.Subtract(chart_bar_rect);
11914 if (m_Compass && m_Compass->IsShown()) {
11915 wxRect compassRect = m_Compass->
GetRect();
11916 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
11917 chart_all_text_region.Subtract(compassRect);
11921 mscratch_dc.DestroyClippingRegion();
11923 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
11924 chart_all_text_region);
11930 wxRegionIterator upd_final(rgn_blit);
11931 while (upd_final) {
11932 wxRect rect = upd_final.GetRect();
11933 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
11954 temp_dc.SelectObject(wxNullBitmap);
11956 mscratch_dc.SelectObject(wxNullBitmap);
11958 dc.DestroyClippingRegion();
11963void ChartCanvas::PaintCleanup() {
11975 m_bTCupdate =
false;
11979 WarpPointer(warp_x, warp_y);
11986 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
11987 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
11991wxColour GetErrorGraphicColor(
double val)
12010 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
12011 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
12012 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
12013 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
12014 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
12015 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
12016 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
12017 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
12018 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
12019 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
12020 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
12021 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
12022 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
12023 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
12024 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
12025 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
12026 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
12027 else if( val >= 48) c.Set(_T(
"#410000"));
12032void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12035 gr_image.InitAlpha();
12037 double maxval = -10000;
12038 double minval = 10000;
12055 maxval = wxMax(maxval, (glat - rlat));
12056 minval = wxMin(minval, (glat - rlat));
12073 double f = ((glat - rlat)-minval)/(maxval - minval);
12075 double dy = (f * 40);
12077 wxColour c = GetErrorGraphicColor(dy);
12078 unsigned char r = c.Red();
12079 unsigned char g = c.Green();
12080 unsigned char b = c.Blue();
12082 gr_image.SetRGB(j, i, r,g,b);
12083 if((glat - rlat )!= 0)
12084 gr_image.SetAlpha(j, i, 128);
12086 gr_image.SetAlpha(j, i, 255);
12093 wxBitmap *pbm =
new wxBitmap(gr_image);
12094 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12095 pbm->SetMask(gr_mask);
12097 pmdc->DrawBitmap(*pbm, 0,0);
12105void ChartCanvas::CancelMouseRoute() {
12107 m_pMouseRoute = NULL;
12108 m_bDrawingRoute =
false;
12111int ChartCanvas::GetNextContextMenuId() {
12112 return CanvasMenuHandler::GetNextContextMenuId();
12115bool ChartCanvas::SetCursor(
const wxCursor &c) {
12117 if (g_bopengl && m_glcc)
12118 return m_glcc->SetCursor(c);
12121 return wxWindow::SetCursor(c);
12124void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12125 if (g_bquiting)
return;
12135 if (!m_RolloverPopupTimer.IsRunning() &&
12136 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12137 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12138 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12139 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12142 if (m_glcc && g_bopengl) {
12145 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12147 m_glcc->Refresh(eraseBackground,
12158 if (pthumbwin && pthumbwin->IsShown()) {
12159 pthumbwin->Raise();
12160 pthumbwin->Refresh(
false);
12164 if (m_pCIWin && m_pCIWin->IsShown()) {
12166 m_pCIWin->Refresh(
false);
12174 wxWindow::Refresh(eraseBackground, rect);
12177void ChartCanvas::Update() {
12178 if (m_glcc && g_bopengl) {
12183 wxWindow::Update();
12187 if (!pemboss)
return;
12188 int x = pemboss->x, y = pemboss->y;
12189 const double factor = 200;
12191 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
12192 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12193 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
12196 wxMemoryDC snip_dc;
12197 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12198 snip_dc.SelectObject(snip_bmp);
12200 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12201 snip_dc.SelectObject(wxNullBitmap);
12203 wxImage snip_img = snip_bmp.ConvertToImage();
12206 unsigned char *pdata = snip_img.GetData();
12208 for (
int y = 0; y < pemboss->height; y++) {
12209 int map_index = (y * pemboss->width);
12210 for (
int x = 0; x < pemboss->width; x++) {
12211 double val = (pemboss->pmap[map_index] * factor) / 256.;
12213 int nred = (int)((*pdata) + val);
12214 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12215 *pdata++ = (
unsigned char)nred;
12217 int ngreen = (int)((*pdata) + val);
12218 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12219 *pdata++ = (
unsigned char)ngreen;
12221 int nblue = (int)((*pdata) + val);
12222 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12223 *pdata++ = (
unsigned char)nblue;
12231 wxBitmap emb_bmp(snip_img);
12234 wxMemoryDC result_dc;
12235 result_dc.SelectObject(emb_bmp);
12238 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12240 result_dc.SelectObject(wxNullBitmap);
12246 if (GetQuiltMode()) {
12248 int refIndex = GetQuiltRefChartdbIndex();
12249 if (refIndex >= 0) {
12250 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
12251 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12252 if (current_type == CHART_TYPE_MBTILES) {
12253 ChartBase *pChart = m_pQuilt->GetRefChart();
12256 zoom_factor = ptc->GetZoomFactor();
12261 if (zoom_factor <= 3.9)
return NULL;
12263 if (m_singleChart) {
12264 if (zoom_factor <= 3.9)
return NULL;
12269 if (m_pEM_OverZoom) {
12270 m_pEM_OverZoom->x = 4;
12271 m_pEM_OverZoom->y = 0;
12272 if (g_MainToolbar && IsPrimaryCanvas()) {
12273 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12274 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12277 return m_pEM_OverZoom;
12280void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12290 g_overlayCanvas =
this;
12292 if (g_pi_manager) {
12293 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12294 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12298 AISDrawAreaNotices(dc, GetVP(),
this);
12300 wxDC *pdc = dc.GetDC();
12302 pdc->DestroyClippingRegion();
12303 wxDCClipper(*pdc, ru);
12306 if (m_bShowNavobjects) {
12307 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12308 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12309 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12310 DrawAnchorWatchPoints(dc);
12312 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12313 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12316 AISDraw(dc, GetVP(),
this);
12320 RenderVisibleSectorLights(dc);
12322 RenderAllChartOutlines(dc, GetVP());
12323 RenderRouteLegs(dc);
12324 RenderShipToActive(dc,
false);
12326 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12327 if (g_pi_manager) {
12328 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12329 OVERLAY_OVER_SHIPS);
12332 DrawEmboss(dc, EmbossDepthScale());
12333 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12334 if (g_pi_manager) {
12335 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12336 OVERLAY_OVER_EMBOSS);
12338 if (!g_PrintingInProgress) {
12339 if (IsPrimaryCanvas()) {
12340 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12343 if (IsPrimaryCanvas()) {
12344 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12347 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12349 if (m_pTrackRolloverWin) {
12350 m_pTrackRolloverWin->Draw(dc);
12351 m_brepaint_piano =
true;
12354 if (m_pRouteRolloverWin) {
12355 m_pRouteRolloverWin->Draw(dc);
12356 m_brepaint_piano =
true;
12359 if (m_pAISRolloverWin) {
12360 m_pAISRolloverWin->Draw(dc);
12361 m_brepaint_piano =
true;
12364 if (g_pi_manager) {
12365 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12371 if (!m_bShowDepthUnits)
return NULL;
12373 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12375 if (GetQuiltMode()) {
12376 wxString s = m_pQuilt->GetQuiltDepthUnit();
12378 if (s == _T(
"FEET"))
12379 depth_unit_type = DEPTH_UNIT_FEET;
12380 else if (s.StartsWith(_T(
"FATHOMS")))
12381 depth_unit_type = DEPTH_UNIT_FATHOMS;
12382 else if (s.StartsWith(_T(
"METERS")))
12383 depth_unit_type = DEPTH_UNIT_METERS;
12384 else if (s.StartsWith(_T(
"METRES")))
12385 depth_unit_type = DEPTH_UNIT_METERS;
12386 else if (s.StartsWith(_T(
"METRIC")))
12387 depth_unit_type = DEPTH_UNIT_METERS;
12388 else if (s.StartsWith(_T(
"METER")))
12389 depth_unit_type = DEPTH_UNIT_METERS;
12392 if (m_singleChart) {
12393 depth_unit_type = m_singleChart->GetDepthUnitType();
12394 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12395 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12400 switch (depth_unit_type) {
12401 case DEPTH_UNIT_FEET:
12404 case DEPTH_UNIT_METERS:
12405 ped = m_pEM_Meters;
12407 case DEPTH_UNIT_FATHOMS:
12408 ped = m_pEM_Fathoms;
12414 ped->x = (GetVP().
pix_width - ped->width);
12416 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12417 wxRect r = m_Compass->
GetRect();
12418 ped->y = r.y + r.height;
12425void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12428 if (style->embossFont == wxEmptyString) {
12429 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12431 font.SetPointSize(60);
12432 font.SetWeight(wxFONTWEIGHT_BOLD);
12434 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12435 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12437 int emboss_width = 500;
12438 int emboss_height = 200;
12442 delete m_pEM_Meters;
12443 delete m_pEM_Fathoms;
12447 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12449 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12451 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12454#define OVERZOOM_TEXT _("OverZoom")
12456void ChartCanvas::SetOverzoomFont() {
12461 if (style->embossFont == wxEmptyString) {
12462 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12464 font.SetPointSize(40);
12465 font.SetWeight(wxFONTWEIGHT_BOLD);
12467 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12468 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12470 wxClientDC dc(
this);
12472 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12474 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12475 font.SetPointSize(font.GetPointSize() - 1);
12477 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12479 m_overzoomFont = font;
12480 m_overzoomTextWidth = w;
12481 m_overzoomTextHeight = h;
12484void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12485 delete m_pEM_OverZoom;
12487 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12489 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12490 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12493emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12494 int height,
const wxString &str,
12499 wxBitmap bmp(width, height, -1);
12502 wxMemoryDC temp_dc;
12503 temp_dc.SelectObject(bmp);
12506 temp_dc.SetBackground(*wxWHITE_BRUSH);
12507 temp_dc.SetTextBackground(*wxWHITE);
12508 temp_dc.SetTextForeground(*wxBLACK);
12512 temp_dc.SetFont(font);
12515 temp_dc.GetTextExtent(str, &str_w, &str_h);
12517 temp_dc.DrawText(str, 1, 1);
12520 temp_dc.SelectObject(wxNullBitmap);
12523 wxImage img = bmp.ConvertToImage();
12525 int image_width = str_w * 105 / 100;
12526 int image_height = str_h * 105 / 100;
12527 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12528 wxMin(image_height, img.GetHeight()));
12529 wxImage imgs = img.GetSubImage(r);
12533 case GLOBAL_COLOR_SCHEME_DAY:
12537 case GLOBAL_COLOR_SCHEME_DUSK:
12540 case GLOBAL_COLOR_SCHEME_NIGHT:
12547 const int w = imgs.GetWidth();
12548 const int h = imgs.GetHeight();
12549 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12554 for (
int y = 1; y < h - 1; y++) {
12555 for (
int x = 1; x < w - 1; x++) {
12557 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12558 val = (int)(val * val_factor);
12559 index = (y * w) + x;
12572void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12573 Track *active_track = NULL;
12574 for (
Track *pTrackDraw : g_TrackList) {
12575 if (g_pActiveTrack == pTrackDraw) {
12576 active_track = pTrackDraw;
12580 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12583 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12586void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12587 Track *active_track = NULL;
12588 for (
Track *pTrackDraw : g_TrackList) {
12589 if (g_pActiveTrack == pTrackDraw) {
12590 active_track = pTrackDraw;
12594 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12597void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12598 Route *active_route = NULL;
12600 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12601 node = node->GetNext()) {
12602 Route *pRouteDraw = node->GetData();
12603 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12604 active_route = pRouteDraw;
12609 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12614 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12617void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12618 Route *active_route = NULL;
12620 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12621 node = node->GetNext()) {
12622 Route *pRouteDraw = node->GetData();
12623 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12624 active_route = pRouteDraw;
12628 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12631void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12632 if (!pWayPointMan)
return;
12634 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12639 if (pWP->m_bIsInRoute) {
12640 node = node->GetNext();
12645 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12649 if (pWP->GetShowWaypointRangeRings() &&
12650 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12651 double factor = 1.00;
12652 if (pWP->GetWaypointRangeRingsStepUnits() ==
12654 factor = 1 / 1.852;
12656 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12657 pWP->GetWaypointRangeRingsStep() / 60.;
12661 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12662 pWP->m_lat + radius, pWP->m_lon + radius);
12663 if (!BltBBox.IntersectOut(radar_box)) {
12670 node = node->GetNext();
12674void ChartCanvas::DrawBlinkObjects(
void) {
12676 wxRect update_rect;
12678 if (!pWayPointMan)
return;
12680 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12685 if (pWP->m_bBlink) {
12686 update_rect.Union(pWP->CurrentRect_in_DC);
12690 node = node->GetNext();
12692 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12695void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12698 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12700 wxPoint lAnchorPoint1, lAnchorPoint2;
12703 if (pAnchorWatchPoint1) {
12704 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12708 if (pAnchorWatchPoint2) {
12709 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12714 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12715 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12717 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12718 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12719 dc.SetBrush(*ppBrush);
12723 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12728 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12733 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12738 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12743double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12746 wxPoint lAnchorPoint;
12749 double tlat1, tlon1;
12751 if (pAnchorWatchPoint) {
12752 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12753 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12754 dabs = fabs(d1 / 1852.);
12755 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12760 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12761 pow((
double)(lAnchorPoint.y - r1.y), 2));
12764 if (d1 < 0) lpp = -lpp;
12772void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12773 if (!ptcmgr)
return;
12775 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12777 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12778 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12783 if ((type ==
't') || (type ==
'T')) {
12784 if (BBox.Contains(lat, lon)) {
12786 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12792extern wxDateTime gTimeSource;
12794void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12795 if (!ptcmgr)
return;
12797 wxDateTime this_now = gTimeSource;
12798 bool cur_time = !gTimeSource.IsValid();
12799 if (cur_time) this_now = wxDateTime::Now();
12800 time_t t_this_now = this_now.GetTicks();
12802 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12803 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12804 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12805 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12807 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12808 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12811 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12812 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12815 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12816 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12817 wxBRUSHSTYLE_SOLID);
12818 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12819 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12820 wxBRUSHSTYLE_SOLID);
12822 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
12823 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12824 int font_size = wxMax(10, dFont->GetPointSize());
12827 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
12828 false, dFont->GetFaceName());
12830 dc.SetPen(*pblack_pen);
12831 dc.SetBrush(*pgreen_brush);
12835 case GLOBAL_COLOR_SCHEME_DAY:
12838 case GLOBAL_COLOR_SCHEME_DUSK:
12841 case GLOBAL_COLOR_SCHEME_NIGHT:
12842 bm = m_bmTideNight;
12849 int bmw = bm.GetWidth();
12850 int bmh = bm.GetHeight();
12852 float scale_factor = 1.0;
12856 float icon_pixelRefDim = 45;
12860 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
12861 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
12862 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12876 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
12878 float nominal_icon_size_pixels = 48;
12879 float pix_factor = (2 * height) / nominal_icon_size_pixels;
12889 double targetHeight0 = 16.0;
12892 double displaySize = m_display_size_mm;
12893 displaySize = wxMax(displaySize, 100);
12895 float targetHeight = wxMin(targetHeight0, displaySize / 15);
12897 double pix_factor = targetHeight / symHeight;
12900 scale_factor *= pix_factor;
12902 float user_scale_factor = g_ChartScaleFactorExp;
12903 if (g_ChartScaleFactorExp > 1.0)
12904 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
12907 scale_factor *= user_scale_factor;
12908 scale_factor *= GetContentScaleFactor();
12911 double marge = 0.05;
12912 std::vector<LLBBox> drawn_boxes;
12913 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12914 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12917 if ((type ==
't') || (type ==
'T'))
12922 if (BBox.ContainsMarge(lat, lon, marge)) {
12924 if (GetVP().chart_scale < 500000) {
12925 bool bdrawn =
false;
12926 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
12927 if (drawn_boxes[i].Contains(lat, lon)) {
12932 if (bdrawn)
continue;
12935 this_box.Set(lat, lon, lat, lon);
12936 this_box.EnLarge(.005);
12937 drawn_boxes.push_back(this_box);
12943 if (GetVP().chart_scale > 500000) {
12944 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
12948 dc.SetFont(*plabelFont);
12960 if (ptcmgr->GetTideFlowSens(
12961 t_this_now, BACKWARD_TEN_MINUTES_STEP,
12965 ptcmgr->GetHightOrLowTide(
12966 t_this_now + BACKWARD_TEN_MINUTES_STEP,
12967 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
12979 if (tctime > t_this_now)
12980 ptcmgr->GetHightOrLowTide(
12981 t_this_now, BACKWARD_TEN_MINUTES_STEP,
12982 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
12986 ptcmgr->GetHightOrLowTide(
12987 t_this_now, FORWARD_TEN_MINUTES_STEP,
12988 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13002 int width = (int)(12 * scale_factor + 0.5);
13003 int height = (int)(45 * scale_factor + 0.5);
13004 int linew = wxMax(1, (
int)(scale_factor));
13005 int xDraw = r.x - (width / 2);
13006 int yDraw = r.y - (height / 2);
13009 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13010 int hs = (httime > lttime) ? -4 : 4;
13011 hs *= (int)(scale_factor + 0.5);
13012 if (ts > 0.995 || ts < 0.005) hs = 0;
13013 int ht_y = (int)(height * ts);
13016 pblack_pen->SetWidth(linew);
13017 dc.SetPen(*pblack_pen);
13018 dc.SetBrush(*pyelo_brush);
13019 dc.DrawRectangle(xDraw, yDraw, width, height);
13023 dc.SetPen(*pblue_pen);
13024 dc.SetBrush(*pblue_brush);
13025 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13026 (width - (4 * linew)), height - ht_y);
13032 arrow[0].x = xDraw + 2 * linew;
13033 arrow[1].x = xDraw + width / 2;
13034 arrow[2].x = xDraw + width - 2 * linew;
13035 pyelo_pen->SetWidth(linew);
13036 pblue_pen->SetWidth(linew);
13037 if (ts > 0.35 || ts < 0.15)
13039 hl = (int)(height * 0.25) + yDraw;
13041 arrow[1].y = hl + hs;
13044 dc.SetPen(*pyelo_pen);
13046 dc.SetPen(*pblue_pen);
13047 dc.DrawLines(3, arrow);
13049 if (ts > 0.60 || ts < 0.40)
13051 hl = (int)(height * 0.5) + yDraw;
13053 arrow[1].y = hl + hs;
13056 dc.SetPen(*pyelo_pen);
13058 dc.SetPen(*pblue_pen);
13059 dc.DrawLines(3, arrow);
13061 if (ts < 0.65 || ts > 0.85)
13063 hl = (int)(height * 0.75) + yDraw;
13065 arrow[1].y = hl + hs;
13068 dc.SetPen(*pyelo_pen);
13070 dc.SetPen(*pblue_pen);
13071 dc.DrawLines(3, arrow);
13075 s.Printf(_T(
"%3.1f"), nowlev);
13077 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13079 dc.GetTextExtent(s, &wx1, NULL);
13081 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13096void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13097 if (!ptcmgr)
return;
13099 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13101 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13102 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13107 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13108 if ((BBox.Contains(lat, lon))) {
13110 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13116void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13117 if (!ptcmgr)
return;
13119 float tcvalue, dir;
13123 double lon_last = 0.;
13124 double lat_last = 0.;
13126 double marge = 0.2;
13127 bool cur_time = !gTimeSource.IsValid();
13129 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13130 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13132 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13133 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13134 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13135 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13137 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13138 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13139 wxBRUSHSTYLE_SOLID);
13140 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13141 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13142 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13143 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13145 double skew_angle = GetVPRotation();
13147 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13148 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13149 int font_size = wxMax(10, dFont->GetPointSize());
13152 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13153 false, dFont->GetFaceName());
13155 float scale_factor = 1.0;
13162 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
13163 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
13164 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13170 float nominal_icon_size_pixels = 6;
13171 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
13178 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13180 float nominal_icon_size_pixels = 15;
13181 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13188 float icon_pixelRefDim = 5;
13193 double targetHeight0 = 2.0;
13196 double displaySize = m_display_size_mm;
13197 displaySize = wxMax(displaySize, 100);
13199 float targetHeight = wxMin(targetHeight0, displaySize / 50);
13200 double pix_factor = targetHeight / symHeight;
13203 scale_factor *= pix_factor;
13205 float user_scale_factor = g_ChartScaleFactorExp;
13206 if (g_ChartScaleFactorExp > 1.0)
13207 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13210 scale_factor *= user_scale_factor;
13212 scale_factor *= GetContentScaleFactor();
13215 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13216 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13221 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13222 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13227 int dd = (int)(5.0 * scale_factor + 0.5);
13238 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13239 dc.SetPen(*pblack_pen);
13240 dc.SetBrush(*porange_brush);
13241 dc.DrawPolygon(4, d);
13244 dc.SetBrush(*pblack_brush);
13245 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13249 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13263 double a1 = fabs(tcvalue) * 10.;
13265 a1 = wxMax(1.0, a1);
13266 double a2 = log10(a1);
13268 float cscale = scale_factor * a2 * 0.4;
13270 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13271 dc.SetPen(*porange_pen);
13272 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13276 if (bDrawCurrentValues) {
13277 dc.SetFont(*pTCFont);
13278 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13279 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13300void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
13301 pCwin =
new TCWin(
this, x, y, pvIDX);
13304#define NUM_CURRENT_ARROW_POINTS 9
13305static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13306 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13307 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13308 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13310void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13312 if (
scale > 1e-2) {
13313 float sin_rot = sin(rot_angle * PI / 180.);
13314 float cos_rot = cos(rot_angle * PI / 180.);
13318 float xt = CurrentArrowArray[0].x;
13319 float yt = CurrentArrowArray[0].y;
13321 float xp = (xt * cos_rot) - (yt * sin_rot);
13322 float yp = (xt * sin_rot) + (yt * cos_rot);
13323 int x1 = (int)(xp *
scale);
13324 int y1 = (int)(yp *
scale);
13327 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13328 xt = CurrentArrowArray[ip].x;
13329 yt = CurrentArrowArray[ip].y;
13331 float xp = (xt * cos_rot) - (yt * sin_rot);
13332 float yp = (xt * sin_rot) + (yt * cos_rot);
13333 int x2 = (int)(xp *
scale);
13334 int y2 = (int)(yp *
scale);
13336 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13344wxString ChartCanvas::FindValidUploadPort() {
13347 if (!g_uploadConnection.IsEmpty() &&
13348 g_uploadConnection.StartsWith(_T(
"Serial"))) {
13349 port = g_uploadConnection;
13355 for (
auto *cp : TheConnectionParams()) {
13356 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13357 port << _T(
"Serial:") << cp->Port;
13363void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13366 if (NULL == g_pais_query_dialog_active) {
13367 int pos_x = g_ais_query_dialog_x;
13368 int pos_y = g_ais_query_dialog_y;
13370 if (g_pais_query_dialog_active) {
13371 g_pais_query_dialog_active->Destroy();
13377 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13378 wxPoint(pos_x, pos_y));
13380 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13381 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13382 g_pais_query_dialog_active->SetMMSI(mmsi);
13383 g_pais_query_dialog_active->UpdateText();
13384 wxSize sz = g_pais_query_dialog_active->GetSize();
13386 bool b_reset_pos =
false;
13391 RECT frame_title_rect;
13392 frame_title_rect.left = pos_x;
13393 frame_title_rect.top = pos_y;
13394 frame_title_rect.right = pos_x + sz.x;
13395 frame_title_rect.bottom = pos_y + 30;
13397 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13398 b_reset_pos =
true;
13403 wxRect window_title_rect;
13404 window_title_rect.x = pos_x;
13405 window_title_rect.y = pos_y;
13406 window_title_rect.width = sz.x;
13407 window_title_rect.height = 30;
13409 wxRect ClientRect = wxGetClientDisplayRect();
13410 ClientRect.Deflate(
13412 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13416 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13419 g_pais_query_dialog_active->SetMMSI(mmsi);
13420 g_pais_query_dialog_active->UpdateText();
13423 g_pais_query_dialog_active->Show();
13426void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13427 bool cur_mode = GetQuiltMode();
13429 if (!GetQuiltMode())
13430 SetQuiltMode(
true);
13431 else if (GetQuiltMode()) {
13432 SetQuiltMode(
false);
13433 g_sticky_chart = GetQuiltReferenceChartIndex();
13436 if (cur_mode != GetQuiltMode()) {
13437 SetupCanvasQuiltMode();
13446 if (ps52plib) ps52plib->GenerateStateHash();
13448 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13449 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13452void ChartCanvas::DoCanvasStackDelta(
int direction) {
13453 if (!GetQuiltMode()) {
13454 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13455 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13456 if ((current_stack_index + direction) < 0)
return;
13458 if (m_bpersistent_quilt ) {
13460 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13462 if (IsChartQuiltableRef(new_dbIndex)) {
13463 ToggleCanvasQuiltMode();
13464 SelectQuiltRefdbChart(new_dbIndex);
13465 m_bpersistent_quilt =
false;
13468 SelectChartFromStack(current_stack_index + direction);
13471 std::vector<int> piano_chart_index_array =
13472 GetQuiltExtendedStackdbIndexArray();
13473 int refdb = GetQuiltRefChartdbIndex();
13476 int current_index = -1;
13477 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13478 if (refdb == piano_chart_index_array[i]) {
13483 if (current_index == -1)
return;
13486 int target_family = ctet.GetChartFamily();
13488 int new_index = -1;
13489 int check_index = current_index + direction;
13490 bool found =
false;
13491 int check_dbIndex = -1;
13492 int new_dbIndex = -1;
13496 (
unsigned int)check_index < piano_chart_index_array.size() &&
13497 (check_index >= 0)) {
13498 check_dbIndex = piano_chart_index_array[check_index];
13499 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13500 if (target_family == cte.GetChartFamily()) {
13502 new_index = check_index;
13503 new_dbIndex = check_dbIndex;
13507 check_index += direction;
13510 if (!found)
return;
13512 if (!IsChartQuiltableRef(new_dbIndex)) {
13513 ToggleCanvasQuiltMode();
13514 SelectdbChart(new_dbIndex);
13515 m_bpersistent_quilt =
true;
13517 SelectQuiltRefChart(new_index);
13521 gFrame->UpdateGlobalMenuItems();
13523 SetQuiltChartHiLiteIndex(-1);
13534void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13537 switch (event.GetId()) {
13551 DoCanvasStackDelta(1);
13556 DoCanvasStackDelta(-1);
13566 ShowCurrents(!GetbShowCurrent());
13573 ShowTides(!GetbShowTide());
13580 if (0 == m_routeState) {
13587 androidSetRouteAnnunciator(m_routeState == 1);
13593 SetAISCanvasDisplayStyle(-1);
13605void ChartCanvas::SetShowAIS(
bool show) {
13607 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13608 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13611void ChartCanvas::SetAttenAIS(
bool show) {
13612 m_bShowAISScaled = show;
13613 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13614 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13617void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13620 bool bShowAIS_Array[3] = {
true,
true,
false};
13621 bool bShowScaled_Array[3] = {
false,
true,
true};
13622 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13623 _(
"Attenuate less critical AIS targets"),
13624 _(
"Hide AIS Targets")};
13625 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13626 _T(
"AIS_Disabled")};
13628 int AIS_Toolbar_Switch = 0;
13629 if (StyleIndx == -1) {
13631 for (
int i = 1; i < ArraySize; i++) {
13632 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13633 (bShowScaled_Array[i] == m_bShowAISScaled))
13634 AIS_Toolbar_Switch = i;
13636 AIS_Toolbar_Switch++;
13637 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13638 AIS_Toolbar_Switch++;
13641 AIS_Toolbar_Switch = StyleIndx;
13644 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13646 int AIS_Toolbar_Switch_Next =
13647 AIS_Toolbar_Switch + 1;
13648 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13649 AIS_Toolbar_Switch_Next++;
13650 if (AIS_Toolbar_Switch_Next >= ArraySize)
13651 AIS_Toolbar_Switch_Next = 0;
13654 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13655 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13658void ChartCanvas::TouchAISToolActive(
void) {}
13660void ChartCanvas::UpdateAISTBTool(
void) {}
13668void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13670 bool b_update =
false;
13671 int cc1_edge_comp = 2;
13672 wxRect rect = m_Compass->
GetRect();
13673 wxSize parent_size = GetSize();
13675 parent_size *= m_displayScale;
13679 wxPoint tentative_pt(parent_size.x - rect.width - cc1_edge_comp,
13680 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13681 wxRect tentative_rect(tentative_pt, rect.GetSize());
13683 m_Compass->Move(tentative_pt);
13685 if (m_Compass && m_Compass->IsShown())
13686 m_Compass->UpdateStatus(b_force_new | b_update);
13688 if (b_force_new | b_update) Refresh();
13691void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13692 ChartTypeEnum New_Type,
13693 ChartFamilyEnum New_Family) {
13694 if (!GetpCurrentStack())
return;
13695 if (!ChartData)
return;
13697 if (index < GetpCurrentStack()->nEntry) {
13700 pTentative_Chart = ChartData->OpenStackChartConditional(
13701 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13703 if (pTentative_Chart) {
13704 if (m_singleChart) m_singleChart->Deactivate();
13706 m_singleChart = pTentative_Chart;
13707 m_singleChart->Activate();
13709 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13710 GetpCurrentStack(), m_singleChart->GetFullPath());
13723 double best_scale_ppm = GetBestVPScale(m_singleChart);
13724 double rotation = GetVPRotation();
13725 double oldskew = GetVPSkew();
13726 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13728 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13729 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13730 if (fabs(newskew) > 0.0001) rotation = newskew;
13733 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13735 UpdateGPSCompassStatusBox(
true);
13739 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13740 if (idx < 0)
return;
13742 std::vector<int> piano_active_chart_index_array;
13743 piano_active_chart_index_array.push_back(
13744 GetpCurrentStack()->GetCurrentEntrydbIndex());
13745 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13748void ChartCanvas::SelectdbChart(
int dbindex) {
13749 if (!GetpCurrentStack())
return;
13750 if (!ChartData)
return;
13752 if (dbindex >= 0) {
13755 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13757 if (pTentative_Chart) {
13758 if (m_singleChart) m_singleChart->Deactivate();
13760 m_singleChart = pTentative_Chart;
13761 m_singleChart->Activate();
13763 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13764 GetpCurrentStack(), m_singleChart->GetFullPath());
13777 double best_scale_ppm = GetBestVPScale(m_singleChart);
13781 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13791void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13794 if (!GetQuiltMode()) {
13795 if (GetpCurrentStack()) {
13796 int stack_index = -1;
13797 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13798 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13799 if (check_dbIndex < 0)
continue;
13801 ChartData->GetChartTableEntry(check_dbIndex);
13802 if (type == cte.GetChartType()) {
13805 }
else if (family == cte.GetChartFamily()) {
13811 if (stack_index >= 0) {
13812 SelectChartFromStack(stack_index);
13816 int sel_dbIndex = -1;
13817 std::vector<int> piano_chart_index_array =
13818 GetQuiltExtendedStackdbIndexArray();
13819 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13820 int check_dbIndex = piano_chart_index_array[i];
13821 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13822 if (type == cte.GetChartType()) {
13823 if (IsChartQuiltableRef(check_dbIndex)) {
13824 sel_dbIndex = check_dbIndex;
13827 }
else if (family == cte.GetChartFamily()) {
13828 if (IsChartQuiltableRef(check_dbIndex)) {
13829 sel_dbIndex = check_dbIndex;
13835 if (sel_dbIndex >= 0) {
13836 SelectQuiltRefdbChart(sel_dbIndex,
false);
13838 AdjustQuiltRefChart();
13845 SetQuiltChartHiLiteIndex(-1);
13850bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
13851 return std::find(m_tile_yesshow_index_array.begin(),
13852 m_tile_yesshow_index_array.end(),
13853 index) != m_tile_yesshow_index_array.end();
13856bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
13857 return std::find(m_tile_noshow_index_array.begin(),
13858 m_tile_noshow_index_array.end(),
13859 index) != m_tile_noshow_index_array.end();
13862void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
13863 if (std::find(m_tile_noshow_index_array.begin(),
13864 m_tile_noshow_index_array.end(),
13865 index) == m_tile_noshow_index_array.end()) {
13866 m_tile_noshow_index_array.push_back(index);
13876void ChartCanvas::HandlePianoClick(
13877 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
13878 if (g_options && g_options->IsShown())
13880 if (!m_pCurrentStack)
return;
13881 if (!ChartData)
return;
13896 double distance = 25000;
13897 int closest_index = -1;
13898 for (
int chart_index : selected_dbIndex_array) {
13899 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
13900 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
13901 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
13904 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
13905 if (test_distance < distance) {
13906 distance = test_distance;
13907 closest_index = chart_index;
13911 int selected_dbIndex = selected_dbIndex_array[0];
13912 if (closest_index >= 0) selected_dbIndex = closest_index;
13914 if (!GetQuiltMode()) {
13915 if (m_bpersistent_quilt ) {
13916 if (IsChartQuiltableRef(selected_dbIndex)) {
13917 ToggleCanvasQuiltMode();
13918 SelectQuiltRefdbChart(selected_dbIndex);
13919 m_bpersistent_quilt =
false;
13921 SelectChartFromStack(selected_index);
13924 SelectChartFromStack(selected_index);
13925 g_sticky_chart = selected_dbIndex;
13929 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
13933 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
13934 bool bfound =
false;
13935 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
13936 if (m_tile_noshow_index_array[i] ==
13937 selected_dbIndex) {
13938 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
13945 m_tile_noshow_index_array.push_back(selected_dbIndex);
13949 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
13950 m_tile_yesshow_index_array.push_back(selected_dbIndex);
13954 if (IsChartQuiltableRef(selected_dbIndex)) {
13960 bool set_scale =
false;
13961 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
13962 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
13968 SelectQuiltRefdbChart(selected_dbIndex,
true);
13970 SelectQuiltRefdbChart(selected_dbIndex,
false);
13975 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
13977 double proposed_scale_onscreen =
13980 if (g_bPreserveScaleOnX) {
13981 proposed_scale_onscreen =
13982 wxMin(proposed_scale_onscreen,
13984 GetCanvasWidth()));
13986 proposed_scale_onscreen =
13987 wxMin(proposed_scale_onscreen,
13989 GetCanvasWidth()));
13991 proposed_scale_onscreen =
13992 wxMax(proposed_scale_onscreen,
14001 ToggleCanvasQuiltMode();
14002 SelectdbChart(selected_dbIndex);
14003 m_bpersistent_quilt =
true;
14008 SetQuiltChartHiLiteIndex(-1);
14009 gFrame->UpdateGlobalMenuItems();
14011 HideChartInfoWindow();
14016void ChartCanvas::HandlePianoRClick(
14017 int x,
int y,
int selected_index,
14018 const std::vector<int> &selected_dbIndex_array) {
14019 if (g_options && g_options->IsShown())
14021 if (!GetpCurrentStack())
return;
14023 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14024 UpdateCanvasControlBar();
14026 SetQuiltChartHiLiteIndex(-1);
14029void ChartCanvas::HandlePianoRollover(
14030 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14031 int n_charts,
int scale) {
14032 if (g_options && g_options->IsShown())
14034 if (!GetpCurrentStack())
return;
14035 if (!ChartData)
return;
14037 if (ChartData->IsBusy())
return;
14039 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14041 if (!GetQuiltMode()) {
14042 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14045 std::vector<int> piano_chart_index_array;
14046 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14047 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14048 if ((GetpCurrentStack()->nEntry > 1) ||
14049 (piano_chart_index_array.size() >= 1)) {
14050 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14052 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14054 }
else if (GetpCurrentStack()->nEntry == 1) {
14056 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14057 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14058 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14060 }
else if ((-1 == selected_index) &&
14061 (0 == selected_dbIndex_array.size())) {
14062 ShowChartInfoWindow(key_location.x, -1);
14066 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14068 if ((GetpCurrentStack()->nEntry > 1) ||
14069 (piano_chart_index_array.size() >= 1)) {
14071 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14072 selected_dbIndex_array);
14073 else if (n_charts == 1)
14074 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14076 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14083void ChartCanvas::ClearPianoRollover() {
14084 ClearQuiltChartHiLiteIndexArray();
14085 ShowChartInfoWindow(0, -1);
14086 std::vector<int> vec;
14087 ShowCompositeInfoWindow(0, 0, 0, vec);
14091void ChartCanvas::UpdateCanvasControlBar(
void) {
14092 if (m_pianoFrozen)
return;
14094 if (!GetpCurrentStack())
return;
14095 if (!ChartData)
return;
14096 if (!g_bShowChartBar)
return;
14099 int sel_family = -1;
14101 std::vector<int> piano_chart_index_array;
14102 std::vector<int> empty_piano_chart_index_array;
14104 wxString old_hash = m_Piano->GetStoredHash();
14106 if (GetQuiltMode()) {
14107 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14108 GetQuiltFullScreendbIndexArray());
14110 std::vector<int> piano_active_chart_index_array =
14111 GetQuiltCandidatedbIndexArray();
14112 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14114 std::vector<int> piano_eclipsed_chart_index_array =
14115 GetQuiltEclipsedStackdbIndexArray();
14116 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14118 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14119 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14121 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14122 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14124 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
14125 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14128 if (m_singleChart) {
14129 sel_type = m_singleChart->GetChartType();
14130 sel_family = m_singleChart->GetChartFamily();
14135 std::vector<int> piano_skew_chart_index_array;
14136 std::vector<int> piano_tmerc_chart_index_array;
14137 std::vector<int> piano_poly_chart_index_array;
14139 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14141 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14142 double skew_norm = ctei.GetChartSkew();
14143 if (skew_norm > 180.) skew_norm -= 360.;
14145 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14146 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14149 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14150 if (fabs(skew_norm) > 1.)
14151 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14153 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14154 }
else if (fabs(skew_norm) > 1.)
14155 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14157 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14158 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14159 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14161 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14162 if (new_hash != old_hash) {
14163 m_Piano->FormatKeys();
14164 HideChartInfoWindow();
14165 m_Piano->ResetRollover();
14166 SetQuiltChartHiLiteIndex(-1);
14167 m_brepaint_piano =
true;
14173 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14175 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14176 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14177 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14178 if (e == CHART_FAMILY_RASTER) mask |= 1;
14179 if (e == CHART_FAMILY_VECTOR) {
14180 if (t == CHART_TYPE_CM93COMP)
14187 wxString s_indicated;
14188 if (sel_type == CHART_TYPE_CM93COMP)
14189 s_indicated = _T(
"cm93");
14191 if (sel_family == CHART_FAMILY_RASTER)
14192 s_indicated = _T(
"raster");
14193 else if (sel_family == CHART_FAMILY_VECTOR)
14194 s_indicated = _T(
"vector");
14197 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14200void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14202void ChartCanvas::PianoPopupMenu(
14203 int x,
int y,
int selected_index,
14204 const std::vector<int> &selected_dbIndex_array) {
14205 if (!GetpCurrentStack())
return;
14208 if (!GetQuiltMode())
return;
14210 m_piano_ctx_menu =
new wxMenu();
14212 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14222 menu_selected_dbIndex = selected_dbIndex_array[0];
14223 menu_selected_index = selected_index;
14226 bool b_is_in_noshow =
false;
14227 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14228 if (m_quilt_noshow_index_array[i] ==
14229 menu_selected_dbIndex)
14231 b_is_in_noshow =
true;
14236 if (b_is_in_noshow) {
14237 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14238 _(
"Show This Chart"));
14239 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14240 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14241 }
else if (GetpCurrentStack()->nEntry > 1) {
14242 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14243 _(
"Hide This Chart"));
14244 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14245 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14249 wxPoint pos = wxPoint(x, y - 30);
14252 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14253 PopupMenu(m_piano_ctx_menu, pos);
14255 delete m_piano_ctx_menu;
14256 m_piano_ctx_menu = NULL;
14258 HideChartInfoWindow();
14259 m_Piano->ResetRollover();
14261 SetQuiltChartHiLiteIndex(-1);
14262 ClearQuiltChartHiLiteIndexArray();
14267void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14268 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14269 if (m_quilt_noshow_index_array[i] ==
14270 menu_selected_dbIndex)
14272 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14278void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14279 if (!GetpCurrentStack())
return;
14280 if (!ChartData)
return;
14282 RemoveChartFromQuilt(menu_selected_dbIndex);
14286 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14287 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
14289 int i = menu_selected_index + 1;
14290 bool b_success =
false;
14291 while (i < GetpCurrentStack()->nEntry - 1) {
14292 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14293 if (type == ChartData->GetDBChartType(dbIndex)) {
14294 SelectQuiltRefChart(i);
14304 i = menu_selected_index - 1;
14306 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14307 if (type == ChartData->GetDBChartType(dbIndex)) {
14308 SelectQuiltRefChart(i);
14318void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14320 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14321 if (m_quilt_noshow_index_array[i] ==
14324 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14329 m_quilt_noshow_index_array.push_back(dbIndex);
14332bool ChartCanvas::UpdateS52State() {
14333 bool retval =
false;
14337 ps52plib->SetShowS57Text(m_encShowText);
14338 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14339 ps52plib->m_bShowSoundg = m_encShowDepth;
14340 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14341 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14344 if (!m_encShowLights)
14345 ps52plib->AddObjNoshow(
"LIGHTS");
14347 ps52plib->RemoveObjNoshow(
"LIGHTS");
14348 ps52plib->SetLightsOff(!m_encShowLights);
14349 ps52plib->m_bExtendLightSectors =
true;
14352 ps52plib->SetAnchorOn(m_encShowAnchor);
14353 ps52plib->SetQualityOfData(m_encShowDataQual);
14359void ChartCanvas::SetShowENCDataQual(
bool show) {
14360 m_encShowDataQual = show;
14361 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14362 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14364 m_s52StateHash = 0;
14367void ChartCanvas::SetShowENCText(
bool show) {
14368 m_encShowText = show;
14369 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14370 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14372 m_s52StateHash = 0;
14375void ChartCanvas::SetENCDisplayCategory(
int category) {
14376 m_encDisplayCategory = category;
14377 m_s52StateHash = 0;
14380void ChartCanvas::SetShowENCDepth(
bool show) {
14381 m_encShowDepth = show;
14382 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14383 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14385 m_s52StateHash = 0;
14388void ChartCanvas::SetShowENCLightDesc(
bool show) {
14389 m_encShowLightDesc = show;
14390 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14391 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14393 m_s52StateHash = 0;
14396void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14397 m_encShowBuoyLabels = show;
14398 m_s52StateHash = 0;
14401void ChartCanvas::SetShowENCLights(
bool show) {
14402 m_encShowLights = show;
14403 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14404 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14406 m_s52StateHash = 0;
14409void ChartCanvas::SetShowENCAnchor(
bool show) {
14410 m_encShowAnchor = show;
14411 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14412 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14414 m_s52StateHash = 0;
14417wxRect ChartCanvas::GetMUIBarRect() {
14420 rv = m_muiBar->GetRect();
14426void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14427 if (!GetAlertString().IsEmpty()) {
14428 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14429 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14431 dc.SetFont(*pfont);
14432 dc.SetPen(*wxTRANSPARENT_PEN);
14434 dc.SetBrush(wxColour(243, 229, 47));
14436 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14440 wxRect sbr = GetScaleBarRect();
14441 int xp = sbr.x + sbr.width + 10;
14442 int yp = (sbr.y + sbr.height) - h;
14444 int wdraw = w + 10;
14445 dc.DrawRectangle(xp, yp, wdraw, h);
14446 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14447 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14457#define BRIGHT_XCALIB
14458#define __OPCPN_USEICC__
14461#ifdef __OPCPN_USEICC__
14462int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14463 double co_green,
double co_blue);
14465wxString temp_file_name;
14469class ocpnCurtain:
public wxDialog
14471 DECLARE_CLASS( ocpnCurtain )
14472 DECLARE_EVENT_TABLE()
14475 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14477 bool ProcessEvent(wxEvent& event);
14481IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14483BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14486ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14488 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14491ocpnCurtain::~ocpnCurtain()
14495bool ocpnCurtain::ProcessEvent(wxEvent& event)
14497 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14498 return GetParent()->GetEventHandler()->ProcessEvent(event);
14503#include <windows.h>
14506typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14507typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14508SetDeviceGammaRamp_ptr_type
14509 g_pSetDeviceGammaRamp;
14510GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14512WORD *g_pSavedGammaMap;
14516int InitScreenBrightness(
void) {
14519 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14523 if (NULL == hGDI32DLL) {
14524 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14526 if (NULL != hGDI32DLL) {
14528 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14529 hGDI32DLL,
"SetDeviceGammaRamp");
14530 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14531 hGDI32DLL,
"GetDeviceGammaRamp");
14534 if ((NULL == g_pSetDeviceGammaRamp) ||
14535 (NULL == g_pGetDeviceGammaRamp)) {
14536 FreeLibrary(hGDI32DLL);
14545 if (!g_pSavedGammaMap) {
14546 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14549 bbr = g_pGetDeviceGammaRamp(
14550 hDC, g_pSavedGammaMap);
14551 ReleaseDC(NULL, hDC);
14556 wxRegKey *pRegKey =
new wxRegKey(
14557 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14558 _T(
"NT\\CurrentVersion\\ICM"));
14559 if (!pRegKey->Exists()) pRegKey->Create();
14560 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14562 g_brightness_init =
true;
14568 if (NULL == g_pcurtain) {
14569 if (gFrame->CanSetTransparent()) {
14571 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14572 wxPoint(0, 0), ::wxGetDisplaySize(),
14573 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14574 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14581 g_pcurtain->Hide();
14583 HWND hWnd = GetHwndOf(g_pcurtain);
14584 SetWindowLong(hWnd, GWL_EXSTYLE,
14585 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14586 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14587 g_pcurtain->SetTransparent(0);
14589 g_pcurtain->Maximize();
14590 g_pcurtain->Show();
14593 g_pcurtain->Enable();
14594 g_pcurtain->Disable();
14601 g_brightness_init =
true;
14607 wxString cmd(_T (
"xcalib -version" ));
14609 wxArrayString output;
14610 long r = wxExecute(cmd, output);
14613 _T(
" External application \"xcalib\" not found. Screen brightness ")
14614 _T(
"not changed."));
14616 g_brightness_init =
true;
14621int RestoreScreenBrightness(
void) {
14624 if (g_pSavedGammaMap) {
14625 HDC hDC = GetDC(NULL);
14626 g_pSetDeviceGammaRamp(hDC,
14628 ReleaseDC(NULL, hDC);
14630 free(g_pSavedGammaMap);
14631 g_pSavedGammaMap = NULL;
14635 g_pcurtain->Close();
14636 g_pcurtain->Destroy();
14640 g_brightness_init =
false;
14645#ifdef BRIGHT_XCALIB
14646 if (g_brightness_init) {
14648 cmd = _T(
"xcalib -clear");
14649 wxExecute(cmd, wxEXEC_ASYNC);
14650 g_brightness_init =
false;
14660int SetScreenBrightness(
int brightness) {
14667 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14669 g_pcurtain->Close();
14670 g_pcurtain->Destroy();
14674 InitScreenBrightness();
14676 if (NULL == hGDI32DLL) {
14678 wchar_t wdll_name[80];
14679 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14680 LPCWSTR cstr = wdll_name;
14682 hGDI32DLL = LoadLibrary(cstr);
14684 if (NULL != hGDI32DLL) {
14686 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14687 hGDI32DLL,
"SetDeviceGammaRamp");
14688 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14689 hGDI32DLL,
"GetDeviceGammaRamp");
14692 if ((NULL == g_pSetDeviceGammaRamp) ||
14693 (NULL == g_pGetDeviceGammaRamp)) {
14694 FreeLibrary(hGDI32DLL);
14701 HDC hDC = GetDC(NULL);
14712 int increment = brightness * 256 / 100;
14715 WORD GammaTable[3][256];
14718 for (
int i = 0; i < 256; i++) {
14719 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14720 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14721 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14723 table_val += increment;
14725 if (table_val > 65535) table_val = 65535;
14728 g_pSetDeviceGammaRamp(hDC, GammaTable);
14729 ReleaseDC(NULL, hDC);
14736 if (g_pSavedGammaMap) {
14737 HDC hDC = GetDC(NULL);
14738 g_pSetDeviceGammaRamp(hDC,
14740 ReleaseDC(NULL, hDC);
14743 if (brightness < 100) {
14744 if (NULL == g_pcurtain) InitScreenBrightness();
14747 int sbrite = wxMax(1, brightness);
14748 sbrite = wxMin(100, sbrite);
14750 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14754 g_pcurtain->Close();
14755 g_pcurtain->Destroy();
14765#ifdef BRIGHT_XCALIB
14767 if (!g_brightness_init) {
14768 last_brightness = 100;
14769 g_brightness_init =
true;
14770 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14771 InitScreenBrightness();
14774#ifdef __OPCPN_USEICC__
14777 if (!CreateSimpleICCProfileFile(
14778 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14779 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14780 wxString cmd(_T (
"xcalib " ));
14781 cmd += temp_file_name;
14783 wxExecute(cmd, wxEXEC_ASYNC);
14792 if (brightness > last_brightness) {
14794 cmd = _T(
"xcalib -clear");
14795 wxExecute(cmd, wxEXEC_ASYNC);
14797 ::wxMilliSleep(10);
14799 int brite_adj = wxMax(1, brightness);
14800 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14801 wxExecute(cmd, wxEXEC_ASYNC);
14803 int brite_adj = wxMax(1, brightness);
14804 int factor = (brite_adj * 100) / last_brightness;
14805 factor = wxMax(1, factor);
14807 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14808 wxExecute(cmd, wxEXEC_ASYNC);
14813 last_brightness = brightness;
14820#ifdef __OPCPN_USEICC__
14822#define MLUT_TAG 0x6d4c5554L
14823#define VCGT_TAG 0x76636774L
14825int GetIntEndian(
unsigned char *s) {
14830 p = (
unsigned char *)&ret;
14833 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14835 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14840unsigned short GetShortEndian(
unsigned char *s) {
14841 unsigned short ret;
14845 p = (
unsigned char *)&ret;
14848 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
14850 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
14856int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14857 double co_green,
double co_blue) {
14861 fp = fopen(file_name,
"wb");
14862 if (!fp)
return -1;
14868 for (
int i = 0; i < 128; i++) header[i] = 0;
14870 fwrite(header, 128, 1, fp);
14874 int numTags = GetIntEndian((
unsigned char *)&numTags0);
14875 fwrite(&numTags, 1, 4, fp);
14877 int tagName0 = VCGT_TAG;
14878 int tagName = GetIntEndian((
unsigned char *)&tagName0);
14879 fwrite(&tagName, 1, 4, fp);
14881 int tagOffset0 = 128 + 4 *
sizeof(int);
14882 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
14883 fwrite(&tagOffset, 1, 4, fp);
14886 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
14887 fwrite(&tagSize, 1, 4, fp);
14889 fwrite(&tagName, 1, 4, fp);
14891 fwrite(&tagName, 1, 4, fp);
14896 int gammatype0 = 0;
14897 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
14898 fwrite(&gammatype, 1, 4, fp);
14900 int numChannels0 = 3;
14901 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
14902 fwrite(&numChannels, 1, 2, fp);
14904 int numEntries0 = 256;
14905 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
14906 fwrite(&numEntries, 1, 2, fp);
14908 int entrySize0 = 1;
14909 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
14910 fwrite(&entrySize, 1, 2, fp);
14912 unsigned char ramp[256];
14915 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
14916 fwrite(ramp, 256, 1, fp);
14919 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
14920 fwrite(ramp, 256, 1, fp);
14923 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
14924 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.
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 at the mouse cursor position in degrees.
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 at the mouse cursor position in degrees.
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)
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.
Represents the view port for chart display in OpenCPN.
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.
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.
Tools to send data to plugins.
Route validators for dialog validation.
Represents an entry in the chart table, containing information about a single chart.