33#include <wx/graphics.h>
34#include <wx/clipbrd.h>
35#include <wx/aui/aui.h>
39#include <wx/listimpl.cpp>
41#include "model/ais_decoder.h"
43#include "model/ais_target_data.h"
45#include "model/conn_params.h"
46#include "model/cutil.h"
47#include "model/geodesic.h"
49#include "model/idents.h"
50#include "model/multiplexer.h"
52#include "model/nav_object_database.h"
53#include "model/navutil_base.h"
54#include "model/own_ship.h"
56#include "model/route.h"
57#include "model/routeman.h"
58#include "model/select.h"
59#include "model/select_item.h"
60#include "model/track.h"
61#include "model/wx28compat.h"
64#include "AISTargetAlertDialog.h"
65#include "CanvasConfig.h"
66#include "canvasMenu.h"
67#include "CanvasOptions.h"
76#include "hotkeys_dlg.h"
78#include "glTextureDescriptor.h"
80#include "iENCToolbar.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"
126#include "notification_manager_gui.h"
131#include <wx/msw/msvcrt.h>
140extern float g_ShipScaleFactorExp;
141extern double g_mouse_zoom_sensitivity;
146#define printf printf2
148int __cdecl printf2(
const char *format, ...) {
152 va_start(argptr, format);
153 int ret = vsnprintf(str,
sizeof(str), format, argptr);
155 OutputDebugStringA(str);
160#if defined(__MSVC__) && (_MSC_VER < 1700)
161#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
167#define OCPN_ALT_MENUBAR 1
175extern bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
176extern void catch_signals(
int signo);
178extern void AlphaBlending(
ocpnDC &dc,
int x,
int y,
int size_x,
int size_y,
179 float radius, wxColour color,
180 unsigned char transparency);
182extern double g_ChartNotRenderScaleFactor;
184extern bool bDBUpdateInProgress;
185extern ColorScheme global_color_scheme;
186extern int g_nbrightness;
191extern RouteList *pRouteList;
192extern std::vector<Track *> g_TrackList;
203extern double AnchorPointMinDist;
204extern bool AnchorAlertOn1;
205extern bool AnchorAlertOn2;
210extern wxString GetLayerName(
int id);
211extern wxString g_uploadConnection;
212extern bool g_bsimplifiedScalebar;
214extern bool bDrawCurrentValues;
216extern s52plib *ps52plib;
218extern bool g_bTempShowMenuBar;
219extern bool g_bShowMenuBar;
220extern bool g_bShowCompassWin;
225extern int g_iNavAidRadarRingsNumberVisible;
226extern bool g_bNavAidRadarRingsShown;
227extern float g_fNavAidRadarRingsStep;
228extern int g_pNavAidRadarRingsStepUnits;
229extern bool g_bWayPointPreventDragging;
230extern bool g_bEnableZoomToCursor;
231extern bool g_bShowChartBar;
232extern int g_ENCSoundingScaleFactor;
233extern int g_ENCTextScaleFactor;
234extern int g_maxzoomin;
236bool g_bShowShipToActive;
237int g_shipToActiveStyle;
238int g_shipToActiveColor;
242extern int g_S57_dialog_sx, g_S57_dialog_sy;
245extern int g_detailslider_dialog_x, g_detailslider_dialog_y;
247extern bool g_b_overzoom_x;
248extern double g_plus_minus_zoom_factor;
250extern int g_OwnShipIconType;
251extern double g_n_ownship_length_meters;
252extern double g_n_ownship_beam_meters;
253extern double g_n_gps_antenna_offset_y;
254extern double g_n_gps_antenna_offset_x;
255extern int g_n_ownship_min_mm;
257extern double g_COGAvg;
259extern int g_click_stop;
261extern double g_ownship_predictor_minutes;
262extern int g_cog_predictor_style;
263extern wxString g_cog_predictor_color;
264extern int g_cog_predictor_endmarker;
265extern int g_ownship_HDTpredictor_style;
266extern wxString g_ownship_HDTpredictor_color;
267extern int g_ownship_HDTpredictor_endmarker;
268extern int g_ownship_HDTpredictor_width;
269extern double g_ownship_HDTpredictor_miles;
271extern bool g_bquiting;
278extern bool g_bopengl;
280extern bool g_bFullScreenQuilt;
282extern bool g_bsmoothpanzoom;
283extern bool g_bSmoothRecenter;
287extern bool g_b_assume_azerty;
289extern ChartGroupArray *g_pGroupArray;
294extern OcpnSound *g_anchorwatch_sound;
296extern bool g_bresponsive;
297extern int g_chart_zoom_modifier_raster;
298extern int g_chart_zoom_modifier_vector;
299extern int g_ChartScaleFactor;
304extern double g_gl_ms_per_frame;
305extern bool g_benable_rotate;
306extern bool g_bRollover;
308extern bool g_bSpaceDropMark;
309extern bool g_bAutoHideToolbar;
310extern int g_nAutoHideToolbar;
311extern bool g_bDeferredInitDone;
313extern wxString g_CmdSoundString;
338static bool mouse_leftisdown;
340bool g_brouteCreating;
342bool g_bShowTrackPointTime;
348bool g_brightness_init;
351int g_cog_predictor_width;
352extern double g_display_size_mm;
356extern wxColour g_colourOwnshipRangeRingsColour;
360extern double g_defaultBoatSpeed;
361double g_defaultBoatSpeedUserUnit;
363extern int g_nAIS_activity_timer;
364extern bool g_bskew_comp;
365extern float g_compass_scalefactor;
366extern int g_COGAvgSec;
367extern bool g_btenhertz;
369wxGLContext *g_pGLcontext;
372extern unsigned int g_canvasConfig;
377extern float g_toolbar_scalefactor;
380wxString g_ObjQFileExt;
385extern int g_GUIScaleFactor;
388wxString g_lastS52PLIBPluginMessage;
389extern bool g_bChartBarEx;
390bool g_PrintingInProgress;
393#define MAX_BRIGHT 100
399EVT_PAINT(ChartCanvas::OnPaint)
400EVT_ACTIVATE(ChartCanvas::OnActivate)
401EVT_SIZE(ChartCanvas::OnSize)
402#ifndef HAVE_WX_GESTURE_EVENTS
403EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
405EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
406EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
407EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
408EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
409EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
410EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
411EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
412EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
413EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
414EVT_KEY_UP(ChartCanvas::OnKeyUp)
415EVT_CHAR(ChartCanvas::OnKeyChar)
416EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
417EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
418EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
419EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
420EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
421EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
422EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
423EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
429 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
430 m_nmea_log(nmea_log) {
431 parent_frame = (
MyFrame *)frame;
432 m_canvasIndex = canvasIndex;
436 SetBackgroundColour(wxColour(0, 0, 0));
437 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
441 m_bDrawingRoute =
false;
442 m_bRouteEditing =
false;
443 m_bMarkEditing =
false;
444 m_bRoutePoinDragging =
false;
445 m_bIsInRadius =
false;
446 m_bMayToggleMenuBar =
true;
449 m_bShowNavobjects =
true;
451 m_bAppendingRoute =
false;
452 pThumbDIBShow = NULL;
453 m_bShowCurrent =
false;
455 bShowingCurrent =
false;
459 m_b_paint_enable =
true;
462 pss_overlay_bmp = NULL;
463 pss_overlay_mask = NULL;
464 m_bChartDragging =
false;
465 m_bMeasure_Active =
false;
466 m_bMeasure_DistCircle =
false;
467 m_pMeasureRoute = NULL;
468 m_pTrackRolloverWin = NULL;
469 m_pRouteRolloverWin = NULL;
470 m_pAISRolloverWin = NULL;
472 m_disable_edge_pan =
false;
473 m_dragoffsetSet =
false;
477 m_singleChart = NULL;
478 m_upMode = NORTH_UP_MODE;
480 m_bShowAISScaled =
false;
481 m_timed_move_vp_active =
false;
488 m_pSelectedRoute = NULL;
489 m_pSelectedTrack = NULL;
490 m_pRoutePointEditTarget = NULL;
491 m_pFoundPoint = NULL;
492 m_pMouseRoute = NULL;
493 m_prev_pMousePoint = NULL;
494 m_pEditRouteArray = NULL;
495 m_pFoundRoutePoint = NULL;
496 m_FinishRouteOnKillFocus =
true;
498 m_pRolloverRouteSeg = NULL;
499 m_pRolloverTrackSeg = NULL;
500 m_bsectors_shown =
false;
502 m_bbrightdir =
false;
507 m_pos_image_user_day = NULL;
508 m_pos_image_user_dusk = NULL;
509 m_pos_image_user_night = NULL;
510 m_pos_image_user_grey_day = NULL;
511 m_pos_image_user_grey_dusk = NULL;
512 m_pos_image_user_grey_night = NULL;
515 m_rotation_speed = 0;
521 m_pos_image_user_yellow_day = NULL;
522 m_pos_image_user_yellow_dusk = NULL;
523 m_pos_image_user_yellow_night = NULL;
525 SetOwnShipState(SHIP_INVALID);
527 undo =
new Undo(
this);
533 m_focus_indicator_pix = 1;
535 m_pCurrentStack = NULL;
536 m_bpersistent_quilt =
false;
537 m_piano_ctx_menu = NULL;
539 m_NotificationsList = NULL;
540 m_notification_button = NULL;
542 g_ChartNotRenderScaleFactor = 2.0;
543 m_bShowScaleInStatusBar =
true;
546 m_bShowScaleInStatusBar =
false;
547 m_show_focus_bar =
true;
549 m_bShowOutlines =
false;
550 m_bDisplayGrid =
false;
551 m_bShowDepthUnits =
true;
552 m_encDisplayCategory = (int)STANDARD;
554 m_encShowLights =
true;
555 m_encShowAnchor =
true;
556 m_encShowDataQual =
false;
558 m_pQuilt =
new Quilt(
this);
560 SetAlertString(_T(
""));
563 g_PrintingInProgress =
false;
565#ifdef HAVE_WX_GESTURE_EVENTS
566 m_oldVPSScale = -1.0;
567 m_popupWanted =
false;
573 singleClickEventIsValid =
false;
582 pCursorPencil = NULL;
587 SetCursor(*pCursorArrow);
589 pPanTimer =
new wxTimer(
this, m_MouseDragging);
592 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
593 pMovementTimer->Stop();
595 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
596 pMovementStopTimer->Stop();
598 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
599 pRotDefTimer->Stop();
601 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
602 m_DoubleClickTimer->Stop();
604 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
605 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
606 m_chart_drag_inertia_active =
false;
608 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
609 m_animationActive =
false;
613 m_panx_target_final = m_pany_target_final = 0;
614 m_panx_target_now = m_pany_target_now = 0;
616 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
617 pCurTrackTimer->Stop();
618 m_curtrack_timer_msec = 10;
620 m_wheelzoom_stop_oneshot = 0;
621 m_last_wheel_dir = 0;
623 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
625 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
627 m_rollover_popup_timer_msec = 20;
629 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
631 m_b_rot_hidef =
true;
636 m_upMode = NORTH_UP_MODE;
637 m_bLookAhead =
false;
641 m_cs = GLOBAL_COLOR_SCHEME_DAY;
644 VPoint.view_scale_ppm = 1;
648 m_canvas_scale_factor = 1.;
650 m_canvas_width = 1000;
652 m_overzoomTextWidth = 0;
653 m_overzoomTextHeight = 0;
657 gShapeBasemap.Reset();
662 m_pEM_Fathoms = NULL;
664 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
666 m_pEM_OverZoom = NULL;
668 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
672 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"),
676 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
679 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
682 double factor_dusk = 0.5;
683 double factor_night = 0.25;
686 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
688 int rimg_width = m_os_image_red_day.GetWidth();
689 int rimg_height = m_os_image_red_day.GetHeight();
691 m_os_image_red_dusk = m_os_image_red_day.Copy();
692 m_os_image_red_night = m_os_image_red_day.Copy();
694 for (
int iy = 0; iy < rimg_height; iy++) {
695 for (
int ix = 0; ix < rimg_width; ix++) {
696 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
697 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
698 m_os_image_red_day.GetGreen(ix, iy),
699 m_os_image_red_day.GetBlue(ix, iy));
700 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
701 hsv.value = hsv.value * factor_dusk;
702 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
703 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
705 hsv = wxImage::RGBtoHSV(rgb);
706 hsv.value = hsv.value * factor_night;
707 nrgb = wxImage::HSVtoRGB(hsv);
708 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
714 m_os_image_grey_day =
715 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
717 int gimg_width = m_os_image_grey_day.GetWidth();
718 int gimg_height = m_os_image_grey_day.GetHeight();
720 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
721 m_os_image_grey_night = m_os_image_grey_day.Copy();
723 for (
int iy = 0; iy < gimg_height; iy++) {
724 for (
int ix = 0; ix < gimg_width; ix++) {
725 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
726 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
727 m_os_image_grey_day.GetGreen(ix, iy),
728 m_os_image_grey_day.GetBlue(ix, iy));
729 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
730 hsv.value = hsv.value * factor_dusk;
731 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
732 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
734 hsv = wxImage::RGBtoHSV(rgb);
735 hsv.value = hsv.value * factor_night;
736 nrgb = wxImage::HSVtoRGB(hsv);
737 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
743 m_os_image_yellow_day = m_os_image_red_day.Copy();
745 gimg_width = m_os_image_yellow_day.GetWidth();
746 gimg_height = m_os_image_yellow_day.GetHeight();
748 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
749 m_os_image_yellow_night = m_os_image_red_day.Copy();
751 for (
int iy = 0; iy < gimg_height; iy++) {
752 for (
int ix = 0; ix < gimg_width; ix++) {
753 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
754 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
755 m_os_image_yellow_day.GetGreen(ix, iy),
756 m_os_image_yellow_day.GetBlue(ix, iy));
757 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
758 hsv.hue += 60. / 360.;
759 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
760 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
762 hsv = wxImage::RGBtoHSV(rgb);
763 hsv.value = hsv.value * factor_dusk;
764 hsv.hue += 60. / 360.;
765 nrgb = wxImage::HSVtoRGB(hsv);
766 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
768 hsv = wxImage::RGBtoHSV(rgb);
769 hsv.hue += 60. / 360.;
770 hsv.value = hsv.value * factor_night;
771 nrgb = wxImage::HSVtoRGB(hsv);
772 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
778 m_pos_image_red = &m_os_image_red_day;
779 m_pos_image_yellow = &m_os_image_yellow_day;
780 m_pos_image_grey = &m_os_image_grey_day;
784 m_pBrightPopup = NULL;
787 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
790 int gridFontSize = 8;
791#if defined(__WXOSX__) || defined(__WXGTK3__)
793 gridFontSize *= GetContentScaleFactor();
797 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
798 FALSE, wxString(_T (
"Arial" )));
800 m_Piano =
new Piano(
this);
802 m_bShowCompassWin =
true;
805 m_Compass->SetScaleFactor(g_compass_scalefactor);
806 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
809 m_notification_button->SetScaleFactor(g_compass_scalefactor);
810 m_notification_button->Show(
true);
812 m_pianoFrozen =
false;
814 SetMinSize(wxSize(200, 200));
816 m_displayScale = 1.0;
817#if defined(__WXOSX__) || defined(__WXGTK3__)
819 m_displayScale = GetContentScaleFactor();
821 VPoint.SetPixelScale(m_displayScale);
823#ifdef HAVE_WX_GESTURE_EVENTS
826 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
827 wxLogError(
"Failed to enable touch events");
832 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
833 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
835 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
836 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
838 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
839 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
841 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
842 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
847 auto ¬eman = NotificationManager::GetInstance();
849 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
850 evt_notificationlist_change_listener.Listen(
851 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
852 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
853 if (m_NotificationsList && m_NotificationsList->IsShown()) {
854 m_NotificationsList->ReloadNotificationList();
860ChartCanvas::~ChartCanvas() {
861 delete pThumbDIBShow;
869 delete pCursorPencil;
873 delete pMovementTimer;
874 delete pMovementStopTimer;
875 delete pCurTrackTimer;
877 delete m_DoubleClickTimer;
879 delete m_pTrackRolloverWin;
880 delete m_pRouteRolloverWin;
881 delete m_pAISRolloverWin;
882 delete m_pBrightPopup;
888 m_dc_route.SelectObject(wxNullBitmap);
891 delete pWorldBackgroundChart;
892 delete pss_overlay_bmp;
896 delete m_pEM_Fathoms;
898 delete m_pEM_OverZoom;
903 delete m_pos_image_user_day;
904 delete m_pos_image_user_dusk;
905 delete m_pos_image_user_night;
906 delete m_pos_image_user_grey_day;
907 delete m_pos_image_user_grey_dusk;
908 delete m_pos_image_user_grey_night;
909 delete m_pos_image_user_yellow_day;
910 delete m_pos_image_user_yellow_dusk;
911 delete m_pos_image_user_yellow_night;
915 if (!g_bdisable_opengl) {
918#if wxCHECK_VERSION(2, 9, 0)
919 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
926 MUIBar *muiBar = m_muiBar;
930 delete m_pCurrentStack;
935void ChartCanvas::RebuildCursors() {
941 delete pCursorPencil;
945 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
949 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
950 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
951 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
952 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
953 wxImage ICursorPencil =
954 style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
955 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
957#if !defined(__WXMSW__) && !defined(__WXQT__)
958 ICursorLeft.ConvertAlphaToMask(128);
959 ICursorRight.ConvertAlphaToMask(128);
960 ICursorUp.ConvertAlphaToMask(128);
961 ICursorDown.ConvertAlphaToMask(128);
962 ICursorPencil.ConvertAlphaToMask(10);
963 ICursorCross.ConvertAlphaToMask(10);
966 if (ICursorLeft.Ok()) {
967 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
968 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
969 pCursorLeft =
new wxCursor(ICursorLeft);
971 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
973 if (ICursorRight.Ok()) {
974 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
975 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
976 pCursorRight =
new wxCursor(ICursorRight);
978 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
980 if (ICursorUp.Ok()) {
981 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
982 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
983 pCursorUp =
new wxCursor(ICursorUp);
985 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
987 if (ICursorDown.Ok()) {
988 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
989 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
990 pCursorDown =
new wxCursor(ICursorDown);
992 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
994 if (ICursorPencil.Ok()) {
995 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
996 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
997 pCursorPencil =
new wxCursor(ICursorPencil);
999 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
1001 if (ICursorCross.Ok()) {
1002 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
1003 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
1004 pCursorCross =
new wxCursor(ICursorCross);
1006 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
1008 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
1009 pPlugIn_Cursor = NULL;
1012void ChartCanvas::CanvasApplyLocale() {
1013 CreateDepthUnitEmbossMaps(m_cs);
1014 CreateOZEmbossMapData(m_cs);
1017void ChartCanvas::SetupGlCanvas() {
1020 if (!g_bdisable_opengl) {
1022 wxLogMessage(_T(
"Creating glChartCanvas"));
1027 if (IsPrimaryCanvas()) {
1034 wxGLContext *pctx =
new wxGLContext(m_glcc);
1035 m_glcc->SetContext(pctx);
1036 g_pGLcontext = pctx;
1039 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
1041 m_glcc->SetContext(g_pGLcontext);
1051 if (!g_bdisable_opengl) {
1054 wxLogMessage(_T(
"Creating glChartCanvas"));
1058 if (IsPrimaryCanvas()) {
1059 qDebug() <<
"Creating Primary glChartCanvas";
1067 wxGLContext *pctx =
new wxGLContext(m_glcc);
1068 m_glcc->SetContext(pctx);
1069 g_pGLcontext = pctx;
1070 m_glcc->m_pParentCanvas =
this;
1073 qDebug() <<
"Creating Secondary glChartCanvas";
1079 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1082 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1083 m_glcc->SetContext(pwxctx);
1084 m_glcc->m_pParentCanvas =
this;
1092void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1093 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1108 if (m_routeState && m_FinishRouteOnKillFocus)
1109 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1111 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1115void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1116 m_routeFinishTimer.Stop();
1120 gFrame->UpdateGlobalMenuItems(
this);
1122 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1125void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1126 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1129#ifdef HAVE_WX_GESTURE_EVENTS
1130void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1136 m_popupWanted =
true;
1139void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1143void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1145void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1147void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1148 wxPoint pos =
event.GetPosition();
1152 if (!m_popupWanted) {
1153 wxMouseEvent ev(wxEVT_LEFT_UP);
1160 m_popupWanted =
false;
1162 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1169void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1172 wxPoint pos =
event.GetPosition();
1176void ChartCanvas::OnMotion(wxMouseEvent &event) {
1181 event.m_leftDown = m_leftdown;
1185void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1187 if (event.IsGestureEnd())
return;
1189 double factor =
event.GetZoomFactor();
1191 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1196 double wanted_factor = m_oldVPSScale / current_vps * factor;
1201 if (event.IsGestureStart()) {
1202 m_zoomStartPoint =
event.GetPosition();
1204 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1206 m_zoomStartPoint =
event.GetPosition();
1210void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1212void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1213 DoRotateCanvas(0.0);
1217void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1222 m_restore_dbindex = pcc->DBindex;
1224 if (pcc->GroupID < 0) pcc->GroupID = 0;
1226 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1229 m_groupIndex = pcc->GroupID;
1231 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1245 m_encDisplayCategory = pcc->nENCDisplayCategory;
1246 m_encShowDepth = pcc->bShowENCDepths;
1247 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1248 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1249 m_encShowLights = pcc->bShowENCLights;
1250 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1251 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1252 m_encShowDataQual = pcc->bShowENCDataQuality;
1256 m_upMode = NORTH_UP_MODE;
1258 m_upMode = COURSE_UP_MODE;
1260 m_upMode = HEAD_UP_MODE;
1264 m_singleChart = NULL;
1267void ChartCanvas::ApplyGlobalSettings() {
1270 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1271 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1273 m_notification_button->UpdateStatus();
1276void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1277 bool groupOK = CheckGroup(m_groupIndex);
1280 SetGroupIndex(m_groupIndex,
true);
1284void ChartCanvas::SetShowGPS(
bool bshow) {
1285 if (m_bShowGPS != bshow) {
1288 m_Compass->SetScaleFactor(g_compass_scalefactor);
1289 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1294void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1295 m_bShowCompassWin = bshow;
1297 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1298 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1302int ChartCanvas::GetPianoHeight() {
1304 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1309void ChartCanvas::ConfigureChartBar() {
1312 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1313 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1315 if (GetQuiltMode()) {
1316 m_Piano->SetRoundedRectangles(
true);
1318 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1319 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1320 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1323void ChartCanvas::ShowTides(
bool bShow) {
1324 gFrame->LoadHarmonics();
1326 if (ptcmgr->IsReady()) {
1327 SetbShowTide(bShow);
1329 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1331 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1332 SetbShowTide(
false);
1333 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1336 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1337 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1348void ChartCanvas::ShowCurrents(
bool bShow) {
1349 gFrame->LoadHarmonics();
1351 if (ptcmgr->IsReady()) {
1352 SetbShowCurrent(bShow);
1353 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1355 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1356 SetbShowCurrent(
false);
1357 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1360 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1361 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1373extern bool g_bPreserveScaleOnX;
1375extern int g_sticky_chart;
1377void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1379void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1380 SetAlertString(_T(
""));
1382 int new_index = index;
1383 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1385 bool bgroup_override =
false;
1386 int old_group_index = new_index;
1388 if (!CheckGroup(new_index)) {
1390 bgroup_override =
true;
1393 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1397 int current_chart_native_scale = GetCanvasChartNativeScale();
1400 m_groupIndex = new_index;
1403 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1406 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1410 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1414 g_sticky_chart = -1;
1418 UpdateCanvasOnGroupChange();
1421 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1423 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1426 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1427 double best_scale = GetBestStartScale(dbi_hint, vp);
1431 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1435 canvasChartsRefresh(dbi_hint);
1437 UpdateCanvasControlBar();
1439 if (!autoSwitch && bgroup_override) {
1441 wxString msg(_(
"Group \""));
1443 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1444 msg += pGroup->m_group_name;
1446 msg += _(
"\" is empty.");
1448 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1455 if (bgroup_override) {
1456 wxString msg(_(
"Group \""));
1458 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1459 msg += pGroup->m_group_name;
1461 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1463 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1467bool ChartCanvas::CheckGroup(
int igroup) {
1468 if (!ChartData)
return true;
1470 if (igroup == 0)
return true;
1475 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1477 if (pGroup->m_element_array.empty())
1481 for (
const auto &elem : pGroup->m_element_array) {
1482 for (
unsigned int ic = 0;
1483 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1485 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1487 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1492 for (
const auto &elem : pGroup->m_element_array) {
1493 const wxString &element_root = elem.m_element_name;
1494 wxString test_string = _T(
"GSHH");
1495 if (element_root.Upper().Contains(test_string))
return true;
1501void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1502 if (!ChartData)
return;
1504 AbstractPlatform::ShowBusySpinner();
1508 SetQuiltRefChart(-1);
1510 m_singleChart = NULL;
1516 if (!m_pCurrentStack) {
1518 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1521 if (-1 != dbi_hint) {
1522 if (GetQuiltMode()) {
1523 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1524 SetQuiltRefChart(dbi_hint);
1528 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1530 if (pTentative_Chart) {
1533 if (m_singleChart) m_singleChart->Deactivate();
1535 m_singleChart = pTentative_Chart;
1536 m_singleChart->Activate();
1538 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1539 GetpCurrentStack(), m_singleChart->GetFullPath());
1547 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1548 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1549 SetQuiltRefChart(selected_index);
1553 SetupCanvasQuiltMode();
1554 if (!GetQuiltMode() && m_singleChart == 0) {
1556 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1557 m_singleChart = pDummyChart;
1563 UpdateCanvasControlBar();
1564 UpdateGPSCompassStatusBox(
true);
1566 SetCursor(wxCURSOR_ARROW);
1568 AbstractPlatform::HideBusySpinner();
1571bool ChartCanvas::DoCanvasUpdate(
void) {
1573 double vpLat, vpLon;
1574 bool blong_jump =
false;
1575 meters_to_shift = 0;
1578 bool bNewChart =
false;
1579 bool bNewView =
false;
1580 bool bCanvasChartAutoOpen =
true;
1582 bool bNewPiano =
false;
1583 bool bOpenSpecified;
1589 if (bDBUpdateInProgress)
return false;
1590 if (!ChartData)
return false;
1592 if (ChartData->IsBusy())
return false;
1618 double dx = m_OSoffsetx;
1619 double dy = m_OSoffsety;
1623 if (GetUpMode() == NORTH_UP_MODE) {
1624 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1626 double offset_angle = atan2(d_north, d_east);
1627 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1628 double chart_angle = GetVPRotation();
1629 double target_angle = chart_angle + offset_angle;
1630 double d_east_mod = offset_distance * cos(target_angle);
1631 double d_north_mod = offset_distance * sin(target_angle);
1632 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1635 extern double gCog_gt;
1638 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1639 double cog_to_use = gCog;
1641 (fabs(gCog - gCog_gt) > 20)) {
1642 cog_to_use = gCog_gt;
1645 if (!g_btenhertz) cog_to_use = g_COGAvg;
1647 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1649 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1650 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1652 double pixel_delta_tent =
1653 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1655 double pixel_delta = 0;
1660 if (!std::isnan(gSog)) {
1664 pixel_delta = pixel_delta_tent;
1667 meters_to_shift = 0;
1669 if (!std::isnan(gCog)) {
1670 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1671 dir_to_shift = cog_to_use;
1672 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1678 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1692 if (GetQuiltMode()) {
1693 int current_db_index = -1;
1694 if (m_pCurrentStack)
1697 ->GetCurrentEntrydbIndex();
1705 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1707 if (m_pCurrentStack->nEntry) {
1708 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1710 SelectQuiltRefdbChart(new_dbIndex,
true);
1711 m_bautofind =
false;
1715 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1716 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1721 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1727 double proposed_scale_onscreen =
1730 int initial_db_index = m_restore_dbindex;
1731 if (initial_db_index < 0) {
1732 if (m_pCurrentStack->nEntry) {
1734 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1739 if (m_pCurrentStack->nEntry) {
1740 int initial_type = ChartData->GetDBChartType(initial_db_index);
1745 if (!IsChartQuiltableRef(initial_db_index)) {
1749 int stack_index = 0;
1751 if (stack_index >= 0) {
1752 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1753 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1754 if (IsChartQuiltableRef(test_db_index) &&
1756 ChartData->GetDBChartType(initial_db_index))) {
1757 initial_db_index = test_db_index;
1765 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1767 SetQuiltRefChart(initial_db_index);
1768 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1776 0, GetVPRotation());
1781 bool super_jump =
false;
1783 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1784 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1785 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1787 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead) {
1789 if (blong_jump) nstep = 20;
1790 StartTimedMovementVP(vpLat, vpLon, nstep);
1799 pLast_Ch = m_singleChart;
1800 ChartTypeEnum new_open_type;
1801 ChartFamilyEnum new_open_family;
1803 new_open_type = pLast_Ch->GetChartType();
1804 new_open_family = pLast_Ch->GetChartFamily();
1806 new_open_type = CHART_TYPE_KAP;
1807 new_open_family = CHART_FAMILY_RASTER;
1810 bOpenSpecified = m_bFirstAuto;
1813 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1816 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1818 if (NULL == pDummyChart) {
1824 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1826 m_singleChart = pDummyChart;
1831 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1833 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1836 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1837 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1844 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1850 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1855 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1858 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1863 if (NULL != m_singleChart)
1864 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1865 m_singleChart->GetFullPath());
1868 m_pCurrentStack->CurrentStackEntry = tEntry;
1878 if (bCanvasChartAutoOpen) {
1879 bool search_direction =
1881 int start_index = 0;
1885 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1886 (LastStack.nEntry == 0)) {
1887 search_direction =
true;
1888 start_index = m_pCurrentStack->nEntry - 1;
1892 if (bOpenSpecified) {
1893 search_direction =
false;
1895 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1898 new_open_type = CHART_TYPE_DONTCARE;
1901 pProposed = ChartData->OpenStackChartConditional(
1902 m_pCurrentStack, start_index, search_direction, new_open_type,
1906 if (NULL == pProposed)
1907 pProposed = ChartData->OpenStackChartConditional(
1908 m_pCurrentStack, start_index, search_direction,
1909 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1911 if (NULL == pProposed)
1912 pProposed = ChartData->OpenStackChartConditional(
1913 m_pCurrentStack, start_index, search_direction,
1914 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1925 if (NULL == pProposed) {
1926 if (NULL == pDummyChart) {
1932 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1934 pProposed = pDummyChart;
1938 if (m_singleChart) m_singleChart->Deactivate();
1939 m_singleChart = pProposed;
1941 if (m_singleChart) {
1942 m_singleChart->Activate();
1943 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1944 m_pCurrentStack, m_singleChart->GetFullPath());
1949 if (NULL != m_singleChart) {
1955 if (!GetVP().IsValid())
1956 set_scale = 1. / 20000.;
1958 double proposed_scale_onscreen;
1961 double new_scale_ppm =
1962 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1970 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1971 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1972 double equivalent_vp_scale =
1974 double new_scale_ppm =
1975 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1980 proposed_scale_onscreen =
1981 wxMin(proposed_scale_onscreen,
1984 proposed_scale_onscreen =
1985 wxMax(proposed_scale_onscreen,
1994 m_singleChart->GetChartSkew() * PI / 180.,
2001 if ((m_bFollow) && m_singleChart)
2003 m_singleChart->GetChartSkew() * PI / 180.,
2012 m_bFirstAuto =
false;
2016 if (bNewChart && !bNewView) Refresh(
false);
2021 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
2024 return bNewChart | bNewView;
2027void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
2028 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
2030 SetQuiltRefChart(db_index);
2032 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
2035 double best_scale_ppm = GetBestVPScale(pc);
2039 SetQuiltRefChart(-1);
2041 SetQuiltRefChart(-1);
2044void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
2045 std::vector<int> piano_chart_index_array =
2046 GetQuiltExtendedStackdbIndexArray();
2047 int current_db_index = piano_chart_index_array[selected_index];
2049 SelectQuiltRefdbChart(current_db_index);
2052double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2056 if ((g_bPreserveScaleOnX) ||
2057 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2063 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2064 double equivalent_vp_scale =
2066 double new_scale_ppm =
2067 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2074 double max_underzoom_multiplier = 2.0;
2075 if (GetVP().b_quilt) {
2076 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2077 pchart->GetChartType(),
2078 pchart->GetChartFamily());
2079 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2082 proposed_scale_onscreen = wxMin(
2083 proposed_scale_onscreen,
2085 max_underzoom_multiplier);
2088 proposed_scale_onscreen =
2089 wxMax(proposed_scale_onscreen,
2097void ChartCanvas::SetupCanvasQuiltMode(
void) {
2100 ChartData->LockCache();
2102 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2106 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2107 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2108 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2109 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2111 m_Piano->SetRoundedRectangles(
true);
2114 int target_new_dbindex = -1;
2115 if (m_pCurrentStack) {
2116 target_new_dbindex =
2117 GetQuiltReferenceChartIndex();
2119 if (-1 != target_new_dbindex) {
2120 if (!IsChartQuiltableRef(target_new_dbindex)) {
2121 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2122 int type = ChartData->GetDBChartType(target_new_dbindex);
2125 int stack_index = m_pCurrentStack->CurrentStackEntry;
2127 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2128 (stack_index >= 0)) {
2129 int proj_tent = ChartData->GetDBChartProj(
2130 m_pCurrentStack->GetDBIndex(stack_index));
2131 int type_tent = ChartData->GetDBChartType(
2132 m_pCurrentStack->GetDBIndex(stack_index));
2134 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2135 if ((proj == proj_tent) && (type_tent == type)) {
2136 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2146 if (IsChartQuiltableRef(target_new_dbindex))
2147 SelectQuiltRefdbChart(target_new_dbindex,
2150 SelectQuiltRefdbChart(-1,
false);
2152 m_singleChart = NULL;
2155 AdjustQuiltRefChart();
2163 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2167 std::vector<int> empty_array;
2168 m_Piano->SetActiveKeyArray(empty_array);
2169 m_Piano->SetNoshowIndexArray(empty_array);
2170 m_Piano->SetEclipsedIndexArray(empty_array);
2173 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2174 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2175 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2176 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2178 m_Piano->SetRoundedRectangles(
false);
2184 if (!GetQuiltMode()) {
2185 if (ChartData && ChartData->IsValid()) {
2189 if (m_bFollow ==
true) {
2197 if (!m_singleChart) {
2200 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2208 int cur_max_scale = (int)1e8;
2210 ChartBase *pChart = GetFirstQuiltChart();
2214 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2216 if (pChart->GetNativeScale() < cur_max_scale) {
2217 Candidate_Chart = pChart;
2218 cur_max_scale = pChart->GetNativeScale();
2221 pChart = GetNextQuiltChart();
2224 m_singleChart = Candidate_Chart;
2228 if (NULL == m_singleChart) {
2229 m_singleChart = ChartData->OpenStackChartConditional(
2230 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2231 CHART_FAMILY_DONTCARE);
2237 InvalidateAllQuiltPatchs();
2239 if (m_singleChart) {
2240 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2241 std::vector<int> one_array;
2242 one_array.push_back(dbi);
2243 m_Piano->SetActiveKeyArray(one_array);
2246 if (m_singleChart) {
2247 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2251 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2255bool ChartCanvas::IsTempMenuBarEnabled() {
2258 wxGetOsVersion(&major);
2266double ChartCanvas::GetCanvasRangeMeters() {
2268 GetSize(&width, &height);
2269 int minDimension = wxMin(width, height);
2272 range *= cos(GetVP().clat * PI / 180.);
2276void ChartCanvas::SetCanvasRangeMeters(
double range) {
2278 GetSize(&width, &height);
2279 int minDimension = wxMin(width, height);
2281 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2285bool ChartCanvas::SetUserOwnship() {
2289 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2290 double factor_dusk = 0.5;
2291 double factor_night = 0.25;
2293 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2294 m_pos_image_user_day =
new wxImage;
2295 *m_pos_image_user_day = pbmp->ConvertToImage();
2296 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2298 int gimg_width = m_pos_image_user_day->GetWidth();
2299 int gimg_height = m_pos_image_user_day->GetHeight();
2302 m_pos_image_user_dusk =
new wxImage;
2303 m_pos_image_user_night =
new wxImage;
2305 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2306 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2308 for (
int iy = 0; iy < gimg_height; iy++) {
2309 for (
int ix = 0; ix < gimg_width; ix++) {
2310 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2311 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2312 m_pos_image_user_day->GetGreen(ix, iy),
2313 m_pos_image_user_day->GetBlue(ix, iy));
2314 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2315 hsv.value = hsv.value * factor_dusk;
2316 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2317 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2320 hsv = wxImage::RGBtoHSV(rgb);
2321 hsv.value = hsv.value * factor_night;
2322 nrgb = wxImage::HSVtoRGB(hsv);
2323 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2330 m_pos_image_user_grey_day =
new wxImage;
2331 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2333 m_pos_image_user_grey_dusk =
new wxImage;
2334 m_pos_image_user_grey_night =
new wxImage;
2336 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2337 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2339 for (
int iy = 0; iy < gimg_height; iy++) {
2340 for (
int ix = 0; ix < gimg_width; ix++) {
2341 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2342 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2343 m_pos_image_user_grey_day->GetGreen(ix, iy),
2344 m_pos_image_user_grey_day->GetBlue(ix, iy));
2345 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2346 hsv.value = hsv.value * factor_dusk;
2347 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2348 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2351 hsv = wxImage::RGBtoHSV(rgb);
2352 hsv.value = hsv.value * factor_night;
2353 nrgb = wxImage::HSVtoRGB(hsv);
2354 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2361 m_pos_image_user_yellow_day =
new wxImage;
2362 m_pos_image_user_yellow_dusk =
new wxImage;
2363 m_pos_image_user_yellow_night =
new wxImage;
2365 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2366 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2367 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2369 for (
int iy = 0; iy < gimg_height; iy++) {
2370 for (
int ix = 0; ix < gimg_width; ix++) {
2371 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2372 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2373 m_pos_image_user_grey_day->GetGreen(ix, iy),
2374 m_pos_image_user_grey_day->GetBlue(ix, iy));
2378 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2379 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2380 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2382 hsv = wxImage::RGBtoHSV(rgb);
2383 hsv.value = hsv.value * factor_dusk;
2384 nrgb = wxImage::HSVtoRGB(hsv);
2385 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2387 hsv = wxImage::RGBtoHSV(rgb);
2388 hsv.value = hsv.value * factor_night;
2389 nrgb = wxImage::HSVtoRGB(hsv);
2390 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2402 m_display_size_mm = size;
2409 double horizontal = sd.x;
2413 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2414 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2417 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2418 ps52plib->SetPPMM(m_pix_per_mm);
2423 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2425 m_display_size_mm, sd.x, sd.y);
2429 ssx = g_monitor_info[g_current_monitor].width;
2430 ssy = g_monitor_info[g_current_monitor].height;
2431 msg.Printf(_T(
"monitor size: %d %d"), ssx, ssy);
2434 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2437void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2439 wxString msg(event.m_string.c_str(), wxConvUTF8);
2441 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2442 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2445 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2447 compress_msg_array.RemoveAt(event.thread);
2448 compress_msg_array.Insert( msg, event.thread);
2451 compress_msg_array.Add(msg);
2454 wxString combined_msg;
2455 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2456 combined_msg += compress_msg_array[i];
2457 combined_msg += _T(
"\n");
2461 pprog->Update(pprog_count, combined_msg, &skip );
2462 pprog->SetSize(pprog_size);
2467void ChartCanvas::InvalidateGL() {
2468 if (!m_glcc)
return;
2470 if (g_bopengl) m_glcc->Invalidate();
2472 if (m_Compass) m_Compass->UpdateStatus(
true);
2475int ChartCanvas::GetCanvasChartNativeScale() {
2477 if (!VPoint.b_quilt) {
2478 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2480 ret = (int)m_pQuilt->GetRefNativeScale();
2485ChartBase *ChartCanvas::GetChartAtCursor() {
2487 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2488 target_chart = m_singleChart;
2489 else if (VPoint.b_quilt)
2490 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2492 target_chart = NULL;
2493 return target_chart;
2496ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2500 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2502 target_chart = NULL;
2503 return target_chart;
2506int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2507 int new_dbIndex = -1;
2508 if (!VPoint.b_quilt) {
2509 if (m_pCurrentStack) {
2510 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2511 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2513 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2523 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2525 for (
unsigned int is = 0; is < im; is++) {
2527 m_pQuilt->GetExtendedStackIndexArray()[is]);
2530 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2540void ChartCanvas::EnablePaint(
bool b_enable) {
2541 m_b_paint_enable = b_enable;
2543 if (m_glcc) m_glcc->EnablePaint(b_enable);
2547bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2549void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2551std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2552 return m_pQuilt->GetQuiltIndexArray();
2556void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2557 VPoint.b_quilt = b_quilt;
2558 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2561bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2563int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2564 return m_pQuilt->GetRefChartdbIndex();
2567void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2568 m_pQuilt->InvalidateAllQuiltPatchs();
2571ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2572 return m_pQuilt->GetLargestScaleChart();
2575ChartBase *ChartCanvas::GetFirstQuiltChart() {
2576 return m_pQuilt->GetFirstChart();
2579ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2581int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2583void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2584 m_pQuilt->SetHiliteIndex(dbIndex);
2587void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2588 m_pQuilt->SetHiliteIndexArray(hilite_array);
2591void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2592 m_pQuilt->ClearHiliteIndexArray();
2595std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2597 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2600int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2601 return m_pQuilt->GetRefChartdbIndex();
2604std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2605 return m_pQuilt->GetExtendedStackIndexArray();
2608std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2609 return m_pQuilt->GetFullscreenIndexArray();
2612std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2613 return m_pQuilt->GetEclipsedStackIndexArray();
2616void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2618double ChartCanvas::GetQuiltMaxErrorFactor() {
2619 return m_pQuilt->GetMaxErrorFactor();
2622bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2623 return m_pQuilt->IsChartQuiltableRef(db_index);
2627 double chartMaxScale =
2629 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2632void ChartCanvas::StartMeasureRoute() {
2633 if (!m_routeState) {
2634 if (m_bMeasure_Active) {
2636 NavObjectChanges::getInstance());
2637 m_pMeasureRoute = NULL;
2640 m_bMeasure_Active =
true;
2641 m_nMeasureState = 1;
2642 m_bDrawingRoute =
false;
2644 SetCursor(*pCursorPencil);
2649void ChartCanvas::CancelMeasureRoute() {
2650 m_bMeasure_Active =
false;
2651 m_nMeasureState = 0;
2652 m_bDrawingRoute =
false;
2654 g_pRouteMan->
DeleteRoute(m_pMeasureRoute, NavObjectChanges::getInstance());
2655 m_pMeasureRoute = NULL;
2657 SetCursor(*pCursorArrow);
2660ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2662void ChartCanvas::SetVP(
ViewPort &vp) {
2673void ChartCanvas::TriggerDeferredFocus() {
2676 m_deferredFocusTimer.Start(20,
true);
2678#if defined(__WXGTK__) || defined(__WXOSX__)
2689void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2694void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2695 if (SendKeyEventToPlugins(event))
2699 int key_char =
event.GetKeyCode();
2702 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2708 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2713 if (g_benable_rotate) {
2734void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2735 if (SendKeyEventToPlugins(event))
2739 bool b_handled =
false;
2741 m_modkeys =
event.GetModifiers();
2743 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2745#ifdef OCPN_ALT_MENUBAR
2751 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2753 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2754 if (!g_bTempShowMenuBar) {
2755 g_bTempShowMenuBar =
true;
2756 parent_frame->ApplyGlobalSettings(
false);
2758 m_bMayToggleMenuBar =
false;
2764 if (event.GetKeyCode() != WXK_ALT) {
2765 m_bMayToggleMenuBar =
false;
2772 switch (event.GetKeyCode()) {
2779 event.GetPosition(&x, &y);
2780 m_FinishRouteOnKillFocus =
false;
2781 CallPopupMenu(x, y);
2782 m_FinishRouteOnKillFocus =
true;
2786 m_modkeys |= wxMOD_ALT;
2790 m_modkeys |= wxMOD_CONTROL;
2795 case WXK_RAW_CONTROL:
2796 m_modkeys |= wxMOD_RAW_CONTROL;
2801 if (m_modkeys == wxMOD_CONTROL)
2802 parent_frame->DoStackDown(
this);
2803 else if (g_bsmoothpanzoom) {
2804 StartTimedMovement();
2813 if (g_bsmoothpanzoom) {
2814 StartTimedMovement();
2822 if (m_modkeys == wxMOD_CONTROL)
2823 parent_frame->DoStackUp(
this);
2824 else if (g_bsmoothpanzoom) {
2825 StartTimedMovement();
2834 if (g_bsmoothpanzoom) {
2835 StartTimedMovement();
2847 SetShowENCText(!GetShowENCText());
2853 if (!m_bMeasure_Active) {
2854 if (event.ShiftDown())
2855 m_bMeasure_DistCircle =
true;
2857 m_bMeasure_DistCircle =
false;
2859 StartMeasureRoute();
2861 CancelMeasureRoute();
2863 SetCursor(*pCursorArrow);
2873 parent_frame->ToggleColorScheme();
2875 TriggerDeferredFocus();
2879 int mod = m_modkeys & wxMOD_SHIFT;
2880 if (mod != m_brightmod) {
2882 m_bbrightdir = !m_bbrightdir;
2885 if (!m_bbrightdir) {
2886 g_nbrightness -= 10;
2887 if (g_nbrightness <= MIN_BRIGHT) {
2888 g_nbrightness = MIN_BRIGHT;
2889 m_bbrightdir =
true;
2892 g_nbrightness += 10;
2893 if (g_nbrightness >= MAX_BRIGHT) {
2894 g_nbrightness = MAX_BRIGHT;
2895 m_bbrightdir =
false;
2899 SetScreenBrightness(g_nbrightness);
2900 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2909 parent_frame->DoStackDown(
this);
2913 parent_frame->DoStackUp(
this);
2918 double t0 = wxGetLocalTimeMillis().ToDouble();
2920 double t1 = wxGetLocalTimeMillis().ToDouble() - t0;
2922 ToggleCanvasQuiltMode();
2923 auto ¬eman = NotificationManager::GetInstance();
2924 noteman.AddNotification(NotificationSeverity::kCritical,
2925 "Test Notification long message.\nMultiline "
2926 "message that may be many, many chars wide.");
2933 parent_frame->ToggleFullScreen();
2938 if (m_modkeys == wxMOD_ALT) {
2943 UpdateGPSCompassStatusBox(
true);
2944 auto ¬eman = NotificationManager::GetInstance();
2945 noteman.AddNotification(NotificationSeverity::kInformational,
2946 "Test Timed Notification", 10);
2948 ToggleChartOutlines();
2954 parent_frame->ActivateMOB();
2958 case WXK_NUMPAD_ADD:
2963 case WXK_NUMPAD_SUBTRACT:
2964 case WXK_PAGEDOWN: {
2965 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2970 if (m_bMeasure_Active) {
2971 if (m_nMeasureState > 2) {
2972 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2973 m_pMeasureRoute->m_lastMousePointIndex =
2974 m_pMeasureRoute->GetnPoints();
2976 gFrame->RefreshAllCanvas();
2978 CancelMeasureRoute();
2979 StartMeasureRoute();
2987 if (event.GetKeyCode() < 128)
2989 int key_char =
event.GetKeyCode();
2993 if (!g_b_assume_azerty) {
2995 if (g_benable_rotate) {
3027 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3034 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3035 m_modkeys & wxMOD_RAW_CONTROL) {
3036 parent_frame->ToggleFullScreen();
3041 if (event.ControlDown()) key_char -= 64;
3043 if (key_char >=
'0' && key_char <=
'9')
3044 SetGroupIndex(key_char -
'0');
3049 SetShowENCAnchor(!GetShowENCAnchor());
3055 parent_frame->ToggleColorScheme();
3060 event.GetPosition(&x, &y);
3061 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3062 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3064 if (!pPopupDetailSlider) {
3065 if (VPoint.b_quilt) {
3067 if (m_pQuilt->GetChartAtPix(
3072 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3074 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3079 if (m_singleChart) {
3080 ChartType = m_singleChart->GetChartType();
3081 ChartFam = m_singleChart->GetChartFamily();
3085 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3086 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3088 this, -1, ChartType, ChartFam,
3089 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3090 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
3091 if (pPopupDetailSlider) pPopupDetailSlider->Show();
3095 if (pPopupDetailSlider) pPopupDetailSlider->Close();
3096 pPopupDetailSlider = NULL;
3106 SetShowENCLights(!GetShowENCLights());
3112 if (event.ShiftDown())
3113 m_bMeasure_DistCircle =
true;
3115 m_bMeasure_DistCircle =
false;
3117 StartMeasureRoute();
3121 if (g_bInlandEcdis && ps52plib) {
3122 SetENCDisplayCategory((_DisCat)STANDARD);
3127 ToggleChartOutlines();
3131 ToggleCanvasQuiltMode();
3135 parent_frame->ToggleTestPause();
3138 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3139 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3140 g_iNavAidRadarRingsNumberVisible = 1;
3141 else if (!g_bNavAidRadarRingsShown &&
3142 g_iNavAidRadarRingsNumberVisible == 1)
3143 g_iNavAidRadarRingsNumberVisible = 0;
3146 SetShowENCDepth(!m_encShowDepth);
3151 SetShowENCText(!GetShowENCText());
3156 SetShowENCDataQual(!GetShowENCDataQual());
3161 m_bShowNavobjects = !m_bShowNavobjects;
3176 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3181 if (event.ControlDown()) gFrame->DropMarker(
false);
3187 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3188 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3189 if ((indexActive + 1) <= r->GetnPoints()) {
3200 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3206 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3212 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3219 parent_frame->DoSettings();
3223 parent_frame->Close();
3231 if (NULL == pGoToPositionDialog)
3234 pGoToPositionDialog->SetCanvas(
this);
3235 pGoToPositionDialog->Show();
3239 if (undo->AnythingToRedo()) {
3240 undo->RedoNextAction();
3247 if (event.ShiftDown()) {
3248 if (undo->AnythingToRedo()) {
3249 undo->RedoNextAction();
3254 if (undo->AnythingToUndo()) {
3255 undo->UndoLastAction();
3264 if (m_bMeasure_Active) {
3265 CancelMeasureRoute();
3267 SetCursor(*pCursorArrow);
3270 gFrame->RefreshAllCanvas();
3284 switch (gamma_state) {
3304 SetScreenBrightness(g_nbrightness);
3309 if (event.ControlDown()) {
3310 m_bShowCompassWin = !m_bShowCompassWin;
3311 SetShowGPSCompassWindow(m_bShowCompassWin);
3328void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3329 if (SendKeyEventToPlugins(event))
3333 switch (event.GetKeyCode()) {
3335 parent_frame->SwitchKBFocus(
this);
3341 if (!m_pany) m_panspeed = 0;
3347 if (!m_panx) m_panspeed = 0;
3350 case WXK_NUMPAD_ADD:
3351 case WXK_NUMPAD_SUBTRACT:
3354 if (m_mustmove) DoMovement(m_mustmove);
3360 m_modkeys &= ~wxMOD_ALT;
3361#ifdef OCPN_ALT_MENUBAR
3366 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3367 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3368 parent_frame->ApplyGlobalSettings(
false);
3370 m_bMayToggleMenuBar =
true;
3376 m_modkeys &= ~wxMOD_CONTROL;
3380 if (event.GetKeyCode() < 128)
3382 int key_char =
event.GetKeyCode();
3386 if (!g_b_assume_azerty) {
3394 DoMovement(m_mustmove);
3400 DoMovement(m_mustmove);
3401 m_rotation_speed = 0;
3409 DoMovement(m_mustmove);
3419void ChartCanvas::ToggleChartOutlines(
void) {
3420 m_bShowOutlines = !m_bShowOutlines;
3426 if (g_bopengl) InvalidateGL();
3430void ChartCanvas::ToggleLookahead() {
3431 m_bLookAhead = !m_bLookAhead;
3436void ChartCanvas::SetUpMode(
int mode) {
3439 if (mode != NORTH_UP_MODE) {
3442 if (!std::isnan(gCog)) stuff = gCog;
3444 if (g_COGAvgSec > 0) {
3445 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3448 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3450 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3451 SetVPRotation(GetVPSkew());
3456 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3457 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3459 UpdateGPSCompassStatusBox(
true);
3460 gFrame->DoChartUpdate();
3463bool ChartCanvas::DoCanvasCOGSet(
void) {
3464 if (GetUpMode() == NORTH_UP_MODE)
return false;
3465 double cog_use = g_COGAvg;
3466 if (g_btenhertz) cog_use = gCog;
3468 double rotation = 0;
3469 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3470 rotation = -gHdt * PI / 180.;
3471 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3472 rotation = -cog_use * PI / 180.;
3474 SetVPRotation(rotation);
3478double easeOutCubic(
double t) {
3480 return 1.0 - pow(1.0 - t, 3.0);
3483void ChartCanvas::StartChartDragInertia() {
3486 m_bChartDragging =
false;
3489 m_chart_drag_inertia_time = 750;
3490 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3495 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3499 size_t length = m_drag_vec_t.size();
3500 for (
size_t i = 0; i < n_vel; i++) {
3501 xacc += m_drag_vec_x.at(length - 1 - i);
3502 yacc += m_drag_vec_y.at(length - 1 - i);
3503 tacc += m_drag_vec_t.at(length - 1 - i);
3506 m_chart_drag_velocity_x = xacc / tacc;
3507 m_chart_drag_velocity_y = yacc / tacc;
3509 m_chart_drag_inertia_active =
true;
3512 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3518void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3519 if (!m_chart_drag_inertia_active)
return;
3522 wxLongLong now = wxGetLocalTimeMillis();
3523 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3524 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3525 if (t > 1.0) t = 1.0;
3526 double e = 1.0 - easeOutCubic(t);
3529 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3531 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3537 m_last_elapsed = elapsed;
3541 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3542 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3543 double inertia_lat, inertia_lon;
3550 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3551 m_chart_drag_inertia_timer.Stop();
3552 m_chart_drag_inertia_active =
false;
3555 m_target_lat = GetVP().
clat;
3556 m_target_lon = GetVP().
clon;
3557 m_pan_drag.x = m_pan_drag.y = 0;
3558 m_panx = m_pany = 0;
3561 int target_redraw_interval = 40;
3562 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3566void ChartCanvas::StopMovement() {
3567 m_panx = m_pany = 0;
3570 m_rotation_speed = 0;
3573#if !defined(__WXGTK__) && !defined(__WXQT__)
3584bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3586 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3588 if (!pMovementTimer->IsRunning()) {
3590 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3593 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3598 m_last_movement_time = wxDateTime::UNow();
3602void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3605 m_target_lat = target_lat;
3606 m_target_lon = target_lon;
3609 m_start_lat = GetVP().
clat;
3610 m_start_lon = GetVP().
clon;
3612 m_VPMovementTimer.Start(1,
true);
3613 m_timed_move_vp_active =
true;
3615 m_timedVP_step = nstep;
3618void ChartCanvas::DoTimedMovementVP() {
3619 if (!m_timed_move_vp_active)
return;
3620 if (m_stvpc++ > m_timedVP_step * 2) {
3627 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3642 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3643 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3645 m_run_lat = new_lat;
3646 m_run_lon = new_lon;
3652void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3654void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3656void ChartCanvas::StartTimedMovementTarget() {}
3658void ChartCanvas::DoTimedMovementTarget() {}
3660void ChartCanvas::StopMovementTarget() {}
3662void ChartCanvas::DoTimedMovement() {
3663 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3667 wxDateTime now = wxDateTime::UNow();
3669 if (m_last_movement_time.IsValid())
3670 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3672 m_last_movement_time = now;
3680void ChartCanvas::DoMovement(
long dt) {
3682 if (dt == 0) dt = 1;
3685 if (m_mustmove < 0) m_mustmove = 0;
3687 if (m_pan_drag.x || m_pan_drag.y) {
3689 m_pan_drag.x = m_pan_drag.y = 0;
3692 if (m_panx || m_pany) {
3693 const double slowpan = .1, maxpan = 2;
3694 if (m_modkeys == wxMOD_ALT)
3695 m_panspeed = slowpan;
3697 m_panspeed += (double)dt / 500;
3698 m_panspeed = wxMin(maxpan, m_panspeed);
3700 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3703 if (m_zoom_factor != 1) {
3704 double alpha = 400, beta = 1.5;
3705 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3707 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3709 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3714 if (zoom_factor > 1) {
3715 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3719 else if (zoom_factor < 1) {
3720 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3725 if (fabs(zoom_factor - 1) > 1e-4)
3728 if (m_wheelzoom_stop_oneshot > 0) {
3729 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3730 m_wheelzoom_stop_oneshot = 0;
3735 if (zoom_factor > 1) {
3737 m_wheelzoom_stop_oneshot = 0;
3740 }
else if (zoom_factor < 1) {
3742 m_wheelzoom_stop_oneshot = 0;
3749 if (m_rotation_speed) {
3750 double speed = m_rotation_speed;
3751 if (m_modkeys == wxMOD_ALT) speed /= 10;
3752 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3756void ChartCanvas::SetColorScheme(ColorScheme cs) {
3757 SetAlertString(_T(
""));
3761 case GLOBAL_COLOR_SCHEME_DAY:
3762 m_pos_image_red = &m_os_image_red_day;
3763 m_pos_image_grey = &m_os_image_grey_day;
3764 m_pos_image_yellow = &m_os_image_yellow_day;
3765 m_pos_image_user = m_pos_image_user_day;
3766 m_pos_image_user_grey = m_pos_image_user_grey_day;
3767 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3768 m_cTideBitmap = m_bmTideDay;
3769 m_cCurrentBitmap = m_bmCurrentDay;
3772 case GLOBAL_COLOR_SCHEME_DUSK:
3773 m_pos_image_red = &m_os_image_red_dusk;
3774 m_pos_image_grey = &m_os_image_grey_dusk;
3775 m_pos_image_yellow = &m_os_image_yellow_dusk;
3776 m_pos_image_user = m_pos_image_user_dusk;
3777 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3778 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3779 m_cTideBitmap = m_bmTideDusk;
3780 m_cCurrentBitmap = m_bmCurrentDusk;
3782 case GLOBAL_COLOR_SCHEME_NIGHT:
3783 m_pos_image_red = &m_os_image_red_night;
3784 m_pos_image_grey = &m_os_image_grey_night;
3785 m_pos_image_yellow = &m_os_image_yellow_night;
3786 m_pos_image_user = m_pos_image_user_night;
3787 m_pos_image_user_grey = m_pos_image_user_grey_night;
3788 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3789 m_cTideBitmap = m_bmTideNight;
3790 m_cCurrentBitmap = m_bmCurrentNight;
3793 m_pos_image_red = &m_os_image_red_day;
3794 m_pos_image_grey = &m_os_image_grey_day;
3795 m_pos_image_yellow = &m_os_image_yellow_day;
3796 m_pos_image_user = m_pos_image_user_day;
3797 m_pos_image_user_grey = m_pos_image_user_grey_day;
3798 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3799 m_cTideBitmap = m_bmTideDay;
3800 m_cCurrentBitmap = m_bmCurrentDay;
3804 CreateDepthUnitEmbossMaps(cs);
3805 CreateOZEmbossMapData(cs);
3808 m_fog_color = wxColor(
3812 case GLOBAL_COLOR_SCHEME_DUSK:
3815 case GLOBAL_COLOR_SCHEME_NIGHT:
3821 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3822 m_fog_color.Blue() * dim);
3826 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3827 SetBackgroundColour( wxColour(0,0,0) );
3829 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3832 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3834 SetBackgroundColour( wxNullColour );
3841 m_Piano->SetColorScheme(cs);
3843 m_Compass->SetColorScheme(cs);
3845 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3847 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3849 if (g_bopengl && m_glcc) {
3850 m_glcc->SetColorScheme(cs);
3851 g_glTextureManager->ClearAllRasterTextures();
3856 m_brepaint_piano =
true;
3863wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3864 wxImage img = Bitmap.ConvertToImage();
3865 int sx = img.GetWidth();
3866 int sy = img.GetHeight();
3868 wxImage new_img(img);
3870 for (
int i = 0; i < sx; i++) {
3871 for (
int j = 0; j < sy; j++) {
3872 if (!img.IsTransparent(i, j)) {
3873 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3874 (
unsigned char)(img.GetGreen(i, j) * factor),
3875 (
unsigned char)(img.GetBlue(i, j) * factor));
3880 wxBitmap ret = wxBitmap(new_img);
3885void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3888 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3890 if (!m_pBrightPopup) {
3893 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3897 m_pBrightPopup->SetSize(x, y);
3898 m_pBrightPopup->Move(120, 120);
3901 int bmpsx = m_pBrightPopup->GetSize().x;
3902 int bmpsy = m_pBrightPopup->GetSize().y;
3904 wxBitmap bmp(bmpsx, bmpsx);
3905 wxMemoryDC mdc(bmp);
3907 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3908 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3909 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3910 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3913 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3915 mdc.SetFont(*pfont);
3918 if (brightness == max)
3920 else if (brightness == min)
3923 val.Printf(_T(
"%3d"), brightness);
3925 mdc.DrawText(val, 0, 0);
3927 mdc.SelectObject(wxNullBitmap);
3929 m_pBrightPopup->SetBitmap(bmp);
3930 m_pBrightPopup->Show();
3931 m_pBrightPopup->Refresh();
3934void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3935 m_b_rot_hidef =
true;
3939void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3940 if (!g_bRollover)
return;
3942 bool b_need_refresh =
false;
3944 wxSize win_size = GetSize() * m_displayScale;
3945 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3948 bool showAISRollover =
false;
3949 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3951 SelectItem *pFind = pSelectAIS->FindSelection(
3954 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3955 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3958 showAISRollover =
true;
3960 if (NULL == m_pAISRolloverWin) {
3962 m_pAISRolloverWin->IsActive(
false);
3963 b_need_refresh =
true;
3964 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3965 m_AISRollover_MMSI != FoundAIS_MMSI) {
3971 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3972 m_pAISRolloverWin->IsActive(
false);
3973 m_AISRollover_MMSI = 0;
3978 m_AISRollover_MMSI = FoundAIS_MMSI;
3980 if (!m_pAISRolloverWin->IsActive()) {
3981 wxString s = ptarget->GetRolloverString();
3982 m_pAISRolloverWin->SetString(s);
3984 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3985 AIS_ROLLOVER, win_size);
3986 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3987 m_pAISRolloverWin->IsActive(
true);
3988 b_need_refresh =
true;
3992 m_AISRollover_MMSI = 0;
3993 showAISRollover =
false;
3998 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3999 m_pAISRolloverWin->IsActive(
false);
4000 m_AISRollover_MMSI = 0;
4001 b_need_refresh =
true;
4006 bool showRouteRollover =
false;
4008 if (NULL == m_pRolloverRouteSeg) {
4013 SelectableItemList SelList = pSelect->FindSelectionList(
4015 wxSelectableItemListNode *node = SelList.GetFirst();
4021 if (pr && pr->IsVisible()) {
4022 m_pRolloverRouteSeg = pFindSel;
4023 showRouteRollover =
true;
4025 if (NULL == m_pRouteRolloverWin) {
4027 m_pRouteRolloverWin->IsActive(
false);
4030 if (!m_pRouteRolloverWin->IsActive()) {
4038 DistanceBearingMercator(
4039 segShow_point_b->m_lat, segShow_point_b->m_lon,
4040 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4042 if (!pr->m_bIsInLayer)
4043 s.Append(_(
"Route") + _T(
": "));
4045 s.Append(_(
"Layer Route: "));
4047 if (pr->m_RouteNameString.IsEmpty())
4048 s.Append(_(
"(unnamed)"));
4050 s.Append(pr->m_RouteNameString);
4052 s << _T(
"\n") << _(
"Total Length: ")
4053 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
4054 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4055 << segShow_point_b->GetName() << _T(
"\n");
4058 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4059 (
int)floor(brg + 0.5), 0x00B0);
4062 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4064 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4065 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4067 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4068 (
int)floor(varBrg + 0.5), 0x00B0);
4071 s << FormatDistanceAdaptive(dist);
4076 double shiptoEndLeg = 0.;
4077 bool validActive =
false;
4078 if (pr->IsActive() &&
4079 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
4082 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
4083 wxRoutePointListNode *node =
4084 (pr->pRoutePointList)->GetFirst()->GetNext();
4086 float dist_to_endleg = 0;
4090 prp = node->GetData();
4092 shiptoEndLeg += prp->m_seg_len;
4093 else if (prp->m_bIsActive)
4095 dist_to_endleg += prp->m_seg_len;
4096 if (prp->IsSame(segShow_point_a))
break;
4097 node = node->GetNext();
4099 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
4104 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
4105 << segShow_point_b->GetName() << _T(
"\n");
4108 ->GetCurrentRngToActivePoint();
4113 s << FormatDistanceAdaptive(shiptoEndLeg);
4117 if (!std::isnan(gCog) && !std::isnan(gSog))
4119 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
4122 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
4123 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4125 << wxString(ttg_sec > SECONDS_PER_DAY
4126 ? ttg_span.Format(_(
"%Dd %H:%M"))
4127 : ttg_span.Format(_(
"%H:%M")));
4128 wxDateTime dtnow, eta;
4129 eta = dtnow.SetToCurrent().Add(ttg_span);
4130 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
4131 << eta.Format(_T(
" %d %H:%M"));
4133 s << _T(
" ---- ----");
4135 m_pRouteRolloverWin->SetString(s);
4137 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4138 LEG_ROLLOVER, win_size);
4139 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4140 m_pRouteRolloverWin->IsActive(
true);
4141 b_need_refresh =
true;
4142 showRouteRollover =
true;
4146 node = node->GetNext();
4152 m_pRolloverRouteSeg))
4153 showRouteRollover =
false;
4154 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4155 showRouteRollover =
false;
4157 showRouteRollover =
true;
4161 if (m_routeState) showRouteRollover =
false;
4164 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4165 showRouteRollover =
false;
4167 if (m_pRouteRolloverWin &&
4168 !showRouteRollover) {
4169 m_pRouteRolloverWin->IsActive(
false);
4170 m_pRolloverRouteSeg = NULL;
4171 m_pRouteRolloverWin->Destroy();
4172 m_pRouteRolloverWin = NULL;
4173 b_need_refresh =
true;
4174 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4175 m_pRouteRolloverWin->IsActive(
true);
4176 b_need_refresh =
true;
4181 bool showTrackRollover =
false;
4183 if (NULL == m_pRolloverTrackSeg) {
4188 SelectableItemList SelList = pSelect->FindSelectionList(
4190 wxSelectableItemListNode *node = SelList.GetFirst();
4196 if (pt && pt->IsVisible()) {
4197 m_pRolloverTrackSeg = pFindSel;
4198 showTrackRollover =
true;
4200 if (NULL == m_pTrackRolloverWin) {
4202 m_pTrackRolloverWin->IsActive(
false);
4205 if (!m_pTrackRolloverWin->IsActive()) {
4213 DistanceBearingMercator(
4214 segShow_point_b->m_lat, segShow_point_b->m_lon,
4215 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4217 if (!pt->m_bIsInLayer)
4218 s.Append(_(
"Track") + _T(
": "));
4220 s.Append(_(
"Layer Track: "));
4222 if (pt->GetName().IsEmpty())
4223 s.Append(_(
"(unnamed)"));
4225 s.Append(pt->GetName());
4226 double tlenght = pt->Length();
4227 s << _T(
"\n") << _(
"Total Track: ")
4228 << FormatDistanceAdaptive(tlenght);
4229 if (pt->GetLastPoint()->GetTimeString() &&
4230 pt->GetPoint(0)->GetTimeString()) {
4231 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4232 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4233 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4234 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4235 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4236 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4237 << getUsrSpeedUnit();
4238 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4239 : ttime.Format(_T(
" %H:%M")));
4243 if (g_bShowTrackPointTime && strlen(segShow_point_b->GetTimeString()))
4244 s << _T(
"\n") << _(
"Segment Created: ")
4245 << segShow_point_b->GetTimeString();
4249 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4254 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4256 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4257 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4259 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4263 s << FormatDistanceAdaptive(dist);
4265 if (segShow_point_a->GetTimeString() &&
4266 segShow_point_b->GetTimeString()) {
4267 wxDateTime apoint = segShow_point_a->GetCreateTime();
4268 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4269 if (apoint.IsValid() && bpoint.IsValid()) {
4270 double segmentSpeed = toUsrSpeed(
4271 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4272 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4273 << getUsrSpeedUnit();
4277 m_pTrackRolloverWin->SetString(s);
4279 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4280 LEG_ROLLOVER, win_size);
4281 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4282 m_pTrackRolloverWin->IsActive(
true);
4283 b_need_refresh =
true;
4284 showTrackRollover =
true;
4288 node = node->GetNext();
4294 m_pRolloverTrackSeg))
4295 showTrackRollover =
false;
4296 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4297 showTrackRollover =
false;
4299 showTrackRollover =
true;
4303 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4304 showTrackRollover =
false;
4307 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4308 showTrackRollover =
false;
4314 if (m_pTrackRolloverWin &&
4315 !showTrackRollover) {
4316 m_pTrackRolloverWin->IsActive(
false);
4317 m_pRolloverTrackSeg = NULL;
4318 m_pTrackRolloverWin->Destroy();
4319 m_pTrackRolloverWin = NULL;
4320 b_need_refresh =
true;
4321 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4322 m_pTrackRolloverWin->IsActive(
true);
4323 b_need_refresh =
true;
4326 if (b_need_refresh) Refresh();
4329void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4330 if ((GetShowENCLights() || m_bsectors_shown) &&
4331 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4332 extendedSectorLegs)) {
4333 if (!m_bsectors_shown) {
4335 m_bsectors_shown =
true;
4338 if (m_bsectors_shown) {
4340 m_bsectors_shown =
false;
4348#if defined(__WXGTK__) || defined(__WXQT__)
4353 double cursor_lat, cursor_lon;
4356 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4357 while (cursor_lon < -180.) cursor_lon += 360.;
4359 while (cursor_lon > 180.) cursor_lon -= 360.;
4361 SetCursorStatus(cursor_lat, cursor_lon);
4367void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4368 if (!parent_frame->m_pStatusBar)
return;
4372 s1 += toSDMM(1, cursor_lat);
4374 s1 += toSDMM(2, cursor_lon);
4376 if (STAT_FIELD_CURSOR_LL >= 0)
4377 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4379 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4384 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4385 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4386 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4388 wxString s = st + sm;
4389 s << FormatDistanceAdaptive(dist);
4401 if (g_bShowLiveETA) {
4404 float boatSpeedDefault = g_defaultBoatSpeed;
4409 if (!std::isnan(gSog)) {
4411 if (boatSpeed < 0.5) {
4414 realTimeETA = dist / boatSpeed * 60;
4423 s << minutesToHoursDays(realTimeETA);
4428 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4429 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4431 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4436 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4444wxString minutesToHoursDays(
float timeInMinutes) {
4447 if (timeInMinutes == 0) {
4452 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4453 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4458 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4461 hours = (int)timeInMinutes / 60;
4462 min = (int)timeInMinutes % 60;
4465 s << wxString::Format(_T(
"%d"), hours);
4468 s << wxString::Format(_T(
"%d"), hours);
4470 s << wxString::Format(_T(
"%d"), min);
4477 else if (timeInMinutes > 24 * 60) {
4480 days = (int)(timeInMinutes / 60) / 24;
4481 hours = (int)(timeInMinutes / 60) % 24;
4484 s << wxString::Format(_T(
"%d"), days);
4487 s << wxString::Format(_T(
"%d"), days);
4489 s << wxString::Format(_T(
"%d"), hours);
4501void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4509 wxPoint2DDouble *r) {
4514 double rlon, wxPoint2DDouble *r) {
4525 if (!g_bopengl && m_singleChart &&
4526 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4527 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4528 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4529 (m_singleChart->GetChartProjectionType() !=
4530 PROJECTION_TRANSVERSE_MERCATOR) &&
4531 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4532 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4533 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4547 Cur_BSB_Ch->SetVPRasterParms(vp);
4548 double rpixxd, rpixyd;
4549 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4575 if (std::isnan(p.m_x)) {
4576 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4580 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4581 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4583 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4602 if (!g_bopengl && m_singleChart &&
4603 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4604 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4605 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4606 (m_singleChart->GetChartProjectionType() !=
4607 PROJECTION_TRANSVERSE_MERCATOR) &&
4608 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4609 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4610 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4621 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4624 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4629 else if (slon > 180.)
4640 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4646 extendedSectorLegs.clear();
4651 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4653 if (g_bsmoothpanzoom) {
4654 if (StartTimedMovement(stoptimer)) {
4656 m_zoom_factor = factor;
4661 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4666 extendedSectorLegs.clear();
4671 if (!ChartData)
return;
4672 if (!m_pCurrentStack)
return;
4678 if (m_bzooming)
return;
4687 double proposed_scale_onscreen =
4690 bool b_do_zoom =
false;
4699 if (!VPoint.b_quilt) {
4702 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4703 if (new_db_index >= 0)
4704 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4708 int current_ref_stack_index = -1;
4709 if (m_pCurrentStack->nEntry) {
4711 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4712 m_pQuilt->SetReferenceChart(trial_index);
4713 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4714 if (new_db_index >= 0)
4715 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4719 if (m_pCurrentStack)
4720 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4730 double min_allowed_scale =
4733 if (proposed_scale_onscreen < min_allowed_scale) {
4738 proposed_scale_onscreen = min_allowed_scale;
4742 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4745 }
else if (factor < 1) {
4750 bool b_smallest =
false;
4752 if (!VPoint.b_quilt) {
4757 LLBBox viewbox = VPoint.GetBBox();
4759 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4760 double max_allowed_scale;
4774 if (proposed_scale_onscreen > max_allowed_scale) {
4776 proposed_scale_onscreen = max_allowed_scale;
4781 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4782 if (new_db_index >= 0)
4783 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4785 if (m_pCurrentStack)
4786 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4789 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4791 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4792 proposed_scale_onscreen =
4793 wxMin(proposed_scale_onscreen,
4799 m_absolute_min_scale_ppm)
4808 bool b_allow_ztc =
true;
4809 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4810 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4812 double brg, distance;
4813 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4816 meters_to_shift = distance * 1852;
4824 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4827 if (m_bFollow) DoCanvasUpdate();
4834void ChartCanvas::RotateCanvas(
double dir) {
4837 if (g_bsmoothpanzoom) {
4838 if (StartTimedMovement()) {
4840 m_rotation_speed = dir * 60;
4843 double speed = dir * 10;
4844 if (m_modkeys == wxMOD_ALT) speed /= 20;
4845 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4849void ChartCanvas::DoRotateCanvas(
double rotation) {
4850 while (rotation < 0) rotation += 2 * PI;
4851 while (rotation > 2 * PI) rotation -= 2 * PI;
4853 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4855 SetVPRotation(rotation);
4856 parent_frame->UpdateRotationState(VPoint.
rotation);
4859void ChartCanvas::DoTiltCanvas(
double tilt) {
4860 while (tilt < 0) tilt = 0;
4861 while (tilt > .95) tilt = .95;
4863 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4869void ChartCanvas::TogglebFollow(
void) {
4876void ChartCanvas::ClearbFollow(
void) {
4879 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4881 UpdateFollowButtonState();
4885 parent_frame->SetChartUpdatePeriod();
4888void ChartCanvas::SetbFollow(
void) {
4891 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4892 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4900 p.m_x += m_OSoffsetx;
4901 p.m_y -= m_OSoffsety;
4910 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4911 UpdateFollowButtonState();
4913 if (!g_bSmoothRecenter) {
4917 parent_frame->SetChartUpdatePeriod();
4920void ChartCanvas::UpdateFollowButtonState(
void) {
4923 m_muiBar->SetFollowButtonState(0);
4926 m_muiBar->SetFollowButtonState(2);
4928 m_muiBar->SetFollowButtonState(1);
4934 androidSetFollowTool(0);
4937 androidSetFollowTool(2);
4939 androidSetFollowTool(1);
4944void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4945 if (g_bSmoothRecenter && !m_routeState) {
4946 if (StartSmoothJump(lat, lon, scale_ppm))
4950 double gcDist, gcBearingEnd;
4951 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4953 gcBearingEnd += 180;
4954 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4957 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4958 double new_lat = lat + (lat_offset / (1852 * 60));
4959 double new_lon = lon + (lon_offset / (1852 * 60));
4962 StartSmoothJump(lat, lon, scale_ppm);
4967 if (lon > 180.0) lon -= 360.0;
4973 if (!GetQuiltMode()) {
4975 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4976 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4980 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4981 AdjustQuiltRefChart();
4988 UpdateFollowButtonState();
4996bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5001 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5002 double distance_pixels = gcDist *
GetVPScale();
5003 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5009 m_startLat = m_vLat;
5010 m_startLon = m_vLon;
5015 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5016 m_endScale = scale_ppm;
5019 m_animationDuration = 600;
5020 m_animationStart = wxGetLocalTimeMillis();
5027 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5028 m_animationActive =
true;
5033void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5035 wxLongLong now = wxGetLocalTimeMillis();
5036 double elapsed = (now - m_animationStart).ToDouble();
5037 double t = elapsed / m_animationDuration.ToDouble();
5038 if (t > 1.0) t = 1.0;
5041 double e = easeOutCubic(t);
5044 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5045 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5046 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5051 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5057 m_animationActive =
false;
5058 UpdateFollowButtonState();
5065 if (!ChartData)
return false;
5070 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
5071 UpdateFollowButtonState();
5077 extendedSectorLegs.clear();
5087 if (iters++ > 5)
return false;
5088 if (!std::isnan(dlat))
break;
5091 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5097 else if (dlat < -90)
5100 if (dlon > 360.) dlon -= 360.;
5101 if (dlon < -360.) dlon += 360.;
5116 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5120 if (VPoint.b_quilt) {
5121 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5122 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5124 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
5126 double tweak_scale_ppm =
5132 if (new_ref_dbIndex == -1) {
5137 int trial_index = -1;
5138 if (m_pCurrentStack->nEntry) {
5140 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5143 if (trial_index < 0) {
5144 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5145 if (full_screen_array.size())
5146 trial_index = full_screen_array[full_screen_array.size() - 1];
5149 if (trial_index >= 0) {
5150 m_pQuilt->SetReferenceChart(trial_index);
5161 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5163 double offset_angle = atan2(offy, offx);
5164 double offset_distance = sqrt((offy * offy) + (offx * offx));
5165 double chart_angle = GetVPRotation();
5166 double target_angle = chart_angle - offset_angle;
5167 double d_east_mod = offset_distance * cos(target_angle);
5168 double d_north_mod = offset_distance * sin(target_angle);
5173 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5174 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5176 UpdateFollowButtonState();
5182 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5187void ChartCanvas::ReloadVP(
bool b_adjust) {
5188 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5190 LoadVP(VPoint, b_adjust);
5193void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5195 if (g_bopengl && m_glcc) {
5196 m_glcc->Invalidate();
5197 if (m_glcc->GetSize() != GetSize()) {
5198 m_glcc->SetSize(GetSize());
5203 m_cache_vp.Invalidate();
5204 m_bm_cache_vp.Invalidate();
5207 VPoint.Invalidate();
5209 if (m_pQuilt) m_pQuilt->Invalidate();
5218 vp.m_projection_type, b_adjust);
5221void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5222 m_pQuilt->SetReferenceChart(dbIndex);
5223 VPoint.Invalidate();
5224 m_pQuilt->Invalidate();
5227double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5229 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5236int ChartCanvas::AdjustQuiltRefChart() {
5239 wxASSERT(ChartData);
5241 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5243 double min_ref_scale =
5244 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5245 double max_ref_scale =
5246 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5249 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5251 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5253 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5255 int ref_family = pc->GetChartFamily();
5258 unsigned int target_stack_index = 0;
5259 int target_stack_index_check =
5260 m_pQuilt->GetExtendedStackIndexArray()
5261 [m_pQuilt->GetRefChartdbIndex()];
5263 if (wxNOT_FOUND != target_stack_index_check)
5264 target_stack_index = target_stack_index_check;
5266 int extended_array_count =
5267 m_pQuilt->GetExtendedStackIndexArray().size();
5268 while ((!brender_ok) &&
5269 ((
int)target_stack_index < (extended_array_count - 1))) {
5270 target_stack_index++;
5272 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5274 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
5275 IsChartQuiltableRef(test_db_index)) {
5278 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5280 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5287 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5288 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
5289 IsChartQuiltableRef(new_db_index)) {
5290 m_pQuilt->SetReferenceChart(new_db_index);
5293 ret = m_pQuilt->GetRefChartdbIndex();
5295 ret = m_pQuilt->GetRefChartdbIndex();
5298 ret = m_pQuilt->GetRefChartdbIndex();
5307void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5308 delete m_pCurrentStack;
5310 wxASSERT(ChartData);
5311 ChartData->BuildChartStack(m_pCurrentStack, VPoint.
clat, VPoint.
clon,
5320bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5321 double latNE,
double lonNE) {
5323 double latc = (latSW + latNE) / 2.0;
5324 double lonc = (lonSW + lonNE) / 2.0;
5327 double ne_easting, ne_northing;
5328 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5330 double sw_easting, sw_northing;
5331 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5333 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5340 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5343bool ChartCanvas::SetVPProjection(
int projection) {
5349 double prev_true_scale_ppm = m_true_scale_ppm;
5354 m_absolute_min_scale_ppm));
5362bool ChartCanvas::SetVPRotation(
double angle) {
5364 VPoint.
skew, angle);
5367 double skew,
double rotation,
int projection,
5368 bool b_adjust,
bool b_refresh) {
5373 if (VPoint.IsValid()) {
5374 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5375 (fabs(VPoint.
skew - skew) < 1e-9) &&
5376 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5377 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5378 (VPoint.m_projection_type == projection ||
5379 projection == PROJECTION_UNKNOWN))
5382 if (VPoint.m_projection_type != projection)
5383 VPoint.InvalidateTransformCache();
5393 if (projection != PROJECTION_UNKNOWN)
5394 VPoint.SetProjectionType(projection);
5395 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5396 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5399 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5400 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5401 if (VPoint.
clat > 89.5)
5403 else if (VPoint.
clat < -89.5)
5404 VPoint.
clat = -89.5;
5409 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5410 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5422 bool bwasValid = VPoint.IsValid();
5427 m_cache_vp.Invalidate();
5432 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5436 int mouseX = mouse_x;
5437 int mouseY = mouse_y;
5438 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5444 SendCursorLatLonToAllPlugIns(lat, lon);
5447 if (!VPoint.b_quilt && m_singleChart) {
5452 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5456 if ((!m_cache_vp.IsValid()) ||
5461 wxPoint cp_last, cp_this;
5465 if (cp_last != cp_this) {
5471 if (m_pCurrentStack) {
5472 assert(ChartData != 0);
5473 int current_db_index;
5475 m_pCurrentStack->GetCurrentEntrydbIndex();
5477 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5479 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5482 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5486 if (VPoint.b_quilt) {
5488 m_pQuilt->InvalidateAllQuiltPatchs();
5492 if (!m_pCurrentStack)
return false;
5494 int current_db_index;
5496 m_pCurrentStack->GetCurrentEntrydbIndex();
5498 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5499 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5502 int current_ref_stack_index = -1;
5503 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5504 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5505 current_ref_stack_index = i;
5508 if (g_bFullScreenQuilt) {
5509 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5513 bool b_needNewRef =
false;
5516 if ((-1 == current_ref_stack_index) &&
5517 (m_pQuilt->GetRefChartdbIndex() >= 0))
5518 b_needNewRef =
true;
5525 bool renderable =
true;
5527 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5528 if (referenceChart) {
5529 double chartMaxScale = referenceChart->GetNormalScaleMax(
5531 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5533 if (!renderable) b_needNewRef =
true;
5538 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5539 int target_scale = cte_ref.GetScale();
5540 int target_type = cte_ref.GetChartType();
5541 int candidate_stack_index;
5548 candidate_stack_index = 0;
5549 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5551 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5552 int candidate_scale = cte_candidate.GetScale();
5553 int candidate_type = cte_candidate.GetChartType();
5555 if ((candidate_scale >= target_scale) &&
5556 (candidate_type == target_type)) {
5557 bool renderable =
true;
5558 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5559 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5560 if (tentative_referenceChart) {
5561 double chartMaxScale =
5562 tentative_referenceChart->GetNormalScaleMax(
5564 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5567 if (renderable)
break;
5570 candidate_stack_index++;
5575 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5576 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5577 while (candidate_stack_index >= 0) {
5578 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5581 ChartData->GetChartTableEntry(idx);
5582 int candidate_scale = cte_candidate.GetScale();
5583 int candidate_type = cte_candidate.GetChartType();
5585 if ((candidate_scale <= target_scale) &&
5586 (candidate_type == target_type))
5589 candidate_stack_index--;
5594 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5595 (candidate_stack_index < 0))
5596 candidate_stack_index = 0;
5598 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5600 m_pQuilt->SetReferenceChart(new_ref_index);
5606 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5611 bool renderable =
true;
5613 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5614 if (referenceChart) {
5615 double chartMaxScale = referenceChart->GetNormalScaleMax(
5617 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5618 proj = ChartData->GetDBChartProj(ref_db_index);
5620 proj = PROJECTION_MERCATOR;
5622 VPoint.b_MercatorProjectionOverride =
5623 (m_pQuilt->GetnCharts() == 0 || !renderable);
5625 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5627 VPoint.SetProjectionType(proj);
5634 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5639 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5659 m_pQuilt->Invalidate();
5674 ChartData->PurgeCacheUnusedCharts(0.7);
5676 if (b_refresh) Refresh(
false);
5683 }
else if (!g_bopengl) {
5684 OcpnProjType projection = PROJECTION_UNKNOWN;
5687 projection = m_singleChart->GetChartProjectionType();
5688 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5689 VPoint.SetProjectionType(projection);
5693 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5694 m_cache_vp.Invalidate();
5698 UpdateCanvasControlBar();
5704 if (VPoint.GetBBox().GetValid()) {
5707 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5716 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5719 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5726 wxPoint2DDouble r, r1;
5728 double delta_check =
5732 double check_point = wxMin(89., VPoint.
clat);
5734 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5737 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5738 VPoint.
clon, 0, &rhumbDist);
5743 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5744 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5746 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5750 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5756 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5758 if (m_true_scale_ppm)
5759 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5764 double round_factor = 1000.;
5768 round_factor = 100.;
5770 round_factor = 1000.;
5773 double retina_coef = 1;
5777 retina_coef = GetContentScaleFactor();
5788 double true_scale_display =
5789 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5794 if (m_displayed_scale_factor > 10.0)
5795 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5796 m_displayed_scale_factor);
5797 else if (m_displayed_scale_factor > 1.0)
5798 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5799 m_displayed_scale_factor);
5800 else if (m_displayed_scale_factor > 0.1) {
5801 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5802 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5803 }
else if (m_displayed_scale_factor > 0.01) {
5804 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5805 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5808 _T(
"%s %4.0f (---)"), _(
"Scale"),
5809 true_scale_display);
5812 m_scaleValue = true_scale_display;
5814 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5816 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5817 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5819 bool b_noshow =
false;
5823 wxClientDC dc(parent_frame->GetStatusBar());
5825 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5826 dc.SetFont(*templateFont);
5827 dc.GetTextExtent(text, &w, &h);
5832 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5833 if (w && w > rect.width) {
5834 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5835 m_displayed_scale_factor);
5839 dc.GetTextExtent(text, &w, &h);
5841 if (w && w > rect.width) {
5847 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5852 m_vLat = VPoint.
clat;
5853 m_vLon = VPoint.
clon;
5867static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5871static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5872 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5874wxColour ChartCanvas::PredColor() {
5877 if (SHIP_NORMAL == m_ownship_state)
5878 return GetGlobalColor(_T (
"URED" ));
5880 else if (SHIP_LOWACCURACY == m_ownship_state)
5881 return GetGlobalColor(_T (
"YELO1" ));
5883 return GetGlobalColor(_T (
"NODTA" ));
5886wxColour ChartCanvas::ShipColor() {
5890 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5892 if (SHIP_LOWACCURACY == m_ownship_state)
5893 return GetGlobalColor(_T (
"YELO1" ));
5895 return GetGlobalColor(_T (
"URED" ));
5898void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5899 wxPoint2DDouble lShipMidPoint) {
5900 dc.SetPen(wxPen(PredColor(), 2));
5902 if (SHIP_NORMAL == m_ownship_state)
5903 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5905 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5907 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5908 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5910 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5912 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5913 lShipMidPoint.m_y + 12);
5916void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5917 wxPoint GPSOffsetPixels,
5918 wxPoint2DDouble lGPSPoint) {
5919 if (m_animationActive)
return;
5923 float ref_dim = m_display_size_mm / 24;
5924 ref_dim = wxMin(ref_dim, 12);
5925 ref_dim = wxMax(ref_dim, 6);
5928 cPred.Set(g_cog_predictor_color);
5929 if (cPred == wxNullColour) cPred = PredColor();
5936 double nominal_line_width_pix = wxMax(
5938 floor(m_pix_per_mm / 2));
5942 if (nominal_line_width_pix > g_cog_predictor_width)
5943 g_cog_predictor_width = nominal_line_width_pix;
5946 wxPoint lPredPoint, lHeadPoint;
5948 float pCog = std::isnan(gCog) ? 0 : gCog;
5949 float pSog = std::isnan(gSog) ? 0 : gSog;
5951 double pred_lat, pred_lon;
5952 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5953 &pred_lat, &pred_lon);
5964 float ndelta_pix = 10.;
5965 double hdg_pred_lat, hdg_pred_lon;
5966 bool b_render_hdt =
false;
5967 if (!std::isnan(gHdt)) {
5969 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5972 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5973 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5974 if (dist > ndelta_pix ) {
5975 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5976 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5981 wxPoint lShipMidPoint;
5982 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5983 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5984 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5985 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5987 if (lpp >= img_height / 2) {
5988 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5989 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5990 !std::isnan(gSog)) {
5992 float dash_length = ref_dim;
5993 wxDash dash_long[2];
5995 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5996 g_cog_predictor_width);
5997 dash_long[1] = dash_long[0] / 2.0;
6001 if (dash_length > 250.) {
6002 dash_long[0] = 250. / g_cog_predictor_width;
6003 dash_long[1] = dash_long[0] / 2;
6006 wxPen ppPen2(cPred, g_cog_predictor_width,
6007 (wxPenStyle)g_cog_predictor_style);
6008 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6009 ppPen2.SetDashes(2, dash_long);
6012 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6013 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6015 if (g_cog_predictor_width > 1) {
6016 float line_width = g_cog_predictor_width / 3.;
6018 wxDash dash_long3[2];
6019 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6020 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6022 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
6023 (wxPenStyle)g_cog_predictor_style);
6024 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6025 ppPen3.SetDashes(2, dash_long3);
6027 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6028 lGPSPoint.m_y + GPSOffsetPixels.y,
6029 lPredPoint.x + GPSOffsetPixels.x,
6030 lPredPoint.y + GPSOffsetPixels.y);
6033 if (g_cog_predictor_endmarker) {
6035 double png_pred_icon_scale_factor = .4;
6036 if (g_ShipScaleFactorExp > 1.0)
6037 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6038 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6042 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6043 (
float)(lPredPoint.x - lShipMidPoint.x));
6044 cog_rad += (float)PI;
6046 for (
int i = 0; i < 4; i++) {
6048 double pxa = (double)(s_png_pred_icon[j]);
6049 double pya = (double)(s_png_pred_icon[j + 1]);
6051 pya *= png_pred_icon_scale_factor;
6052 pxa *= png_pred_icon_scale_factor;
6054 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6055 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6057 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6058 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6062 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
6065 dc.SetBrush(wxBrush(cPred));
6067 dc.StrokePolygon(4, icon);
6074 float hdt_dash_length = ref_dim * 0.4;
6076 cPred.Set(g_ownship_HDTpredictor_color);
6077 if (cPred == wxNullColour) cPred = PredColor();
6079 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6080 : g_cog_predictor_width * 0.8);
6081 wxDash dash_short[2];
6083 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6086 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6089 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6090 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6091 ppPen2.SetDashes(2, dash_short);
6095 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6096 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6098 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6100 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
6102 if (g_ownship_HDTpredictor_endmarker) {
6103 double nominal_circle_size_pixels = wxMax(
6104 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6107 if (g_ShipScaleFactorExp > 1.0)
6108 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6110 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6111 lHeadPoint.y + GPSOffsetPixels.y,
6112 nominal_circle_size_pixels / 2);
6117 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6118 double factor = 1.00;
6119 if (g_pNavAidRadarRingsStepUnits == 1)
6121 else if (g_pNavAidRadarRingsStepUnits == 2) {
6122 if (std::isnan(gSog))
6127 factor *= g_fNavAidRadarRingsStep;
6131 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
6134 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6135 pow((
double)(lGPSPoint.m_y - r.y), 2));
6136 int pix_radius = (int)lpp;
6138 extern wxColor GetDimColor(wxColor c);
6139 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6141 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6144 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6146 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6147 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6151void ChartCanvas::ComputeShipScaleFactor(
6152 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6153 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6154 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6155 float screenResolution = m_pix_per_mm;
6158 double ship_bow_lat, ship_bow_lon;
6159 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6160 &ship_bow_lat, &ship_bow_lon);
6161 wxPoint lShipBowPoint;
6162 wxPoint2DDouble b_point =
6166 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6167 powf((
float)(b_point.m_y - a_point.m_y), 2));
6170 float shipLength_mm = shipLength_px / screenResolution;
6173 float ownship_min_mm = g_n_ownship_min_mm;
6174 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6177 float hdt_ant = icon_hdt + 180.;
6178 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6179 float dx = g_n_gps_antenna_offset_x / 1852.;
6180 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6188 if (shipLength_mm < ownship_min_mm) {
6189 dy /= shipLength_mm / ownship_min_mm;
6190 dx /= shipLength_mm / ownship_min_mm;
6193 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6195 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6196 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6202 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6203 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6205 float scale_factor = shipLength_px / ownShipLength;
6208 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6211 scale_factor = wxMax(scale_factor, scale_factor_min);
6213 scale_factor_y = scale_factor;
6214 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6215 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6218void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6219 if (!GetVP().IsValid())
return;
6221 wxPoint GPSOffsetPixels(0, 0);
6222 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6225 float pCog = std::isnan(gCog) ? 0 : gCog;
6226 float pSog = std::isnan(gSog) ? 0 : gSog;
6230 lShipMidPoint = lGPSPoint;
6234 float icon_hdt = pCog;
6235 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6238 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6242 double osd_head_lat, osd_head_lon;
6243 wxPoint osd_head_point;
6245 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6250 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6251 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6252 icon_rad += (float)PI;
6254 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6258 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6262 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6263 if (GetVP().chart_scale >
6266 ShipDrawLargeScale(dc, lShipMidPoint);
6272 if (m_pos_image_user)
6273 pos_image = m_pos_image_user->Copy();
6274 else if (SHIP_NORMAL == m_ownship_state)
6275 pos_image = m_pos_image_red->Copy();
6276 if (SHIP_LOWACCURACY == m_ownship_state)
6277 pos_image = m_pos_image_yellow->Copy();
6278 else if (SHIP_NORMAL != m_ownship_state)
6279 pos_image = m_pos_image_grey->Copy();
6282 if (m_pos_image_user) {
6283 pos_image = m_pos_image_user->Copy();
6285 if (SHIP_LOWACCURACY == m_ownship_state)
6286 pos_image = m_pos_image_user_yellow->Copy();
6287 else if (SHIP_NORMAL != m_ownship_state)
6288 pos_image = m_pos_image_user_grey->Copy();
6291 img_height = pos_image.GetHeight();
6293 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6294 g_OwnShipIconType > 0)
6296 int ownShipWidth = 22;
6297 int ownShipLength = 84;
6298 if (g_OwnShipIconType == 1) {
6299 ownShipWidth = pos_image.GetWidth();
6300 ownShipLength = pos_image.GetHeight();
6303 float scale_factor_x, scale_factor_y;
6304 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6305 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6306 scale_factor_x, scale_factor_y);
6308 if (g_OwnShipIconType == 1) {
6309 pos_image.Rescale(ownShipWidth * scale_factor_x,
6310 ownShipLength * scale_factor_y,
6311 wxIMAGE_QUALITY_HIGH);
6312 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6314 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6317 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6318 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6319 if (rot_image.GetAlpha(ip, jp) > 64)
6320 rot_image.SetAlpha(ip, jp, 255);
6322 wxBitmap os_bm(rot_image);
6324 int w = os_bm.GetWidth();
6325 int h = os_bm.GetHeight();
6328 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6329 lShipMidPoint.m_y - h / 2,
true);
6332 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6333 lShipMidPoint.m_y - h / 2);
6334 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6335 lShipMidPoint.m_y - h / 2 + h);
6338 else if (g_OwnShipIconType == 2) {
6339 wxPoint ownship_icon[10];
6341 for (
int i = 0; i < 10; i++) {
6343 float pxa = (float)(s_ownship_icon[j]);
6344 float pya = (float)(s_ownship_icon[j + 1]);
6345 pya *= scale_factor_y;
6346 pxa *= scale_factor_x;
6348 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6349 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6351 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6352 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6355 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6357 dc.SetBrush(wxBrush(ShipColor()));
6359 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6362 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6364 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6368 img_height = ownShipLength * scale_factor_y;
6372 if (m_pos_image_user) circle_rad = 1;
6374 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6375 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6376 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6379 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6381 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6384 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6385 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6386 if (rot_image.GetAlpha(ip, jp) > 64)
6387 rot_image.SetAlpha(ip, jp, 255);
6389 wxBitmap os_bm(rot_image);
6391 if (g_ShipScaleFactorExp > 1) {
6392 wxImage scaled_image = os_bm.ConvertToImage();
6393 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6395 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6396 scaled_image.GetHeight() * factor,
6397 wxIMAGE_QUALITY_HIGH));
6399 int w = os_bm.GetWidth();
6400 int h = os_bm.GetHeight();
6403 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6404 lShipMidPoint.m_y - h / 2,
true);
6408 if (m_pos_image_user) circle_rad = 1;
6410 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6411 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6412 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6415 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6416 lShipMidPoint.m_y - h / 2);
6417 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6418 lShipMidPoint.m_y - h / 2 + h);
6423 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6436void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6437 float &MinorSpacing) {
6442 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6443 {.000001f, 45.0f, 15.0f},
6444 {.0002f, 30.0f, 10.0f},
6445 {.0003f, 10.0f, 2.0f},
6446 {.0008f, 5.0f, 1.0f},
6447 {.001f, 2.0f, 30.0f / 60.0f},
6448 {.003f, 1.0f, 20.0f / 60.0f},
6449 {.006f, 0.5f, 10.0f / 60.0f},
6450 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6451 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6452 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6453 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6454 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6455 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6456 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6457 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6460 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6461 if (view_scale_ppm < lltab[tabi][0])
break;
6462 MajorSpacing = lltab[tabi][1];
6463 MinorSpacing = lltab[tabi][2];
6477wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6478 int deg = (int)fabs(latlon);
6479 float min = fabs((fabs(latlon) - deg) * 60.0);
6489 }
else if (latlon < 0.0) {
6501 if (spacing >= 1.0) {
6502 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6503 }
else if (spacing >= (1.0 / 60.0)) {
6504 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6506 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6523void ChartCanvas::GridDraw(
ocpnDC &dc) {
6524 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6526 double nlat, elon, slat, wlon;
6529 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6531 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6533 dc.SetFont(*m_pgridFont);
6534 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6537 h = m_canvas_height;
6548 dlon = dlon + 360.0;
6551 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6554 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6557 while (lat < nlat) {
6560 CalcGridText(lat, gridlatMajor,
true);
6562 dc.
DrawLine(0, r.y, w, r.y,
false);
6563 dc.DrawText(st, 0, r.y);
6564 lat = lat + gridlatMajor;
6566 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6570 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6573 while (lat < nlat) {
6576 dc.
DrawLine(0, r.y, 10, r.y,
false);
6577 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6578 lat = lat + gridlatMinor;
6582 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6585 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6588 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6590 wxString st = CalcGridText(lon, gridlonMajor,
false);
6592 dc.
DrawLine(r.x, 0, r.x, h,
false);
6593 dc.DrawText(st, r.x, 0);
6594 lon = lon + gridlonMajor;
6599 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6603 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6605 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6608 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6609 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6610 lon = lon + gridlonMinor;
6617void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6619 double blat, blon, tlat, tlon;
6622 int x_origin = m_bDisplayGrid ? 60 : 20;
6623 int y_origin = m_canvas_height - 50;
6629 if (GetVP().chart_scale > 80000)
6633 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6634 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6639 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6640 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6644 double rotation = -VPoint.
rotation;
6646 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6648 int l1 = (y_origin - r.y) / count;
6650 for (
int i = 0; i < count; i++) {
6657 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6660 double blat, blon, tlat, tlon;
6667 int y_origin = m_canvas_height - chartbar_height - 5;
6671 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6678 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6681 int unit = g_iDistanceFormat;
6683 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6684 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6687 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6688 float places = floor(logdist), rem = logdist - places;
6689 dist = pow(10, places);
6696 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6697 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6698 double rotation = -VPoint.
rotation;
6700 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6704 int l1 = r.x - x_origin;
6706 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6711 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6712 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6713 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6715 dc.SetFont(*m_pgridFont);
6716 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6718 dc.GetTextExtent(s, &w, &h);
6719 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6723void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6728 double ra_max = 40.;
6730 wxPen pen_save = dc.GetPen();
6732 wxDateTime now = wxDateTime::Now();
6738 x0 = x1 = x + radius;
6743 while (angle < 360.) {
6744 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6747 if (angle > 360.) angle = 360.;
6749 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6757 x1 = (int)(x + cos(angle * PI / 180.) * r);
6758 y1 = (int)(y + sin(angle * PI / 180.) * r);
6768 dc.
DrawLine(x + radius, y, x1, y1);
6770 dc.SetPen(pen_save);
6773static bool bAnchorSoundPlaying =
false;
6775static void onAnchorSoundFinished(
void *ptr) {
6776 g_anchorwatch_sound->UnLoad();
6777 bAnchorSoundPlaying =
false;
6780void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6782 bool play_sound =
false;
6783 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6784 if (AnchorAlertOn1) {
6785 wxPoint TargetPoint;
6788 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6789 TargetPoint.y, 100);
6793 AnchorAlertOn1 =
false;
6795 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6796 if (AnchorAlertOn2) {
6797 wxPoint TargetPoint;
6800 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6801 TargetPoint.y, 100);
6805 AnchorAlertOn2 =
false;
6808 if (!bAnchorSoundPlaying) {
6809 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6810 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6811 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6812 if (g_anchorwatch_sound->IsOk()) {
6813 bAnchorSoundPlaying =
true;
6814 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6815 g_anchorwatch_sound->Play();
6821void ChartCanvas::UpdateShips() {
6824 wxClientDC dc(
this);
6825 if (!dc.IsOk())
return;
6827 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6828 if (!test_bitmap.IsOk())
return;
6830 wxMemoryDC temp_dc(test_bitmap);
6832 temp_dc.ResetBoundingBox();
6833 temp_dc.DestroyClippingRegion();
6834 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6840 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6841 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6845 ocpndc.CalcBoundingBox(px.x, px.y);
6850 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6851 temp_dc.MaxY() - temp_dc.MinY());
6853 wxRect own_ship_update_rect = ship_draw_rect;
6855 if (!own_ship_update_rect.IsEmpty()) {
6858 own_ship_update_rect.Union(ship_draw_last_rect);
6859 own_ship_update_rect.Inflate(2);
6862 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6864 ship_draw_last_rect = ship_draw_rect;
6866 temp_dc.SelectObject(wxNullBitmap);
6869void ChartCanvas::UpdateAlerts() {
6874 wxClientDC dc(
this);
6878 dc.GetSize(&sx, &sy);
6881 wxBitmap test_bitmap(sx, sy, -1);
6885 temp_dc.SelectObject(test_bitmap);
6887 temp_dc.ResetBoundingBox();
6888 temp_dc.DestroyClippingRegion();
6889 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6896 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6897 temp_dc.MaxX() - temp_dc.MinX(),
6898 temp_dc.MaxY() - temp_dc.MinY());
6900 if (!alert_rect.IsEmpty())
6901 alert_rect.Inflate(2);
6903 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6906 wxRect alert_update_rect = alert_draw_rect;
6907 alert_update_rect.Union(alert_rect);
6910 RefreshRect(alert_update_rect,
false);
6914 alert_draw_rect = alert_rect;
6916 temp_dc.SelectObject(wxNullBitmap);
6919void ChartCanvas::UpdateAIS() {
6920 if (!g_pAIS)
return;
6925 wxClientDC dc(
this);
6929 dc.GetSize(&sx, &sy);
6937 if (g_pAIS->GetTargetList().size() > 10) {
6938 ais_rect = wxRect(0, 0, sx, sy);
6941 wxBitmap test_bitmap(sx, sy, -1);
6945 temp_dc.SelectObject(test_bitmap);
6947 temp_dc.ResetBoundingBox();
6948 temp_dc.DestroyClippingRegion();
6949 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6953 AISDraw(ocpndc, GetVP(),
this);
6954 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6958 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6959 temp_dc.MaxY() - temp_dc.MinY());
6961 if (!ais_rect.IsEmpty())
6962 ais_rect.Inflate(2);
6964 temp_dc.SelectObject(wxNullBitmap);
6967 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6970 wxRect ais_update_rect = ais_draw_rect;
6971 ais_update_rect.Union(ais_rect);
6974 RefreshRect(ais_update_rect,
false);
6978 ais_draw_rect = ais_rect;
6981void ChartCanvas::ToggleCPAWarn() {
6982 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6988 g_bTCPA_Max =
false;
6992 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6993 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6995 if (!g_AisFirstTimeUse) {
6996 OCPNMessageBox(
this,
6997 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
6998 _(
"CPA") + _T(
" ") + mess, 4, 4);
7003void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7005void ChartCanvas::OnSize(wxSizeEvent &event) {
7006 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7008 GetClientSize(&m_canvas_width, &m_canvas_height);
7012 m_displayScale = GetContentScaleFactor();
7016 m_canvas_width *= m_displayScale;
7017 m_canvas_height *= m_displayScale;
7030 m_absolute_min_scale_ppm =
7032 (1.2 * WGS84_semimajor_axis_meters * PI);
7035 gFrame->ProcessCanvasResize();
7045 SetMUIBarPosition();
7046 UpdateFollowButtonState();
7047 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7051 xr_margin = m_canvas_width * 95 / 100;
7052 xl_margin = m_canvas_width * 5 / 100;
7053 yt_margin = m_canvas_height * 5 / 100;
7054 yb_margin = m_canvas_height * 95 / 100;
7057 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7062 m_brepaint_piano =
true;
7065 m_dc_route.SelectObject(wxNullBitmap);
7068 m_dc_route.SelectObject(*proute_bm);
7082 m_glcc->OnSize(event);
7091void ChartCanvas::ProcessNewGUIScale() {
7099void ChartCanvas::CreateMUIBar() {
7100 if (g_useMUI && !m_muiBar) {
7104 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
7106 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7107 m_muiBar->SetColorScheme(m_cs);
7108 m_muiBarHOSize = m_muiBar->m_size;
7112 SetMUIBarPosition();
7113 UpdateFollowButtonState();
7114 m_muiBar->UpdateDynamicValues();
7115 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7119void ChartCanvas::SetMUIBarPosition() {
7123 int pianoWidth = GetClientSize().x * 0.6f;
7128 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7129 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7131 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7132 m_muiBar->SetColorScheme(m_cs);
7136 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7137 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7139 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7140 m_muiBar->SetColorScheme(m_cs);
7144 m_muiBar->SetBestPosition();
7148void ChartCanvas::DestroyMuiBar() {
7155void ChartCanvas::ShowCompositeInfoWindow(
7156 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7158 if (NULL == m_pCIWin) {
7163 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7166 s = _(
"Composite of ");
7169 s1.Printf(
"%d ", n_charts);
7177 s1.Printf(_(
"Chart scale"));
7180 s2.Printf(
"1:%d\n",
scale);
7184 s1 = _(
"Zoom in for more information");
7188 int char_width = s1.Length();
7189 int char_height = 3;
7191 if (g_bChartBarEx) {
7194 for (
int i : index_vector) {
7196 wxString path = cte.GetFullSystemPath();
7200 char_width = wxMax(char_width, path.Length());
7201 if (j++ >= 9)
break;
7204 s +=
" .\n .\n .\n";
7213 m_pCIWin->SetString(s);
7215 m_pCIWin->FitToChars(char_width, char_height);
7218 p.x = x / GetContentScaleFactor();
7219 if ((p.x + m_pCIWin->GetWinSize().x) >
7220 (m_canvas_width / GetContentScaleFactor()))
7221 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7222 m_pCIWin->GetWinSize().x) /
7225 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7226 4 - m_pCIWin->GetWinSize().y;
7228 m_pCIWin->dbIndex = 0;
7229 m_pCIWin->chart_scale = 0;
7230 m_pCIWin->SetPosition(p);
7231 m_pCIWin->SetBitmap();
7232 m_pCIWin->Refresh();
7236 HideChartInfoWindow();
7240void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7242 if (NULL == m_pCIWin) {
7247 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7254 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
7255 pc = ChartData->OpenChartFromDBAndLock(
7256 dbIndex, FULL_INIT);
7258 int char_width, char_height;
7259 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7260 if (pc) ChartData->UnLockCacheChart(dbIndex);
7262 m_pCIWin->SetString(s);
7263 m_pCIWin->FitToChars(char_width, char_height);
7266 p.x = x / GetContentScaleFactor();
7267 if ((p.x + m_pCIWin->GetWinSize().x) >
7268 (m_canvas_width / GetContentScaleFactor()))
7269 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7270 m_pCIWin->GetWinSize().x) /
7273 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7274 4 - m_pCIWin->GetWinSize().y;
7276 m_pCIWin->dbIndex = dbIndex;
7277 m_pCIWin->SetPosition(p);
7278 m_pCIWin->SetBitmap();
7279 m_pCIWin->Refresh();
7283 HideChartInfoWindow();
7287void ChartCanvas::HideChartInfoWindow(
void) {
7290 m_pCIWin->Destroy();
7294 androidForceFullRepaint();
7299void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7300 wxMouseEvent ev(wxEVT_MOTION);
7303 ev.m_leftDown = mouse_leftisdown;
7305 wxEvtHandler *evthp = GetEventHandler();
7307 ::wxPostEvent(evthp, ev);
7310void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7311 if ((m_panx_target_final - m_panx_target_now) ||
7312 (m_pany_target_final - m_pany_target_now)) {
7313 DoTimedMovementTarget();
7318void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7320bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7322 if (m_disable_edge_pan)
return false;
7325 int pan_margin = m_canvas_width * margin / 100;
7326 int pan_timer_set = 200;
7327 double pan_delta = GetVP().
pix_width * delta / 100;
7331 if (x > m_canvas_width - pan_margin) {
7336 else if (x < pan_margin) {
7341 if (y < pan_margin) {
7346 else if (y > m_canvas_height - pan_margin) {
7355 wxMouseState state = ::wxGetMouseState();
7356#if wxCHECK_VERSION(3, 0, 0)
7357 if (!state.LeftIsDown())
7359 if (!state.LeftDown())
7364 if ((bft) && !pPanTimer->IsRunning()) {
7366 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7372 if ((!bft) && pPanTimer->IsRunning()) {
7382void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7383 bool setBeingEdited) {
7384 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7385 m_pRoutePointEditTarget = NULL;
7386 m_pFoundPoint = NULL;
7390 SelectableItemList SelList = pSelect->FindSelectionList(
7392 wxSelectableItemListNode *node = SelList.GetFirst();
7394 pFind = node->GetData();
7403 bool brp_viz =
false;
7404 if (m_pEditRouteArray) {
7405 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7406 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7407 if (pr->IsVisible()) {
7413 brp_viz = frp->IsVisible();
7417 if (m_pEditRouteArray)
7419 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7420 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7421 pr->m_bIsBeingEdited = setBeingEdited;
7423 m_bRouteEditing = setBeingEdited;
7426 frp->m_bRPIsBeingEdited = setBeingEdited;
7427 m_bMarkEditing = setBeingEdited;
7430 m_pRoutePointEditTarget = frp;
7431 m_pFoundPoint = pFind;
7435 node = node->GetNext();
7439void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7440 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7441 singleClickEventIsValid =
false;
7442 m_DoubleClickTimer->Stop();
7447bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7448 if (!m_bChartDragging && !m_bDrawingRoute) {
7453 if (m_Compass && m_Compass->IsShown()) {
7455 bool isInCompass = logicalRect.Contains(event.GetPosition());
7457 if (m_Compass->MouseEvent(event)) {
7458 cursor_region = CENTER;
7459 if (!g_btouch) SetCanvasCursor(event);
7465 if (m_notification_button && m_notification_button->IsShown()) {
7467 bool isinButton = logicalRect.Contains(event.GetPosition());
7468 if (isinButton && event.LeftDown()) {
7469 HandleNotificationMouseClick();
7476 if (MouseEventToolbar(event))
return true;
7478 if (MouseEventChartBar(event))
return true;
7480 if (MouseEventMUIBar(event))
return true;
7482 if (MouseEventIENCBar(event))
return true;
7487void ChartCanvas::HandleNotificationMouseClick() {
7488 if (!m_NotificationsList) {
7493 wxPoint ClientUpperRight = ClientToScreen(wxPoint(GetSize().x, 0));
7494 wxPoint list_bottom = ClientToScreen(wxPoint(0, GetSize().y / 2));
7495 int size_y = list_bottom.y - (ClientUpperRight.y + 5);
7496 size_y -= GetCharHeight();
7497 size_y = wxMax(size_y, 200);
7499 m_NotificationsList->SetSize(wxSize(GetCharWidth() * 80, size_y));
7501 wxPoint m_currentNLPos = ClientToScreen(wxPoint(
7502 GetSize().x / 2, m_notification_button->
GetRect().y +
7503 m_notification_button->
GetRect().height + 5));
7505 m_NotificationsList->Move(m_currentNLPos);
7506 m_NotificationsList->Hide();
7509 if (m_NotificationsList->IsShown()) {
7510 m_NotificationsList->Hide();
7512 m_NotificationsList->ReloadNotificationList();
7513 m_NotificationsList->Show();
7516bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7517 if (!g_bShowChartBar)
return false;
7519 if (!m_Piano->MouseEvent(event))
return false;
7521 cursor_region = CENTER;
7522 if (!g_btouch) SetCanvasCursor(event);
7526bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7527 if (!IsPrimaryCanvas())
return false;
7529 if (g_MainToolbar) {
7530 if (!g_MainToolbar->MouseEvent(event))
7533 g_MainToolbar->RefreshToolbar();
7536 cursor_region = CENTER;
7537 if (!g_btouch) SetCanvasCursor(event);
7541bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7542 if (!IsPrimaryCanvas())
return false;
7544 if (g_iENCToolbar) {
7545 if (!g_iENCToolbar->MouseEvent(event))
7548 g_iENCToolbar->RefreshToolbar();
7555bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7557 if (!m_muiBar->MouseEvent(event))
return false;
7560 cursor_region = CENTER;
7561 if (!g_btouch) SetCanvasCursor(event);
7573 event.GetPosition(&x, &y);
7575 x *= m_displayScale;
7576 y *= m_displayScale;
7578 m_MouseDragging =
event.Dragging();
7584 if (event.Dragging()) {
7585 if ((x == mouse_x) && (y == mouse_y))
return true;
7591 mouse_leftisdown =
event.LeftDown();
7595 cursor_region = CENTER;
7599 if (m_Compass && m_Compass->IsShown() &&
7600 m_Compass->
GetRect().Contains(event.GetPosition())) {
7601 cursor_region = CENTER;
7602 }
else if (x > xr_margin) {
7603 cursor_region = MID_RIGHT;
7604 }
else if (x < xl_margin) {
7605 cursor_region = MID_LEFT;
7606 }
else if (y > yb_margin - chartbar_height &&
7607 y < m_canvas_height - chartbar_height) {
7608 cursor_region = MID_TOP;
7609 }
else if (y < yt_margin) {
7610 cursor_region = MID_BOT;
7612 cursor_region = CENTER;
7615 if (!g_btouch) SetCanvasCursor(event);
7619 leftIsDown =
event.LeftDown();
7622 if (event.LeftDown()) {
7623 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7626 g_bTempShowMenuBar =
false;
7627 parent_frame->ApplyGlobalSettings(
false);
7635 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7636 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7640 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7641 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7644 event.SetEventObject(
this);
7645 if (SendMouseEventToPlugins(event))
7652 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7653 StartChartDragInertia();
7656 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7658 if (m_DoubleClickTimer->IsRunning()) {
7659 m_DoubleClickTimer->Stop();
7664 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7665 singleClickEvent = event;
7666 singleClickEventIsValid =
true;
7675 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7676 if (g_click_stop > 0) {
7684 if (GetUpMode() == COURSE_UP_MODE) {
7685 m_b_rot_hidef =
false;
7686 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7688 pRotDefTimer->Stop();
7691 bool bRoll = !g_btouch;
7693 bRoll = g_bRollover;
7696 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7697 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7698 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7699 m_RolloverPopupTimer.Start(
7703 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7707 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7716#if !defined(__WXGTK__) && !defined(__WXQT__)
7724 if ((x >= 0) && (y >= 0))
7729 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7730 wxPoint p = ClientToScreen(wxPoint(x, y));
7736 if (m_routeState >= 2) {
7739 m_bDrawingRoute =
true;
7741 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7746 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7749 m_bDrawingRoute =
true;
7751 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7758void ChartCanvas::CallPopupMenu(
int x,
int y) {
7766 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7775#if defined(__WXMAC__) || defined(__ANDROID__)
7779 wxClientDC cdc(GetParent());
7791 if (m_pSelectedRoute) {
7792 m_pSelectedRoute->m_bRtIsSelected =
false;
7793 m_pSelectedRoute->DeSelectRoute();
7795 if (g_bopengl && m_glcc) {
7800 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7803 if (m_pFoundRoutePoint) {
7804 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7806 RefreshRect(m_pFoundRoutePoint->CurrentRect_in_DC);
7811 if (g_btouch && m_pRoutePointEditTarget) {
7812 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7813 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7814 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7819 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7820 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7821 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7822 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7826 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7829 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7835 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7838 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7839 seltype |= SELTYPE_AISTARGET;
7844 m_pFoundRoutePoint = NULL;
7849 Route *pSelectedActiveRoute = NULL;
7850 Route *pSelectedVizRoute = NULL;
7854 SelectableItemList SelList =
7855 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7856 wxSelectableItemListNode *node = SelList.GetFirst();
7866 bool brp_viz =
false;
7868 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7870 if (pr->IsVisible()) {
7875 if (!brp_viz && prp->IsShared())
7877 brp_viz = prp->IsVisible();
7880 brp_viz = prp->IsVisible();
7882 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7887 m_pSelectedRoute = NULL;
7889 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7891 if (pr->m_bRtIsActive) {
7892 pSelectedActiveRoute = pr;
7893 pFoundActiveRoutePoint = prp;
7898 if (NULL == pSelectedVizRoute) {
7899 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7901 if (pr->IsVisible()) {
7902 pSelectedVizRoute = pr;
7903 pFoundVizRoutePoint = prp;
7909 delete proute_array;
7912 node = node->GetNext();
7916 if (pFoundActiveRoutePoint) {
7917 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7918 m_pSelectedRoute = pSelectedActiveRoute;
7919 }
else if (pFoundVizRoutePoint) {
7920 m_pFoundRoutePoint = pFoundVizRoutePoint;
7921 m_pSelectedRoute = pSelectedVizRoute;
7924 m_pFoundRoutePoint = pFirstVizPoint;
7926 if (m_pSelectedRoute) {
7927 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7928 }
else if (m_pFoundRoutePoint)
7929 seltype |= SELTYPE_MARKPOINT;
7933 if (m_pFoundRoutePoint) {
7934 m_pFoundRoutePoint->m_bPtIsSelected =
true;
7937 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7938 RefreshRect(wp_rect,
true);
7947 SelectableItemList SelList =
7948 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7950 if (NULL == m_pSelectedRoute)
7953 wxSelectableItemListNode *node = SelList.GetFirst();
7958 if (pr->IsVisible()) {
7959 m_pSelectedRoute = pr;
7962 node = node->GetNext();
7966 if (m_pSelectedRoute) {
7967 if (NULL == m_pFoundRoutePoint)
7968 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7970 m_pSelectedRoute->m_bRtIsSelected = !(seltype & SELTYPE_ROUTEPOINT);
7971 if (m_pSelectedRoute->m_bRtIsSelected) {
7973 if (g_bopengl && m_glcc) {
7978 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7981 seltype |= SELTYPE_ROUTESEGMENT;
7985 if (pFindTrackSeg) {
7986 m_pSelectedTrack = NULL;
7988 SelectableItemList SelList =
7989 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7992 wxSelectableItemListNode *node = SelList.GetFirst();
7997 if (pt->IsVisible()) {
7998 m_pSelectedTrack = pt;
8001 node = node->GetNext();
8004 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8007 bool bseltc =
false;
8021 SelectableItemList SelList = pSelectTC->FindSelectionList(
8025 wxSelectableItemListNode *node = SelList.GetFirst();
8026 pFind = node->GetData();
8027 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8029 if (SelList.GetCount() > 1) {
8030 node = node->GetNext();
8032 pFind = node->GetData();
8034 if (pIDX_candidate->
IDX_type ==
'c') {
8035 pIDX_best_candidate = pIDX_candidate;
8039 node = node->GetNext();
8042 wxSelectableItemListNode *node = SelList.GetFirst();
8043 pFind = node->GetData();
8044 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8047 m_pIDXCandidate = pIDX_best_candidate;
8050 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
8054 seltype |= SELTYPE_CURRENTPOINT;
8057 else if (pFindTide) {
8058 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8061 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
8065 seltype |= SELTYPE_TIDEPOINT;
8069 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8072 InvokeCanvasMenu(x, y, seltype);
8075 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8076 m_pSelectedRoute->m_bRtIsSelected =
false;
8079 m_pSelectedRoute = NULL;
8081 if (m_pFoundRoutePoint) {
8082 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8083 m_pFoundRoutePoint->m_bPtIsSelected =
false;
8085 m_pFoundRoutePoint = NULL;
8093bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8101 event.GetPosition(&x, &y);
8107 SelectRadius = g_Platform->GetSelectRadiusPix() /
8108 (m_true_scale_ppm * 1852 * 60);
8115 if (event.LeftDClick() && (cursor_region == CENTER)) {
8116 m_DoubleClickTimer->Start();
8117 singleClickEventIsValid =
false;
8121 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8126 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8129 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8130 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8131 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8137 SelectableItemList rpSelList =
8138 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8139 wxSelectableItemListNode *node = rpSelList.GetFirst();
8140 bool b_onRPtarget =
false;
8144 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8145 b_onRPtarget =
true;
8148 node = node->GetNext();
8153 if (m_pRoutePointEditTarget) {
8155 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8158 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8159 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8161 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8164 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8165 m_pRoutePointEditTarget = NULL;
8166 RefreshRect(wp_rect,
true);
8170 node = rpSelList.GetFirst();
8175 wxArrayPtrVoid *proute_array =
8180 bool brp_viz =
false;
8182 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8184 if (pr->IsVisible()) {
8189 delete proute_array;
8193 brp_viz = frp->IsVisible();
8195 brp_viz = frp->IsVisible();
8198 ShowMarkPropertiesDialog(frp);
8206 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8210 if (pr->IsVisible()) {
8211 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8216 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8220 if (pt->IsVisible()) {
8221 ShowTrackPropertiesDialog(pt);
8228 ShowObjectQueryWindow(x, y, zlat, zlon);
8233 if (event.LeftDown()) {
8249 bool appending =
false;
8250 bool inserting =
false;
8253 SetCursor(*pCursorPencil);
8257 m_bRouteEditing =
true;
8259 if (m_routeState == 1) {
8260 m_pMouseRoute =
new Route();
8261 pRouteList->Append(m_pMouseRoute);
8270 double nearby_radius_meters =
8271 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8274 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8275 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8276 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8277 wxArrayPtrVoid *proute_array =
8282 bool brp_viz =
false;
8284 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8286 if (pr->IsVisible()) {
8291 delete proute_array;
8293 pNearbyPoint->IsShared())
8296 pNearbyPoint->IsVisible();
8298 brp_viz = pNearbyPoint->IsVisible();
8301 wxString msg = _(
"Use nearby waypoint?");
8303 const bool noname(pNearbyPoint->GetName() ==
"");
8306 _(
"Use nearby nameless waypoint and name it M with"
8307 " a unique number?");
8310 m_FinishRouteOnKillFocus =
false;
8312 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8313 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8314 m_FinishRouteOnKillFocus =
true;
8315 if (dlg_return == wxID_YES) {
8317 if (m_pMouseRoute) {
8318 int last_wp_num = m_pMouseRoute->GetnPoints();
8320 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8321 wxString wp_name = wxString::Format(
8322 "M%002i-%s", last_wp_num + 1, guid_short);
8323 pNearbyPoint->SetName(wp_name);
8325 pNearbyPoint->SetName(
"WPXX");
8327 pMousePoint = pNearbyPoint;
8330 if (m_routeState > 1)
8331 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8332 Undo_HasParent, NULL);
8335 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8336 bool procede =
false;
8340 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8346 m_FinishRouteOnKillFocus =
false;
8352 _(
"Insert first part of this route in the new route?");
8353 if (tail->GetIndexOf(pMousePoint) ==
8356 dmsg = _(
"Insert this route in the new route?");
8358 if (tail->GetIndexOf(pMousePoint) != 1) {
8359 dlg_return = OCPNMessageBox(
8360 this, dmsg, _(
"OpenCPN Route Create"),
8361 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8362 m_FinishRouteOnKillFocus =
true;
8364 if (dlg_return == wxID_YES) {
8371 _(
"Append last part of this route to the new route?");
8372 if (tail->GetIndexOf(pMousePoint) == 1)
8374 "Append this route to the new route?");
8379 if (tail->GetLastPoint() != pMousePoint) {
8380 dlg_return = OCPNMessageBox(
8381 this, dmsg, _(
"OpenCPN Route Create"),
8382 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8383 m_FinishRouteOnKillFocus =
true;
8385 if (dlg_return == wxID_YES) {
8396 if (!FindRouteContainingWaypoint(pMousePoint))
8397 pMousePoint->SetShared(
true);
8402 if (NULL == pMousePoint) {
8403 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8404 _T(
""), wxEmptyString);
8405 pMousePoint->SetNameShown(
false);
8407 pConfig->AddNewWayPoint(pMousePoint, -1);
8408 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8410 if (m_routeState > 1)
8411 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8412 Undo_IsOrphanded, NULL);
8415 if (m_pMouseRoute) {
8416 if (m_routeState == 1) {
8418 m_pMouseRoute->AddPoint(pMousePoint);
8420 if (m_pMouseRoute->m_NextLegGreatCircle) {
8421 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8422 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8423 &rhumbBearing, &rhumbDist);
8424 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8425 rlat, &gcDist, &gcBearing, NULL);
8426 double gcDistNM = gcDist / 1852.0;
8429 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8430 pow(rhumbDist - gcDistNM - 1, 0.5);
8433 msg << _(
"For this leg the Great Circle route is ")
8434 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8435 << _(
" shorter than rhumbline.\n\n")
8436 << _(
"Would you like include the Great Circle routing points "
8439 m_FinishRouteOnKillFocus =
false;
8440 m_disable_edge_pan =
true;
8443 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8444 wxYES_NO | wxNO_DEFAULT);
8446 m_disable_edge_pan =
false;
8447 m_FinishRouteOnKillFocus =
true;
8449 if (answer == wxID_YES) {
8451 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8452 wxRealPoint gcCoord;
8454 for (
int i = 1; i <= segmentCount; i++) {
8455 double fraction = (double)i * (1.0 / (
double)segmentCount);
8456 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8457 gcDist * fraction, gcBearing,
8458 &gcCoord.x, &gcCoord.y, NULL);
8460 if (i < segmentCount) {
8461 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8462 _T(
""), wxEmptyString);
8463 gcPoint->SetNameShown(
false);
8464 pConfig->AddNewWayPoint(gcPoint, -1);
8465 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8468 gcPoint = pMousePoint;
8471 m_pMouseRoute->AddPoint(gcPoint);
8472 pSelect->AddSelectableRouteSegment(
8473 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8474 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8475 prevGcPoint = gcPoint;
8478 undo->CancelUndoableAction(
true);
8481 m_pMouseRoute->AddPoint(pMousePoint);
8482 pSelect->AddSelectableRouteSegment(
8483 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8484 pMousePoint, m_pMouseRoute);
8485 undo->AfterUndoableAction(m_pMouseRoute);
8489 m_pMouseRoute->AddPoint(pMousePoint);
8490 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8491 rlon, m_prev_pMousePoint,
8492 pMousePoint, m_pMouseRoute);
8493 undo->AfterUndoableAction(m_pMouseRoute);
8499 m_prev_pMousePoint = pMousePoint;
8501 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
8507 int connect = tail->GetIndexOf(pMousePoint);
8512 int length = tail->GetnPoints();
8517 start = connect + 1;
8522 m_pMouseRoute->RemovePoint(
8526 for (i = start; i <= stop; i++) {
8527 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8529 m_pMouseRoute->m_lastMousePointIndex =
8530 m_pMouseRoute->GetnPoints();
8532 gFrame->RefreshAllCanvas();
8536 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8538 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8539 m_pMouseRoute->FinalizeForRendering();
8541 gFrame->RefreshAllCanvas();
8545 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8547 SetCursor(*pCursorPencil);
8549 if (!m_pMeasureRoute) {
8550 m_pMeasureRoute =
new Route();
8551 pRouteList->Append(m_pMeasureRoute);
8554 if (m_nMeasureState == 1) {
8560 wxString(_T (
"circle" )),
8561 wxEmptyString, wxEmptyString);
8562 pMousePoint->m_bShowName =
false;
8563 pMousePoint->SetShowWaypointRangeRings(
false);
8565 m_pMeasureRoute->AddPoint(pMousePoint);
8569 m_prev_pMousePoint = pMousePoint;
8570 m_pMeasureRoute->m_lastMousePointIndex = m_pMeasureRoute->GetnPoints();
8573 gFrame->RefreshAllCanvas();
8578 FindRoutePointsAtCursor(SelectRadius,
true);
8583 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8591 if (ret)
return true;
8594 if (event.Dragging()) {
8599 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8601 SelectableItemList SelList = pSelect->FindSelectionList(
8603 wxSelectableItemListNode *node = SelList.GetFirst();
8605 pFind = node->GetData();
8607 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8608 node = node->GetNext();
8613 if (m_pRoutePointEditTarget &&
8614 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8616 SelectableItemList SelList = pSelect->FindSelectionList(
8618 wxSelectableItemListNode *node = SelList.GetFirst();
8620 pFind = node->GetData();
8622 if (m_pRoutePointEditTarget == frp) {
8623 m_bIsInRadius =
true;
8626 node = node->GetNext();
8629 if (!m_dragoffsetSet) {
8631 .PresetDragOffset(
this, mouse_x, mouse_y);
8632 m_dragoffsetSet =
true;
8637 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8638 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8640 if (NULL == g_pMarkInfoDialog) {
8641 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8642 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8643 DraggingAllowed =
false;
8645 if (m_pRoutePointEditTarget &&
8646 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8647 DraggingAllowed =
false;
8649 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8651 if (DraggingAllowed) {
8652 if (!undo->InUndoableAction()) {
8653 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8654 Undo_NeedsCopy, m_pFoundPoint);
8660 if (!g_bopengl && m_pEditRouteArray) {
8661 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8662 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8667 if (g_pRouteMan->IsRouteValid(pr)) {
8669 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8670 pre_rect.Union(route_rect);
8678 if (CheckEdgePan(x, y,
true, 5, 2))
8686 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8688 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8689 m_pRoutePointEditTarget,
8690 SELTYPE_DRAGHANDLE);
8691 m_pFoundPoint->m_slat =
8692 m_pRoutePointEditTarget->m_lat;
8693 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8695 m_pRoutePointEditTarget->m_lat =
8697 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8698 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8699 m_pFoundPoint->m_slat =
8701 m_pFoundPoint->m_slon = new_cursor_lon;
8705 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8706 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8707 g_pMarkInfoDialog->UpdateProperties(
true);
8717 if (m_pEditRouteArray) {
8718 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8720 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8721 if (g_pRouteMan->IsRouteValid(pr)) {
8723 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8724 post_rect.Union(route_rect);
8730 pre_rect.Union(post_rect);
8731 RefreshRect(pre_rect,
false);
8733 gFrame->RefreshCanvasOther(
this);
8734 m_bRoutePoinDragging =
true;
8739 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8740 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8742 if (NULL == g_pMarkInfoDialog) {
8743 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8744 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8745 DraggingAllowed =
false;
8747 if (m_pRoutePointEditTarget &&
8748 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8749 DraggingAllowed =
false;
8751 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8753 if (DraggingAllowed) {
8754 if (!undo->InUndoableAction()) {
8755 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8756 Undo_NeedsCopy, m_pFoundPoint);
8764 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8765 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8767 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8768 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8770 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8776 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8777 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8778 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8779 (
int)(lppmax - (pre_rect.height / 2)));
8787 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8790 m_pRoutePointEditTarget,
8791 SELTYPE_DRAGHANDLE);
8792 m_pFoundPoint->m_slat =
8793 m_pRoutePointEditTarget->m_lat;
8794 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8796 m_pRoutePointEditTarget->m_lat =
8799 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8805 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8806 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8807 g_pMarkInfoDialog->UpdateProperties(
true);
8812 if (!g_btouch) InvalidateGL();
8818 .CalculateDCRect(m_dc_route,
this, &post_rect);
8819 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8820 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8821 (
int)(lppmax - (post_rect.height / 2)));
8824 pre_rect.Union(post_rect);
8825 RefreshRect(pre_rect,
false);
8827 gFrame->RefreshCanvasOther(
this);
8828 m_bRoutePoinDragging =
true;
8833 if (ret)
return true;
8836 if (event.LeftUp()) {
8837 bool b_startedit_route =
false;
8838 m_dragoffsetSet =
false;
8841 m_bChartDragging =
false;
8842 m_bIsInRadius =
false;
8847 m_bedge_pan =
false;
8852 bool appending =
false;
8853 bool inserting =
false;
8859 if (m_pRoutePointEditTarget) {
8860 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8861 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8865 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8866 RefreshRect(wp_rect,
true);
8868 m_pRoutePointEditTarget = NULL;
8870 m_bRouteEditing =
true;
8872 if (m_routeState == 1) {
8873 m_pMouseRoute =
new Route();
8874 m_pMouseRoute->SetHiLite(50);
8875 pRouteList->Append(m_pMouseRoute);
8884 double nearby_radius_meters =
8885 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8888 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8889 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8890 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8893 m_FinishRouteOnKillFocus =
8895 dlg_return = OCPNMessageBox(
8896 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8897 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8898 m_FinishRouteOnKillFocus =
true;
8900 dlg_return = wxID_YES;
8902 if (dlg_return == wxID_YES) {
8903 pMousePoint = pNearbyPoint;
8906 if (m_routeState > 1)
8907 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8908 Undo_HasParent, NULL);
8909 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8911 bool procede =
false;
8915 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8921 m_FinishRouteOnKillFocus =
false;
8922 if (m_routeState == 1) {
8926 _(
"Insert first part of this route in the new route?");
8927 if (tail->GetIndexOf(pMousePoint) ==
8930 dmsg = _(
"Insert this route in the new route?");
8932 if (tail->GetIndexOf(pMousePoint) != 1) {
8934 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8935 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8936 m_FinishRouteOnKillFocus =
true;
8938 if (dlg_return == wxID_YES) {
8945 _(
"Append last part of this route to the new route?");
8946 if (tail->GetIndexOf(pMousePoint) == 1)
8948 "Append this route to the new route?");
8952 if (tail->GetLastPoint() != pMousePoint) {
8954 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8955 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8956 m_FinishRouteOnKillFocus =
true;
8958 if (dlg_return == wxID_YES) {
8969 if (!FindRouteContainingWaypoint(pMousePoint))
8970 pMousePoint->SetShared(
true);
8974 if (NULL == pMousePoint) {
8975 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8976 _T(
""), wxEmptyString);
8977 pMousePoint->SetNameShown(
false);
8979 pConfig->AddNewWayPoint(pMousePoint, -1);
8980 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8982 if (m_routeState > 1)
8983 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8984 Undo_IsOrphanded, NULL);
8987 if (m_routeState == 1) {
8989 m_pMouseRoute->AddPoint(pMousePoint);
8991 if (m_pMouseRoute->m_NextLegGreatCircle) {
8992 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8993 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8994 &rhumbBearing, &rhumbDist);
8995 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
8996 &gcDist, &gcBearing, NULL);
8997 double gcDistNM = gcDist / 1852.0;
9000 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9001 pow(rhumbDist - gcDistNM - 1, 0.5);
9004 msg << _(
"For this leg the Great Circle route is ")
9005 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
9006 << _(
" shorter than rhumbline.\n\n")
9007 << _(
"Would you like include the Great Circle routing points "
9011 m_FinishRouteOnKillFocus =
false;
9012 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9013 wxYES_NO | wxNO_DEFAULT);
9014 m_FinishRouteOnKillFocus =
true;
9016 int answer = wxID_NO;
9019 if (answer == wxID_YES) {
9021 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9022 wxRealPoint gcCoord;
9024 for (
int i = 1; i <= segmentCount; i++) {
9025 double fraction = (double)i * (1.0 / (
double)segmentCount);
9026 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9027 gcDist * fraction, gcBearing,
9028 &gcCoord.x, &gcCoord.y, NULL);
9030 if (i < segmentCount) {
9031 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
9032 _T(
""), wxEmptyString);
9033 gcPoint->SetNameShown(
false);
9034 pConfig->AddNewWayPoint(gcPoint, -1);
9035 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9038 gcPoint = pMousePoint;
9041 m_pMouseRoute->AddPoint(gcPoint);
9042 pSelect->AddSelectableRouteSegment(
9043 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9044 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9045 prevGcPoint = gcPoint;
9048 undo->CancelUndoableAction(
true);
9051 m_pMouseRoute->AddPoint(pMousePoint);
9052 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9053 rlon, m_prev_pMousePoint,
9054 pMousePoint, m_pMouseRoute);
9055 undo->AfterUndoableAction(m_pMouseRoute);
9059 m_pMouseRoute->AddPoint(pMousePoint);
9060 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9061 rlon, m_prev_pMousePoint,
9062 pMousePoint, m_pMouseRoute);
9063 undo->AfterUndoableAction(m_pMouseRoute);
9069 m_prev_pMousePoint = pMousePoint;
9070 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
9076 int connect = tail->GetIndexOf(pMousePoint);
9081 int length = tail->GetnPoints();
9086 start = connect + 1;
9091 m_pMouseRoute->RemovePoint(
9095 for (i = start; i <= stop; i++) {
9096 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9098 m_pMouseRoute->m_lastMousePointIndex =
9099 m_pMouseRoute->GetnPoints();
9101 gFrame->RefreshAllCanvas();
9105 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9107 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9108 m_pMouseRoute->FinalizeForRendering();
9113 }
else if (m_bMeasure_Active && m_nMeasureState)
9116 m_bedge_pan =
false;
9120 if (m_nMeasureState == 1) {
9121 m_pMeasureRoute =
new Route();
9122 pRouteList->Append(m_pMeasureRoute);
9127 if (m_pMeasureRoute) {
9130 wxEmptyString, wxEmptyString);
9131 pMousePoint->m_bShowName =
false;
9133 m_pMeasureRoute->AddPoint(pMousePoint);
9137 m_prev_pMousePoint = pMousePoint;
9138 m_pMeasureRoute->m_lastMousePointIndex =
9139 m_pMeasureRoute->GetnPoints();
9143 CancelMeasureRoute();
9149 bool bSelectAllowed =
true;
9150 if (NULL == g_pMarkInfoDialog) {
9151 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9152 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9153 bSelectAllowed =
false;
9160 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9162 if (bSelectAllowed) {
9163 bool b_was_editing_mark = m_bMarkEditing;
9164 bool b_was_editing_route = m_bRouteEditing;
9165 FindRoutePointsAtCursor(SelectRadius,
9171 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->m_bIsInLayer)
9172 m_pRoutePointEditTarget = NULL;
9174 if (!b_was_editing_route) {
9175 if (m_pEditRouteArray) {
9176 b_startedit_route =
true;
9180 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9181 m_pTrackRolloverWin->IsActive(
false);
9183 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9184 m_pRouteRolloverWin->IsActive(
false);
9188 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9190 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9195 if (g_pRouteMan->IsRouteValid(pr)) {
9198 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9199 pre_rect.Union(route_rect);
9202 RefreshRect(pre_rect,
true);
9205 b_startedit_route =
false;
9209 if (m_pRoutePointEditTarget) {
9210 if (b_was_editing_mark ||
9211 b_was_editing_route) {
9212 if (m_lastRoutePointEditTarget) {
9213 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9214 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9216 .EnableDragHandle(
false);
9217 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9218 SELTYPE_DRAGHANDLE);
9222 if (m_pRoutePointEditTarget) {
9223 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
true;
9224 m_pRoutePointEditTarget->m_bPtIsSelected =
true;
9225 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9226 wxPoint2DDouble dragHandlePoint =
9228 .GetDragHandlePoint(
this);
9229 pSelect->AddSelectablePoint(
9230 dragHandlePoint.m_y, dragHandlePoint.m_x,
9231 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9234 if (m_lastRoutePointEditTarget) {
9235 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9236 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9238 .EnableDragHandle(
false);
9239 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9240 SELTYPE_DRAGHANDLE);
9243 wxArrayPtrVoid *lastEditRouteArray =
9245 m_lastRoutePointEditTarget);
9246 if (lastEditRouteArray) {
9247 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9249 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9250 if (g_pRouteMan->IsRouteValid(pr)) {
9251 pr->m_bIsBeingEdited =
false;
9254 delete lastEditRouteArray;
9265 if (m_lastRoutePointEditTarget) {
9268 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9269 RefreshRect(wp_rect,
true);
9272 if (m_pRoutePointEditTarget) {
9275 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9276 RefreshRect(wp_rect,
true);
9285 bool b_start_rollover =
false;
9286 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9287 SelectItem *pFind = pSelectAIS->FindSelection(
9289 if (pFind) b_start_rollover =
true;
9292 if (!b_start_rollover && !b_startedit_route) {
9293 SelectableItemList SelList = pSelect->FindSelectionList(
9295 wxSelectableItemListNode *node = SelList.GetFirst();
9301 if (pr && pr->IsVisible()) {
9302 b_start_rollover =
true;
9305 node = node->GetNext();
9309 if (!b_start_rollover && !b_startedit_route) {
9310 SelectableItemList SelList = pSelect->FindSelectionList(
9312 wxSelectableItemListNode *node = SelList.GetFirst();
9318 if (tr && tr->IsVisible()) {
9319 b_start_rollover =
true;
9322 node = node->GetNext();
9326 if (b_start_rollover)
9327 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9331 bool appending =
false;
9332 bool inserting =
false;
9334 if (m_bRouteEditing ) {
9336 if (m_pRoutePointEditTarget) {
9342 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9343 double nearby_radius_meters =
9344 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9345 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9346 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9347 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9348 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9349 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9353 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9355 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9356 if (pr && pr->pRoutePointList) {
9357 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
9370 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9375 OCPNMessageBox(
this,
9376 _(
"Replace this RoutePoint by the nearby "
9378 _(
"OpenCPN RoutePoint change"),
9379 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9380 if (dlg_return == wxID_YES) {
9385 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9388 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9390 if (tail && current && (tail != current)) {
9392 connect = tail->GetIndexOf(pNearbyPoint);
9393 int index_current_route =
9394 current->GetIndexOf(m_pRoutePointEditTarget);
9395 index_last = current->GetIndexOf(current->GetLastPoint());
9396 dlg_return1 = wxID_NO;
9398 index_current_route) {
9400 if (connect != tail->GetnPoints()) {
9403 _(
"Last part of route to be appended to dragged "
9407 _(
"Full route to be appended to dragged route?");
9409 dlg_return1 = OCPNMessageBox(
9410 this, dmsg, _(
"OpenCPN Route Create"),
9411 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9412 if (dlg_return1 == wxID_YES) {
9416 }
else if (index_current_route ==
9421 _(
"First part of route to be inserted into dragged "
9423 if (connect == tail->GetnPoints())
9425 "Full route to be inserted into dragged route?");
9427 dlg_return1 = OCPNMessageBox(
9428 this, dmsg, _(
"OpenCPN Route Create"),
9429 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9430 if (dlg_return1 == wxID_YES) {
9437 if (m_pRoutePointEditTarget->IsShared()) {
9439 dlg_return = OCPNMessageBox(
9441 _(
"Do you really want to delete and replace this "
9443 _T(
"\n") + _(
"which has been created manually?"),
9444 (
"OpenCPN RoutePoint warning"),
9445 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9448 if (dlg_return == wxID_YES) {
9449 pMousePoint = pNearbyPoint;
9451 pMousePoint->SetShared(
true);
9455 pMousePoint->m_bIsInRoute =
true;
9461 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9463 if (m_pEditRouteArray) {
9464 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9466 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9467 if (g_pRouteMan->IsRouteValid(pr)) {
9471 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9473 pSelect->DeleteAllSelectableRoutePoints(pr);
9474 pSelect->DeleteAllSelectableRouteSegments(pr);
9476 pr->pRoutePointList->Insert(nRP, pMousePoint);
9477 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9479 pSelect->AddAllSelectableRouteSegments(pr);
9480 pSelect->AddAllSelectableRoutePoints(pr);
9482 pr->FinalizeForRendering();
9483 pr->UpdateSegmentDistances();
9484 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9490 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9491 if (m_pEditRouteArray) {
9492 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9494 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9495 if (g_pRouteMan->IsRouteValid(pr)) {
9496 if (pRoutePropDialog->GetRoute() == pr) {
9497 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9512 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9515 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9516 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9517 g_pMarkInfoDialog->Hide();
9519 delete m_pRoutePointEditTarget;
9520 m_lastRoutePointEditTarget = NULL;
9521 m_pRoutePointEditTarget = NULL;
9522 undo->AfterUndoableAction(pMousePoint);
9523 undo->InvalidateUndo();
9528 else if (m_bMarkEditing) {
9529 if (m_pRoutePointEditTarget)
9530 if (m_bRoutePoinDragging)
9531 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9534 if (m_pRoutePointEditTarget)
9535 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9537 if (!m_pRoutePointEditTarget) {
9538 delete m_pEditRouteArray;
9539 m_pEditRouteArray = NULL;
9540 m_bRouteEditing =
false;
9542 m_bRoutePoinDragging =
false;
9549 int length = tail->GetnPoints();
9550 for (
int i = connect + 1; i <= length; i++) {
9551 current->AddPointAndSegment(tail->GetPoint(i),
false);
9552 if (current) current->m_lastMousePointIndex = current->GetnPoints();
9554 gFrame->RefreshAllCanvas();
9557 current->FinalizeForRendering();
9558 current->m_bIsBeingEdited =
false;
9560 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9563 pSelect->DeleteAllSelectableRoutePoints(current);
9564 pSelect->DeleteAllSelectableRouteSegments(current);
9565 for (
int i = 1; i < connect; i++) {
9566 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9568 pSelect->AddAllSelectableRouteSegments(current);
9569 pSelect->AddAllSelectableRoutePoints(current);
9570 current->FinalizeForRendering();
9571 current->m_bIsBeingEdited =
false;
9572 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9576 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9577 if (m_pEditRouteArray) {
9578 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9579 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9580 if (g_pRouteMan->IsRouteValid(pr)) {
9581 if (pRoutePropDialog->GetRoute() == pr) {
9582 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9592 if (m_bRouteEditing) {
9595 bool appending =
false;
9596 bool inserting =
false;
9599 if (m_pRoutePointEditTarget) {
9600 m_pRoutePointEditTarget->m_bBlink =
false;
9604 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9605 double nearby_radius_meters =
9606 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9607 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9608 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9609 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9610 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9611 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9612 bool duplicate =
false;
9614 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9616 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9617 if (pr && pr->pRoutePointList) {
9618 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
9631 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9636 OCPNMessageBox(
this,
9637 _(
"Replace this RoutePoint by the nearby "
9639 _(
"OpenCPN RoutePoint change"),
9640 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9641 if (dlg_return == wxID_YES) {
9645 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9648 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9650 if (tail && current && (tail != current)) {
9652 connect = tail->GetIndexOf(pNearbyPoint);
9653 int index_current_route =
9654 current->GetIndexOf(m_pRoutePointEditTarget);
9655 index_last = current->GetIndexOf(current->GetLastPoint());
9656 dlg_return1 = wxID_NO;
9658 index_current_route) {
9660 if (connect != tail->GetnPoints()) {
9663 _(
"Last part of route to be appended to dragged "
9667 _(
"Full route to be appended to dragged route?");
9669 dlg_return1 = OCPNMessageBox(
9670 this, dmsg, _(
"OpenCPN Route Create"),
9671 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9672 if (dlg_return1 == wxID_YES) {
9676 }
else if (index_current_route ==
9681 _(
"First part of route to be inserted into dragged "
9683 if (connect == tail->GetnPoints())
9685 "Full route to be inserted into dragged route?");
9687 dlg_return1 = OCPNMessageBox(
9688 this, dmsg, _(
"OpenCPN Route Create"),
9689 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9690 if (dlg_return1 == wxID_YES) {
9697 if (m_pRoutePointEditTarget->IsShared()) {
9698 dlg_return = wxID_NO;
9699 dlg_return = OCPNMessageBox(
9701 _(
"Do you really want to delete and replace this "
9703 _T(
"\n") + _(
"which has been created manually?"),
9704 (
"OpenCPN RoutePoint warning"),
9705 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9708 if (dlg_return == wxID_YES) {
9709 pMousePoint = pNearbyPoint;
9711 pMousePoint->SetShared(
true);
9715 pMousePoint->m_bIsInRoute =
true;
9721 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9723 if (m_pEditRouteArray) {
9724 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9726 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9727 if (g_pRouteMan->IsRouteValid(pr)) {
9730 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9732 pSelect->DeleteAllSelectableRoutePoints(pr);
9733 pSelect->DeleteAllSelectableRouteSegments(pr);
9735 pr->pRoutePointList->Insert(nRP, pMousePoint);
9736 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9738 pSelect->AddAllSelectableRouteSegments(pr);
9739 pSelect->AddAllSelectableRoutePoints(pr);
9741 pr->FinalizeForRendering();
9742 pr->UpdateSegmentDistances();
9743 pr->m_bIsBeingEdited =
false;
9745 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9757 int length = tail->GetnPoints();
9758 for (
int i = connect + 1; i <= length; i++) {
9759 current->AddPointAndSegment(tail->GetPoint(i),
false);
9761 current->m_lastMousePointIndex = current->GetnPoints();
9763 gFrame->RefreshAllCanvas();
9766 current->FinalizeForRendering();
9767 current->m_bIsBeingEdited =
false;
9769 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9772 pSelect->DeleteAllSelectableRoutePoints(current);
9773 pSelect->DeleteAllSelectableRouteSegments(current);
9774 for (
int i = 1; i < connect; i++) {
9775 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9777 pSelect->AddAllSelectableRouteSegments(current);
9778 pSelect->AddAllSelectableRoutePoints(current);
9779 current->FinalizeForRendering();
9780 current->m_bIsBeingEdited =
false;
9781 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9785 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9786 if (m_pEditRouteArray) {
9787 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9789 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9790 if (g_pRouteMan->IsRouteValid(pr)) {
9791 if (pRoutePropDialog->GetRoute() == pr) {
9792 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9800 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9803 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9804 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9805 g_pMarkInfoDialog->Hide();
9807 delete m_pRoutePointEditTarget;
9808 m_lastRoutePointEditTarget = NULL;
9809 undo->AfterUndoableAction(pMousePoint);
9810 undo->InvalidateUndo();
9812 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9813 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9815 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9818 delete m_pEditRouteArray;
9819 m_pEditRouteArray = NULL;
9823 m_bRouteEditing =
false;
9824 m_pRoutePointEditTarget = NULL;
9830 else if (m_bMarkEditing) {
9831 if (m_pRoutePointEditTarget) {
9832 if (m_bRoutePoinDragging)
9833 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9834 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9835 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9839 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9840 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9841 RefreshRect(wp_rect,
true);
9844 m_pRoutePointEditTarget = NULL;
9845 m_bMarkEditing =
false;
9850 else if (leftIsDown) {
9855 if (!m_bChartDragging && !m_bMeasure_Active) {
9857 m_bChartDragging =
false;
9861 m_bRoutePoinDragging =
false;
9864 if (ret)
return true;
9867 if (event.RightDown()) {
9878 m_FinishRouteOnKillFocus =
false;
9879 CallPopupMenu(mx, my);
9880 m_FinishRouteOnKillFocus =
true;
9891 if (event.ShiftDown()) {
9895 event.GetPosition(&x, &y);
9897 x *= m_displayScale;
9898 y *= m_displayScale;
9904 int wheel_dir =
event.GetWheelRotation();
9907 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9908 wheel_dir = wheel_dir > 0 ? 1 : -1;
9910 double factor = g_mouse_zoom_sensitivity;
9911 if (wheel_dir < 0) factor = 1 / factor;
9913 if (g_bsmoothpanzoom) {
9914 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9915 if (wheel_dir == m_last_wheel_dir) {
9916 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9921 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9922 m_wheelstopwatch.Start(0);
9927 m_last_wheel_dir = wheel_dir;
9932 if (event.LeftDown()) {
9939 last_drag.x = x, last_drag.y = y;
9940 panleftIsDown =
true;
9943 if (event.LeftUp()) {
9944 if (panleftIsDown) {
9946 panleftIsDown =
false;
9949 if (!m_bChartDragging && !m_bMeasure_Active) {
9950 switch (cursor_region) {
9972 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
9977 m_bChartDragging =
false;
9983 if (event.Dragging() && event.LeftIsDown()) {
10001 struct timespec now;
10002 clock_gettime(CLOCK_MONOTONIC, &now);
10003 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10005 if (
false == m_bChartDragging) {
10007 last_drag.x = x, last_drag.y = y;
10008 m_bChartDragging =
true;
10009 m_chart_drag_total_time = 0;
10010 m_chart_drag_total_x = 0;
10011 m_chart_drag_total_y = 0;
10012 m_inertia_last_drag_x = x;
10013 m_inertia_last_drag_y = y;
10014 m_drag_vec_x.clear();
10015 m_drag_vec_y.clear();
10016 m_drag_vec_t.clear();
10017 m_last_drag_time = tnow;
10021 uint64_t delta_t = tnow - m_last_drag_time;
10022 double delta_tf = delta_t / 1e9;
10024 m_chart_drag_total_time += delta_tf;
10025 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10026 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10028 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10029 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10030 m_drag_vec_t.push_back(delta_tf);
10032 m_inertia_last_drag_x = x;
10033 m_inertia_last_drag_y = y;
10034 m_last_drag_time = tnow;
10036 if ((last_drag.x != x) || (last_drag.y != y)) {
10037 if (!m_routeState) {
10040 m_bChartDragging =
true;
10041 StartTimedMovement();
10042 m_pan_drag.x += last_drag.x - x;
10043 m_pan_drag.y += last_drag.y - y;
10044 last_drag.x = x, last_drag.y = y;
10048 if ((last_drag.x != x) || (last_drag.y != y)) {
10049 if (!m_routeState) {
10052 m_bChartDragging =
true;
10053 StartTimedMovement();
10054 m_pan_drag.x += last_drag.x - x;
10055 m_pan_drag.y += last_drag.y - y;
10056 last_drag.x = x, last_drag.y = y;
10063 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10065 m_DoubleClickTimer->Start();
10066 singleClickEventIsValid =
false;
10074void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10075 if (MouseEventOverlayWindows(event))
return;
10082void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10085 wxCursor *ptarget_cursor = pCursorArrow;
10086 if (!pPlugIn_Cursor) {
10087 ptarget_cursor = pCursorArrow;
10088 if ((!m_routeState) &&
10089 (!m_bMeasure_Active) ) {
10090 if (cursor_region == MID_RIGHT) {
10091 ptarget_cursor = pCursorRight;
10092 }
else if (cursor_region == MID_LEFT) {
10093 ptarget_cursor = pCursorLeft;
10094 }
else if (cursor_region == MID_TOP) {
10095 ptarget_cursor = pCursorDown;
10096 }
else if (cursor_region == MID_BOT) {
10097 ptarget_cursor = pCursorUp;
10099 ptarget_cursor = pCursorArrow;
10101 }
else if (m_bMeasure_Active ||
10103 ptarget_cursor = pCursorPencil;
10105 ptarget_cursor = pPlugIn_Cursor;
10108 SetCursor(*ptarget_cursor);
10111void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10112 SetCursor(*pCursorArrow);
10115void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10119 wxArrayString files;
10121 ChartBase *target_chart = GetChartAtCursor();
10122 if (target_chart) {
10123 file.Assign(target_chart->GetFullPath());
10124 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10125 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10128 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10130 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10131 unsigned int im = stackIndexArray.size();
10132 int scale = 2147483647;
10133 if (VPoint.b_quilt && im > 0) {
10134 for (
unsigned int is = 0; is < im; is++) {
10135 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
10136 CHART_TYPE_MBTILES) {
10137 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10139 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10140 if (ChartData->GetChartTableEntry(stackIndexArray[is])
10142 .Contains(lat, lon)) {
10143 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10146 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10147 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
10155 std::vector<Ais8_001_22 *> area_notices;
10157 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10160 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10161 auto target_data = target.second;
10162 if (!target_data->area_notices.empty()) {
10163 for (
auto &ani : target_data->area_notices) {
10168 for (Ais8_001_22_SubAreaList::iterator sa =
10169 area_notice.sub_areas.begin();
10170 sa != area_notice.sub_areas.end(); ++sa) {
10171 switch (sa->shape) {
10172 case AIS8_001_22_SHAPE_CIRCLE: {
10173 wxPoint target_point;
10175 bbox.Expand(target_point);
10176 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10179 case AIS8_001_22_SHAPE_RECT: {
10180 wxPoint target_point;
10182 bbox.Expand(target_point);
10183 if (sa->e_dim_m > sa->n_dim_m)
10184 bbox.EnLarge(sa->e_dim_m * vp_scale);
10186 bbox.EnLarge(sa->n_dim_m * vp_scale);
10189 case AIS8_001_22_SHAPE_POLYGON:
10190 case AIS8_001_22_SHAPE_POLYLINE: {
10191 for (
int i = 0; i < 4; ++i) {
10192 double lat = sa->latitude;
10193 double lon = sa->longitude;
10194 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10196 wxPoint target_point;
10198 bbox.Expand(target_point);
10202 case AIS8_001_22_SHAPE_SECTOR: {
10203 double lat1 = sa->latitude;
10204 double lon1 = sa->longitude;
10206 wxPoint target_point;
10208 bbox.Expand(target_point);
10209 for (
int i = 0; i < 18; ++i) {
10212 sa->left_bound_deg +
10213 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10214 sa->radius_m / 1852.0, &lat, &lon);
10216 bbox.Expand(target_point);
10218 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10221 bbox.Expand(target_point);
10227 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10228 area_notices.push_back(&area_notice);
10235 if (target_chart || !area_notices.empty() || file.HasName()) {
10237 int sel_rad_pix = 5;
10238 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10243 SetCursor(wxCURSOR_WAIT);
10244 bool lightsVis = m_encShowLights;
10245 if (!lightsVis) SetShowENCLights(
true);
10248 ListOfObjRazRules *rule_list = NULL;
10249 ListOfPI_S57Obj *pi_rule_list = NULL;
10252 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10253 else if (target_plugin_chart)
10254 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10255 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10257 ListOfObjRazRules *overlay_rule_list = NULL;
10258 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10261 if (CHs57_Overlay) {
10262 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10263 zlat, zlon, SelectRadius, &GetVP());
10266 if (!lightsVis) SetShowENCLights(
false);
10269 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10270 wxString face = dFont->GetFaceName();
10272 if (NULL == g_pObjectQueryDialog) {
10273 g_pObjectQueryDialog =
10274 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10275 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10278 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10279 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10283 fg = g_pObjectQueryDialog->GetForegroundColour();
10287 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
10288 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10291 int points = dFont->GetPointSize();
10293 int points = dFont->GetPointSize() + 1;
10297 for (
int i = -2; i < 5; i++) {
10298 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10300 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10302 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
10304 if (overlay_rule_list && CHs57_Overlay) {
10305 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10306 objText << _T(
"<hr noshade>");
10309 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10310 an != area_notices.end(); ++an) {
10311 objText << _T(
"<b>AIS Area Notice:</b> " );
10312 objText << ais8_001_22_notice_names[(*an)->notice_type];
10313 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10314 (*an)->sub_areas.begin();
10315 sa != (*an)->sub_areas.end(); ++sa)
10316 if (!sa->text.empty()) objText << sa->text;
10317 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10318 objText << _T(
"<hr noshade>" );
10322 objText << Chs57->CreateObjDescriptions(rule_list);
10323 else if (target_plugin_chart)
10324 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10327 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
10330 wxString AddFiles, filenameOK;
10332 if (!target_plugin_chart) {
10335 AddFiles = wxString::Format(
10336 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
10338 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
10339 _T(
"cellpadding=3>"),
10340 file.GetFullName());
10342 file.Assign(file.GetPath(), wxT(
""));
10343 wxDir dir(file.GetFullPath());
10345 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10347 file.Assign(dir.GetNameWithSep().append(filename));
10348 wxString FormatString =
10349 _T(
"<td valign=top><font size=-2><a ")
10350 _T("href=\"%s\">%s</a></font></td>");
10351 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10352 filenameOK = file.GetFullPath();
10354 if (3 * ((
int)filecount / 3) == filecount)
10355 FormatString.Prepend(_T(
"<tr>"));
10357 FormatString.Prepend(
10358 _T(
"<td>  </td>"));
10361 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10362 file.GetFullName());
10365 cont = dir.GetNext(&filename);
10367 objText << AddFiles << _T(
"</table>");
10369 objText << _T(
"</font>");
10370 objText << _T(
"</body></html>");
10372 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10373 g_pObjectQueryDialog->SetHTMLPage(objText);
10374 g_pObjectQueryDialog->Show();
10376 if ((!Chs57 && filecount == 1)) {
10378 wxHtmlLinkInfo hli(filenameOK);
10379 wxHtmlLinkEvent hle(1, hli);
10380 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10383 if (rule_list) rule_list->Clear();
10386 if (overlay_rule_list) overlay_rule_list->Clear();
10387 delete overlay_rule_list;
10389 if (pi_rule_list) pi_rule_list->Clear();
10390 delete pi_rule_list;
10392 SetCursor(wxCURSOR_ARROW);
10396void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10398 if (!g_pMarkInfoDialog) {
10405 wxSize canvas_size = GetSize();
10408 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10410 g_pMarkInfoDialog->Layout();
10412 wxPoint canvas_pos = GetPosition();
10413 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10415 bool newFit =
false;
10416 if (canvas_size.x < fitted_size.x) {
10417 fitted_size.x = canvas_size.x - 40;
10418 if (canvas_size.y < fitted_size.y)
10419 fitted_size.y -= 40;
10421 if (canvas_size.y < fitted_size.y) {
10422 fitted_size.y = canvas_size.y - 40;
10423 if (canvas_size.x < fitted_size.x)
10424 fitted_size.x -= 40;
10428 g_pMarkInfoDialog->SetSize(fitted_size);
10429 g_pMarkInfoDialog->Centre();
10433 markPoint->m_bRPIsBeingEdited =
false;
10435 wxString title_base = _(
"Mark Properties");
10436 if (markPoint->m_bIsInRoute) {
10437 title_base = _(
"Waypoint Properties");
10439 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10440 g_pMarkInfoDialog->UpdateProperties();
10441 if (markPoint->m_bIsInLayer) {
10442 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title_base, _(
"Layer"),
10443 GetLayerName(markPoint->m_LayerID)));
10444 g_pMarkInfoDialog->SetDialogTitle(caption);
10446 g_pMarkInfoDialog->SetDialogTitle(title_base);
10448 g_pMarkInfoDialog->Show();
10449 g_pMarkInfoDialog->Raise();
10450 g_pMarkInfoDialog->InitialFocus();
10451 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10454void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10455 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10456 pRoutePropDialog->SetRouteAndUpdate(selected);
10458 pRoutePropDialog->Show();
10459 pRoutePropDialog->Raise();
10461 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10464 if (g_bresponsive) {
10465 wxSize canvas_size = GetSize();
10466 wxPoint canvas_pos = GetPosition();
10467 wxSize fitted_size = pRoutePropDialog->GetSize();
10470 if (canvas_size.x < fitted_size.x) {
10471 fitted_size.x = canvas_size.x;
10472 if (canvas_size.y < fitted_size.y)
10473 fitted_size.y -= 20;
10475 if (canvas_size.y < fitted_size.y) {
10476 fitted_size.y = canvas_size.y;
10477 if (canvas_size.x < fitted_size.x)
10478 fitted_size.x -= 20;
10481 pRoutePropDialog->SetSize(fitted_size);
10482 pRoutePropDialog->Centre();
10487 wxPoint xxp = ClientToScreen(canvas_pos);
10491 pRoutePropDialog->SetRouteAndUpdate(selected);
10493 pRoutePropDialog->Show();
10498void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10499 pTrackPropDialog = TrackPropDlg::getInstance(
10502 pTrackPropDialog->SetTrackAndUpdate(selected);
10505 pTrackPropDialog->Show();
10510void pupHandler_PasteWaypoint() {
10513 int pasteBuffer = kml.ParsePasteBuffer();
10514 RoutePoint *pasted = kml.GetParsedRoutePoint();
10515 if (!pasted)
return;
10517 double nearby_radius_meters =
10518 g_Platform->GetSelectRadiusPix() /
10519 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10521 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10522 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10524 int answer = wxID_NO;
10525 if (nearPoint && !nearPoint->m_bIsInLayer) {
10528 "There is an existing waypoint at the same location as the one you are "
10529 "pasting. Would you like to merge the pasted data with it?\n\n");
10530 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10531 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10532 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10535 if (answer == wxID_YES) {
10536 nearPoint->SetName(pasted->GetName());
10537 nearPoint->m_MarkDescription = pasted->m_MarkDescription;
10538 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10539 pRouteManagerDialog->UpdateWptListCtrl();
10542 if (answer == wxID_NO) {
10545 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10547 pConfig->AddNewWayPoint(newPoint, -1);
10549 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10550 pRouteManagerDialog->UpdateWptListCtrl();
10551 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10552 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10555 gFrame->InvalidateAllGL();
10556 gFrame->RefreshAllCanvas(
false);
10559void pupHandler_PasteRoute() {
10562 int pasteBuffer = kml.ParsePasteBuffer();
10563 Route *pasted = kml.GetParsedRoute();
10564 if (!pasted)
return;
10566 double nearby_radius_meters =
10567 g_Platform->GetSelectRadiusPix() /
10568 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10574 bool mergepoints =
false;
10575 bool createNewRoute =
true;
10576 int existingWaypointCounter = 0;
10578 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10579 curPoint = pasted->GetPoint(i);
10580 nearPoint = pWayPointMan->GetNearbyWaypoint(
10581 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10583 mergepoints =
true;
10584 existingWaypointCounter++;
10588 curPoint->m_bPtIsSelected =
true;
10592 int answer = wxID_NO;
10596 "There are existing waypoints at the same location as some of the ones "
10597 "you are pasting. Would you like to just merge the pasted data into "
10599 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10600 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10601 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10603 if (answer == wxID_CANCEL) {
10610 if (mergepoints && answer == wxID_YES &&
10611 existingWaypointCounter == pasted->GetnPoints()) {
10612 wxRouteListNode *route_node = pRouteList->GetFirst();
10613 while (route_node) {
10614 Route *proute = route_node->GetData();
10616 if (pasted->m_RouteNameString == proute->m_RouteNameString) {
10617 createNewRoute =
false;
10620 route_node = route_node->GetNext();
10624 Route *newRoute = 0;
10627 if (createNewRoute) {
10628 newRoute =
new Route();
10629 newRoute->m_RouteNameString = pasted->m_RouteNameString;
10632 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10633 curPoint = pasted->GetPoint(i);
10634 if (answer == wxID_YES && curPoint->m_bPtIsSelected) {
10635 curPoint->m_bPtIsSelected =
false;
10636 newPoint = pWayPointMan->GetNearbyWaypoint(
10637 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10638 newPoint->SetName(curPoint->GetName());
10639 newPoint->m_MarkDescription = curPoint->m_MarkDescription;
10641 if (createNewRoute) newRoute->AddPoint(newPoint);
10643 curPoint->m_bPtIsSelected =
false;
10647 newPoint->SetIconName(_T(
"circle"));
10648 newPoint->m_bIsVisible =
true;
10649 newPoint->m_bShowName =
false;
10650 newPoint->SetShared(
false);
10652 newRoute->AddPoint(newPoint);
10653 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10655 pConfig->AddNewWayPoint(newPoint, -1);
10658 if (i > 1 && createNewRoute)
10659 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10660 curPoint->m_lat, curPoint->m_lon,
10661 prevPoint, newPoint, newRoute);
10662 prevPoint = newPoint;
10665 if (createNewRoute) {
10666 pRouteList->Append(newRoute);
10667 pConfig->AddNewRoute(newRoute);
10669 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10670 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10673 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10674 pRouteManagerDialog->UpdateRouteListCtrl();
10675 pRouteManagerDialog->UpdateWptListCtrl();
10677 gFrame->InvalidateAllGL();
10678 gFrame->RefreshAllCanvas(
false);
10680 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10681 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10684void pupHandler_PasteTrack() {
10687 int pasteBuffer = kml.ParsePasteBuffer();
10688 Track *pasted = kml.GetParsedTrack();
10689 if (!pasted)
return;
10697 newTrack->SetName(pasted->GetName());
10699 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10700 curPoint = pasted->GetPoint(i);
10704 wxDateTime now = wxDateTime::Now();
10707 newTrack->AddPoint(newPoint);
10710 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10711 newPoint->m_lat, newPoint->m_lon,
10712 prevPoint, newPoint, newTrack);
10714 prevPoint = newPoint;
10717 g_TrackList.push_back(newTrack);
10718 pConfig->AddNewTrack(newTrack);
10720 gFrame->InvalidateAllGL();
10721 gFrame->RefreshAllCanvas(
false);
10724bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10726 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10727 m_pIDXCandidate, m_nmea_log);
10730 wxEVT_COMMAND_MENU_SELECTED,
10731 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10733 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10736 wxEVT_COMMAND_MENU_SELECTED,
10737 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10739 delete m_canvasMenu;
10740 m_canvasMenu = NULL;
10750void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10753 if (m_canvasMenu) {
10754 m_canvasMenu->PopupMenuHandler(event);
10759void ChartCanvas::StartRoute(
void) {
10761 if (g_brouteCreating)
return;
10763 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10765 g_brouteCreating =
true;
10767 m_bDrawingRoute =
false;
10768 SetCursor(*pCursorPencil);
10770 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10772 HideGlobalToolbar();
10775 androidSetRouteAnnunciator(
true);
10779void ChartCanvas::FinishRoute(
void) {
10781 m_prev_pMousePoint = NULL;
10782 m_bDrawingRoute =
false;
10785 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10787 androidSetRouteAnnunciator(
false);
10790 SetCursor(*pCursorArrow);
10792 if (m_pMouseRoute) {
10793 if (m_bAppendingRoute)
10794 pConfig->UpdateRoute(m_pMouseRoute);
10796 if (m_pMouseRoute->GetnPoints() > 1) {
10797 pConfig->AddNewRoute(m_pMouseRoute);
10800 NavObjectChanges::getInstance());
10801 m_pMouseRoute = NULL;
10804 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10806 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10807 (pRoutePropDialog->IsShown())) {
10808 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10811 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10812 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10813 pRouteManagerDialog->UpdateRouteListCtrl();
10816 m_bAppendingRoute =
false;
10817 m_pMouseRoute = NULL;
10819 m_pSelectedRoute = NULL;
10821 undo->InvalidateUndo();
10822 gFrame->RefreshAllCanvas(
true);
10824 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10826 ShowGlobalToolbar();
10828 g_brouteCreating =
false;
10831void ChartCanvas::HideGlobalToolbar() {
10832 if (m_canvasIndex == 0) {
10833 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10837void ChartCanvas::ShowGlobalToolbar() {
10838 if (m_canvasIndex == 0) {
10839 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10843void ChartCanvas::ShowAISTargetList(
void) {
10844 if (NULL == g_pAISTargetList) {
10848 g_pAISTargetList->UpdateAISTargetList();
10851void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10852 if (!m_bShowOutlines)
return;
10854 if (!ChartData)
return;
10856 int nEntry = ChartData->GetChartTableEntries();
10858 for (
int i = 0; i < nEntry; i++) {
10862 bool b_group_draw =
false;
10863 if (m_groupIndex > 0) {
10864 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10865 int index = pt->GetGroupArray()[ig];
10866 if (m_groupIndex == index) {
10867 b_group_draw =
true;
10872 b_group_draw =
true;
10874 if (b_group_draw) RenderChartOutline(dc, i, vp);
10880 if (VPoint.b_quilt) {
10881 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10882 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10886 }
else if (m_singleChart &&
10887 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10891 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10894 if (zoom_factor > 8.0) {
10895 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10898 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10902 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
10906void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10908 if (g_bopengl && m_glcc) {
10910 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10915 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10916 if (!ChartData->IsChartAvailable(dbIndex))
return;
10919 float plylat, plylon;
10920 float plylat1, plylon1;
10922 int pixx, pixy, pixx1, pixy1;
10925 ChartData->GetDBBoundingBox(dbIndex, box);
10929 if (box.GetLonRange() == 360)
return;
10931 double lon_bias = 0;
10933 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10935 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10937 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10938 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10940 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10941 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10944 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10947 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10948 if (0 == nAuxPlyEntries)
10952 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10953 plylon += lon_bias;
10959 for (
int i = 0; i < nPly - 1; i++) {
10960 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
10961 plylon1 += lon_bias;
10967 int pixxs1 = pixx1;
10968 int pixys1 = pixy1;
10970 bool b_skip =
false;
10974 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
10975 pow((
double)(pixy1 - pixy), 2)) /
10981 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10986 if (fabs(dist - distgc) > 10000. * 1852.)
10992 ClipResult res = cohen_sutherland_line_clip_i(
10994 if (res != Invisible && !b_skip)
10995 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11003 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11004 plylon1 += lon_bias;
11010 ClipResult res = cohen_sutherland_line_clip_i(
11012 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11019 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
11020 for (
int j = 0; j < nAuxPlyEntries; j++) {
11022 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11027 for (
int i = 0; i < nAuxPly - 1; i++) {
11028 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11034 int pixxs1 = pixx1;
11035 int pixys1 = pixy1;
11037 bool b_skip =
false;
11041 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11042 ((pixy1 - pixy) * (pixy1 - pixy))) /
11047 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11052 if (fabs(dist - distgc) > 10000. * 1852.)
11058 ClipResult res = cohen_sutherland_line_clip_i(
11060 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11068 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11073 ClipResult res = cohen_sutherland_line_clip_i(
11075 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11080static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11081 const wxString &second) {
11082 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11084 int pointsize = dFont->GetPointSize();
11088 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11089 false, dFont->GetFaceName());
11091 dc.SetFont(*psRLI_font);
11099 int hilite_offset = 3;
11102 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11103 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11105 dc.GetTextExtent(first, &w1, &h1);
11106 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11112 w = wxMax(w1, w2) + (h1 / 2);
11117 xp = ref_point.x - w;
11119 yp += hilite_offset;
11121 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11123 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11124 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11126 dc.DrawText(first, xp, yp);
11127 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11130void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11131 if (!g_bAllowShipToActive)
return;
11133 Route *rt = g_pRouteMan->GetpActiveRoute();
11136 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11137 wxPoint2DDouble pa, pb;
11143 g_pRouteMan->GetRoutePen()->GetWidth();
11144 if (rt->m_width != wxPENSTYLE_INVALID)
11145 width = rt->m_width;
11146 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11147 g_shipToActiveStyle, 5)];
11148 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11150 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11152 g_pRouteMan->GetActiveRoutePen()->GetColour();
11153 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11156 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11159 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11160 (
int)pb.m_y, GetVP(),
true);
11164#ifdef USE_ANDROID_GLES2
11165 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11167 if (style != wxPENSTYLE_SOLID) {
11168 if (glChartCanvas::dash_map.find(style) !=
11169 glChartCanvas::dash_map.end()) {
11170 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11174 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11177 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11178 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11184void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11186 if (m_routeState >= 2) route = m_pMouseRoute;
11187 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11188 route = m_pMeasureRoute;
11190 if (!route)
return;
11193 if (!g_pRouteMan->IsRouteValid(route))
return;
11198 int np = route->GetnPoints();
11200 if (g_btouch && (np > 1)) np--;
11202 render_lat = rp.m_lat;
11203 render_lon = rp.m_lon;
11206 double rhumbBearing, rhumbDist;
11208 &rhumbBearing, &rhumbDist);
11209 double brg = rhumbBearing;
11210 double dist = rhumbDist;
11214 double gcBearing, gcBearing2, gcDist;
11215 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11218 double gcDistm = gcDist / 1852.0;
11221 rhumbBearing = 90.;
11223 wxPoint destPoint, lastPoint;
11225 route->m_NextLegGreatCircle =
false;
11226 int milesDiff = rhumbDist - gcDistm;
11227 if (milesDiff > 1) {
11230 route->m_NextLegGreatCircle =
true;
11234 RouteGui(*route).DrawPointWhich(dc,
this, route->m_lastMousePointIndex,
11237 if (route->m_NextLegGreatCircle) {
11238 for (
int i = 1; i <= milesDiff; i++) {
11239 double p = (double)i * (1.0 / (
double)milesDiff);
11241 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11242 &pLon, &pLat, &gcBearing2);
11244 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11246 lastPoint = destPoint;
11249 if (r_rband.x && r_rband.y) {
11250 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11252 if (m_bMeasure_DistCircle) {
11253 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11254 powf((
float)(r_rband.y - lastPoint.y), 2));
11256 dc.SetPen(*g_pRouteMan->GetRoutePen());
11257 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11258 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11264 wxString routeInfo;
11266 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11272 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11274 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11275 (
int)varBrg, 0x00B0);
11278 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
11281 if (!route->m_bIsInLayer)
11282 s0.Append(_(
"Route") + _T(
": "));
11284 s0.Append(_(
"Layer Route: "));
11286 double disp_length = route->m_route_length;
11287 if (!g_btouch) disp_length += dist;
11288 s0 += FormatDistanceAdaptive(disp_length);
11290 RouteLegInfo(dc, r_rband, routeInfo, s0);
11292 m_brepaint_piano =
true;
11295void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11296 if (!m_bShowVisibleSectors)
return;
11298 if (g_bDeferredInitDone) {
11300 double rhumbBearing, rhumbDist;
11301 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11302 &rhumbBearing, &rhumbDist);
11304 if (rhumbDist > 0.05)
11306 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11307 m_sectorlegsVisible);
11308 m_sector_glat = gLat;
11309 m_sector_glon = gLon;
11311 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11315void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11323void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11324 if (!ps52plib)
return;
11326 if (VPoint.b_quilt) {
11327 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11329 if (m_pQuilt->IsQuiltVector()) {
11330 if (ps52plib->GetStateHash() != m_s52StateHash) {
11332 m_s52StateHash = ps52plib->GetStateHash();
11336 if (ps52plib->GetStateHash() != m_s52StateHash) {
11338 m_s52StateHash = ps52plib->GetStateHash();
11343 bool bSendPlibState =
true;
11344 if (VPoint.b_quilt) {
11345 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11348 if (bSendPlibState) {
11350 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
11351 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
11352 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
11353 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
11354 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
11357 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
11358 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
11359 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
11360 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] = m_encShowAnchor;
11361 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] = GetShowENCDataQual();
11362 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
11363 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
11367 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
11368 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
11372 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
11373 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
11374 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
11375 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] =
11376 ps52plib->m_bShowS57ImportantTextOnly;
11377 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
11378 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
11379 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
11380 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
11381 v[_T(
"OpenCPN S52PLIB ColorShades")] =
11382 S52_getMarinerParam(S52_MAR_TWO_SHADES);
11385 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
11386 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
11387 v[_T(
"OpenCPN Scale Factor Exp")] =
11388 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11389 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
11395 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11396 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11397 g_lastS52PLIBPluginMessage = out;
11403void ChartCanvas::OnPaint(wxPaintEvent &event) {
11404 wxPaintDC dc(
this);
11414 if (!m_b_paint_enable) {
11419 UpdateCanvasS52PLIBConfig();
11422 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11424 if (m_glcc && g_bopengl) {
11425 if (!s_in_update) {
11435 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11437 wxRegion ru = GetUpdateRegion();
11439 int rx, ry, rwidth, rheight;
11440 ru.GetBox(rx, ry, rwidth, rheight);
11444#ifdef ocpnUSE_DIBSECTION
11447 wxMemoryDC temp_dc;
11455 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11456 height += m_Piano->GetHeight();
11458 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11462 int thumbx, thumby, thumbsx, thumbsy;
11463 pthumbwin->GetPosition(&thumbx, &thumby);
11464 pthumbwin->GetSize(&thumbsx, &thumbsy);
11465 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11467 if (pthumbwin->IsShown()) {
11468 rgn_chart.Subtract(rgn_thumbwin);
11469 ru.Subtract(rgn_thumbwin);
11475 wxRegion rgn_blit = ru;
11476 if (g_bShowChartBar) {
11477 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11478 GetClientSize().x, m_Piano->GetHeight());
11481 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11482 if (style->chartStatusWindowTransparent)
11483 m_brepaint_piano =
true;
11485 ru.Subtract(chart_bar_rect);
11489 if (m_Compass && m_Compass->IsShown()) {
11490 wxRect compassRect = m_Compass->
GetRect();
11491 if (ru.Contains(compassRect) != wxOutRegion) {
11492 ru.Subtract(compassRect);
11496 wxRect noteRect = m_notification_button->
GetRect();
11497 if (ru.Contains(noteRect) != wxOutRegion) {
11498 ru.Subtract(noteRect);
11502 bool b_newview =
true;
11507 m_cache_vp.IsValid()) {
11513 bool b_rcache_ok =
false;
11514 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11515 b_rcache_ok = !b_newview;
11518 if (VPoint.b_MercatorProjectionOverride)
11519 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11533 if (b_rcache_ok) chart_get_region.Clear();
11536 if (VPoint.b_quilt)
11538 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11540 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11545 AbstractPlatform::ShowBusySpinner();
11549 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11550 (m_working_bm.GetHeight() != svp.
pix_height))
11554 if (fabs(VPoint.
rotation) < 0.01) {
11555 bool b_save =
true;
11557 if (g_SencThreadManager) {
11558 if (g_SencThreadManager->GetJobCount()) {
11560 m_cache_vp.Invalidate();
11574 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11579 int dy = c_new.y - c_old.y;
11580 int dx = c_new.x - c_old.x;
11585 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11589 temp_dc.SelectObject(m_working_bm);
11591 wxMemoryDC cache_dc;
11592 cache_dc.SelectObject(m_cached_chart_bm);
11596 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11599 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11605 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11608 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11616 update_region.Union(
11619 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11624 update_region.Union(
11627 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11631 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11633 cache_dc.SelectObject(wxNullBitmap);
11637 temp_dc.SelectObject(m_cached_chart_bm);
11640 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11644 temp_dc.SelectObject(m_working_bm);
11645 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11650 temp_dc.SelectObject(m_cached_chart_bm);
11655 temp_dc.SelectObject(m_working_bm);
11656 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11669 wxMemoryDC scratch_dc_0;
11670 scratch_dc_0.SelectObject(m_cached_chart_bm);
11673 scratch_dc_0.SelectObject(wxNullBitmap);
11682 temp_dc.SelectObject(m_working_bm);
11685 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11686 chart_get_all_region);
11689 AbstractPlatform::HideBusySpinner();
11695 if (!m_singleChart) {
11696 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11701 if (!chart_get_region.IsEmpty()) {
11702 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11706 if (temp_dc.IsOk()) {
11711 if (!VPoint.b_quilt) {
11714 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11715 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11722 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11723 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11726 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11728 temp_dc.DestroyClippingRegion();
11733 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11735 if (!backgroundRegion.IsEmpty()) {
11741 wxColour water = pWorldBackgroundChart->water;
11742 if (water.IsOk()) {
11743 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11744 temp_dc.SetBrush(wxBrush(water));
11746 while (upd.HaveRects()) {
11747 wxRect rect = upd.GetRect();
11748 temp_dc.DrawRectangle(rect);
11753 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11754 temp_dc.SetDeviceClippingRegion(*clip_region);
11755 delete clip_region;
11759 SetVPRotation(VPoint.
skew);
11762 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11768 wxMemoryDC *pChartDC = &temp_dc;
11769 wxMemoryDC rotd_dc;
11771 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11773 if (!b_rcache_ok) {
11775 wxMemoryDC tbase_dc;
11777 tbase_dc.SelectObject(bm_base);
11779 tbase_dc.SelectObject(wxNullBitmap);
11781 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11784 wxImage base_image;
11785 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11793 bool b_rot_ok =
false;
11794 if (base_image.IsOk()) {
11797 m_b_rot_hidef =
false;
11801 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11802 m_b_rot_hidef, &m_roffset);
11807 rot_vp.IsValid() && (ri.IsOk())) {
11814 m_prot_bm =
new wxBitmap(ri);
11817 m_roffset.x += VPoint.rv_rect.x;
11818 m_roffset.y += VPoint.rv_rect.y;
11821 if (m_prot_bm && m_prot_bm->IsOk()) {
11822 rotd_dc.SelectObject(*m_prot_bm);
11823 pChartDC = &rotd_dc;
11825 pChartDC = &temp_dc;
11826 m_roffset = wxPoint(0, 0);
11829 pChartDC = &temp_dc;
11830 m_roffset = wxPoint(0, 0);
11833 wxPoint offset = m_roffset;
11836 m_cache_vp = VPoint;
11839 wxMemoryDC mscratch_dc;
11840 mscratch_dc.SelectObject(*pscratch_bm);
11842 mscratch_dc.ResetBoundingBox();
11843 mscratch_dc.DestroyClippingRegion();
11844 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11847 wxRegionIterator upd(rgn_blit);
11849 wxRect rect = upd.GetRect();
11851 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11852 rect.x - offset.x, rect.y - offset.y);
11858 if (m_show_focus_bar && (g_canvasConfig != 0)) {
11859 if (
this == wxWindow::FindFocus()) {
11860 g_focusCanvas =
this;
11862 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11863 mscratch_dc.SetPen(wxPen(colour));
11864 mscratch_dc.SetBrush(wxBrush(colour));
11866 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11867 mscratch_dc.DrawRectangle(activeRect);
11872 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11873 unsigned int im = stackIndexArray.size();
11874 if (VPoint.b_quilt && im > 0) {
11875 std::vector<int> tiles_to_show;
11876 for (
unsigned int is = 0; is < im; is++) {
11878 ChartData->GetChartTableEntry(stackIndexArray[is]);
11879 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11882 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11883 tiles_to_show.push_back(stackIndexArray[is]);
11887 if (tiles_to_show.size())
11888 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11895 ocpnDC scratch_dc(mscratch_dc);
11896 DrawOverlayObjects(scratch_dc, ru);
11899 RebuildTideSelectList(GetVP().GetBBox());
11900 DrawAllTidesInBBox(scratch_dc, GetVP().GetBBox());
11903 if (m_bShowCurrent) {
11904 RebuildCurrentSelectList(GetVP().GetBBox());
11905 DrawAllCurrentsInBBox(scratch_dc, GetVP().GetBBox());
11908 if (m_brepaint_piano && g_bShowChartBar) {
11909 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), mscratch_dc);
11912 if (m_Compass) m_Compass->Paint(scratch_dc);
11914 auto ¬eman = NotificationManager::GetInstance();
11915 if (noteman.GetNotificationCount()) {
11916 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
11917 if (m_notification_button->UpdateStatus()) Refresh();
11918 m_notification_button->Show(
true);
11919 m_notification_button->Paint(scratch_dc);
11921 m_notification_button->Show(
false);
11924 RenderAlertMessage(mscratch_dc, GetVP());
11929#ifdef ocpnUSE_DIBSECTION
11934 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11935 q_dc.SelectObject(qbm);
11938 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11941 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11942 q_dc.SetBrush(qbr);
11943 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11946 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11949 q_dc.SelectObject(wxNullBitmap);
11956 if( VPoint.b_quilt ) {
11957 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11958 ChartBase *chart = m_pQuilt->GetRefChart();
11959 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11964 ChPI->ClearPLIBTextList();
11967 ps52plib->ClearTextList();
11971 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11973 wxColor maskBackground = wxColour(1,0,0);
11974 t_dc.SelectObject( qbm );
11975 t_dc.SetBackground(wxBrush(maskBackground));
11979 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
11982 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
11983 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
11986 wxRegionIterator upd_final( ru );
11987 while( upd_final ) {
11988 wxRect rect = upd_final.GetRect();
11989 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
11993 t_dc.SelectObject( wxNullBitmap );
11999 if (VPoint.b_quilt) {
12000 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12001 ChartBase *chart = m_pQuilt->GetRefChart();
12002 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12006 ChPI->ClearPLIBTextList();
12008 if (ps52plib) ps52plib->ClearTextList();
12013 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12015 if (g_bShowChartBar && m_Piano) {
12016 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12017 GetVP().pix_width, m_Piano->GetHeight());
12020 if (!style->chartStatusWindowTransparent)
12021 chart_all_text_region.Subtract(chart_bar_rect);
12024 if (m_Compass && m_Compass->IsShown()) {
12025 wxRect compassRect = m_Compass->
GetRect();
12026 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12027 chart_all_text_region.Subtract(compassRect);
12031 mscratch_dc.DestroyClippingRegion();
12033 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12034 chart_all_text_region);
12040 wxRegionIterator upd_final(rgn_blit);
12041 while (upd_final) {
12042 wxRect rect = upd_final.GetRect();
12043 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12064 temp_dc.SelectObject(wxNullBitmap);
12066 mscratch_dc.SelectObject(wxNullBitmap);
12068 dc.DestroyClippingRegion();
12073void ChartCanvas::PaintCleanup() {
12085 m_bTCupdate =
false;
12089 WarpPointer(warp_x, warp_y);
12096 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12097 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12101wxColour GetErrorGraphicColor(
double val)
12120 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
12121 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
12122 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
12123 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
12124 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
12125 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
12126 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
12127 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
12128 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
12129 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
12130 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
12131 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
12132 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
12133 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
12134 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
12135 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
12136 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
12137 else if( val >= 48) c.Set(_T(
"#410000"));
12142void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12145 gr_image.InitAlpha();
12147 double maxval = -10000;
12148 double minval = 10000;
12165 maxval = wxMax(maxval, (glat - rlat));
12166 minval = wxMin(minval, (glat - rlat));
12183 double f = ((glat - rlat)-minval)/(maxval - minval);
12185 double dy = (f * 40);
12187 wxColour c = GetErrorGraphicColor(dy);
12188 unsigned char r = c.Red();
12189 unsigned char g = c.Green();
12190 unsigned char b = c.Blue();
12192 gr_image.SetRGB(j, i, r,g,b);
12193 if((glat - rlat )!= 0)
12194 gr_image.SetAlpha(j, i, 128);
12196 gr_image.SetAlpha(j, i, 255);
12203 wxBitmap *pbm =
new wxBitmap(gr_image);
12204 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12205 pbm->SetMask(gr_mask);
12207 pmdc->DrawBitmap(*pbm, 0,0);
12215void ChartCanvas::CancelMouseRoute() {
12217 m_pMouseRoute = NULL;
12218 m_bDrawingRoute =
false;
12221int ChartCanvas::GetNextContextMenuId() {
12222 return CanvasMenuHandler::GetNextContextMenuId();
12225bool ChartCanvas::SetCursor(
const wxCursor &c) {
12227 if (g_bopengl && m_glcc)
12228 return m_glcc->SetCursor(c);
12231 return wxWindow::SetCursor(c);
12234void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12235 if (g_bquiting)
return;
12245 if (!m_RolloverPopupTimer.IsRunning() &&
12246 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12247 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12248 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12249 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12252 if (m_glcc && g_bopengl) {
12255 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12257 m_glcc->Refresh(eraseBackground,
12268 if (pthumbwin && pthumbwin->IsShown()) {
12269 pthumbwin->Raise();
12270 pthumbwin->Refresh(
false);
12274 if (m_pCIWin && m_pCIWin->IsShown()) {
12276 m_pCIWin->Refresh(
false);
12284 wxWindow::Refresh(eraseBackground, rect);
12287void ChartCanvas::Update() {
12288 if (m_glcc && g_bopengl) {
12293 wxWindow::Update();
12297 if (!pemboss)
return;
12298 int x = pemboss->x, y = pemboss->y;
12299 const double factor = 200;
12301 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
12302 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12303 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
12306 wxMemoryDC snip_dc;
12307 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12308 snip_dc.SelectObject(snip_bmp);
12310 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12311 snip_dc.SelectObject(wxNullBitmap);
12313 wxImage snip_img = snip_bmp.ConvertToImage();
12316 unsigned char *pdata = snip_img.GetData();
12318 for (
int y = 0; y < pemboss->height; y++) {
12319 int map_index = (y * pemboss->width);
12320 for (
int x = 0; x < pemboss->width; x++) {
12321 double val = (pemboss->pmap[map_index] * factor) / 256.;
12323 int nred = (int)((*pdata) + val);
12324 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12325 *pdata++ = (
unsigned char)nred;
12327 int ngreen = (int)((*pdata) + val);
12328 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12329 *pdata++ = (
unsigned char)ngreen;
12331 int nblue = (int)((*pdata) + val);
12332 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12333 *pdata++ = (
unsigned char)nblue;
12341 wxBitmap emb_bmp(snip_img);
12344 wxMemoryDC result_dc;
12345 result_dc.SelectObject(emb_bmp);
12348 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12350 result_dc.SelectObject(wxNullBitmap);
12356 if (GetQuiltMode()) {
12358 int refIndex = GetQuiltRefChartdbIndex();
12359 if (refIndex >= 0) {
12360 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
12361 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12362 if (current_type == CHART_TYPE_MBTILES) {
12363 ChartBase *pChart = m_pQuilt->GetRefChart();
12366 zoom_factor = ptc->GetZoomFactor();
12371 if (zoom_factor <= 3.9)
return NULL;
12373 if (m_singleChart) {
12374 if (zoom_factor <= 3.9)
return NULL;
12379 if (m_pEM_OverZoom) {
12380 m_pEM_OverZoom->x = 4;
12381 m_pEM_OverZoom->y = 0;
12382 if (g_MainToolbar && IsPrimaryCanvas()) {
12383 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12384 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12387 return m_pEM_OverZoom;
12390void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12400 g_overlayCanvas =
this;
12402 if (g_pi_manager) {
12403 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12404 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12408 AISDrawAreaNotices(dc, GetVP(),
this);
12410 wxDC *pdc = dc.GetDC();
12412 pdc->DestroyClippingRegion();
12413 wxDCClipper(*pdc, ru);
12416 if (m_bShowNavobjects) {
12417 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12418 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12419 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12420 DrawAnchorWatchPoints(dc);
12422 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12423 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12426 AISDraw(dc, GetVP(),
this);
12430 RenderVisibleSectorLights(dc);
12432 RenderAllChartOutlines(dc, GetVP());
12433 RenderRouteLegs(dc);
12434 RenderShipToActive(dc,
false);
12436 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12437 if (g_pi_manager) {
12438 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12439 OVERLAY_OVER_SHIPS);
12442 DrawEmboss(dc, EmbossDepthScale());
12443 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12444 if (g_pi_manager) {
12445 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12446 OVERLAY_OVER_EMBOSS);
12448 if (!g_PrintingInProgress) {
12449 if (IsPrimaryCanvas()) {
12450 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12453 if (IsPrimaryCanvas()) {
12454 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12457 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12459 if (m_pTrackRolloverWin) {
12460 m_pTrackRolloverWin->Draw(dc);
12461 m_brepaint_piano =
true;
12464 if (m_pRouteRolloverWin) {
12465 m_pRouteRolloverWin->Draw(dc);
12466 m_brepaint_piano =
true;
12469 if (m_pAISRolloverWin) {
12470 m_pAISRolloverWin->Draw(dc);
12471 m_brepaint_piano =
true;
12474 if (g_pi_manager) {
12475 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12481 if (!m_bShowDepthUnits)
return NULL;
12483 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12485 if (GetQuiltMode()) {
12486 wxString s = m_pQuilt->GetQuiltDepthUnit();
12488 if (s == _T(
"FEET"))
12489 depth_unit_type = DEPTH_UNIT_FEET;
12490 else if (s.StartsWith(_T(
"FATHOMS")))
12491 depth_unit_type = DEPTH_UNIT_FATHOMS;
12492 else if (s.StartsWith(_T(
"METERS")))
12493 depth_unit_type = DEPTH_UNIT_METERS;
12494 else if (s.StartsWith(_T(
"METRES")))
12495 depth_unit_type = DEPTH_UNIT_METERS;
12496 else if (s.StartsWith(_T(
"METRIC")))
12497 depth_unit_type = DEPTH_UNIT_METERS;
12498 else if (s.StartsWith(_T(
"METER")))
12499 depth_unit_type = DEPTH_UNIT_METERS;
12502 if (m_singleChart) {
12503 depth_unit_type = m_singleChart->GetDepthUnitType();
12504 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12505 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12510 switch (depth_unit_type) {
12511 case DEPTH_UNIT_FEET:
12514 case DEPTH_UNIT_METERS:
12515 ped = m_pEM_Meters;
12517 case DEPTH_UNIT_FATHOMS:
12518 ped = m_pEM_Fathoms;
12524 ped->x = (GetVP().
pix_width - ped->width);
12526 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12527 wxRect r = m_Compass->
GetRect();
12528 ped->y = r.y + r.height;
12535void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12538 if (style->embossFont == wxEmptyString) {
12539 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12541 font.SetPointSize(60);
12542 font.SetWeight(wxFONTWEIGHT_BOLD);
12544 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12545 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12547 int emboss_width = 500;
12548 int emboss_height = 200;
12552 delete m_pEM_Meters;
12553 delete m_pEM_Fathoms;
12557 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12559 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12561 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12564#define OVERZOOM_TEXT _("OverZoom")
12566void ChartCanvas::SetOverzoomFont() {
12571 if (style->embossFont == wxEmptyString) {
12572 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12574 font.SetPointSize(40);
12575 font.SetWeight(wxFONTWEIGHT_BOLD);
12577 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12578 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12580 wxClientDC dc(
this);
12582 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12584 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12585 font.SetPointSize(font.GetPointSize() - 1);
12587 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12589 m_overzoomFont = font;
12590 m_overzoomTextWidth = w;
12591 m_overzoomTextHeight = h;
12594void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12595 delete m_pEM_OverZoom;
12597 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12599 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12600 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12603emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12604 int height,
const wxString &str,
12609 wxBitmap bmp(width, height, -1);
12612 wxMemoryDC temp_dc;
12613 temp_dc.SelectObject(bmp);
12616 temp_dc.SetBackground(*wxWHITE_BRUSH);
12617 temp_dc.SetTextBackground(*wxWHITE);
12618 temp_dc.SetTextForeground(*wxBLACK);
12622 temp_dc.SetFont(font);
12625 temp_dc.GetTextExtent(str, &str_w, &str_h);
12627 temp_dc.DrawText(str, 1, 1);
12630 temp_dc.SelectObject(wxNullBitmap);
12633 wxImage img = bmp.ConvertToImage();
12635 int image_width = str_w * 105 / 100;
12636 int image_height = str_h * 105 / 100;
12637 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12638 wxMin(image_height, img.GetHeight()));
12639 wxImage imgs = img.GetSubImage(r);
12643 case GLOBAL_COLOR_SCHEME_DAY:
12647 case GLOBAL_COLOR_SCHEME_DUSK:
12650 case GLOBAL_COLOR_SCHEME_NIGHT:
12657 const int w = imgs.GetWidth();
12658 const int h = imgs.GetHeight();
12659 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12664 for (
int y = 1; y < h - 1; y++) {
12665 for (
int x = 1; x < w - 1; x++) {
12667 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12668 val = (int)(val * val_factor);
12669 index = (y * w) + x;
12682void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12683 Track *active_track = NULL;
12684 for (
Track *pTrackDraw : g_TrackList) {
12685 if (g_pActiveTrack == pTrackDraw) {
12686 active_track = pTrackDraw;
12690 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12693 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12696void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12697 Track *active_track = NULL;
12698 for (
Track *pTrackDraw : g_TrackList) {
12699 if (g_pActiveTrack == pTrackDraw) {
12700 active_track = pTrackDraw;
12704 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12707void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12708 Route *active_route = NULL;
12710 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12711 node = node->GetNext()) {
12712 Route *pRouteDraw = node->GetData();
12713 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12714 active_route = pRouteDraw;
12719 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12724 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12727void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12728 Route *active_route = NULL;
12730 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12731 node = node->GetNext()) {
12732 Route *pRouteDraw = node->GetData();
12733 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12734 active_route = pRouteDraw;
12738 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12741void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12742 if (!pWayPointMan)
return;
12744 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12749 if (pWP->m_bIsInRoute) {
12750 node = node->GetNext();
12755 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12759 if (pWP->GetShowWaypointRangeRings() &&
12760 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12761 double factor = 1.00;
12762 if (pWP->GetWaypointRangeRingsStepUnits() ==
12764 factor = 1 / 1.852;
12766 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12767 pWP->GetWaypointRangeRingsStep() / 60.;
12771 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12772 pWP->m_lat + radius, pWP->m_lon + radius);
12773 if (!BltBBox.IntersectOut(radar_box)) {
12780 node = node->GetNext();
12784void ChartCanvas::DrawBlinkObjects(
void) {
12786 wxRect update_rect;
12788 if (!pWayPointMan)
return;
12790 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12795 if (pWP->m_bBlink) {
12796 update_rect.Union(pWP->CurrentRect_in_DC);
12800 node = node->GetNext();
12802 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12805void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12808 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12810 wxPoint lAnchorPoint1, lAnchorPoint2;
12813 if (pAnchorWatchPoint1) {
12814 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12818 if (pAnchorWatchPoint2) {
12819 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12824 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12825 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12827 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12828 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12829 dc.SetBrush(*ppBrush);
12833 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12838 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12843 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12848 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12853double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12856 wxPoint lAnchorPoint;
12859 double tlat1, tlon1;
12861 if (pAnchorWatchPoint) {
12862 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12863 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12864 dabs = fabs(d1 / 1852.);
12865 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12870 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12871 pow((
double)(lAnchorPoint.y - r1.y), 2));
12874 if (d1 < 0) lpp = -lpp;
12882void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12883 if (!ptcmgr)
return;
12885 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12887 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12888 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12893 if ((type ==
't') || (type ==
'T')) {
12894 if (BBox.Contains(lat, lon)) {
12896 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12902extern wxDateTime gTimeSource;
12904void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12905 if (!ptcmgr)
return;
12907 wxDateTime this_now = gTimeSource;
12908 bool cur_time = !gTimeSource.IsValid();
12909 if (cur_time) this_now = wxDateTime::Now();
12910 time_t t_this_now = this_now.GetTicks();
12912 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12913 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12914 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12915 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12917 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12918 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12921 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12922 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12925 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12926 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12927 wxBRUSHSTYLE_SOLID);
12928 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12929 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12930 wxBRUSHSTYLE_SOLID);
12932 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
12933 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12934 int font_size = wxMax(10, dFont->GetPointSize());
12937 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
12938 false, dFont->GetFaceName());
12940 dc.SetPen(*pblack_pen);
12941 dc.SetBrush(*pgreen_brush);
12945 case GLOBAL_COLOR_SCHEME_DAY:
12948 case GLOBAL_COLOR_SCHEME_DUSK:
12951 case GLOBAL_COLOR_SCHEME_NIGHT:
12952 bm = m_bmTideNight;
12959 int bmw = bm.GetWidth();
12960 int bmh = bm.GetHeight();
12962 float scale_factor = 1.0;
12966 float icon_pixelRefDim = 45;
12970 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
12971 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
12972 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12986 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
12988 float nominal_icon_size_pixels = 48;
12989 float pix_factor = (2 * height) / nominal_icon_size_pixels;
12999 double targetHeight0 = 16.0;
13002 double displaySize = m_display_size_mm;
13003 displaySize = wxMax(displaySize, 100);
13005 float targetHeight = wxMin(targetHeight0, displaySize / 15);
13007 double pix_factor = targetHeight / symHeight;
13010 scale_factor *= pix_factor;
13012 float user_scale_factor = g_ChartScaleFactorExp;
13013 if (g_ChartScaleFactorExp > 1.0)
13014 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13017 scale_factor *= user_scale_factor;
13018 scale_factor *= GetContentScaleFactor();
13021 double marge = 0.05;
13022 std::vector<LLBBox> drawn_boxes;
13023 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13024 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13027 if ((type ==
't') || (type ==
'T'))
13032 if (BBox.ContainsMarge(lat, lon, marge)) {
13034 if (GetVP().chart_scale < 500000) {
13035 bool bdrawn =
false;
13036 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13037 if (drawn_boxes[i].Contains(lat, lon)) {
13042 if (bdrawn)
continue;
13045 this_box.Set(lat, lon, lat, lon);
13046 this_box.EnLarge(.005);
13047 drawn_boxes.push_back(this_box);
13053 if (GetVP().chart_scale > 500000) {
13054 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13058 dc.SetFont(*plabelFont);
13070 if (ptcmgr->GetTideFlowSens(
13071 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13075 ptcmgr->GetHightOrLowTide(
13076 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13077 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13089 if (tctime > t_this_now)
13090 ptcmgr->GetHightOrLowTide(
13091 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13092 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13096 ptcmgr->GetHightOrLowTide(
13097 t_this_now, FORWARD_TEN_MINUTES_STEP,
13098 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13112 int width = (int)(12 * scale_factor + 0.5);
13113 int height = (int)(45 * scale_factor + 0.5);
13114 int linew = wxMax(1, (
int)(scale_factor));
13115 int xDraw = r.x - (width / 2);
13116 int yDraw = r.y - (height / 2);
13119 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13120 int hs = (httime > lttime) ? -4 : 4;
13121 hs *= (int)(scale_factor + 0.5);
13122 if (ts > 0.995 || ts < 0.005) hs = 0;
13123 int ht_y = (int)(height * ts);
13126 pblack_pen->SetWidth(linew);
13127 dc.SetPen(*pblack_pen);
13128 dc.SetBrush(*pyelo_brush);
13129 dc.DrawRectangle(xDraw, yDraw, width, height);
13133 dc.SetPen(*pblue_pen);
13134 dc.SetBrush(*pblue_brush);
13135 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13136 (width - (4 * linew)), height - ht_y);
13142 arrow[0].x = xDraw + 2 * linew;
13143 arrow[1].x = xDraw + width / 2;
13144 arrow[2].x = xDraw + width - 2 * linew;
13145 pyelo_pen->SetWidth(linew);
13146 pblue_pen->SetWidth(linew);
13147 if (ts > 0.35 || ts < 0.15)
13149 hl = (int)(height * 0.25) + yDraw;
13151 arrow[1].y = hl + hs;
13154 dc.SetPen(*pyelo_pen);
13156 dc.SetPen(*pblue_pen);
13157 dc.DrawLines(3, arrow);
13159 if (ts > 0.60 || ts < 0.40)
13161 hl = (int)(height * 0.5) + yDraw;
13163 arrow[1].y = hl + hs;
13166 dc.SetPen(*pyelo_pen);
13168 dc.SetPen(*pblue_pen);
13169 dc.DrawLines(3, arrow);
13171 if (ts < 0.65 || ts > 0.85)
13173 hl = (int)(height * 0.75) + yDraw;
13175 arrow[1].y = hl + hs;
13178 dc.SetPen(*pyelo_pen);
13180 dc.SetPen(*pblue_pen);
13181 dc.DrawLines(3, arrow);
13185 s.Printf(_T(
"%3.1f"), nowlev);
13187 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13189 dc.GetTextExtent(s, &wx1, NULL);
13191 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13206void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13207 if (!ptcmgr)
return;
13209 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13211 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13212 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13217 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13218 if ((BBox.Contains(lat, lon))) {
13220 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13226void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13227 if (!ptcmgr)
return;
13229 float tcvalue, dir;
13233 double lon_last = 0.;
13234 double lat_last = 0.;
13236 double marge = 0.2;
13237 bool cur_time = !gTimeSource.IsValid();
13239 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13240 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13242 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13243 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13244 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13245 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13247 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13248 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13249 wxBRUSHSTYLE_SOLID);
13250 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13251 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13252 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13253 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13255 double skew_angle = GetVPRotation();
13257 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13258 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13259 int font_size = wxMax(10, dFont->GetPointSize());
13262 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13263 false, dFont->GetFaceName());
13265 float scale_factor = 1.0;
13272 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
13273 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
13274 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13280 float nominal_icon_size_pixels = 6;
13281 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
13288 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13290 float nominal_icon_size_pixels = 15;
13291 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13298 float icon_pixelRefDim = 5;
13303 double targetHeight0 = 2.0;
13306 double displaySize = m_display_size_mm;
13307 displaySize = wxMax(displaySize, 100);
13309 float targetHeight = wxMin(targetHeight0, displaySize / 50);
13310 double pix_factor = targetHeight / symHeight;
13313 scale_factor *= pix_factor;
13315 float user_scale_factor = g_ChartScaleFactorExp;
13316 if (g_ChartScaleFactorExp > 1.0)
13317 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13320 scale_factor *= user_scale_factor;
13322 scale_factor *= GetContentScaleFactor();
13325 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13326 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13331 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13332 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13337 int dd = (int)(5.0 * scale_factor + 0.5);
13348 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13349 dc.SetPen(*pblack_pen);
13350 dc.SetBrush(*porange_brush);
13351 dc.DrawPolygon(4, d);
13354 dc.SetBrush(*pblack_brush);
13355 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13359 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13373 double a1 = fabs(tcvalue) * 10.;
13375 a1 = wxMax(1.0, a1);
13376 double a2 = log10(a1);
13378 float cscale = scale_factor * a2 * 0.4;
13380 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13381 dc.SetPen(*porange_pen);
13382 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13386 if (bDrawCurrentValues) {
13387 dc.SetFont(*pTCFont);
13388 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13389 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13410void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
13411 pCwin =
new TCWin(
this, x, y, pvIDX);
13414#define NUM_CURRENT_ARROW_POINTS 9
13415static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13416 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13417 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13418 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13420void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13422 if (
scale > 1e-2) {
13423 float sin_rot = sin(rot_angle * PI / 180.);
13424 float cos_rot = cos(rot_angle * PI / 180.);
13428 float xt = CurrentArrowArray[0].x;
13429 float yt = CurrentArrowArray[0].y;
13431 float xp = (xt * cos_rot) - (yt * sin_rot);
13432 float yp = (xt * sin_rot) + (yt * cos_rot);
13433 int x1 = (int)(xp *
scale);
13434 int y1 = (int)(yp *
scale);
13437 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13438 xt = CurrentArrowArray[ip].x;
13439 yt = CurrentArrowArray[ip].y;
13441 float xp = (xt * cos_rot) - (yt * sin_rot);
13442 float yp = (xt * sin_rot) + (yt * cos_rot);
13443 int x2 = (int)(xp *
scale);
13444 int y2 = (int)(yp *
scale);
13446 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13454wxString ChartCanvas::FindValidUploadPort() {
13457 if (!g_uploadConnection.IsEmpty() &&
13458 g_uploadConnection.StartsWith(_T(
"Serial"))) {
13459 port = g_uploadConnection;
13465 for (
auto *cp : TheConnectionParams()) {
13466 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13467 port << _T(
"Serial:") << cp->Port;
13473void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13476 if (NULL == g_pais_query_dialog_active) {
13477 int pos_x = g_ais_query_dialog_x;
13478 int pos_y = g_ais_query_dialog_y;
13480 if (g_pais_query_dialog_active) {
13481 g_pais_query_dialog_active->Destroy();
13487 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13488 wxPoint(pos_x, pos_y));
13490 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13491 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13492 g_pais_query_dialog_active->SetMMSI(mmsi);
13493 g_pais_query_dialog_active->UpdateText();
13494 wxSize sz = g_pais_query_dialog_active->GetSize();
13496 bool b_reset_pos =
false;
13501 RECT frame_title_rect;
13502 frame_title_rect.left = pos_x;
13503 frame_title_rect.top = pos_y;
13504 frame_title_rect.right = pos_x + sz.x;
13505 frame_title_rect.bottom = pos_y + 30;
13507 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13508 b_reset_pos =
true;
13513 wxRect window_title_rect;
13514 window_title_rect.x = pos_x;
13515 window_title_rect.y = pos_y;
13516 window_title_rect.width = sz.x;
13517 window_title_rect.height = 30;
13519 wxRect ClientRect = wxGetClientDisplayRect();
13520 ClientRect.Deflate(
13522 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13526 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13529 g_pais_query_dialog_active->SetMMSI(mmsi);
13530 g_pais_query_dialog_active->UpdateText();
13533 g_pais_query_dialog_active->Show();
13536void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13537 bool cur_mode = GetQuiltMode();
13539 if (!GetQuiltMode())
13540 SetQuiltMode(
true);
13541 else if (GetQuiltMode()) {
13542 SetQuiltMode(
false);
13543 g_sticky_chart = GetQuiltReferenceChartIndex();
13546 if (cur_mode != GetQuiltMode()) {
13547 SetupCanvasQuiltMode();
13556 if (ps52plib) ps52plib->GenerateStateHash();
13558 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13559 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13562void ChartCanvas::DoCanvasStackDelta(
int direction) {
13563 if (!GetQuiltMode()) {
13564 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13565 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13566 if ((current_stack_index + direction) < 0)
return;
13568 if (m_bpersistent_quilt ) {
13570 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13572 if (IsChartQuiltableRef(new_dbIndex)) {
13573 ToggleCanvasQuiltMode();
13574 SelectQuiltRefdbChart(new_dbIndex);
13575 m_bpersistent_quilt =
false;
13578 SelectChartFromStack(current_stack_index + direction);
13581 std::vector<int> piano_chart_index_array =
13582 GetQuiltExtendedStackdbIndexArray();
13583 int refdb = GetQuiltRefChartdbIndex();
13586 int current_index = -1;
13587 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13588 if (refdb == piano_chart_index_array[i]) {
13593 if (current_index == -1)
return;
13596 int target_family = ctet.GetChartFamily();
13598 int new_index = -1;
13599 int check_index = current_index + direction;
13600 bool found =
false;
13601 int check_dbIndex = -1;
13602 int new_dbIndex = -1;
13606 (
unsigned int)check_index < piano_chart_index_array.size() &&
13607 (check_index >= 0)) {
13608 check_dbIndex = piano_chart_index_array[check_index];
13609 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13610 if (target_family == cte.GetChartFamily()) {
13612 new_index = check_index;
13613 new_dbIndex = check_dbIndex;
13617 check_index += direction;
13620 if (!found)
return;
13622 if (!IsChartQuiltableRef(new_dbIndex)) {
13623 ToggleCanvasQuiltMode();
13624 SelectdbChart(new_dbIndex);
13625 m_bpersistent_quilt =
true;
13627 SelectQuiltRefChart(new_index);
13631 gFrame->UpdateGlobalMenuItems();
13633 SetQuiltChartHiLiteIndex(-1);
13644void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13647 switch (event.GetId()) {
13661 DoCanvasStackDelta(1);
13666 DoCanvasStackDelta(-1);
13676 ShowCurrents(!GetbShowCurrent());
13683 ShowTides(!GetbShowTide());
13690 if (0 == m_routeState) {
13697 androidSetRouteAnnunciator(m_routeState == 1);
13703 SetAISCanvasDisplayStyle(-1);
13715void ChartCanvas::SetShowAIS(
bool show) {
13717 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13718 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13721void ChartCanvas::SetAttenAIS(
bool show) {
13722 m_bShowAISScaled = show;
13723 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13724 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13727void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13730 bool bShowAIS_Array[3] = {
true,
true,
false};
13731 bool bShowScaled_Array[3] = {
false,
true,
true};
13732 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13733 _(
"Attenuate less critical AIS targets"),
13734 _(
"Hide AIS Targets")};
13735 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13736 _T(
"AIS_Disabled")};
13738 int AIS_Toolbar_Switch = 0;
13739 if (StyleIndx == -1) {
13741 for (
int i = 1; i < ArraySize; i++) {
13742 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13743 (bShowScaled_Array[i] == m_bShowAISScaled))
13744 AIS_Toolbar_Switch = i;
13746 AIS_Toolbar_Switch++;
13747 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13748 AIS_Toolbar_Switch++;
13751 AIS_Toolbar_Switch = StyleIndx;
13754 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13756 int AIS_Toolbar_Switch_Next =
13757 AIS_Toolbar_Switch + 1;
13758 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13759 AIS_Toolbar_Switch_Next++;
13760 if (AIS_Toolbar_Switch_Next >= ArraySize)
13761 AIS_Toolbar_Switch_Next = 0;
13764 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13765 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13768void ChartCanvas::TouchAISToolActive(
void) {}
13770void ChartCanvas::UpdateAISTBTool(
void) {}
13778void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13780 bool b_update =
false;
13781 int cc1_edge_comp = 2;
13782 wxRect rect = m_Compass->
GetRect();
13783 wxSize parent_size = GetSize();
13785 parent_size *= m_displayScale;
13789 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
13790 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13791 wxRect compass_rect(compass_pt, rect.GetSize());
13793 m_Compass->Move(compass_pt);
13795 if (m_Compass && m_Compass->IsShown())
13796 m_Compass->UpdateStatus(b_force_new | b_update);
13798 wxPoint note_point =
13799 wxPoint(compass_rect.x - compass_rect.width, compass_rect.y);
13800 m_notification_button->Move(note_point);
13802 m_notification_button->UpdateStatus();
13803 if (b_force_new | b_update) Refresh();
13806void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13807 ChartTypeEnum New_Type,
13808 ChartFamilyEnum New_Family) {
13809 if (!GetpCurrentStack())
return;
13810 if (!ChartData)
return;
13812 if (index < GetpCurrentStack()->nEntry) {
13815 pTentative_Chart = ChartData->OpenStackChartConditional(
13816 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13818 if (pTentative_Chart) {
13819 if (m_singleChart) m_singleChart->Deactivate();
13821 m_singleChart = pTentative_Chart;
13822 m_singleChart->Activate();
13824 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13825 GetpCurrentStack(), m_singleChart->GetFullPath());
13838 double best_scale_ppm = GetBestVPScale(m_singleChart);
13839 double rotation = GetVPRotation();
13840 double oldskew = GetVPSkew();
13841 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13843 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13844 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13845 if (fabs(newskew) > 0.0001) rotation = newskew;
13848 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13850 UpdateGPSCompassStatusBox(
true);
13854 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13855 if (idx < 0)
return;
13857 std::vector<int> piano_active_chart_index_array;
13858 piano_active_chart_index_array.push_back(
13859 GetpCurrentStack()->GetCurrentEntrydbIndex());
13860 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13863void ChartCanvas::SelectdbChart(
int dbindex) {
13864 if (!GetpCurrentStack())
return;
13865 if (!ChartData)
return;
13867 if (dbindex >= 0) {
13870 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13872 if (pTentative_Chart) {
13873 if (m_singleChart) m_singleChart->Deactivate();
13875 m_singleChart = pTentative_Chart;
13876 m_singleChart->Activate();
13878 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13879 GetpCurrentStack(), m_singleChart->GetFullPath());
13892 double best_scale_ppm = GetBestVPScale(m_singleChart);
13896 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13906void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13909 if (!GetQuiltMode()) {
13910 if (GetpCurrentStack()) {
13911 int stack_index = -1;
13912 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13913 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13914 if (check_dbIndex < 0)
continue;
13916 ChartData->GetChartTableEntry(check_dbIndex);
13917 if (type == cte.GetChartType()) {
13920 }
else if (family == cte.GetChartFamily()) {
13926 if (stack_index >= 0) {
13927 SelectChartFromStack(stack_index);
13931 int sel_dbIndex = -1;
13932 std::vector<int> piano_chart_index_array =
13933 GetQuiltExtendedStackdbIndexArray();
13934 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13935 int check_dbIndex = piano_chart_index_array[i];
13936 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13937 if (type == cte.GetChartType()) {
13938 if (IsChartQuiltableRef(check_dbIndex)) {
13939 sel_dbIndex = check_dbIndex;
13942 }
else if (family == cte.GetChartFamily()) {
13943 if (IsChartQuiltableRef(check_dbIndex)) {
13944 sel_dbIndex = check_dbIndex;
13950 if (sel_dbIndex >= 0) {
13951 SelectQuiltRefdbChart(sel_dbIndex,
false);
13953 AdjustQuiltRefChart();
13960 SetQuiltChartHiLiteIndex(-1);
13965bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
13966 return std::find(m_tile_yesshow_index_array.begin(),
13967 m_tile_yesshow_index_array.end(),
13968 index) != m_tile_yesshow_index_array.end();
13971bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
13972 return std::find(m_tile_noshow_index_array.begin(),
13973 m_tile_noshow_index_array.end(),
13974 index) != m_tile_noshow_index_array.end();
13977void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
13978 if (std::find(m_tile_noshow_index_array.begin(),
13979 m_tile_noshow_index_array.end(),
13980 index) == m_tile_noshow_index_array.end()) {
13981 m_tile_noshow_index_array.push_back(index);
13991void ChartCanvas::HandlePianoClick(
13992 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
13993 if (g_options && g_options->IsShown())
13995 if (!m_pCurrentStack)
return;
13996 if (!ChartData)
return;
14011 double distance = 25000;
14012 int closest_index = -1;
14013 for (
int chart_index : selected_dbIndex_array) {
14014 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
14015 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14016 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14019 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14020 if (test_distance < distance) {
14021 distance = test_distance;
14022 closest_index = chart_index;
14026 int selected_dbIndex = selected_dbIndex_array[0];
14027 if (closest_index >= 0) selected_dbIndex = closest_index;
14029 if (!GetQuiltMode()) {
14030 if (m_bpersistent_quilt ) {
14031 if (IsChartQuiltableRef(selected_dbIndex)) {
14032 ToggleCanvasQuiltMode();
14033 SelectQuiltRefdbChart(selected_dbIndex);
14034 m_bpersistent_quilt =
false;
14036 SelectChartFromStack(selected_index);
14039 SelectChartFromStack(selected_index);
14040 g_sticky_chart = selected_dbIndex;
14044 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14048 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
14049 bool bfound =
false;
14050 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14051 if (m_tile_noshow_index_array[i] ==
14052 selected_dbIndex) {
14053 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14060 m_tile_noshow_index_array.push_back(selected_dbIndex);
14064 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14065 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14069 if (IsChartQuiltableRef(selected_dbIndex)) {
14075 bool set_scale =
false;
14076 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
14077 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14083 SelectQuiltRefdbChart(selected_dbIndex,
true);
14085 SelectQuiltRefdbChart(selected_dbIndex,
false);
14090 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14092 double proposed_scale_onscreen =
14095 if (g_bPreserveScaleOnX) {
14096 proposed_scale_onscreen =
14097 wxMin(proposed_scale_onscreen,
14099 GetCanvasWidth()));
14101 proposed_scale_onscreen =
14102 wxMin(proposed_scale_onscreen,
14104 GetCanvasWidth()));
14106 proposed_scale_onscreen =
14107 wxMax(proposed_scale_onscreen,
14116 ToggleCanvasQuiltMode();
14117 SelectdbChart(selected_dbIndex);
14118 m_bpersistent_quilt =
true;
14123 SetQuiltChartHiLiteIndex(-1);
14124 gFrame->UpdateGlobalMenuItems();
14126 HideChartInfoWindow();
14131void ChartCanvas::HandlePianoRClick(
14132 int x,
int y,
int selected_index,
14133 const std::vector<int> &selected_dbIndex_array) {
14134 if (g_options && g_options->IsShown())
14136 if (!GetpCurrentStack())
return;
14138 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14139 UpdateCanvasControlBar();
14141 SetQuiltChartHiLiteIndex(-1);
14144void ChartCanvas::HandlePianoRollover(
14145 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14146 int n_charts,
int scale) {
14147 if (g_options && g_options->IsShown())
14149 if (!GetpCurrentStack())
return;
14150 if (!ChartData)
return;
14152 if (ChartData->IsBusy())
return;
14154 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14156 if (!GetQuiltMode()) {
14157 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14160 std::vector<int> piano_chart_index_array;
14161 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14162 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14163 if ((GetpCurrentStack()->nEntry > 1) ||
14164 (piano_chart_index_array.size() >= 1)) {
14165 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14167 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14169 }
else if (GetpCurrentStack()->nEntry == 1) {
14171 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14172 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14173 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14175 }
else if ((-1 == selected_index) &&
14176 (0 == selected_dbIndex_array.size())) {
14177 ShowChartInfoWindow(key_location.x, -1);
14181 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14183 if ((GetpCurrentStack()->nEntry > 1) ||
14184 (piano_chart_index_array.size() >= 1)) {
14186 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14187 selected_dbIndex_array);
14188 else if (n_charts == 1)
14189 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14191 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14198void ChartCanvas::ClearPianoRollover() {
14199 ClearQuiltChartHiLiteIndexArray();
14200 ShowChartInfoWindow(0, -1);
14201 std::vector<int> vec;
14202 ShowCompositeInfoWindow(0, 0, 0, vec);
14206void ChartCanvas::UpdateCanvasControlBar(
void) {
14207 if (m_pianoFrozen)
return;
14209 if (!GetpCurrentStack())
return;
14210 if (!ChartData)
return;
14211 if (!g_bShowChartBar)
return;
14214 int sel_family = -1;
14216 std::vector<int> piano_chart_index_array;
14217 std::vector<int> empty_piano_chart_index_array;
14219 wxString old_hash = m_Piano->GetStoredHash();
14221 if (GetQuiltMode()) {
14222 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14223 GetQuiltFullScreendbIndexArray());
14225 std::vector<int> piano_active_chart_index_array =
14226 GetQuiltCandidatedbIndexArray();
14227 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14229 std::vector<int> piano_eclipsed_chart_index_array =
14230 GetQuiltEclipsedStackdbIndexArray();
14231 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14233 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14234 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14236 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14237 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14239 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
14240 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14243 if (m_singleChart) {
14244 sel_type = m_singleChart->GetChartType();
14245 sel_family = m_singleChart->GetChartFamily();
14250 std::vector<int> piano_skew_chart_index_array;
14251 std::vector<int> piano_tmerc_chart_index_array;
14252 std::vector<int> piano_poly_chart_index_array;
14254 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14256 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14257 double skew_norm = ctei.GetChartSkew();
14258 if (skew_norm > 180.) skew_norm -= 360.;
14260 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14261 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14264 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14265 if (fabs(skew_norm) > 1.)
14266 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14268 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14269 }
else if (fabs(skew_norm) > 1.)
14270 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14272 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14273 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14274 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14276 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14277 if (new_hash != old_hash) {
14278 m_Piano->FormatKeys();
14279 HideChartInfoWindow();
14280 m_Piano->ResetRollover();
14281 SetQuiltChartHiLiteIndex(-1);
14282 m_brepaint_piano =
true;
14288 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14290 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14291 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14292 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14293 if (e == CHART_FAMILY_RASTER) mask |= 1;
14294 if (e == CHART_FAMILY_VECTOR) {
14295 if (t == CHART_TYPE_CM93COMP)
14302 wxString s_indicated;
14303 if (sel_type == CHART_TYPE_CM93COMP)
14304 s_indicated = _T(
"cm93");
14306 if (sel_family == CHART_FAMILY_RASTER)
14307 s_indicated = _T(
"raster");
14308 else if (sel_family == CHART_FAMILY_VECTOR)
14309 s_indicated = _T(
"vector");
14312 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14315void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14317void ChartCanvas::PianoPopupMenu(
14318 int x,
int y,
int selected_index,
14319 const std::vector<int> &selected_dbIndex_array) {
14320 if (!GetpCurrentStack())
return;
14323 if (!GetQuiltMode())
return;
14325 m_piano_ctx_menu =
new wxMenu();
14327 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14337 menu_selected_dbIndex = selected_dbIndex_array[0];
14338 menu_selected_index = selected_index;
14341 bool b_is_in_noshow =
false;
14342 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14343 if (m_quilt_noshow_index_array[i] ==
14344 menu_selected_dbIndex)
14346 b_is_in_noshow =
true;
14351 if (b_is_in_noshow) {
14352 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14353 _(
"Show This Chart"));
14354 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14355 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14356 }
else if (GetpCurrentStack()->nEntry > 1) {
14357 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14358 _(
"Hide This Chart"));
14359 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14360 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14364 wxPoint pos = wxPoint(x, y - 30);
14367 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14368 PopupMenu(m_piano_ctx_menu, pos);
14370 delete m_piano_ctx_menu;
14371 m_piano_ctx_menu = NULL;
14373 HideChartInfoWindow();
14374 m_Piano->ResetRollover();
14376 SetQuiltChartHiLiteIndex(-1);
14377 ClearQuiltChartHiLiteIndexArray();
14382void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14383 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14384 if (m_quilt_noshow_index_array[i] ==
14385 menu_selected_dbIndex)
14387 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14393void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14394 if (!GetpCurrentStack())
return;
14395 if (!ChartData)
return;
14397 RemoveChartFromQuilt(menu_selected_dbIndex);
14401 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14402 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
14404 int i = menu_selected_index + 1;
14405 bool b_success =
false;
14406 while (i < GetpCurrentStack()->nEntry - 1) {
14407 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14408 if (type == ChartData->GetDBChartType(dbIndex)) {
14409 SelectQuiltRefChart(i);
14419 i = menu_selected_index - 1;
14421 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14422 if (type == ChartData->GetDBChartType(dbIndex)) {
14423 SelectQuiltRefChart(i);
14433void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14435 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14436 if (m_quilt_noshow_index_array[i] ==
14439 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14444 m_quilt_noshow_index_array.push_back(dbIndex);
14447bool ChartCanvas::UpdateS52State() {
14448 bool retval =
false;
14452 ps52plib->SetShowS57Text(m_encShowText);
14453 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14454 ps52plib->m_bShowSoundg = m_encShowDepth;
14455 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14456 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14459 if (!m_encShowLights)
14460 ps52plib->AddObjNoshow(
"LIGHTS");
14462 ps52plib->RemoveObjNoshow(
"LIGHTS");
14463 ps52plib->SetLightsOff(!m_encShowLights);
14464 ps52plib->m_bExtendLightSectors =
true;
14467 ps52plib->SetAnchorOn(m_encShowAnchor);
14468 ps52plib->SetQualityOfData(m_encShowDataQual);
14474void ChartCanvas::SetShowENCDataQual(
bool show) {
14475 m_encShowDataQual = show;
14476 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14477 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14479 m_s52StateHash = 0;
14482void ChartCanvas::SetShowENCText(
bool show) {
14483 m_encShowText = show;
14484 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14485 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14487 m_s52StateHash = 0;
14490void ChartCanvas::SetENCDisplayCategory(
int category) {
14491 m_encDisplayCategory = category;
14492 m_s52StateHash = 0;
14495void ChartCanvas::SetShowENCDepth(
bool show) {
14496 m_encShowDepth = show;
14497 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14498 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14500 m_s52StateHash = 0;
14503void ChartCanvas::SetShowENCLightDesc(
bool show) {
14504 m_encShowLightDesc = show;
14505 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14506 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14508 m_s52StateHash = 0;
14511void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14512 m_encShowBuoyLabels = show;
14513 m_s52StateHash = 0;
14516void ChartCanvas::SetShowENCLights(
bool show) {
14517 m_encShowLights = show;
14518 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14519 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14521 m_s52StateHash = 0;
14524void ChartCanvas::SetShowENCAnchor(
bool show) {
14525 m_encShowAnchor = show;
14526 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14527 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14529 m_s52StateHash = 0;
14532wxRect ChartCanvas::GetMUIBarRect() {
14535 rv = m_muiBar->GetRect();
14541void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14542 if (!GetAlertString().IsEmpty()) {
14543 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14544 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14546 dc.SetFont(*pfont);
14547 dc.SetPen(*wxTRANSPARENT_PEN);
14549 dc.SetBrush(wxColour(243, 229, 47));
14551 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14555 wxRect sbr = GetScaleBarRect();
14556 int xp = sbr.x + sbr.width + 10;
14557 int yp = (sbr.y + sbr.height) - h;
14559 int wdraw = w + 10;
14560 dc.DrawRectangle(xp, yp, wdraw, h);
14561 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14562 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14572#define BRIGHT_XCALIB
14573#define __OPCPN_USEICC__
14576#ifdef __OPCPN_USEICC__
14577int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14578 double co_green,
double co_blue);
14580wxString temp_file_name;
14584class ocpnCurtain:
public wxDialog
14586 DECLARE_CLASS( ocpnCurtain )
14587 DECLARE_EVENT_TABLE()
14590 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14592 bool ProcessEvent(wxEvent& event);
14596IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14598BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14601ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14603 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14606ocpnCurtain::~ocpnCurtain()
14610bool ocpnCurtain::ProcessEvent(wxEvent& event)
14612 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14613 return GetParent()->GetEventHandler()->ProcessEvent(event);
14618#include <windows.h>
14621typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14622typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14623SetDeviceGammaRamp_ptr_type
14624 g_pSetDeviceGammaRamp;
14625GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14627WORD *g_pSavedGammaMap;
14631int InitScreenBrightness(
void) {
14634 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14638 if (NULL == hGDI32DLL) {
14639 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14641 if (NULL != hGDI32DLL) {
14643 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14644 hGDI32DLL,
"SetDeviceGammaRamp");
14645 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14646 hGDI32DLL,
"GetDeviceGammaRamp");
14649 if ((NULL == g_pSetDeviceGammaRamp) ||
14650 (NULL == g_pGetDeviceGammaRamp)) {
14651 FreeLibrary(hGDI32DLL);
14660 if (!g_pSavedGammaMap) {
14661 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14664 bbr = g_pGetDeviceGammaRamp(
14665 hDC, g_pSavedGammaMap);
14666 ReleaseDC(NULL, hDC);
14671 wxRegKey *pRegKey =
new wxRegKey(
14672 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14673 _T(
"NT\\CurrentVersion\\ICM"));
14674 if (!pRegKey->Exists()) pRegKey->Create();
14675 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14677 g_brightness_init =
true;
14683 if (NULL == g_pcurtain) {
14684 if (gFrame->CanSetTransparent()) {
14686 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14687 wxPoint(0, 0), ::wxGetDisplaySize(),
14688 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14689 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14696 g_pcurtain->Hide();
14698 HWND hWnd = GetHwndOf(g_pcurtain);
14699 SetWindowLong(hWnd, GWL_EXSTYLE,
14700 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14701 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14702 g_pcurtain->SetTransparent(0);
14704 g_pcurtain->Maximize();
14705 g_pcurtain->Show();
14708 g_pcurtain->Enable();
14709 g_pcurtain->Disable();
14716 g_brightness_init =
true;
14722 wxString cmd(_T (
"xcalib -version" ));
14724 wxArrayString output;
14725 long r = wxExecute(cmd, output);
14728 _T(
" External application \"xcalib\" not found. Screen brightness ")
14729 _T(
"not changed."));
14731 g_brightness_init =
true;
14736int RestoreScreenBrightness(
void) {
14739 if (g_pSavedGammaMap) {
14740 HDC hDC = GetDC(NULL);
14741 g_pSetDeviceGammaRamp(hDC,
14743 ReleaseDC(NULL, hDC);
14745 free(g_pSavedGammaMap);
14746 g_pSavedGammaMap = NULL;
14750 g_pcurtain->Close();
14751 g_pcurtain->Destroy();
14755 g_brightness_init =
false;
14760#ifdef BRIGHT_XCALIB
14761 if (g_brightness_init) {
14763 cmd = _T(
"xcalib -clear");
14764 wxExecute(cmd, wxEXEC_ASYNC);
14765 g_brightness_init =
false;
14775int SetScreenBrightness(
int brightness) {
14782 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14784 g_pcurtain->Close();
14785 g_pcurtain->Destroy();
14789 InitScreenBrightness();
14791 if (NULL == hGDI32DLL) {
14793 wchar_t wdll_name[80];
14794 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14795 LPCWSTR cstr = wdll_name;
14797 hGDI32DLL = LoadLibrary(cstr);
14799 if (NULL != hGDI32DLL) {
14801 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14802 hGDI32DLL,
"SetDeviceGammaRamp");
14803 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14804 hGDI32DLL,
"GetDeviceGammaRamp");
14807 if ((NULL == g_pSetDeviceGammaRamp) ||
14808 (NULL == g_pGetDeviceGammaRamp)) {
14809 FreeLibrary(hGDI32DLL);
14816 HDC hDC = GetDC(NULL);
14827 int increment = brightness * 256 / 100;
14830 WORD GammaTable[3][256];
14833 for (
int i = 0; i < 256; i++) {
14834 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14835 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14836 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14838 table_val += increment;
14840 if (table_val > 65535) table_val = 65535;
14843 g_pSetDeviceGammaRamp(hDC, GammaTable);
14844 ReleaseDC(NULL, hDC);
14851 if (g_pSavedGammaMap) {
14852 HDC hDC = GetDC(NULL);
14853 g_pSetDeviceGammaRamp(hDC,
14855 ReleaseDC(NULL, hDC);
14858 if (brightness < 100) {
14859 if (NULL == g_pcurtain) InitScreenBrightness();
14862 int sbrite = wxMax(1, brightness);
14863 sbrite = wxMin(100, sbrite);
14865 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14869 g_pcurtain->Close();
14870 g_pcurtain->Destroy();
14880#ifdef BRIGHT_XCALIB
14882 if (!g_brightness_init) {
14883 last_brightness = 100;
14884 g_brightness_init =
true;
14885 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14886 InitScreenBrightness();
14889#ifdef __OPCPN_USEICC__
14892 if (!CreateSimpleICCProfileFile(
14893 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14894 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14895 wxString cmd(_T (
"xcalib " ));
14896 cmd += temp_file_name;
14898 wxExecute(cmd, wxEXEC_ASYNC);
14907 if (brightness > last_brightness) {
14909 cmd = _T(
"xcalib -clear");
14910 wxExecute(cmd, wxEXEC_ASYNC);
14912 ::wxMilliSleep(10);
14914 int brite_adj = wxMax(1, brightness);
14915 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14916 wxExecute(cmd, wxEXEC_ASYNC);
14918 int brite_adj = wxMax(1, brightness);
14919 int factor = (brite_adj * 100) / last_brightness;
14920 factor = wxMax(1, factor);
14922 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14923 wxExecute(cmd, wxEXEC_ASYNC);
14928 last_brightness = brightness;
14935#ifdef __OPCPN_USEICC__
14937#define MLUT_TAG 0x6d4c5554L
14938#define VCGT_TAG 0x76636774L
14940int GetIntEndian(
unsigned char *s) {
14945 p = (
unsigned char *)&ret;
14948 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14950 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14955unsigned short GetShortEndian(
unsigned char *s) {
14956 unsigned short ret;
14960 p = (
unsigned char *)&ret;
14963 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
14965 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
14971int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14972 double co_green,
double co_blue) {
14976 fp = fopen(file_name,
"wb");
14977 if (!fp)
return -1;
14983 for (
int i = 0; i < 128; i++) header[i] = 0;
14985 fwrite(header, 128, 1, fp);
14989 int numTags = GetIntEndian((
unsigned char *)&numTags0);
14990 fwrite(&numTags, 1, 4, fp);
14992 int tagName0 = VCGT_TAG;
14993 int tagName = GetIntEndian((
unsigned char *)&tagName0);
14994 fwrite(&tagName, 1, 4, fp);
14996 int tagOffset0 = 128 + 4 *
sizeof(int);
14997 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
14998 fwrite(&tagOffset, 1, 4, fp);
15001 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15002 fwrite(&tagSize, 1, 4, fp);
15004 fwrite(&tagName, 1, 4, fp);
15006 fwrite(&tagName, 1, 4, fp);
15011 int gammatype0 = 0;
15012 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15013 fwrite(&gammatype, 1, 4, fp);
15015 int numChannels0 = 3;
15016 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15017 fwrite(&numChannels, 1, 2, fp);
15019 int numEntries0 = 256;
15020 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15021 fwrite(&numEntries, 1, 2, fp);
15023 int entrySize0 = 1;
15024 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15025 fwrite(&entrySize, 1, 2, fp);
15027 unsigned char ramp[256];
15030 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15031 fwrite(ramp, 256, 1, fp);
15034 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15035 fwrite(ramp, 256, 1, fp);
15038 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15039 fwrite(ramp, 256, 1, fp);
Global state for AIS decoder.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Represents an active track that is currently being recorded.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
void DoZoomCanvas(double factor, bool can_zoom_to_cursor=true)
Internal function that implements the actual zoom operation.
double GetCanvasTrueScale()
Return the physical pixels per meter at chart center, accounting for latitude distortion.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Set the viewport center point.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Manages the chart database and provides access to chart data.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
Primary navigation console display for route and vessel tracking.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
Represents a navigational route in the navigation system.
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute, 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.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
void SetBoxes(void)
Computes the bounding box coordinates for the current viewport.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Global variables reflecting command line options and arguments.
Hooks into gui available in model.
Class NotificationManager.
int GetChartbarHeight(void)
Gets height of chart bar in pixels.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
void EnableTenHertzUpdate(bool enable)
Enable or disable 10 Hz update rate.
bool GetEnableTenHertzUpdate()
Check if 10 Hz update rate is enabled.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Tools to send data to plugins.
Route validators for dialog validation.
Represents an entry in the chart table, containing information about a single chart.