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;
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;
315extern bool g_CanvasHideNotificationIcon;
339static bool mouse_leftisdown;
341bool g_brouteCreating;
343bool g_bShowTrackPointTime;
349bool g_brightness_init;
352int g_cog_predictor_width;
353extern double g_display_size_mm;
357extern wxColour g_colourOwnshipRangeRingsColour;
361extern double g_defaultBoatSpeed;
362double g_defaultBoatSpeedUserUnit;
364extern int g_nAIS_activity_timer;
365extern bool g_bskew_comp;
366extern float g_compass_scalefactor;
367extern int g_COGAvgSec;
368extern bool g_btenhertz;
370wxGLContext *g_pGLcontext;
373extern unsigned int g_canvasConfig;
378extern float g_toolbar_scalefactor;
381wxString g_ObjQFileExt;
386extern int g_GUIScaleFactor;
389wxString g_lastS52PLIBPluginMessage;
390extern bool g_bChartBarEx;
391bool g_PrintingInProgress;
394#define MAX_BRIGHT 100
400EVT_PAINT(ChartCanvas::OnPaint)
401EVT_ACTIVATE(ChartCanvas::OnActivate)
402EVT_SIZE(ChartCanvas::OnSize)
403#ifndef HAVE_WX_GESTURE_EVENTS
404EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
406EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
407EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
408EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
409EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
410EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
411EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
412EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
413EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
414EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
415EVT_KEY_UP(ChartCanvas::OnKeyUp)
416EVT_CHAR(ChartCanvas::OnKeyChar)
417EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
418EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
419EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
420EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
421EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
422EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
423EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
424EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
430 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
431 m_nmea_log(nmea_log) {
432 parent_frame = (
MyFrame *)frame;
433 m_canvasIndex = canvasIndex;
437 SetBackgroundColour(wxColour(0, 0, 0));
438 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
442 m_bDrawingRoute =
false;
443 m_bRouteEditing =
false;
444 m_bMarkEditing =
false;
445 m_bRoutePoinDragging =
false;
446 m_bIsInRadius =
false;
447 m_bMayToggleMenuBar =
true;
450 m_bShowNavobjects =
true;
452 m_bAppendingRoute =
false;
453 pThumbDIBShow = NULL;
454 m_bShowCurrent =
false;
456 bShowingCurrent =
false;
460 m_b_paint_enable =
true;
463 pss_overlay_bmp = NULL;
464 pss_overlay_mask = NULL;
465 m_bChartDragging =
false;
466 m_bMeasure_Active =
false;
467 m_bMeasure_DistCircle =
false;
468 m_pMeasureRoute = NULL;
469 m_pTrackRolloverWin = NULL;
470 m_pRouteRolloverWin = NULL;
471 m_pAISRolloverWin = NULL;
473 m_disable_edge_pan =
false;
474 m_dragoffsetSet =
false;
478 m_singleChart = NULL;
479 m_upMode = NORTH_UP_MODE;
481 m_bShowAISScaled =
false;
482 m_timed_move_vp_active =
false;
489 m_pSelectedRoute = NULL;
490 m_pSelectedTrack = NULL;
491 m_pRoutePointEditTarget = NULL;
492 m_pFoundPoint = NULL;
493 m_pMouseRoute = NULL;
494 m_prev_pMousePoint = NULL;
495 m_pEditRouteArray = NULL;
496 m_pFoundRoutePoint = NULL;
497 m_FinishRouteOnKillFocus =
true;
499 m_pRolloverRouteSeg = NULL;
500 m_pRolloverTrackSeg = NULL;
501 m_bsectors_shown =
false;
503 m_bbrightdir =
false;
508 m_pos_image_user_day = NULL;
509 m_pos_image_user_dusk = NULL;
510 m_pos_image_user_night = NULL;
511 m_pos_image_user_grey_day = NULL;
512 m_pos_image_user_grey_dusk = NULL;
513 m_pos_image_user_grey_night = NULL;
516 m_rotation_speed = 0;
522 m_pos_image_user_yellow_day = NULL;
523 m_pos_image_user_yellow_dusk = NULL;
524 m_pos_image_user_yellow_night = NULL;
526 SetOwnShipState(SHIP_INVALID);
528 undo =
new Undo(
this);
534 m_focus_indicator_pix = 1;
536 m_pCurrentStack = NULL;
537 m_bpersistent_quilt =
false;
538 m_piano_ctx_menu = NULL;
540 m_NotificationsList = NULL;
541 m_notification_button = NULL;
543 g_ChartNotRenderScaleFactor = 2.0;
544 m_bShowScaleInStatusBar =
true;
547 m_bShowScaleInStatusBar =
false;
548 m_show_focus_bar =
true;
550 m_bShowOutlines =
false;
551 m_bDisplayGrid =
false;
552 m_bShowDepthUnits =
true;
553 m_encDisplayCategory = (int)STANDARD;
555 m_encShowLights =
true;
556 m_encShowAnchor =
true;
557 m_encShowDataQual =
false;
559 m_pQuilt =
new Quilt(
this);
561 SetAlertString(_T(
""));
564 g_PrintingInProgress =
false;
566#ifdef HAVE_WX_GESTURE_EVENTS
567 m_oldVPSScale = -1.0;
568 m_popupWanted =
false;
574 singleClickEventIsValid =
false;
583 pCursorPencil = NULL;
588 SetCursor(*pCursorArrow);
590 pPanTimer =
new wxTimer(
this, m_MouseDragging);
593 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
594 pMovementTimer->Stop();
596 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
597 pMovementStopTimer->Stop();
599 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
600 pRotDefTimer->Stop();
602 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
603 m_DoubleClickTimer->Stop();
605 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
606 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
607 m_chart_drag_inertia_active =
false;
609 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
610 m_animationActive =
false;
614 m_panx_target_final = m_pany_target_final = 0;
615 m_panx_target_now = m_pany_target_now = 0;
617 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
618 pCurTrackTimer->Stop();
619 m_curtrack_timer_msec = 10;
621 m_wheelzoom_stop_oneshot = 0;
622 m_last_wheel_dir = 0;
624 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
626 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
628 m_rollover_popup_timer_msec = 20;
630 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
632 m_b_rot_hidef =
true;
637 m_upMode = NORTH_UP_MODE;
638 m_bLookAhead =
false;
642 m_cs = GLOBAL_COLOR_SCHEME_DAY;
645 VPoint.view_scale_ppm = 1;
649 m_canvas_scale_factor = 1.;
651 m_canvas_width = 1000;
653 m_overzoomTextWidth = 0;
654 m_overzoomTextHeight = 0;
658 gShapeBasemap.Reset();
663 m_pEM_Fathoms = NULL;
665 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
667 m_pEM_OverZoom = NULL;
669 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
673 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"),
677 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
680 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
683 double factor_dusk = 0.5;
684 double factor_night = 0.25;
687 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
689 int rimg_width = m_os_image_red_day.GetWidth();
690 int rimg_height = m_os_image_red_day.GetHeight();
692 m_os_image_red_dusk = m_os_image_red_day.Copy();
693 m_os_image_red_night = m_os_image_red_day.Copy();
695 for (
int iy = 0; iy < rimg_height; iy++) {
696 for (
int ix = 0; ix < rimg_width; ix++) {
697 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
698 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
699 m_os_image_red_day.GetGreen(ix, iy),
700 m_os_image_red_day.GetBlue(ix, iy));
701 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
702 hsv.value = hsv.value * factor_dusk;
703 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
704 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
706 hsv = wxImage::RGBtoHSV(rgb);
707 hsv.value = hsv.value * factor_night;
708 nrgb = wxImage::HSVtoRGB(hsv);
709 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
715 m_os_image_grey_day =
716 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
718 int gimg_width = m_os_image_grey_day.GetWidth();
719 int gimg_height = m_os_image_grey_day.GetHeight();
721 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
722 m_os_image_grey_night = m_os_image_grey_day.Copy();
724 for (
int iy = 0; iy < gimg_height; iy++) {
725 for (
int ix = 0; ix < gimg_width; ix++) {
726 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
727 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
728 m_os_image_grey_day.GetGreen(ix, iy),
729 m_os_image_grey_day.GetBlue(ix, iy));
730 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
731 hsv.value = hsv.value * factor_dusk;
732 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
733 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
735 hsv = wxImage::RGBtoHSV(rgb);
736 hsv.value = hsv.value * factor_night;
737 nrgb = wxImage::HSVtoRGB(hsv);
738 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
744 m_os_image_yellow_day = m_os_image_red_day.Copy();
746 gimg_width = m_os_image_yellow_day.GetWidth();
747 gimg_height = m_os_image_yellow_day.GetHeight();
749 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
750 m_os_image_yellow_night = m_os_image_red_day.Copy();
752 for (
int iy = 0; iy < gimg_height; iy++) {
753 for (
int ix = 0; ix < gimg_width; ix++) {
754 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
755 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
756 m_os_image_yellow_day.GetGreen(ix, iy),
757 m_os_image_yellow_day.GetBlue(ix, iy));
758 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
759 hsv.hue += 60. / 360.;
760 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
761 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
763 hsv = wxImage::RGBtoHSV(rgb);
764 hsv.value = hsv.value * factor_dusk;
765 hsv.hue += 60. / 360.;
766 nrgb = wxImage::HSVtoRGB(hsv);
767 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
769 hsv = wxImage::RGBtoHSV(rgb);
770 hsv.hue += 60. / 360.;
771 hsv.value = hsv.value * factor_night;
772 nrgb = wxImage::HSVtoRGB(hsv);
773 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
779 m_pos_image_red = &m_os_image_red_day;
780 m_pos_image_yellow = &m_os_image_yellow_day;
781 m_pos_image_grey = &m_os_image_grey_day;
785 m_pBrightPopup = NULL;
788 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
791 int gridFontSize = 8;
792#if defined(__WXOSX__) || defined(__WXGTK3__)
794 gridFontSize *= GetContentScaleFactor();
798 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
799 FALSE, wxString(_T (
"Arial" )));
801 m_Piano =
new Piano(
this);
803 m_bShowCompassWin =
true;
806 m_Compass->SetScaleFactor(g_compass_scalefactor);
807 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
810 m_notification_button->SetScaleFactor(g_compass_scalefactor);
811 m_notification_button->Show(
true);
813 m_pianoFrozen =
false;
815 SetMinSize(wxSize(200, 200));
817 m_displayScale = 1.0;
818#if defined(__WXOSX__) || defined(__WXGTK3__)
820 m_displayScale = GetContentScaleFactor();
822 VPoint.SetPixelScale(m_displayScale);
824#ifdef HAVE_WX_GESTURE_EVENTS
827 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
828 wxLogError(
"Failed to enable touch events");
833 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
834 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
836 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
837 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
839 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
840 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
842 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
843 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
848 auto ¬eman = NotificationManager::GetInstance();
850 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
851 evt_notificationlist_change_listener.Listen(
852 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
853 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
854 if (m_NotificationsList && m_NotificationsList->IsShown()) {
855 m_NotificationsList->ReloadNotificationList();
861ChartCanvas::~ChartCanvas() {
862 delete pThumbDIBShow;
870 delete pCursorPencil;
874 delete pMovementTimer;
875 delete pMovementStopTimer;
876 delete pCurTrackTimer;
878 delete m_DoubleClickTimer;
880 delete m_pTrackRolloverWin;
881 delete m_pRouteRolloverWin;
882 delete m_pAISRolloverWin;
883 delete m_pBrightPopup;
889 m_dc_route.SelectObject(wxNullBitmap);
892 delete pWorldBackgroundChart;
893 delete pss_overlay_bmp;
897 delete m_pEM_Fathoms;
899 delete m_pEM_OverZoom;
904 delete m_pos_image_user_day;
905 delete m_pos_image_user_dusk;
906 delete m_pos_image_user_night;
907 delete m_pos_image_user_grey_day;
908 delete m_pos_image_user_grey_dusk;
909 delete m_pos_image_user_grey_night;
910 delete m_pos_image_user_yellow_day;
911 delete m_pos_image_user_yellow_dusk;
912 delete m_pos_image_user_yellow_night;
916 if (!g_bdisable_opengl) {
919#if wxCHECK_VERSION(2, 9, 0)
920 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
927 MUIBar *muiBar = m_muiBar;
931 delete m_pCurrentStack;
936void ChartCanvas::RebuildCursors() {
942 delete pCursorPencil;
946 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
950 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
951 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
952 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
953 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
954 wxImage ICursorPencil =
955 style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
956 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
958#if !defined(__WXMSW__) && !defined(__WXQT__)
959 ICursorLeft.ConvertAlphaToMask(128);
960 ICursorRight.ConvertAlphaToMask(128);
961 ICursorUp.ConvertAlphaToMask(128);
962 ICursorDown.ConvertAlphaToMask(128);
963 ICursorPencil.ConvertAlphaToMask(10);
964 ICursorCross.ConvertAlphaToMask(10);
967 if (ICursorLeft.Ok()) {
968 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
969 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
970 pCursorLeft =
new wxCursor(ICursorLeft);
972 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
974 if (ICursorRight.Ok()) {
975 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
976 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
977 pCursorRight =
new wxCursor(ICursorRight);
979 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
981 if (ICursorUp.Ok()) {
982 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
983 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
984 pCursorUp =
new wxCursor(ICursorUp);
986 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
988 if (ICursorDown.Ok()) {
989 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
990 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
991 pCursorDown =
new wxCursor(ICursorDown);
993 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
995 if (ICursorPencil.Ok()) {
996 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
997 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
998 pCursorPencil =
new wxCursor(ICursorPencil);
1000 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
1002 if (ICursorCross.Ok()) {
1003 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
1004 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
1005 pCursorCross =
new wxCursor(ICursorCross);
1007 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
1009 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
1010 pPlugIn_Cursor = NULL;
1013void ChartCanvas::CanvasApplyLocale() {
1014 CreateDepthUnitEmbossMaps(m_cs);
1015 CreateOZEmbossMapData(m_cs);
1018void ChartCanvas::SetupGlCanvas() {
1021 if (!g_bdisable_opengl) {
1023 wxLogMessage(_T(
"Creating glChartCanvas"));
1028 if (IsPrimaryCanvas()) {
1035 wxGLContext *pctx =
new wxGLContext(m_glcc);
1036 m_glcc->SetContext(pctx);
1037 g_pGLcontext = pctx;
1040 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
1042 m_glcc->SetContext(g_pGLcontext);
1052 if (!g_bdisable_opengl) {
1055 wxLogMessage(_T(
"Creating glChartCanvas"));
1059 if (IsPrimaryCanvas()) {
1060 qDebug() <<
"Creating Primary glChartCanvas";
1068 wxGLContext *pctx =
new wxGLContext(m_glcc);
1069 m_glcc->SetContext(pctx);
1070 g_pGLcontext = pctx;
1071 m_glcc->m_pParentCanvas =
this;
1074 qDebug() <<
"Creating Secondary glChartCanvas";
1080 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1083 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1084 m_glcc->SetContext(pwxctx);
1085 m_glcc->m_pParentCanvas =
this;
1093void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1094 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1109 if (m_routeState && m_FinishRouteOnKillFocus)
1110 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1112 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1116void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1117 m_routeFinishTimer.Stop();
1121 gFrame->UpdateGlobalMenuItems(
this);
1123 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1126void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1127 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1130#ifdef HAVE_WX_GESTURE_EVENTS
1131void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1137 m_popupWanted =
true;
1140void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1144void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1146void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1148void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1149 wxPoint pos =
event.GetPosition();
1153 if (!m_popupWanted) {
1154 wxMouseEvent ev(wxEVT_LEFT_UP);
1161 m_popupWanted =
false;
1163 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1170void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1173 wxPoint pos =
event.GetPosition();
1177void ChartCanvas::OnMotion(wxMouseEvent &event) {
1182 event.m_leftDown = m_leftdown;
1186void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1188 if (event.IsGestureEnd())
return;
1190 double factor =
event.GetZoomFactor();
1192 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1197 double wanted_factor = m_oldVPSScale / current_vps * factor;
1202 if (event.IsGestureStart()) {
1203 m_zoomStartPoint =
event.GetPosition();
1205 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1207 m_zoomStartPoint =
event.GetPosition();
1211void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1213void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1214 DoRotateCanvas(0.0);
1218void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1223 m_restore_dbindex = pcc->DBindex;
1225 if (pcc->GroupID < 0) pcc->GroupID = 0;
1227 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1230 m_groupIndex = pcc->GroupID;
1232 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1246 m_encDisplayCategory = pcc->nENCDisplayCategory;
1247 m_encShowDepth = pcc->bShowENCDepths;
1248 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1249 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1250 m_encShowLights = pcc->bShowENCLights;
1251 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1252 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1253 m_encShowDataQual = pcc->bShowENCDataQuality;
1257 m_upMode = NORTH_UP_MODE;
1259 m_upMode = COURSE_UP_MODE;
1261 m_upMode = HEAD_UP_MODE;
1265 m_singleChart = NULL;
1268void ChartCanvas::ApplyGlobalSettings() {
1271 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1272 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1274 m_notification_button->UpdateStatus();
1277void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1278 bool groupOK = CheckGroup(m_groupIndex);
1281 SetGroupIndex(m_groupIndex,
true);
1285void ChartCanvas::SetShowGPS(
bool bshow) {
1286 if (m_bShowGPS != bshow) {
1289 m_Compass->SetScaleFactor(g_compass_scalefactor);
1290 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1295void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1296 m_bShowCompassWin = bshow;
1298 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1299 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1303int ChartCanvas::GetPianoHeight() {
1305 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1310void ChartCanvas::ConfigureChartBar() {
1313 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1314 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1316 if (GetQuiltMode()) {
1317 m_Piano->SetRoundedRectangles(
true);
1319 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1320 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1321 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1324void ChartCanvas::ShowTides(
bool bShow) {
1325 gFrame->LoadHarmonics();
1327 if (ptcmgr->IsReady()) {
1328 SetbShowTide(bShow);
1330 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1332 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1333 SetbShowTide(
false);
1334 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1337 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1338 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1349void ChartCanvas::ShowCurrents(
bool bShow) {
1350 gFrame->LoadHarmonics();
1352 if (ptcmgr->IsReady()) {
1353 SetbShowCurrent(bShow);
1354 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1356 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1357 SetbShowCurrent(
false);
1358 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1361 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1362 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1374extern bool g_bPreserveScaleOnX;
1376extern int g_sticky_chart;
1378void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1380void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1381 SetAlertString(_T(
""));
1383 int new_index = index;
1384 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1386 bool bgroup_override =
false;
1387 int old_group_index = new_index;
1389 if (!CheckGroup(new_index)) {
1391 bgroup_override =
true;
1394 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1398 int current_chart_native_scale = GetCanvasChartNativeScale();
1401 m_groupIndex = new_index;
1404 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1407 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1411 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1415 g_sticky_chart = -1;
1419 UpdateCanvasOnGroupChange();
1422 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1424 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1427 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1428 double best_scale = GetBestStartScale(dbi_hint, vp);
1432 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1436 canvasChartsRefresh(dbi_hint);
1438 UpdateCanvasControlBar();
1440 if (!autoSwitch && bgroup_override) {
1442 wxString msg(_(
"Group \""));
1444 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1445 msg += pGroup->m_group_name;
1447 msg += _(
"\" is empty.");
1449 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1456 if (bgroup_override) {
1457 wxString msg(_(
"Group \""));
1459 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1460 msg += pGroup->m_group_name;
1462 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1464 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1468bool ChartCanvas::CheckGroup(
int igroup) {
1469 if (!ChartData)
return true;
1471 if (igroup == 0)
return true;
1476 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1478 if (pGroup->m_element_array.empty())
1482 for (
const auto &elem : pGroup->m_element_array) {
1483 for (
unsigned int ic = 0;
1484 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1486 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1488 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1493 for (
const auto &elem : pGroup->m_element_array) {
1494 const wxString &element_root = elem.m_element_name;
1495 wxString test_string = _T(
"GSHH");
1496 if (element_root.Upper().Contains(test_string))
return true;
1502void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1503 if (!ChartData)
return;
1505 AbstractPlatform::ShowBusySpinner();
1509 SetQuiltRefChart(-1);
1511 m_singleChart = NULL;
1517 if (!m_pCurrentStack) {
1519 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1522 if (-1 != dbi_hint) {
1523 if (GetQuiltMode()) {
1524 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1525 SetQuiltRefChart(dbi_hint);
1529 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1531 if (pTentative_Chart) {
1534 if (m_singleChart) m_singleChart->Deactivate();
1536 m_singleChart = pTentative_Chart;
1537 m_singleChart->Activate();
1539 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1540 GetpCurrentStack(), m_singleChart->GetFullPath());
1548 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1549 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1550 SetQuiltRefChart(selected_index);
1554 SetupCanvasQuiltMode();
1555 if (!GetQuiltMode() && m_singleChart == 0) {
1557 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1558 m_singleChart = pDummyChart;
1564 UpdateCanvasControlBar();
1565 UpdateGPSCompassStatusBox(
true);
1567 SetCursor(wxCURSOR_ARROW);
1569 AbstractPlatform::HideBusySpinner();
1572bool ChartCanvas::DoCanvasUpdate(
void) {
1574 double vpLat, vpLon;
1575 bool blong_jump =
false;
1576 meters_to_shift = 0;
1579 bool bNewChart =
false;
1580 bool bNewView =
false;
1581 bool bCanvasChartAutoOpen =
true;
1583 bool bNewPiano =
false;
1584 bool bOpenSpecified;
1590 if (bDBUpdateInProgress)
return false;
1591 if (!ChartData)
return false;
1593 if (ChartData->IsBusy())
return false;
1619 double dx = m_OSoffsetx;
1620 double dy = m_OSoffsety;
1624 if (GetUpMode() == NORTH_UP_MODE) {
1625 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1627 double offset_angle = atan2(d_north, d_east);
1628 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1629 double chart_angle = GetVPRotation();
1630 double target_angle = chart_angle + offset_angle;
1631 double d_east_mod = offset_distance * cos(target_angle);
1632 double d_north_mod = offset_distance * sin(target_angle);
1633 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1636 extern double gCog_gt;
1639 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1640 double cog_to_use = gCog;
1642 (fabs(gCog - gCog_gt) > 20)) {
1643 cog_to_use = gCog_gt;
1646 if (!g_btenhertz) cog_to_use = g_COGAvg;
1648 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1650 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1651 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1653 double pixel_delta_tent =
1654 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1656 double pixel_delta = 0;
1661 if (!std::isnan(gSog)) {
1665 pixel_delta = pixel_delta_tent;
1668 meters_to_shift = 0;
1670 if (!std::isnan(gCog)) {
1671 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1672 dir_to_shift = cog_to_use;
1673 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1679 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1693 if (GetQuiltMode()) {
1694 int current_db_index = -1;
1695 if (m_pCurrentStack)
1698 ->GetCurrentEntrydbIndex();
1706 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1708 if (m_pCurrentStack->nEntry) {
1709 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1711 SelectQuiltRefdbChart(new_dbIndex,
true);
1712 m_bautofind =
false;
1716 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1717 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1722 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1728 double proposed_scale_onscreen =
1731 int initial_db_index = m_restore_dbindex;
1732 if (initial_db_index < 0) {
1733 if (m_pCurrentStack->nEntry) {
1735 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1740 if (m_pCurrentStack->nEntry) {
1741 int initial_type = ChartData->GetDBChartType(initial_db_index);
1746 if (!IsChartQuiltableRef(initial_db_index)) {
1750 int stack_index = 0;
1752 if (stack_index >= 0) {
1753 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1754 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1755 if (IsChartQuiltableRef(test_db_index) &&
1757 ChartData->GetDBChartType(initial_db_index))) {
1758 initial_db_index = test_db_index;
1766 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1768 SetQuiltRefChart(initial_db_index);
1769 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1777 0, GetVPRotation());
1782 bool super_jump =
false;
1784 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1785 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1786 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1788 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead) {
1790 if (blong_jump) nstep = 20;
1791 StartTimedMovementVP(vpLat, vpLon, nstep);
1800 pLast_Ch = m_singleChart;
1801 ChartTypeEnum new_open_type;
1802 ChartFamilyEnum new_open_family;
1804 new_open_type = pLast_Ch->GetChartType();
1805 new_open_family = pLast_Ch->GetChartFamily();
1807 new_open_type = CHART_TYPE_KAP;
1808 new_open_family = CHART_FAMILY_RASTER;
1811 bOpenSpecified = m_bFirstAuto;
1814 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1817 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1819 if (NULL == pDummyChart) {
1825 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1827 m_singleChart = pDummyChart;
1832 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1834 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1837 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1838 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1845 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1851 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1856 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1859 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1864 if (NULL != m_singleChart)
1865 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1866 m_singleChart->GetFullPath());
1869 m_pCurrentStack->CurrentStackEntry = tEntry;
1879 if (bCanvasChartAutoOpen) {
1880 bool search_direction =
1882 int start_index = 0;
1886 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1887 (LastStack.nEntry == 0)) {
1888 search_direction =
true;
1889 start_index = m_pCurrentStack->nEntry - 1;
1893 if (bOpenSpecified) {
1894 search_direction =
false;
1896 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1899 new_open_type = CHART_TYPE_DONTCARE;
1902 pProposed = ChartData->OpenStackChartConditional(
1903 m_pCurrentStack, start_index, search_direction, new_open_type,
1907 if (NULL == pProposed)
1908 pProposed = ChartData->OpenStackChartConditional(
1909 m_pCurrentStack, start_index, search_direction,
1910 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1912 if (NULL == pProposed)
1913 pProposed = ChartData->OpenStackChartConditional(
1914 m_pCurrentStack, start_index, search_direction,
1915 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1926 if (NULL == pProposed) {
1927 if (NULL == pDummyChart) {
1933 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1935 pProposed = pDummyChart;
1939 if (m_singleChart) m_singleChart->Deactivate();
1940 m_singleChart = pProposed;
1942 if (m_singleChart) {
1943 m_singleChart->Activate();
1944 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1945 m_pCurrentStack, m_singleChart->GetFullPath());
1950 if (NULL != m_singleChart) {
1956 if (!GetVP().IsValid())
1957 set_scale = 1. / 20000.;
1959 double proposed_scale_onscreen;
1962 double new_scale_ppm =
1963 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1971 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1972 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1973 double equivalent_vp_scale =
1975 double new_scale_ppm =
1976 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1981 proposed_scale_onscreen =
1982 wxMin(proposed_scale_onscreen,
1985 proposed_scale_onscreen =
1986 wxMax(proposed_scale_onscreen,
1995 m_singleChart->GetChartSkew() * PI / 180.,
2002 if ((m_bFollow) && m_singleChart)
2004 m_singleChart->GetChartSkew() * PI / 180.,
2013 m_bFirstAuto =
false;
2017 if (bNewChart && !bNewView) Refresh(
false);
2022 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
2025 return bNewChart | bNewView;
2028void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
2029 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
2031 SetQuiltRefChart(db_index);
2033 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
2036 double best_scale_ppm = GetBestVPScale(pc);
2040 SetQuiltRefChart(-1);
2042 SetQuiltRefChart(-1);
2045void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
2046 std::vector<int> piano_chart_index_array =
2047 GetQuiltExtendedStackdbIndexArray();
2048 int current_db_index = piano_chart_index_array[selected_index];
2050 SelectQuiltRefdbChart(current_db_index);
2053double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2057 if ((g_bPreserveScaleOnX) ||
2058 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2064 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2065 double equivalent_vp_scale =
2067 double new_scale_ppm =
2068 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2075 double max_underzoom_multiplier = 2.0;
2076 if (GetVP().b_quilt) {
2077 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2078 pchart->GetChartType(),
2079 pchart->GetChartFamily());
2080 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2083 proposed_scale_onscreen = wxMin(
2084 proposed_scale_onscreen,
2086 max_underzoom_multiplier);
2089 proposed_scale_onscreen =
2090 wxMax(proposed_scale_onscreen,
2098void ChartCanvas::SetupCanvasQuiltMode(
void) {
2101 ChartData->LockCache();
2103 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2107 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2108 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2109 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2110 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2112 m_Piano->SetRoundedRectangles(
true);
2115 int target_new_dbindex = -1;
2116 if (m_pCurrentStack) {
2117 target_new_dbindex =
2118 GetQuiltReferenceChartIndex();
2120 if (-1 != target_new_dbindex) {
2121 if (!IsChartQuiltableRef(target_new_dbindex)) {
2122 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2123 int type = ChartData->GetDBChartType(target_new_dbindex);
2126 int stack_index = m_pCurrentStack->CurrentStackEntry;
2128 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2129 (stack_index >= 0)) {
2130 int proj_tent = ChartData->GetDBChartProj(
2131 m_pCurrentStack->GetDBIndex(stack_index));
2132 int type_tent = ChartData->GetDBChartType(
2133 m_pCurrentStack->GetDBIndex(stack_index));
2135 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2136 if ((proj == proj_tent) && (type_tent == type)) {
2137 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2147 if (IsChartQuiltableRef(target_new_dbindex))
2148 SelectQuiltRefdbChart(target_new_dbindex,
2151 SelectQuiltRefdbChart(-1,
false);
2153 m_singleChart = NULL;
2156 AdjustQuiltRefChart();
2164 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2168 std::vector<int> empty_array;
2169 m_Piano->SetActiveKeyArray(empty_array);
2170 m_Piano->SetNoshowIndexArray(empty_array);
2171 m_Piano->SetEclipsedIndexArray(empty_array);
2174 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2175 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2176 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2177 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2179 m_Piano->SetRoundedRectangles(
false);
2185 if (!GetQuiltMode()) {
2186 if (ChartData && ChartData->IsValid()) {
2190 if (m_bFollow ==
true) {
2198 if (!m_singleChart) {
2201 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2209 int cur_max_scale = (int)1e8;
2211 ChartBase *pChart = GetFirstQuiltChart();
2215 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2217 if (pChart->GetNativeScale() < cur_max_scale) {
2218 Candidate_Chart = pChart;
2219 cur_max_scale = pChart->GetNativeScale();
2222 pChart = GetNextQuiltChart();
2225 m_singleChart = Candidate_Chart;
2229 if (NULL == m_singleChart) {
2230 m_singleChart = ChartData->OpenStackChartConditional(
2231 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2232 CHART_FAMILY_DONTCARE);
2238 InvalidateAllQuiltPatchs();
2240 if (m_singleChart) {
2241 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2242 std::vector<int> one_array;
2243 one_array.push_back(dbi);
2244 m_Piano->SetActiveKeyArray(one_array);
2247 if (m_singleChart) {
2248 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2252 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2256bool ChartCanvas::IsTempMenuBarEnabled() {
2259 wxGetOsVersion(&major);
2267double ChartCanvas::GetCanvasRangeMeters() {
2269 GetSize(&width, &height);
2270 int minDimension = wxMin(width, height);
2273 range *= cos(GetVP().clat * PI / 180.);
2277void ChartCanvas::SetCanvasRangeMeters(
double range) {
2279 GetSize(&width, &height);
2280 int minDimension = wxMin(width, height);
2282 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2286bool ChartCanvas::SetUserOwnship() {
2290 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2291 double factor_dusk = 0.5;
2292 double factor_night = 0.25;
2294 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2295 m_pos_image_user_day =
new wxImage;
2296 *m_pos_image_user_day = pbmp->ConvertToImage();
2297 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2299 int gimg_width = m_pos_image_user_day->GetWidth();
2300 int gimg_height = m_pos_image_user_day->GetHeight();
2303 m_pos_image_user_dusk =
new wxImage;
2304 m_pos_image_user_night =
new wxImage;
2306 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2307 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2309 for (
int iy = 0; iy < gimg_height; iy++) {
2310 for (
int ix = 0; ix < gimg_width; ix++) {
2311 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2312 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2313 m_pos_image_user_day->GetGreen(ix, iy),
2314 m_pos_image_user_day->GetBlue(ix, iy));
2315 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2316 hsv.value = hsv.value * factor_dusk;
2317 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2318 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2321 hsv = wxImage::RGBtoHSV(rgb);
2322 hsv.value = hsv.value * factor_night;
2323 nrgb = wxImage::HSVtoRGB(hsv);
2324 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2331 m_pos_image_user_grey_day =
new wxImage;
2332 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2334 m_pos_image_user_grey_dusk =
new wxImage;
2335 m_pos_image_user_grey_night =
new wxImage;
2337 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2338 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2340 for (
int iy = 0; iy < gimg_height; iy++) {
2341 for (
int ix = 0; ix < gimg_width; ix++) {
2342 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2343 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2344 m_pos_image_user_grey_day->GetGreen(ix, iy),
2345 m_pos_image_user_grey_day->GetBlue(ix, iy));
2346 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2347 hsv.value = hsv.value * factor_dusk;
2348 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2349 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2352 hsv = wxImage::RGBtoHSV(rgb);
2353 hsv.value = hsv.value * factor_night;
2354 nrgb = wxImage::HSVtoRGB(hsv);
2355 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2362 m_pos_image_user_yellow_day =
new wxImage;
2363 m_pos_image_user_yellow_dusk =
new wxImage;
2364 m_pos_image_user_yellow_night =
new wxImage;
2366 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2367 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2368 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2370 for (
int iy = 0; iy < gimg_height; iy++) {
2371 for (
int ix = 0; ix < gimg_width; ix++) {
2372 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2373 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2374 m_pos_image_user_grey_day->GetGreen(ix, iy),
2375 m_pos_image_user_grey_day->GetBlue(ix, iy));
2379 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2380 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2381 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2383 hsv = wxImage::RGBtoHSV(rgb);
2384 hsv.value = hsv.value * factor_dusk;
2385 nrgb = wxImage::HSVtoRGB(hsv);
2386 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2388 hsv = wxImage::RGBtoHSV(rgb);
2389 hsv.value = hsv.value * factor_night;
2390 nrgb = wxImage::HSVtoRGB(hsv);
2391 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2403 m_display_size_mm = size;
2410 double horizontal = sd.x;
2414 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2415 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2418 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2419 ps52plib->SetPPMM(m_pix_per_mm);
2424 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2426 m_display_size_mm, sd.x, sd.y);
2430 ssx = g_monitor_info[g_current_monitor].width;
2431 ssy = g_monitor_info[g_current_monitor].height;
2432 msg.Printf(_T(
"monitor size: %d %d"), ssx, ssy);
2435 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2438void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2440 wxString msg(event.m_string.c_str(), wxConvUTF8);
2442 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2443 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2446 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2448 compress_msg_array.RemoveAt(event.thread);
2449 compress_msg_array.Insert( msg, event.thread);
2452 compress_msg_array.Add(msg);
2455 wxString combined_msg;
2456 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2457 combined_msg += compress_msg_array[i];
2458 combined_msg += _T(
"\n");
2462 pprog->Update(pprog_count, combined_msg, &skip );
2463 pprog->SetSize(pprog_size);
2468void ChartCanvas::InvalidateGL() {
2469 if (!m_glcc)
return;
2471 if (g_bopengl) m_glcc->Invalidate();
2473 if (m_Compass) m_Compass->UpdateStatus(
true);
2476int ChartCanvas::GetCanvasChartNativeScale() {
2478 if (!VPoint.b_quilt) {
2479 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2481 ret = (int)m_pQuilt->GetRefNativeScale();
2486ChartBase *ChartCanvas::GetChartAtCursor() {
2488 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2489 target_chart = m_singleChart;
2490 else if (VPoint.b_quilt)
2491 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2493 target_chart = NULL;
2494 return target_chart;
2497ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2501 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2503 target_chart = NULL;
2504 return target_chart;
2507int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2508 int new_dbIndex = -1;
2509 if (!VPoint.b_quilt) {
2510 if (m_pCurrentStack) {
2511 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2512 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2514 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2524 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2526 for (
unsigned int is = 0; is < im; is++) {
2528 m_pQuilt->GetExtendedStackIndexArray()[is]);
2531 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2541void ChartCanvas::EnablePaint(
bool b_enable) {
2542 m_b_paint_enable = b_enable;
2544 if (m_glcc) m_glcc->EnablePaint(b_enable);
2548bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2550void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2552std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2553 return m_pQuilt->GetQuiltIndexArray();
2557void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2558 VPoint.b_quilt = b_quilt;
2559 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2562bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2564int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2565 return m_pQuilt->GetRefChartdbIndex();
2568void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2569 m_pQuilt->InvalidateAllQuiltPatchs();
2572ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2573 return m_pQuilt->GetLargestScaleChart();
2576ChartBase *ChartCanvas::GetFirstQuiltChart() {
2577 return m_pQuilt->GetFirstChart();
2580ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2582int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2584void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2585 m_pQuilt->SetHiliteIndex(dbIndex);
2588void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2589 m_pQuilt->SetHiliteIndexArray(hilite_array);
2592void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2593 m_pQuilt->ClearHiliteIndexArray();
2596std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2598 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2601int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2602 return m_pQuilt->GetRefChartdbIndex();
2605std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2606 return m_pQuilt->GetExtendedStackIndexArray();
2609std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2610 return m_pQuilt->GetFullscreenIndexArray();
2613std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2614 return m_pQuilt->GetEclipsedStackIndexArray();
2617void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2619double ChartCanvas::GetQuiltMaxErrorFactor() {
2620 return m_pQuilt->GetMaxErrorFactor();
2623bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2624 return m_pQuilt->IsChartQuiltableRef(db_index);
2628 double chartMaxScale =
2630 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2633void ChartCanvas::StartMeasureRoute() {
2634 if (!m_routeState) {
2635 if (m_bMeasure_Active) {
2637 NavObjectChanges::getInstance());
2638 m_pMeasureRoute = NULL;
2641 m_bMeasure_Active =
true;
2642 m_nMeasureState = 1;
2643 m_bDrawingRoute =
false;
2645 SetCursor(*pCursorPencil);
2650void ChartCanvas::CancelMeasureRoute() {
2651 m_bMeasure_Active =
false;
2652 m_nMeasureState = 0;
2653 m_bDrawingRoute =
false;
2655 g_pRouteMan->
DeleteRoute(m_pMeasureRoute, NavObjectChanges::getInstance());
2656 m_pMeasureRoute = NULL;
2658 SetCursor(*pCursorArrow);
2661ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2663void ChartCanvas::SetVP(
ViewPort &vp) {
2674void ChartCanvas::TriggerDeferredFocus() {
2677 m_deferredFocusTimer.Start(20,
true);
2679#if defined(__WXGTK__) || defined(__WXOSX__)
2690void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2695void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2696 if (SendKeyEventToPlugins(event))
2700 int key_char =
event.GetKeyCode();
2703 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2709 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2714 if (g_benable_rotate) {
2735void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2736 if (SendKeyEventToPlugins(event))
2740 bool b_handled =
false;
2742 m_modkeys =
event.GetModifiers();
2744 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2746#ifdef OCPN_ALT_MENUBAR
2752 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2754 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2755 if (!g_bTempShowMenuBar) {
2756 g_bTempShowMenuBar =
true;
2757 parent_frame->ApplyGlobalSettings(
false);
2759 m_bMayToggleMenuBar =
false;
2765 if (event.GetKeyCode() != WXK_ALT) {
2766 m_bMayToggleMenuBar =
false;
2773 switch (event.GetKeyCode()) {
2780 event.GetPosition(&x, &y);
2781 m_FinishRouteOnKillFocus =
false;
2782 CallPopupMenu(x, y);
2783 m_FinishRouteOnKillFocus =
true;
2787 m_modkeys |= wxMOD_ALT;
2791 m_modkeys |= wxMOD_CONTROL;
2796 case WXK_RAW_CONTROL:
2797 m_modkeys |= wxMOD_RAW_CONTROL;
2802 if (m_modkeys == wxMOD_CONTROL)
2803 parent_frame->DoStackDown(
this);
2804 else if (g_bsmoothpanzoom) {
2805 StartTimedMovement();
2814 if (g_bsmoothpanzoom) {
2815 StartTimedMovement();
2823 if (m_modkeys == wxMOD_CONTROL)
2824 parent_frame->DoStackUp(
this);
2825 else if (g_bsmoothpanzoom) {
2826 StartTimedMovement();
2835 if (g_bsmoothpanzoom) {
2836 StartTimedMovement();
2848 SetShowENCText(!GetShowENCText());
2854 if (!m_bMeasure_Active) {
2855 if (event.ShiftDown())
2856 m_bMeasure_DistCircle =
true;
2858 m_bMeasure_DistCircle =
false;
2860 StartMeasureRoute();
2862 CancelMeasureRoute();
2864 SetCursor(*pCursorArrow);
2874 parent_frame->ToggleColorScheme();
2876 TriggerDeferredFocus();
2880 int mod = m_modkeys & wxMOD_SHIFT;
2881 if (mod != m_brightmod) {
2883 m_bbrightdir = !m_bbrightdir;
2886 if (!m_bbrightdir) {
2887 g_nbrightness -= 10;
2888 if (g_nbrightness <= MIN_BRIGHT) {
2889 g_nbrightness = MIN_BRIGHT;
2890 m_bbrightdir =
true;
2893 g_nbrightness += 10;
2894 if (g_nbrightness >= MAX_BRIGHT) {
2895 g_nbrightness = MAX_BRIGHT;
2896 m_bbrightdir =
false;
2900 SetScreenBrightness(g_nbrightness);
2901 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2910 parent_frame->DoStackDown(
this);
2914 parent_frame->DoStackUp(
this);
2919 double t0 = wxGetLocalTimeMillis().ToDouble();
2921 double t1 = wxGetLocalTimeMillis().ToDouble() - t0;
2923 ToggleCanvasQuiltMode();
2924 auto ¬eman = NotificationManager::GetInstance();
2925 noteman.AddNotification(NotificationSeverity::kCritical,
2926 "Test Notification long message.\nMultiline "
2927 "message that may be many, many chars wide.");
2934 parent_frame->ToggleFullScreen();
2939 if (m_modkeys == wxMOD_ALT) {
2944 UpdateGPSCompassStatusBox(
true);
2945 auto ¬eman = NotificationManager::GetInstance();
2946 noteman.AddNotification(NotificationSeverity::kInformational,
2947 "Test Timed Notification", 10);
2949 ToggleChartOutlines();
2955 parent_frame->ActivateMOB();
2959 case WXK_NUMPAD_ADD:
2964 case WXK_NUMPAD_SUBTRACT:
2965 case WXK_PAGEDOWN: {
2966 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2971 if (m_bMeasure_Active) {
2972 if (m_nMeasureState > 2) {
2973 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2975 m_pMeasureRoute->GetnPoints();
2977 gFrame->RefreshAllCanvas();
2979 CancelMeasureRoute();
2980 StartMeasureRoute();
2988 if (event.GetKeyCode() < 128)
2990 int key_char =
event.GetKeyCode();
2994 if (!g_b_assume_azerty) {
2996 if (g_benable_rotate) {
3028 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3035 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3036 m_modkeys & wxMOD_RAW_CONTROL) {
3037 parent_frame->ToggleFullScreen();
3042 if (event.ControlDown()) key_char -= 64;
3044 if (key_char >=
'0' && key_char <=
'9')
3045 SetGroupIndex(key_char -
'0');
3050 SetShowENCAnchor(!GetShowENCAnchor());
3056 parent_frame->ToggleColorScheme();
3061 event.GetPosition(&x, &y);
3062 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3063 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3065 if (!pPopupDetailSlider) {
3066 if (VPoint.b_quilt) {
3068 if (m_pQuilt->GetChartAtPix(
3073 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3075 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3080 if (m_singleChart) {
3081 ChartType = m_singleChart->GetChartType();
3082 ChartFam = m_singleChart->GetChartFamily();
3086 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3087 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3089 this, -1, ChartType, ChartFam,
3090 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3091 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
3092 if (pPopupDetailSlider) pPopupDetailSlider->Show();
3096 if (pPopupDetailSlider) pPopupDetailSlider->Close();
3097 pPopupDetailSlider = NULL;
3104 m_nmea_log->Raise();
3108 SetShowENCLights(!GetShowENCLights());
3114 if (event.ShiftDown())
3115 m_bMeasure_DistCircle =
true;
3117 m_bMeasure_DistCircle =
false;
3119 StartMeasureRoute();
3123 if (g_bInlandEcdis && ps52plib) {
3124 SetENCDisplayCategory((_DisCat)STANDARD);
3129 ToggleChartOutlines();
3133 ToggleCanvasQuiltMode();
3137 parent_frame->ToggleTestPause();
3140 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3141 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3142 g_iNavAidRadarRingsNumberVisible = 1;
3143 else if (!g_bNavAidRadarRingsShown &&
3144 g_iNavAidRadarRingsNumberVisible == 1)
3145 g_iNavAidRadarRingsNumberVisible = 0;
3148 SetShowENCDepth(!m_encShowDepth);
3153 SetShowENCText(!GetShowENCText());
3158 SetShowENCDataQual(!GetShowENCDataQual());
3163 m_bShowNavobjects = !m_bShowNavobjects;
3178 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3183 if (event.ControlDown()) gFrame->DropMarker(
false);
3189 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3190 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3191 if ((indexActive + 1) <= r->GetnPoints()) {
3202 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3208 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3214 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3221 parent_frame->DoSettings();
3225 parent_frame->Close();
3233 if (NULL == pGoToPositionDialog)
3236 pGoToPositionDialog->SetCanvas(
this);
3237 pGoToPositionDialog->Show();
3241 if (undo->AnythingToRedo()) {
3242 undo->RedoNextAction();
3249 if (event.ShiftDown()) {
3250 if (undo->AnythingToRedo()) {
3251 undo->RedoNextAction();
3256 if (undo->AnythingToUndo()) {
3257 undo->UndoLastAction();
3266 if (m_bMeasure_Active) {
3267 CancelMeasureRoute();
3269 SetCursor(*pCursorArrow);
3272 gFrame->RefreshAllCanvas();
3286 switch (gamma_state) {
3306 SetScreenBrightness(g_nbrightness);
3311 if (event.ControlDown()) {
3312 m_bShowCompassWin = !m_bShowCompassWin;
3313 SetShowGPSCompassWindow(m_bShowCompassWin);
3330void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3331 if (SendKeyEventToPlugins(event))
3335 switch (event.GetKeyCode()) {
3337 parent_frame->SwitchKBFocus(
this);
3343 if (!m_pany) m_panspeed = 0;
3349 if (!m_panx) m_panspeed = 0;
3352 case WXK_NUMPAD_ADD:
3353 case WXK_NUMPAD_SUBTRACT:
3356 if (m_mustmove) DoMovement(m_mustmove);
3362 m_modkeys &= ~wxMOD_ALT;
3363#ifdef OCPN_ALT_MENUBAR
3368 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3369 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3370 parent_frame->ApplyGlobalSettings(
false);
3372 m_bMayToggleMenuBar =
true;
3378 m_modkeys &= ~wxMOD_CONTROL;
3382 if (event.GetKeyCode() < 128)
3384 int key_char =
event.GetKeyCode();
3388 if (!g_b_assume_azerty) {
3396 DoMovement(m_mustmove);
3402 DoMovement(m_mustmove);
3403 m_rotation_speed = 0;
3411 DoMovement(m_mustmove);
3421void ChartCanvas::ToggleChartOutlines(
void) {
3422 m_bShowOutlines = !m_bShowOutlines;
3428 if (g_bopengl) InvalidateGL();
3432void ChartCanvas::ToggleLookahead() {
3433 m_bLookAhead = !m_bLookAhead;
3438void ChartCanvas::SetUpMode(
int mode) {
3441 if (mode != NORTH_UP_MODE) {
3444 if (!std::isnan(gCog)) stuff = gCog;
3446 if (g_COGAvgSec > 0) {
3447 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3450 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3452 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3453 SetVPRotation(GetVPSkew());
3458 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3459 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3461 UpdateGPSCompassStatusBox(
true);
3462 gFrame->DoChartUpdate();
3465bool ChartCanvas::DoCanvasCOGSet(
void) {
3466 if (GetUpMode() == NORTH_UP_MODE)
return false;
3467 double cog_use = g_COGAvg;
3468 if (g_btenhertz) cog_use = gCog;
3470 double rotation = 0;
3471 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3472 rotation = -gHdt * PI / 180.;
3473 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3474 rotation = -cog_use * PI / 180.;
3476 SetVPRotation(rotation);
3480double easeOutCubic(
double t) {
3482 return 1.0 - pow(1.0 - t, 3.0);
3485void ChartCanvas::StartChartDragInertia() {
3488 m_bChartDragging =
false;
3491 m_chart_drag_inertia_time = 750;
3492 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3497 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3501 size_t length = m_drag_vec_t.size();
3502 for (
size_t i = 0; i < n_vel; i++) {
3503 xacc += m_drag_vec_x.at(length - 1 - i);
3504 yacc += m_drag_vec_y.at(length - 1 - i);
3505 tacc += m_drag_vec_t.at(length - 1 - i);
3508 m_chart_drag_velocity_x = xacc / tacc;
3509 m_chart_drag_velocity_y = yacc / tacc;
3511 m_chart_drag_inertia_active =
true;
3514 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3520void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3521 if (!m_chart_drag_inertia_active)
return;
3524 wxLongLong now = wxGetLocalTimeMillis();
3525 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3526 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3527 if (t > 1.0) t = 1.0;
3528 double e = 1.0 - easeOutCubic(t);
3531 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3533 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3539 m_last_elapsed = elapsed;
3543 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3544 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3545 double inertia_lat, inertia_lon;
3552 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3553 m_chart_drag_inertia_timer.Stop();
3554 m_chart_drag_inertia_active =
false;
3557 m_target_lat = GetVP().
clat;
3558 m_target_lon = GetVP().
clon;
3559 m_pan_drag.x = m_pan_drag.y = 0;
3560 m_panx = m_pany = 0;
3563 int target_redraw_interval = 40;
3564 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3568void ChartCanvas::StopMovement() {
3569 m_panx = m_pany = 0;
3572 m_rotation_speed = 0;
3575#if !defined(__WXGTK__) && !defined(__WXQT__)
3586bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3588 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3590 if (!pMovementTimer->IsRunning()) {
3592 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3595 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3600 m_last_movement_time = wxDateTime::UNow();
3604void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3607 m_target_lat = target_lat;
3608 m_target_lon = target_lon;
3611 m_start_lat = GetVP().
clat;
3612 m_start_lon = GetVP().
clon;
3614 m_VPMovementTimer.Start(1,
true);
3615 m_timed_move_vp_active =
true;
3617 m_timedVP_step = nstep;
3620void ChartCanvas::DoTimedMovementVP() {
3621 if (!m_timed_move_vp_active)
return;
3622 if (m_stvpc++ > m_timedVP_step * 2) {
3629 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3644 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3645 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3647 m_run_lat = new_lat;
3648 m_run_lon = new_lon;
3654void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3656void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3658void ChartCanvas::StartTimedMovementTarget() {}
3660void ChartCanvas::DoTimedMovementTarget() {}
3662void ChartCanvas::StopMovementTarget() {}
3664void ChartCanvas::DoTimedMovement() {
3665 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3669 wxDateTime now = wxDateTime::UNow();
3671 if (m_last_movement_time.IsValid())
3672 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3674 m_last_movement_time = now;
3682void ChartCanvas::DoMovement(
long dt) {
3684 if (dt == 0) dt = 1;
3687 if (m_mustmove < 0) m_mustmove = 0;
3689 if (m_pan_drag.x || m_pan_drag.y) {
3691 m_pan_drag.x = m_pan_drag.y = 0;
3694 if (m_panx || m_pany) {
3695 const double slowpan = .1, maxpan = 2;
3696 if (m_modkeys == wxMOD_ALT)
3697 m_panspeed = slowpan;
3699 m_panspeed += (double)dt / 500;
3700 m_panspeed = wxMin(maxpan, m_panspeed);
3702 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3705 if (m_zoom_factor != 1) {
3706 double alpha = 400, beta = 1.5;
3707 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3709 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3711 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3716 if (zoom_factor > 1) {
3717 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3721 else if (zoom_factor < 1) {
3722 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3727 if (fabs(zoom_factor - 1) > 1e-4)
3730 if (m_wheelzoom_stop_oneshot > 0) {
3731 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3732 m_wheelzoom_stop_oneshot = 0;
3737 if (zoom_factor > 1) {
3739 m_wheelzoom_stop_oneshot = 0;
3742 }
else if (zoom_factor < 1) {
3744 m_wheelzoom_stop_oneshot = 0;
3751 if (m_rotation_speed) {
3752 double speed = m_rotation_speed;
3753 if (m_modkeys == wxMOD_ALT) speed /= 10;
3754 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3758void ChartCanvas::SetColorScheme(ColorScheme cs) {
3759 SetAlertString(_T(
""));
3763 case GLOBAL_COLOR_SCHEME_DAY:
3764 m_pos_image_red = &m_os_image_red_day;
3765 m_pos_image_grey = &m_os_image_grey_day;
3766 m_pos_image_yellow = &m_os_image_yellow_day;
3767 m_pos_image_user = m_pos_image_user_day;
3768 m_pos_image_user_grey = m_pos_image_user_grey_day;
3769 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3770 m_cTideBitmap = m_bmTideDay;
3771 m_cCurrentBitmap = m_bmCurrentDay;
3774 case GLOBAL_COLOR_SCHEME_DUSK:
3775 m_pos_image_red = &m_os_image_red_dusk;
3776 m_pos_image_grey = &m_os_image_grey_dusk;
3777 m_pos_image_yellow = &m_os_image_yellow_dusk;
3778 m_pos_image_user = m_pos_image_user_dusk;
3779 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3780 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3781 m_cTideBitmap = m_bmTideDusk;
3782 m_cCurrentBitmap = m_bmCurrentDusk;
3784 case GLOBAL_COLOR_SCHEME_NIGHT:
3785 m_pos_image_red = &m_os_image_red_night;
3786 m_pos_image_grey = &m_os_image_grey_night;
3787 m_pos_image_yellow = &m_os_image_yellow_night;
3788 m_pos_image_user = m_pos_image_user_night;
3789 m_pos_image_user_grey = m_pos_image_user_grey_night;
3790 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3791 m_cTideBitmap = m_bmTideNight;
3792 m_cCurrentBitmap = m_bmCurrentNight;
3795 m_pos_image_red = &m_os_image_red_day;
3796 m_pos_image_grey = &m_os_image_grey_day;
3797 m_pos_image_yellow = &m_os_image_yellow_day;
3798 m_pos_image_user = m_pos_image_user_day;
3799 m_pos_image_user_grey = m_pos_image_user_grey_day;
3800 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3801 m_cTideBitmap = m_bmTideDay;
3802 m_cCurrentBitmap = m_bmCurrentDay;
3806 CreateDepthUnitEmbossMaps(cs);
3807 CreateOZEmbossMapData(cs);
3810 m_fog_color = wxColor(
3814 case GLOBAL_COLOR_SCHEME_DUSK:
3817 case GLOBAL_COLOR_SCHEME_NIGHT:
3823 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3824 m_fog_color.Blue() * dim);
3828 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3829 SetBackgroundColour( wxColour(0,0,0) );
3831 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3834 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3836 SetBackgroundColour( wxNullColour );
3843 m_Piano->SetColorScheme(cs);
3845 m_Compass->SetColorScheme(cs);
3847 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3849 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3851 if (g_bopengl && m_glcc) {
3852 m_glcc->SetColorScheme(cs);
3853 g_glTextureManager->ClearAllRasterTextures();
3858 m_brepaint_piano =
true;
3865wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3866 wxImage img = Bitmap.ConvertToImage();
3867 int sx = img.GetWidth();
3868 int sy = img.GetHeight();
3870 wxImage new_img(img);
3872 for (
int i = 0; i < sx; i++) {
3873 for (
int j = 0; j < sy; j++) {
3874 if (!img.IsTransparent(i, j)) {
3875 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3876 (
unsigned char)(img.GetGreen(i, j) * factor),
3877 (
unsigned char)(img.GetBlue(i, j) * factor));
3882 wxBitmap ret = wxBitmap(new_img);
3887void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3890 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3892 if (!m_pBrightPopup) {
3895 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3899 m_pBrightPopup->SetSize(x, y);
3900 m_pBrightPopup->Move(120, 120);
3903 int bmpsx = m_pBrightPopup->GetSize().x;
3904 int bmpsy = m_pBrightPopup->GetSize().y;
3906 wxBitmap bmp(bmpsx, bmpsx);
3907 wxMemoryDC mdc(bmp);
3909 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3910 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3911 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3912 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3915 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3917 mdc.SetFont(*pfont);
3920 if (brightness == max)
3922 else if (brightness == min)
3925 val.Printf(_T(
"%3d"), brightness);
3927 mdc.DrawText(val, 0, 0);
3929 mdc.SelectObject(wxNullBitmap);
3931 m_pBrightPopup->SetBitmap(bmp);
3932 m_pBrightPopup->Show();
3933 m_pBrightPopup->Refresh();
3936void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3937 m_b_rot_hidef =
true;
3941void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3942 if (!g_bRollover)
return;
3944 bool b_need_refresh =
false;
3946 wxSize win_size = GetSize() * m_displayScale;
3947 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3950 bool showAISRollover =
false;
3951 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3953 SelectItem *pFind = pSelectAIS->FindSelection(
3956 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3957 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3960 showAISRollover =
true;
3962 if (NULL == m_pAISRolloverWin) {
3964 m_pAISRolloverWin->IsActive(
false);
3965 b_need_refresh =
true;
3966 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3967 m_AISRollover_MMSI != FoundAIS_MMSI) {
3973 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3974 m_pAISRolloverWin->IsActive(
false);
3975 m_AISRollover_MMSI = 0;
3980 m_AISRollover_MMSI = FoundAIS_MMSI;
3982 if (!m_pAISRolloverWin->IsActive()) {
3983 wxString s = ptarget->GetRolloverString();
3984 m_pAISRolloverWin->SetString(s);
3986 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3987 AIS_ROLLOVER, win_size);
3988 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3989 m_pAISRolloverWin->IsActive(
true);
3990 b_need_refresh =
true;
3994 m_AISRollover_MMSI = 0;
3995 showAISRollover =
false;
4000 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
4001 m_pAISRolloverWin->IsActive(
false);
4002 m_AISRollover_MMSI = 0;
4003 b_need_refresh =
true;
4008 bool showRouteRollover =
false;
4010 if (NULL == m_pRolloverRouteSeg) {
4015 SelectableItemList SelList = pSelect->FindSelectionList(
4017 wxSelectableItemListNode *node = SelList.GetFirst();
4023 if (pr && pr->IsVisible()) {
4024 m_pRolloverRouteSeg = pFindSel;
4025 showRouteRollover =
true;
4027 if (NULL == m_pRouteRolloverWin) {
4029 m_pRouteRolloverWin->IsActive(
false);
4032 if (!m_pRouteRolloverWin->IsActive()) {
4040 DistanceBearingMercator(
4041 segShow_point_b->m_lat, segShow_point_b->m_lon,
4042 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4044 if (!pr->m_bIsInLayer)
4045 s.Append(_(
"Route") + _T(
": "));
4047 s.Append(_(
"Layer Route: "));
4049 if (pr->m_RouteNameString.IsEmpty())
4050 s.Append(_(
"(unnamed)"));
4052 s.Append(pr->m_RouteNameString);
4054 s << _T(
"\n") << _(
"Total Length: ")
4055 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
4056 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4057 << segShow_point_b->GetName() << _T(
"\n");
4060 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4061 (
int)floor(brg + 0.5), 0x00B0);
4064 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4066 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4067 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4069 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4070 (
int)floor(varBrg + 0.5), 0x00B0);
4073 s << FormatDistanceAdaptive(dist);
4078 double shiptoEndLeg = 0.;
4079 bool validActive =
false;
4080 if (pr->IsActive() &&
4081 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
4084 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
4085 wxRoutePointListNode *node =
4086 (pr->pRoutePointList)->GetFirst()->GetNext();
4088 float dist_to_endleg = 0;
4092 prp = node->GetData();
4094 shiptoEndLeg += prp->m_seg_len;
4095 else if (prp->m_bIsActive)
4097 dist_to_endleg += prp->m_seg_len;
4098 if (prp->IsSame(segShow_point_a))
break;
4099 node = node->GetNext();
4101 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
4106 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
4107 << segShow_point_b->GetName() << _T(
"\n");
4110 ->GetCurrentRngToActivePoint();
4115 s << FormatDistanceAdaptive(shiptoEndLeg);
4119 if (!std::isnan(gCog) && !std::isnan(gSog))
4121 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
4124 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
4125 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4127 << wxString(ttg_sec > SECONDS_PER_DAY
4128 ? ttg_span.Format(_(
"%Dd %H:%M"))
4129 : ttg_span.Format(_(
"%H:%M")));
4130 wxDateTime dtnow, eta;
4131 eta = dtnow.SetToCurrent().Add(ttg_span);
4132 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
4133 << eta.Format(_T(
" %d %H:%M"));
4135 s << _T(
" ---- ----");
4137 m_pRouteRolloverWin->SetString(s);
4139 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4140 LEG_ROLLOVER, win_size);
4141 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4142 m_pRouteRolloverWin->IsActive(
true);
4143 b_need_refresh =
true;
4144 showRouteRollover =
true;
4148 node = node->GetNext();
4154 m_pRolloverRouteSeg))
4155 showRouteRollover =
false;
4156 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4157 showRouteRollover =
false;
4159 showRouteRollover =
true;
4163 if (m_routeState) showRouteRollover =
false;
4166 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4167 showRouteRollover =
false;
4169 if (m_pRouteRolloverWin &&
4170 !showRouteRollover) {
4171 m_pRouteRolloverWin->IsActive(
false);
4172 m_pRolloverRouteSeg = NULL;
4173 m_pRouteRolloverWin->Destroy();
4174 m_pRouteRolloverWin = NULL;
4175 b_need_refresh =
true;
4176 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4177 m_pRouteRolloverWin->IsActive(
true);
4178 b_need_refresh =
true;
4183 bool showTrackRollover =
false;
4185 if (NULL == m_pRolloverTrackSeg) {
4190 SelectableItemList SelList = pSelect->FindSelectionList(
4192 wxSelectableItemListNode *node = SelList.GetFirst();
4198 if (pt && pt->IsVisible()) {
4199 m_pRolloverTrackSeg = pFindSel;
4200 showTrackRollover =
true;
4202 if (NULL == m_pTrackRolloverWin) {
4204 m_pTrackRolloverWin->IsActive(
false);
4207 if (!m_pTrackRolloverWin->IsActive()) {
4215 DistanceBearingMercator(
4216 segShow_point_b->m_lat, segShow_point_b->m_lon,
4217 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4219 if (!pt->m_bIsInLayer)
4220 s.Append(_(
"Track") + _T(
": "));
4222 s.Append(_(
"Layer Track: "));
4224 if (pt->GetName().IsEmpty())
4225 s.Append(_(
"(unnamed)"));
4227 s.Append(pt->GetName());
4228 double tlenght = pt->Length();
4229 s << _T(
"\n") << _(
"Total Track: ")
4230 << FormatDistanceAdaptive(tlenght);
4231 if (pt->GetLastPoint()->GetTimeString() &&
4232 pt->GetPoint(0)->GetTimeString()) {
4233 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4234 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4235 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4236 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4237 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4238 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
4239 << getUsrSpeedUnit();
4240 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
4241 : ttime.Format(_T(
" %H:%M")));
4245 if (g_bShowTrackPointTime && strlen(segShow_point_b->GetTimeString()))
4246 s << _T(
"\n") << _(
"Segment Created: ")
4247 << segShow_point_b->GetTimeString();
4251 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4256 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4258 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4259 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4261 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4265 s << FormatDistanceAdaptive(dist);
4267 if (segShow_point_a->GetTimeString() &&
4268 segShow_point_b->GetTimeString()) {
4269 wxDateTime apoint = segShow_point_a->GetCreateTime();
4270 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4271 if (apoint.IsValid() && bpoint.IsValid()) {
4272 double segmentSpeed = toUsrSpeed(
4273 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4274 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4275 << getUsrSpeedUnit();
4279 m_pTrackRolloverWin->SetString(s);
4281 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4282 LEG_ROLLOVER, win_size);
4283 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4284 m_pTrackRolloverWin->IsActive(
true);
4285 b_need_refresh =
true;
4286 showTrackRollover =
true;
4290 node = node->GetNext();
4296 m_pRolloverTrackSeg))
4297 showTrackRollover =
false;
4298 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4299 showTrackRollover =
false;
4301 showTrackRollover =
true;
4305 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4306 showTrackRollover =
false;
4309 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4310 showTrackRollover =
false;
4316 if (m_pTrackRolloverWin &&
4317 !showTrackRollover) {
4318 m_pTrackRolloverWin->IsActive(
false);
4319 m_pRolloverTrackSeg = NULL;
4320 m_pTrackRolloverWin->Destroy();
4321 m_pTrackRolloverWin = NULL;
4322 b_need_refresh =
true;
4323 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4324 m_pTrackRolloverWin->IsActive(
true);
4325 b_need_refresh =
true;
4328 if (b_need_refresh) Refresh();
4331void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4332 if ((GetShowENCLights() || m_bsectors_shown) &&
4333 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4334 extendedSectorLegs)) {
4335 if (!m_bsectors_shown) {
4337 m_bsectors_shown =
true;
4340 if (m_bsectors_shown) {
4342 m_bsectors_shown =
false;
4350#if defined(__WXGTK__) || defined(__WXQT__)
4355 double cursor_lat, cursor_lon;
4358 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4359 while (cursor_lon < -180.) cursor_lon += 360.;
4361 while (cursor_lon > 180.) cursor_lon -= 360.;
4363 SetCursorStatus(cursor_lat, cursor_lon);
4369void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4370 if (!parent_frame->m_pStatusBar)
return;
4374 s1 += toSDMM(1, cursor_lat);
4376 s1 += toSDMM(2, cursor_lon);
4378 if (STAT_FIELD_CURSOR_LL >= 0)
4379 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4381 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4386 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4387 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4388 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4390 wxString s = st + sm;
4391 s << FormatDistanceAdaptive(dist);
4403 if (g_bShowLiveETA) {
4406 float boatSpeedDefault = g_defaultBoatSpeed;
4411 if (!std::isnan(gSog)) {
4413 if (boatSpeed < 0.5) {
4416 realTimeETA = dist / boatSpeed * 60;
4425 s << minutesToHoursDays(realTimeETA);
4430 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4431 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4433 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4438 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4446wxString minutesToHoursDays(
float timeInMinutes) {
4449 if (timeInMinutes == 0) {
4454 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4455 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4460 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4463 hours = (int)timeInMinutes / 60;
4464 min = (int)timeInMinutes % 60;
4467 s << wxString::Format(_T(
"%d"), hours);
4470 s << wxString::Format(_T(
"%d"), hours);
4472 s << wxString::Format(_T(
"%d"), min);
4479 else if (timeInMinutes > 24 * 60) {
4482 days = (int)(timeInMinutes / 60) / 24;
4483 hours = (int)(timeInMinutes / 60) % 24;
4486 s << wxString::Format(_T(
"%d"), days);
4489 s << wxString::Format(_T(
"%d"), days);
4491 s << wxString::Format(_T(
"%d"), hours);
4503void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4511 wxPoint2DDouble *r) {
4516 double rlon, wxPoint2DDouble *r) {
4527 if (!g_bopengl && m_singleChart &&
4528 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4529 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4530 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4531 (m_singleChart->GetChartProjectionType() !=
4532 PROJECTION_TRANSVERSE_MERCATOR) &&
4533 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4534 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4535 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4549 Cur_BSB_Ch->SetVPRasterParms(vp);
4550 double rpixxd, rpixyd;
4551 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4577 if (std::isnan(p.m_x)) {
4578 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4582 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4583 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4585 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4604 if (!g_bopengl && m_singleChart &&
4605 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4606 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4607 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4608 (m_singleChart->GetChartProjectionType() !=
4609 PROJECTION_TRANSVERSE_MERCATOR) &&
4610 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4611 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4612 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4623 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4626 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4631 else if (slon > 180.)
4642 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4648 extendedSectorLegs.clear();
4653 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4655 if (g_bsmoothpanzoom) {
4656 if (StartTimedMovement(stoptimer)) {
4658 m_zoom_factor = factor;
4663 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4668 extendedSectorLegs.clear();
4673 if (!ChartData)
return;
4674 if (!m_pCurrentStack)
return;
4680 if (m_bzooming)
return;
4689 double proposed_scale_onscreen =
4692 bool b_do_zoom =
false;
4701 if (!VPoint.b_quilt) {
4704 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4705 if (new_db_index >= 0)
4706 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4710 int current_ref_stack_index = -1;
4711 if (m_pCurrentStack->nEntry) {
4713 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4714 m_pQuilt->SetReferenceChart(trial_index);
4715 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4716 if (new_db_index >= 0)
4717 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4721 if (m_pCurrentStack)
4722 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4732 double min_allowed_scale =
4735 if (proposed_scale_onscreen < min_allowed_scale) {
4740 proposed_scale_onscreen = min_allowed_scale;
4744 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4747 }
else if (factor < 1) {
4752 bool b_smallest =
false;
4754 if (!VPoint.b_quilt) {
4759 LLBBox viewbox = VPoint.GetBBox();
4761 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4762 double max_allowed_scale;
4776 if (proposed_scale_onscreen > max_allowed_scale) {
4778 proposed_scale_onscreen = max_allowed_scale;
4783 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4784 if (new_db_index >= 0)
4785 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4787 if (m_pCurrentStack)
4788 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4791 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4793 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4794 proposed_scale_onscreen =
4795 wxMin(proposed_scale_onscreen,
4801 m_absolute_min_scale_ppm)
4810 bool b_allow_ztc =
true;
4811 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4812 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4814 double brg, distance;
4815 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4818 meters_to_shift = distance * 1852;
4826 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4829 if (m_bFollow) DoCanvasUpdate();
4836void ChartCanvas::RotateCanvas(
double dir) {
4839 if (g_bsmoothpanzoom) {
4840 if (StartTimedMovement()) {
4842 m_rotation_speed = dir * 60;
4845 double speed = dir * 10;
4846 if (m_modkeys == wxMOD_ALT) speed /= 20;
4847 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4851void ChartCanvas::DoRotateCanvas(
double rotation) {
4852 while (rotation < 0) rotation += 2 * PI;
4853 while (rotation > 2 * PI) rotation -= 2 * PI;
4855 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4857 SetVPRotation(rotation);
4858 parent_frame->UpdateRotationState(VPoint.
rotation);
4861void ChartCanvas::DoTiltCanvas(
double tilt) {
4862 while (tilt < 0) tilt = 0;
4863 while (tilt > .95) tilt = .95;
4865 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4871void ChartCanvas::TogglebFollow(
void) {
4878void ChartCanvas::ClearbFollow(
void) {
4881 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4883 UpdateFollowButtonState();
4887 parent_frame->SetChartUpdatePeriod();
4890void ChartCanvas::SetbFollow(
void) {
4893 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4894 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4902 p.m_x += m_OSoffsetx;
4903 p.m_y -= m_OSoffsety;
4912 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4913 UpdateFollowButtonState();
4915 if (!g_bSmoothRecenter) {
4919 parent_frame->SetChartUpdatePeriod();
4922void ChartCanvas::UpdateFollowButtonState(
void) {
4925 m_muiBar->SetFollowButtonState(0);
4928 m_muiBar->SetFollowButtonState(2);
4930 m_muiBar->SetFollowButtonState(1);
4936 androidSetFollowTool(0);
4939 androidSetFollowTool(2);
4941 androidSetFollowTool(1);
4946void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4947 if (g_bSmoothRecenter && !m_routeState) {
4948 if (StartSmoothJump(lat, lon, scale_ppm))
4952 double gcDist, gcBearingEnd;
4953 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4955 gcBearingEnd += 180;
4956 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4959 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4960 double new_lat = lat + (lat_offset / (1852 * 60));
4961 double new_lon = lon + (lon_offset / (1852 * 60));
4964 StartSmoothJump(lat, lon, scale_ppm);
4969 if (lon > 180.0) lon -= 360.0;
4975 if (!GetQuiltMode()) {
4977 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4978 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4982 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4983 AdjustQuiltRefChart();
4990 UpdateFollowButtonState();
4998bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5003 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5004 double distance_pixels = gcDist *
GetVPScale();
5005 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5011 m_startLat = m_vLat;
5012 m_startLon = m_vLon;
5017 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5018 m_endScale = scale_ppm;
5021 m_animationDuration = 600;
5022 m_animationStart = wxGetLocalTimeMillis();
5029 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5030 m_animationActive =
true;
5035void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5037 wxLongLong now = wxGetLocalTimeMillis();
5038 double elapsed = (now - m_animationStart).ToDouble();
5039 double t = elapsed / m_animationDuration.ToDouble();
5040 if (t > 1.0) t = 1.0;
5043 double e = easeOutCubic(t);
5046 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5047 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5048 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5053 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5059 m_animationActive =
false;
5060 UpdateFollowButtonState();
5067 if (!ChartData)
return false;
5072 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
5073 UpdateFollowButtonState();
5079 extendedSectorLegs.clear();
5089 if (iters++ > 5)
return false;
5090 if (!std::isnan(dlat))
break;
5093 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5099 else if (dlat < -90)
5102 if (dlon > 360.) dlon -= 360.;
5103 if (dlon < -360.) dlon += 360.;
5118 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5122 if (VPoint.b_quilt) {
5123 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5124 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5126 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
5128 double tweak_scale_ppm =
5134 if (new_ref_dbIndex == -1) {
5135#pragma GCC diagnostic push
5136#pragma GCC diagnostic ignored "-Warray-bounds"
5143 int trial_index = -1;
5144 if (m_pCurrentStack->nEntry) {
5146 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5149 if (trial_index < 0) {
5150 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5151 if (full_screen_array.size())
5152 trial_index = full_screen_array[full_screen_array.size() - 1];
5155 if (trial_index >= 0) {
5156 m_pQuilt->SetReferenceChart(trial_index);
5161#pragma GCC diagnostic pop
5168 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5170 double offset_angle = atan2(offy, offx);
5171 double offset_distance = sqrt((offy * offy) + (offx * offx));
5172 double chart_angle = GetVPRotation();
5173 double target_angle = chart_angle - offset_angle;
5174 double d_east_mod = offset_distance * cos(target_angle);
5175 double d_north_mod = offset_distance * sin(target_angle);
5180 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5181 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5183 UpdateFollowButtonState();
5189 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5194void ChartCanvas::ReloadVP(
bool b_adjust) {
5195 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5197 LoadVP(VPoint, b_adjust);
5200void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5202 if (g_bopengl && m_glcc) {
5203 m_glcc->Invalidate();
5204 if (m_glcc->GetSize() != GetSize()) {
5205 m_glcc->SetSize(GetSize());
5210 m_cache_vp.Invalidate();
5211 m_bm_cache_vp.Invalidate();
5214 VPoint.Invalidate();
5216 if (m_pQuilt) m_pQuilt->Invalidate();
5225 vp.m_projection_type, b_adjust);
5228void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5229 m_pQuilt->SetReferenceChart(dbIndex);
5230 VPoint.Invalidate();
5231 m_pQuilt->Invalidate();
5234double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5236 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5243int ChartCanvas::AdjustQuiltRefChart() {
5246 wxASSERT(ChartData);
5248 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5250 double min_ref_scale =
5251 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5252 double max_ref_scale =
5253 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5256 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5258 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5260 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5262 int ref_family = pc->GetChartFamily();
5265 unsigned int target_stack_index = 0;
5266 int target_stack_index_check =
5267 m_pQuilt->GetExtendedStackIndexArray()
5268 [m_pQuilt->GetRefChartdbIndex()];
5270 if (wxNOT_FOUND != target_stack_index_check)
5271 target_stack_index = target_stack_index_check;
5273 int extended_array_count =
5274 m_pQuilt->GetExtendedStackIndexArray().size();
5275 while ((!brender_ok) &&
5276 ((
int)target_stack_index < (extended_array_count - 1))) {
5277 target_stack_index++;
5279 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5281 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
5282 IsChartQuiltableRef(test_db_index)) {
5285 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5287 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5294 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5295 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
5296 IsChartQuiltableRef(new_db_index)) {
5297 m_pQuilt->SetReferenceChart(new_db_index);
5300 ret = m_pQuilt->GetRefChartdbIndex();
5302 ret = m_pQuilt->GetRefChartdbIndex();
5305 ret = m_pQuilt->GetRefChartdbIndex();
5314void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5315 delete m_pCurrentStack;
5317 wxASSERT(ChartData);
5318 ChartData->BuildChartStack(m_pCurrentStack, VPoint.
clat, VPoint.
clon,
5327bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5328 double latNE,
double lonNE) {
5330 double latc = (latSW + latNE) / 2.0;
5331 double lonc = (lonSW + lonNE) / 2.0;
5334 double ne_easting, ne_northing;
5335 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5337 double sw_easting, sw_northing;
5338 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5340 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5347 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5350bool ChartCanvas::SetVPProjection(
int projection) {
5356 double prev_true_scale_ppm = m_true_scale_ppm;
5361 m_absolute_min_scale_ppm));
5369bool ChartCanvas::SetVPRotation(
double angle) {
5371 VPoint.
skew, angle);
5374 double skew,
double rotation,
int projection,
5375 bool b_adjust,
bool b_refresh) {
5380 if (VPoint.IsValid()) {
5381 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5382 (fabs(VPoint.
skew - skew) < 1e-9) &&
5383 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5384 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5385 (VPoint.m_projection_type == projection ||
5386 projection == PROJECTION_UNKNOWN))
5389 if (VPoint.m_projection_type != projection)
5390 VPoint.InvalidateTransformCache();
5400 if (projection != PROJECTION_UNKNOWN)
5401 VPoint.SetProjectionType(projection);
5402 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5403 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5406 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5407 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5408 if (VPoint.
clat > 89.5)
5410 else if (VPoint.
clat < -89.5)
5411 VPoint.
clat = -89.5;
5416 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5417 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5429 bool bwasValid = VPoint.IsValid();
5434 m_cache_vp.Invalidate();
5439 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5443 int mouseX = mouse_x;
5444 int mouseY = mouse_y;
5445 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5451 SendCursorLatLonToAllPlugIns(lat, lon);
5454 if (!VPoint.b_quilt && m_singleChart) {
5459 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5463 if ((!m_cache_vp.IsValid()) ||
5468 wxPoint cp_last, cp_this;
5472 if (cp_last != cp_this) {
5478 if (m_pCurrentStack) {
5479 assert(ChartData != 0);
5480 int current_db_index;
5482 m_pCurrentStack->GetCurrentEntrydbIndex();
5484 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5486 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5489 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5493 if (VPoint.b_quilt) {
5495 m_pQuilt->InvalidateAllQuiltPatchs();
5499 if (!m_pCurrentStack)
return false;
5501 int current_db_index;
5503 m_pCurrentStack->GetCurrentEntrydbIndex();
5505 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5506 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5509 int current_ref_stack_index = -1;
5510 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5511 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5512 current_ref_stack_index = i;
5515 if (g_bFullScreenQuilt) {
5516 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5520 bool b_needNewRef =
false;
5523 if ((-1 == current_ref_stack_index) &&
5524 (m_pQuilt->GetRefChartdbIndex() >= 0))
5525 b_needNewRef =
true;
5532 bool renderable =
true;
5534 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5535 if (referenceChart) {
5536 double chartMaxScale = referenceChart->GetNormalScaleMax(
5538 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5540 if (!renderable) b_needNewRef =
true;
5545 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5546 int target_scale = cte_ref.GetScale();
5547 int target_type = cte_ref.GetChartType();
5548 int candidate_stack_index;
5555 candidate_stack_index = 0;
5556 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5558 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5559 int candidate_scale = cte_candidate.GetScale();
5560 int candidate_type = cte_candidate.GetChartType();
5562 if ((candidate_scale >= target_scale) &&
5563 (candidate_type == target_type)) {
5564 bool renderable =
true;
5565 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5566 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5567 if (tentative_referenceChart) {
5568 double chartMaxScale =
5569 tentative_referenceChart->GetNormalScaleMax(
5571 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5574 if (renderable)
break;
5577 candidate_stack_index++;
5582 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5583 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5584 while (candidate_stack_index >= 0) {
5585 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5588 ChartData->GetChartTableEntry(idx);
5589 int candidate_scale = cte_candidate.GetScale();
5590 int candidate_type = cte_candidate.GetChartType();
5592 if ((candidate_scale <= target_scale) &&
5593 (candidate_type == target_type))
5596 candidate_stack_index--;
5601 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5602 (candidate_stack_index < 0))
5603 candidate_stack_index = 0;
5605 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5607 m_pQuilt->SetReferenceChart(new_ref_index);
5613 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5618 bool renderable =
true;
5620 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5621 if (referenceChart) {
5622 double chartMaxScale = referenceChart->GetNormalScaleMax(
5624 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5625 proj = ChartData->GetDBChartProj(ref_db_index);
5627 proj = PROJECTION_MERCATOR;
5629 VPoint.b_MercatorProjectionOverride =
5630 (m_pQuilt->GetnCharts() == 0 || !renderable);
5632 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5634 VPoint.SetProjectionType(proj);
5641 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5646 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5666 m_pQuilt->Invalidate();
5681 ChartData->PurgeCacheUnusedCharts(0.7);
5683 if (b_refresh) Refresh(
false);
5690 }
else if (!g_bopengl) {
5691 OcpnProjType projection = PROJECTION_UNKNOWN;
5694 projection = m_singleChart->GetChartProjectionType();
5695 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5696 VPoint.SetProjectionType(projection);
5700 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5701 m_cache_vp.Invalidate();
5705 UpdateCanvasControlBar();
5711 if (VPoint.GetBBox().GetValid()) {
5714 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5723 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5726 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5733 wxPoint2DDouble r, r1;
5735 double delta_check =
5739 double check_point = wxMin(89., VPoint.
clat);
5741 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5744 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5745 VPoint.
clon, 0, &rhumbDist);
5750 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5751 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5753 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5757 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5763 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5765 if (m_true_scale_ppm)
5766 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5771 double round_factor = 1000.;
5775 round_factor = 100.;
5777 round_factor = 1000.;
5780 double retina_coef = 1;
5784 retina_coef = GetContentScaleFactor();
5795 double true_scale_display =
5796 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5801 if (m_displayed_scale_factor > 10.0)
5802 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5803 m_displayed_scale_factor);
5804 else if (m_displayed_scale_factor > 1.0)
5805 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5806 m_displayed_scale_factor);
5807 else if (m_displayed_scale_factor > 0.1) {
5808 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5809 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5810 }
else if (m_displayed_scale_factor > 0.01) {
5811 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5812 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5815 _T(
"%s %4.0f (---)"), _(
"Scale"),
5816 true_scale_display);
5819 m_scaleValue = true_scale_display;
5821 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5823 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5824 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5826 bool b_noshow =
false;
5830 wxClientDC dc(parent_frame->GetStatusBar());
5832 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5833 dc.SetFont(*templateFont);
5834 dc.GetTextExtent(text, &w, &h);
5839 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5840 if (w && w > rect.width) {
5841 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5842 m_displayed_scale_factor);
5846 dc.GetTextExtent(text, &w, &h);
5848 if (w && w > rect.width) {
5854 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5859 m_vLat = VPoint.
clat;
5860 m_vLon = VPoint.
clon;
5874static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5878static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5879 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5881wxColour ChartCanvas::PredColor() {
5884 if (SHIP_NORMAL == m_ownship_state)
5885 return GetGlobalColor(_T (
"URED" ));
5887 else if (SHIP_LOWACCURACY == m_ownship_state)
5888 return GetGlobalColor(_T (
"YELO1" ));
5890 return GetGlobalColor(_T (
"NODTA" ));
5893wxColour ChartCanvas::ShipColor() {
5897 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5899 if (SHIP_LOWACCURACY == m_ownship_state)
5900 return GetGlobalColor(_T (
"YELO1" ));
5902 return GetGlobalColor(_T (
"URED" ));
5905void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5906 wxPoint2DDouble lShipMidPoint) {
5907 dc.SetPen(wxPen(PredColor(), 2));
5909 if (SHIP_NORMAL == m_ownship_state)
5910 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5912 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5914 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5915 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5917 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5919 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5920 lShipMidPoint.m_y + 12);
5923void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5924 wxPoint GPSOffsetPixels,
5925 wxPoint2DDouble lGPSPoint) {
5926 if (m_animationActive)
return;
5930 float ref_dim = m_display_size_mm / 24;
5931 ref_dim = wxMin(ref_dim, 12);
5932 ref_dim = wxMax(ref_dim, 6);
5935 cPred.Set(g_cog_predictor_color);
5936 if (cPred == wxNullColour) cPred = PredColor();
5943 double nominal_line_width_pix = wxMax(
5945 floor(m_pix_per_mm / 2));
5949 if (nominal_line_width_pix > g_cog_predictor_width)
5950 g_cog_predictor_width = nominal_line_width_pix;
5953 wxPoint lPredPoint, lHeadPoint;
5955 float pCog = std::isnan(gCog) ? 0 : gCog;
5956 float pSog = std::isnan(gSog) ? 0 : gSog;
5958 double pred_lat, pred_lon;
5959 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5960 &pred_lat, &pred_lon);
5971 float ndelta_pix = 10.;
5972 double hdg_pred_lat, hdg_pred_lon;
5973 bool b_render_hdt =
false;
5974 if (!std::isnan(gHdt)) {
5976 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5979 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5980 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5981 if (dist > ndelta_pix ) {
5982 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5983 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5988 wxPoint lShipMidPoint;
5989 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5990 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5991 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5992 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5994 if (lpp >= img_height / 2) {
5995 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5996 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5997 !std::isnan(gSog)) {
5999 float dash_length = ref_dim;
6000 wxDash dash_long[2];
6002 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6003 g_cog_predictor_width);
6004 dash_long[1] = dash_long[0] / 2.0;
6008 if (dash_length > 250.) {
6009 dash_long[0] = 250. / g_cog_predictor_width;
6010 dash_long[1] = dash_long[0] / 2;
6013 wxPen ppPen2(cPred, g_cog_predictor_width,
6014 (wxPenStyle)g_cog_predictor_style);
6015 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6016 ppPen2.SetDashes(2, dash_long);
6019 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6020 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6022 if (g_cog_predictor_width > 1) {
6023 float line_width = g_cog_predictor_width / 3.;
6025 wxDash dash_long3[2];
6026 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6027 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6029 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
6030 (wxPenStyle)g_cog_predictor_style);
6031 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6032 ppPen3.SetDashes(2, dash_long3);
6034 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6035 lGPSPoint.m_y + GPSOffsetPixels.y,
6036 lPredPoint.x + GPSOffsetPixels.x,
6037 lPredPoint.y + GPSOffsetPixels.y);
6040 if (g_cog_predictor_endmarker) {
6042 double png_pred_icon_scale_factor = .4;
6043 if (g_ShipScaleFactorExp > 1.0)
6044 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6045 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6049 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6050 (
float)(lPredPoint.x - lShipMidPoint.x));
6051 cog_rad += (float)PI;
6053 for (
int i = 0; i < 4; i++) {
6055 double pxa = (double)(s_png_pred_icon[j]);
6056 double pya = (double)(s_png_pred_icon[j + 1]);
6058 pya *= png_pred_icon_scale_factor;
6059 pxa *= png_pred_icon_scale_factor;
6061 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6062 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6064 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6065 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6069 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
6072 dc.SetBrush(wxBrush(cPred));
6074 dc.StrokePolygon(4, icon);
6081 float hdt_dash_length = ref_dim * 0.4;
6083 cPred.Set(g_ownship_HDTpredictor_color);
6084 if (cPred == wxNullColour) cPred = PredColor();
6086 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6087 : g_cog_predictor_width * 0.8);
6088 wxDash dash_short[2];
6090 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6093 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6096 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6097 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6098 ppPen2.SetDashes(2, dash_short);
6102 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6103 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6105 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6107 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
6109 if (g_ownship_HDTpredictor_endmarker) {
6110 double nominal_circle_size_pixels = wxMax(
6111 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6114 if (g_ShipScaleFactorExp > 1.0)
6115 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6117 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6118 lHeadPoint.y + GPSOffsetPixels.y,
6119 nominal_circle_size_pixels / 2);
6124 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6125 double factor = 1.00;
6126 if (g_pNavAidRadarRingsStepUnits == 1)
6128 else if (g_pNavAidRadarRingsStepUnits == 2) {
6129 if (std::isnan(gSog))
6134 factor *= g_fNavAidRadarRingsStep;
6138 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
6141 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6142 pow((
double)(lGPSPoint.m_y - r.y), 2));
6143 int pix_radius = (int)lpp;
6145 extern wxColor GetDimColor(wxColor c);
6146 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6148 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6151 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6153 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6154 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6158void ChartCanvas::ComputeShipScaleFactor(
6159 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6160 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6161 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6162 float screenResolution = m_pix_per_mm;
6165 double ship_bow_lat, ship_bow_lon;
6166 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6167 &ship_bow_lat, &ship_bow_lon);
6168 wxPoint lShipBowPoint;
6169 wxPoint2DDouble b_point =
6173 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6174 powf((
float)(b_point.m_y - a_point.m_y), 2));
6177 float shipLength_mm = shipLength_px / screenResolution;
6180 float ownship_min_mm = g_n_ownship_min_mm;
6181 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6184 float hdt_ant = icon_hdt + 180.;
6185 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6186 float dx = g_n_gps_antenna_offset_x / 1852.;
6187 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6195 if (shipLength_mm < ownship_min_mm) {
6196 dy /= shipLength_mm / ownship_min_mm;
6197 dx /= shipLength_mm / ownship_min_mm;
6200 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6202 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6203 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6209 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6210 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6212 float scale_factor = shipLength_px / ownShipLength;
6215 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6218 scale_factor = wxMax(scale_factor, scale_factor_min);
6220 scale_factor_y = scale_factor;
6221 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6222 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6225void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6226 if (!GetVP().IsValid())
return;
6228 wxPoint GPSOffsetPixels(0, 0);
6229 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6232 float pCog = std::isnan(gCog) ? 0 : gCog;
6233 float pSog = std::isnan(gSog) ? 0 : gSog;
6237 lShipMidPoint = lGPSPoint;
6241 float icon_hdt = pCog;
6242 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6245 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6249 double osd_head_lat, osd_head_lon;
6250 wxPoint osd_head_point;
6252 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6257 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6258 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6259 icon_rad += (float)PI;
6261 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6265 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6269 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6270 if (GetVP().chart_scale >
6273 ShipDrawLargeScale(dc, lShipMidPoint);
6279 if (m_pos_image_user)
6280 pos_image = m_pos_image_user->Copy();
6281 else if (SHIP_NORMAL == m_ownship_state)
6282 pos_image = m_pos_image_red->Copy();
6283 if (SHIP_LOWACCURACY == m_ownship_state)
6284 pos_image = m_pos_image_yellow->Copy();
6285 else if (SHIP_NORMAL != m_ownship_state)
6286 pos_image = m_pos_image_grey->Copy();
6289 if (m_pos_image_user) {
6290 pos_image = m_pos_image_user->Copy();
6292 if (SHIP_LOWACCURACY == m_ownship_state)
6293 pos_image = m_pos_image_user_yellow->Copy();
6294 else if (SHIP_NORMAL != m_ownship_state)
6295 pos_image = m_pos_image_user_grey->Copy();
6298 img_height = pos_image.GetHeight();
6300 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6301 g_OwnShipIconType > 0)
6303 int ownShipWidth = 22;
6304 int ownShipLength = 84;
6305 if (g_OwnShipIconType == 1) {
6306 ownShipWidth = pos_image.GetWidth();
6307 ownShipLength = pos_image.GetHeight();
6310 float scale_factor_x, scale_factor_y;
6311 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6312 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6313 scale_factor_x, scale_factor_y);
6315 if (g_OwnShipIconType == 1) {
6316 pos_image.Rescale(ownShipWidth * scale_factor_x,
6317 ownShipLength * scale_factor_y,
6318 wxIMAGE_QUALITY_HIGH);
6319 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6321 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6324 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6325 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6326 if (rot_image.GetAlpha(ip, jp) > 64)
6327 rot_image.SetAlpha(ip, jp, 255);
6329 wxBitmap os_bm(rot_image);
6331 int w = os_bm.GetWidth();
6332 int h = os_bm.GetHeight();
6335 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6336 lShipMidPoint.m_y - h / 2,
true);
6339 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6340 lShipMidPoint.m_y - h / 2);
6341 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6342 lShipMidPoint.m_y - h / 2 + h);
6345 else if (g_OwnShipIconType == 2) {
6346 wxPoint ownship_icon[10];
6348 for (
int i = 0; i < 10; i++) {
6350 float pxa = (float)(s_ownship_icon[j]);
6351 float pya = (float)(s_ownship_icon[j + 1]);
6352 pya *= scale_factor_y;
6353 pxa *= scale_factor_x;
6355 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6356 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6358 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6359 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6362 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6364 dc.SetBrush(wxBrush(ShipColor()));
6366 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6369 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6371 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6375 img_height = ownShipLength * scale_factor_y;
6379 if (m_pos_image_user) circle_rad = 1;
6381 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6382 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6383 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6386 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6388 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6391 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6392 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6393 if (rot_image.GetAlpha(ip, jp) > 64)
6394 rot_image.SetAlpha(ip, jp, 255);
6396 wxBitmap os_bm(rot_image);
6398 if (g_ShipScaleFactorExp > 1) {
6399 wxImage scaled_image = os_bm.ConvertToImage();
6400 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6402 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6403 scaled_image.GetHeight() * factor,
6404 wxIMAGE_QUALITY_HIGH));
6406 int w = os_bm.GetWidth();
6407 int h = os_bm.GetHeight();
6410 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6411 lShipMidPoint.m_y - h / 2,
true);
6415 if (m_pos_image_user) circle_rad = 1;
6417 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6418 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6419 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6422 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6423 lShipMidPoint.m_y - h / 2);
6424 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6425 lShipMidPoint.m_y - h / 2 + h);
6430 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6443void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6444 float &MinorSpacing) {
6449 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6450 {.000001f, 45.0f, 15.0f},
6451 {.0002f, 30.0f, 10.0f},
6452 {.0003f, 10.0f, 2.0f},
6453 {.0008f, 5.0f, 1.0f},
6454 {.001f, 2.0f, 30.0f / 60.0f},
6455 {.003f, 1.0f, 20.0f / 60.0f},
6456 {.006f, 0.5f, 10.0f / 60.0f},
6457 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6458 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6459 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6460 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6461 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6462 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6463 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6464 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6467 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6468 if (view_scale_ppm < lltab[tabi][0])
break;
6469 MajorSpacing = lltab[tabi][1];
6470 MinorSpacing = lltab[tabi][2];
6484wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6485 int deg = (int)fabs(latlon);
6486 float min = fabs((fabs(latlon) - deg) * 60.0);
6496 }
else if (latlon < 0.0) {
6508 if (spacing >= 1.0) {
6509 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6510 }
else if (spacing >= (1.0 / 60.0)) {
6511 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6513 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6530void ChartCanvas::GridDraw(
ocpnDC &dc) {
6531 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6533 double nlat, elon, slat, wlon;
6536 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6538 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6540 dc.SetFont(*m_pgridFont);
6541 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6544 h = m_canvas_height;
6555 dlon = dlon + 360.0;
6558 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6561 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6564 while (lat < nlat) {
6567 CalcGridText(lat, gridlatMajor,
true);
6569 dc.
DrawLine(0, r.y, w, r.y,
false);
6570 dc.DrawText(st, 0, r.y);
6571 lat = lat + gridlatMajor;
6573 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6577 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6580 while (lat < nlat) {
6583 dc.
DrawLine(0, r.y, 10, r.y,
false);
6584 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6585 lat = lat + gridlatMinor;
6589 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6592 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6595 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6597 wxString st = CalcGridText(lon, gridlonMajor,
false);
6599 dc.
DrawLine(r.x, 0, r.x, h,
false);
6600 dc.DrawText(st, r.x, 0);
6601 lon = lon + gridlonMajor;
6606 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6610 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6612 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6615 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6616 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6617 lon = lon + gridlonMinor;
6624void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6626 double blat, blon, tlat, tlon;
6629 int x_origin = m_bDisplayGrid ? 60 : 20;
6630 int y_origin = m_canvas_height - 50;
6636 if (GetVP().chart_scale > 80000)
6640 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6641 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6646 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6647 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6651 double rotation = -VPoint.
rotation;
6653 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6655 int l1 = (y_origin - r.y) / count;
6657 for (
int i = 0; i < count; i++) {
6664 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6667 double blat, blon, tlat, tlon;
6674 int y_origin = m_canvas_height - chartbar_height - 5;
6678 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6685 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6688 int unit = g_iDistanceFormat;
6690 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6691 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6694 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6695 float places = floor(logdist), rem = logdist - places;
6696 dist = pow(10, places);
6703 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6704 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6705 double rotation = -VPoint.
rotation;
6707 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6711 int l1 = r.x - x_origin;
6713 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6718 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6719 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6720 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6722 dc.SetFont(*m_pgridFont);
6723 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6725 dc.GetTextExtent(s, &w, &h);
6726 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6730void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6735 double ra_max = 40.;
6737 wxPen pen_save = dc.GetPen();
6739 wxDateTime now = wxDateTime::Now();
6745 x0 = x1 = x + radius;
6750 while (angle < 360.) {
6751 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6754 if (angle > 360.) angle = 360.;
6756 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6764 x1 = (int)(x + cos(angle * PI / 180.) * r);
6765 y1 = (int)(y + sin(angle * PI / 180.) * r);
6775 dc.
DrawLine(x + radius, y, x1, y1);
6777 dc.SetPen(pen_save);
6780static bool bAnchorSoundPlaying =
false;
6782static void onAnchorSoundFinished(
void *ptr) {
6783 g_anchorwatch_sound->UnLoad();
6784 bAnchorSoundPlaying =
false;
6787void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6789 bool play_sound =
false;
6790 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6791 if (AnchorAlertOn1) {
6792 wxPoint TargetPoint;
6795 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6796 TargetPoint.y, 100);
6800 AnchorAlertOn1 =
false;
6802 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6803 if (AnchorAlertOn2) {
6804 wxPoint TargetPoint;
6807 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6808 TargetPoint.y, 100);
6812 AnchorAlertOn2 =
false;
6815 if (!bAnchorSoundPlaying) {
6816 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6817 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6818 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6819 if (g_anchorwatch_sound->IsOk()) {
6820 bAnchorSoundPlaying =
true;
6821 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6822 g_anchorwatch_sound->Play();
6828void ChartCanvas::UpdateShips() {
6831 wxClientDC dc(
this);
6832 if (!dc.IsOk())
return;
6834 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6835 if (!test_bitmap.IsOk())
return;
6837 wxMemoryDC temp_dc(test_bitmap);
6839 temp_dc.ResetBoundingBox();
6840 temp_dc.DestroyClippingRegion();
6841 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6847 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6848 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6852 ocpndc.CalcBoundingBox(px.x, px.y);
6857 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6858 temp_dc.MaxY() - temp_dc.MinY());
6860 wxRect own_ship_update_rect = ship_draw_rect;
6862 if (!own_ship_update_rect.IsEmpty()) {
6865 own_ship_update_rect.Union(ship_draw_last_rect);
6866 own_ship_update_rect.Inflate(2);
6869 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6871 ship_draw_last_rect = ship_draw_rect;
6873 temp_dc.SelectObject(wxNullBitmap);
6876void ChartCanvas::UpdateAlerts() {
6881 wxClientDC dc(
this);
6885 dc.GetSize(&sx, &sy);
6888 wxBitmap test_bitmap(sx, sy, -1);
6892 temp_dc.SelectObject(test_bitmap);
6894 temp_dc.ResetBoundingBox();
6895 temp_dc.DestroyClippingRegion();
6896 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6903 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6904 temp_dc.MaxX() - temp_dc.MinX(),
6905 temp_dc.MaxY() - temp_dc.MinY());
6907 if (!alert_rect.IsEmpty())
6908 alert_rect.Inflate(2);
6910 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6913 wxRect alert_update_rect = alert_draw_rect;
6914 alert_update_rect.Union(alert_rect);
6917 RefreshRect(alert_update_rect,
false);
6921 alert_draw_rect = alert_rect;
6923 temp_dc.SelectObject(wxNullBitmap);
6926void ChartCanvas::UpdateAIS() {
6927 if (!g_pAIS)
return;
6932 wxClientDC dc(
this);
6936 dc.GetSize(&sx, &sy);
6944 if (g_pAIS->GetTargetList().size() > 10) {
6945 ais_rect = wxRect(0, 0, sx, sy);
6948 wxBitmap test_bitmap(sx, sy, -1);
6952 temp_dc.SelectObject(test_bitmap);
6954 temp_dc.ResetBoundingBox();
6955 temp_dc.DestroyClippingRegion();
6956 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6960 AISDraw(ocpndc, GetVP(),
this);
6961 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6965 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6966 temp_dc.MaxY() - temp_dc.MinY());
6968 if (!ais_rect.IsEmpty())
6969 ais_rect.Inflate(2);
6971 temp_dc.SelectObject(wxNullBitmap);
6974 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6977 wxRect ais_update_rect = ais_draw_rect;
6978 ais_update_rect.Union(ais_rect);
6981 RefreshRect(ais_update_rect,
false);
6985 ais_draw_rect = ais_rect;
6988void ChartCanvas::ToggleCPAWarn() {
6989 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6995 g_bTCPA_Max =
false;
6999 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
7000 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7002 if (!g_AisFirstTimeUse) {
7003 OCPNMessageBox(
this,
7004 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
7005 _(
"CPA") + _T(
" ") + mess, 4, 4);
7010void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7012void ChartCanvas::OnSize(wxSizeEvent &event) {
7013 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7015 GetClientSize(&m_canvas_width, &m_canvas_height);
7019 m_displayScale = GetContentScaleFactor();
7023 m_canvas_width *= m_displayScale;
7024 m_canvas_height *= m_displayScale;
7037 m_absolute_min_scale_ppm =
7039 (1.2 * WGS84_semimajor_axis_meters * PI);
7042 gFrame->ProcessCanvasResize();
7052 SetMUIBarPosition();
7053 UpdateFollowButtonState();
7054 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7058 xr_margin = m_canvas_width * 95 / 100;
7059 xl_margin = m_canvas_width * 5 / 100;
7060 yt_margin = m_canvas_height * 5 / 100;
7061 yb_margin = m_canvas_height * 95 / 100;
7064 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7069 m_brepaint_piano =
true;
7072 m_dc_route.SelectObject(wxNullBitmap);
7075 m_dc_route.SelectObject(*proute_bm);
7089 m_glcc->OnSize(event);
7098void ChartCanvas::ProcessNewGUIScale() {
7106void ChartCanvas::CreateMUIBar() {
7107 if (g_useMUI && !m_muiBar) {
7111 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
7113 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7114 m_muiBar->SetColorScheme(m_cs);
7115 m_muiBarHOSize = m_muiBar->m_size;
7119 SetMUIBarPosition();
7120 UpdateFollowButtonState();
7121 m_muiBar->UpdateDynamicValues();
7122 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7126void ChartCanvas::SetMUIBarPosition() {
7130 int pianoWidth = GetClientSize().x * 0.6f;
7135 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7136 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7138 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7139 m_muiBar->SetColorScheme(m_cs);
7143 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7144 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7146 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7147 m_muiBar->SetColorScheme(m_cs);
7151 m_muiBar->SetBestPosition();
7155void ChartCanvas::DestroyMuiBar() {
7162void ChartCanvas::ShowCompositeInfoWindow(
7163 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7165 if (NULL == m_pCIWin) {
7170 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7173 s = _(
"Composite of ");
7176 s1.Printf(
"%d ", n_charts);
7184 s1.Printf(_(
"Chart scale"));
7187 s2.Printf(
"1:%d\n",
scale);
7191 s1 = _(
"Zoom in for more information");
7195 int char_width = s1.Length();
7196 int char_height = 3;
7198 if (g_bChartBarEx) {
7201 for (
int i : index_vector) {
7203 wxString path = cte.GetFullSystemPath();
7207 char_width = wxMax(char_width, path.Length());
7208 if (j++ >= 9)
break;
7211 s +=
" .\n .\n .\n";
7220 m_pCIWin->SetString(s);
7222 m_pCIWin->FitToChars(char_width, char_height);
7225 p.x = x / GetContentScaleFactor();
7226 if ((p.x + m_pCIWin->GetWinSize().x) >
7227 (m_canvas_width / GetContentScaleFactor()))
7228 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7229 m_pCIWin->GetWinSize().x) /
7232 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7233 4 - m_pCIWin->GetWinSize().y;
7235 m_pCIWin->dbIndex = 0;
7236 m_pCIWin->chart_scale = 0;
7237 m_pCIWin->SetPosition(p);
7238 m_pCIWin->SetBitmap();
7239 m_pCIWin->Refresh();
7243 HideChartInfoWindow();
7247void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7249 if (NULL == m_pCIWin) {
7254 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7261 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
7262 pc = ChartData->OpenChartFromDBAndLock(
7263 dbIndex, FULL_INIT);
7265 int char_width, char_height;
7266 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7267 if (pc) ChartData->UnLockCacheChart(dbIndex);
7269 m_pCIWin->SetString(s);
7270 m_pCIWin->FitToChars(char_width, char_height);
7273 p.x = x / GetContentScaleFactor();
7274 if ((p.x + m_pCIWin->GetWinSize().x) >
7275 (m_canvas_width / GetContentScaleFactor()))
7276 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7277 m_pCIWin->GetWinSize().x) /
7280 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7281 4 - m_pCIWin->GetWinSize().y;
7283 m_pCIWin->dbIndex = dbIndex;
7284 m_pCIWin->SetPosition(p);
7285 m_pCIWin->SetBitmap();
7286 m_pCIWin->Refresh();
7290 HideChartInfoWindow();
7294void ChartCanvas::HideChartInfoWindow(
void) {
7297 m_pCIWin->Destroy();
7301 androidForceFullRepaint();
7306void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7307 wxMouseEvent ev(wxEVT_MOTION);
7310 ev.m_leftDown = mouse_leftisdown;
7312 wxEvtHandler *evthp = GetEventHandler();
7314 ::wxPostEvent(evthp, ev);
7317void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7318 if ((m_panx_target_final - m_panx_target_now) ||
7319 (m_pany_target_final - m_pany_target_now)) {
7320 DoTimedMovementTarget();
7325void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7327bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7329 if (m_disable_edge_pan)
return false;
7332 int pan_margin = m_canvas_width * margin / 100;
7333 int pan_timer_set = 200;
7334 double pan_delta = GetVP().
pix_width * delta / 100;
7338 if (x > m_canvas_width - pan_margin) {
7343 else if (x < pan_margin) {
7348 if (y < pan_margin) {
7353 else if (y > m_canvas_height - pan_margin) {
7362 wxMouseState state = ::wxGetMouseState();
7363#if wxCHECK_VERSION(3, 0, 0)
7364 if (!state.LeftIsDown())
7366 if (!state.LeftDown())
7371 if ((bft) && !pPanTimer->IsRunning()) {
7373 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7379 if ((!bft) && pPanTimer->IsRunning()) {
7389void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7390 bool setBeingEdited) {
7391 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7392 m_pRoutePointEditTarget = NULL;
7393 m_pFoundPoint = NULL;
7397 SelectableItemList SelList = pSelect->FindSelectionList(
7399 wxSelectableItemListNode *node = SelList.GetFirst();
7401 pFind = node->GetData();
7410 bool brp_viz =
false;
7411 if (m_pEditRouteArray) {
7412 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7413 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7414 if (pr->IsVisible()) {
7420 brp_viz = frp->IsVisible();
7424 if (m_pEditRouteArray)
7426 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7427 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7430 m_bRouteEditing = setBeingEdited;
7433 frp->m_bRPIsBeingEdited = setBeingEdited;
7434 m_bMarkEditing = setBeingEdited;
7437 m_pRoutePointEditTarget = frp;
7438 m_pFoundPoint = pFind;
7442 node = node->GetNext();
7446void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7447 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7448 singleClickEventIsValid =
false;
7449 m_DoubleClickTimer->Stop();
7454bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7455 if (!m_bChartDragging && !m_bDrawingRoute) {
7460 if (m_Compass && m_Compass->IsShown()) {
7462 bool isInCompass = logicalRect.Contains(event.GetPosition());
7464 if (m_Compass->MouseEvent(event)) {
7465 cursor_region = CENTER;
7466 if (!g_btouch) SetCanvasCursor(event);
7472 if (m_notification_button && m_notification_button->IsShown()) {
7474 bool isinButton = logicalRect.Contains(event.GetPosition());
7476 SetCursor(*pCursorArrow);
7477 if (event.LeftDown()) HandleNotificationMouseClick();
7482 if (MouseEventToolbar(event))
return true;
7484 if (MouseEventChartBar(event))
return true;
7486 if (MouseEventMUIBar(event))
return true;
7488 if (MouseEventIENCBar(event))
return true;
7493void ChartCanvas::HandleNotificationMouseClick() {
7494 if (!m_NotificationsList) {
7499 wxPoint ClientUpperRight = ClientToScreen(wxPoint(GetSize().x, 0));
7500 wxPoint list_bottom = ClientToScreen(wxPoint(0, GetSize().y / 2));
7501 int size_y = list_bottom.y - (ClientUpperRight.y + 5);
7502 size_y -= GetCharHeight();
7503 size_y = wxMax(size_y, 200);
7505 m_NotificationsList->SetSize(wxSize(GetCharWidth() * 80, size_y));
7507 wxPoint m_currentNLPos = ClientToScreen(wxPoint(
7508 GetSize().x / 2, m_notification_button->
GetRect().y +
7509 m_notification_button->
GetRect().height + 5));
7511 m_NotificationsList->Move(m_currentNLPos);
7512 m_NotificationsList->Hide();
7515 if (m_NotificationsList->IsShown()) {
7516 m_NotificationsList->Hide();
7518 m_NotificationsList->ReloadNotificationList();
7519 m_NotificationsList->Show();
7522bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7523 if (!g_bShowChartBar)
return false;
7525 if (!m_Piano->MouseEvent(event))
return false;
7527 cursor_region = CENTER;
7528 if (!g_btouch) SetCanvasCursor(event);
7532bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7533 if (!IsPrimaryCanvas())
return false;
7535 if (g_MainToolbar) {
7536 if (!g_MainToolbar->MouseEvent(event))
7539 g_MainToolbar->RefreshToolbar();
7542 cursor_region = CENTER;
7543 if (!g_btouch) SetCanvasCursor(event);
7547bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7548 if (!IsPrimaryCanvas())
return false;
7550 if (g_iENCToolbar) {
7551 if (!g_iENCToolbar->MouseEvent(event))
7554 g_iENCToolbar->RefreshToolbar();
7561bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7563 if (!m_muiBar->MouseEvent(event))
return false;
7566 cursor_region = CENTER;
7567 if (!g_btouch) SetCanvasCursor(event);
7579 event.GetPosition(&x, &y);
7581 x *= m_displayScale;
7582 y *= m_displayScale;
7584 m_MouseDragging =
event.Dragging();
7590 if (event.Dragging()) {
7591 if ((x == mouse_x) && (y == mouse_y))
return true;
7597 mouse_leftisdown =
event.LeftDown();
7601 cursor_region = CENTER;
7605 if (m_Compass && m_Compass->IsShown() &&
7606 m_Compass->
GetRect().Contains(event.GetPosition())) {
7607 cursor_region = CENTER;
7608 }
else if (x > xr_margin) {
7609 cursor_region = MID_RIGHT;
7610 }
else if (x < xl_margin) {
7611 cursor_region = MID_LEFT;
7612 }
else if (y > yb_margin - chartbar_height &&
7613 y < m_canvas_height - chartbar_height) {
7614 cursor_region = MID_TOP;
7615 }
else if (y < yt_margin) {
7616 cursor_region = MID_BOT;
7618 cursor_region = CENTER;
7621 if (!g_btouch) SetCanvasCursor(event);
7625 leftIsDown =
event.LeftDown();
7628 if (event.LeftDown()) {
7629 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7632 g_bTempShowMenuBar =
false;
7633 parent_frame->ApplyGlobalSettings(
false);
7641 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7642 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7646 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7647 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7650 event.SetEventObject(
this);
7651 if (SendMouseEventToPlugins(event))
7658 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7659 StartChartDragInertia();
7662 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7664 if (m_DoubleClickTimer->IsRunning()) {
7665 m_DoubleClickTimer->Stop();
7670 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7671 singleClickEvent = event;
7672 singleClickEventIsValid =
true;
7681 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7682 if (g_click_stop > 0) {
7690 if (GetUpMode() == COURSE_UP_MODE) {
7691 m_b_rot_hidef =
false;
7692 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7694 pRotDefTimer->Stop();
7697 bool bRoll = !g_btouch;
7699 bRoll = g_bRollover;
7702 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7703 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7704 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7705 m_RolloverPopupTimer.Start(
7709 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7713 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7722#if !defined(__WXGTK__) && !defined(__WXQT__)
7730 if ((x >= 0) && (y >= 0))
7735 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7736 wxPoint p = ClientToScreen(wxPoint(x, y));
7742 if (m_routeState >= 2) {
7745 m_bDrawingRoute =
true;
7747 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7752 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7755 m_bDrawingRoute =
true;
7757 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7764void ChartCanvas::CallPopupMenu(
int x,
int y) {
7772 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7781#if defined(__WXMAC__) || defined(__ANDROID__)
7785 wxClientDC cdc(GetParent());
7797 if (m_pSelectedRoute) {
7799 m_pSelectedRoute->DeSelectRoute();
7801 if (g_bopengl && m_glcc) {
7806 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7809 if (m_pFoundRoutePoint) {
7810 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7812 RefreshRect(m_pFoundRoutePoint->CurrentRect_in_DC);
7817 if (g_btouch && m_pRoutePointEditTarget) {
7818 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7819 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7820 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7825 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7826 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7827 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7828 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7832 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7835 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7841 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7844 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7845 seltype |= SELTYPE_AISTARGET;
7850 m_pFoundRoutePoint = NULL;
7855 Route *pSelectedActiveRoute = NULL;
7856 Route *pSelectedVizRoute = NULL;
7860 SelectableItemList SelList =
7861 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7862 wxSelectableItemListNode *node = SelList.GetFirst();
7872 bool brp_viz =
false;
7874 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7876 if (pr->IsVisible()) {
7881 if (!brp_viz && prp->IsShared())
7883 brp_viz = prp->IsVisible();
7886 brp_viz = prp->IsVisible();
7888 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7893 m_pSelectedRoute = NULL;
7895 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7898 pSelectedActiveRoute = pr;
7899 pFoundActiveRoutePoint = prp;
7904 if (NULL == pSelectedVizRoute) {
7905 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7907 if (pr->IsVisible()) {
7908 pSelectedVizRoute = pr;
7909 pFoundVizRoutePoint = prp;
7915 delete proute_array;
7918 node = node->GetNext();
7922 if (pFoundActiveRoutePoint) {
7923 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7924 m_pSelectedRoute = pSelectedActiveRoute;
7925 }
else if (pFoundVizRoutePoint) {
7926 m_pFoundRoutePoint = pFoundVizRoutePoint;
7927 m_pSelectedRoute = pSelectedVizRoute;
7930 m_pFoundRoutePoint = pFirstVizPoint;
7932 if (m_pSelectedRoute) {
7933 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7934 }
else if (m_pFoundRoutePoint)
7935 seltype |= SELTYPE_MARKPOINT;
7939 if (m_pFoundRoutePoint) {
7940 m_pFoundRoutePoint->m_bPtIsSelected =
true;
7943 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7944 RefreshRect(wp_rect,
true);
7953 SelectableItemList SelList =
7954 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7956 if (NULL == m_pSelectedRoute)
7959 wxSelectableItemListNode *node = SelList.GetFirst();
7964 if (pr->IsVisible()) {
7965 m_pSelectedRoute = pr;
7968 node = node->GetNext();
7972 if (m_pSelectedRoute) {
7973 if (NULL == m_pFoundRoutePoint)
7974 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7979 if (g_bopengl && m_glcc) {
7984 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7987 seltype |= SELTYPE_ROUTESEGMENT;
7991 if (pFindTrackSeg) {
7992 m_pSelectedTrack = NULL;
7994 SelectableItemList SelList =
7995 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7998 wxSelectableItemListNode *node = SelList.GetFirst();
8003 if (pt->IsVisible()) {
8004 m_pSelectedTrack = pt;
8007 node = node->GetNext();
8010 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8013 bool bseltc =
false;
8027 SelectableItemList SelList = pSelectTC->FindSelectionList(
8031 wxSelectableItemListNode *node = SelList.GetFirst();
8032 pFind = node->GetData();
8033 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8035 if (SelList.GetCount() > 1) {
8036 node = node->GetNext();
8038 pFind = node->GetData();
8040 if (pIDX_candidate->
IDX_type ==
'c') {
8041 pIDX_best_candidate = pIDX_candidate;
8045 node = node->GetNext();
8048 wxSelectableItemListNode *node = SelList.GetFirst();
8049 pFind = node->GetData();
8050 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8053 m_pIDXCandidate = pIDX_best_candidate;
8056 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
8060 seltype |= SELTYPE_CURRENTPOINT;
8063 else if (pFindTide) {
8064 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8067 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
8071 seltype |= SELTYPE_TIDEPOINT;
8075 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8078 InvokeCanvasMenu(x, y, seltype);
8081 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8085 m_pSelectedRoute = NULL;
8087 if (m_pFoundRoutePoint) {
8088 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8089 m_pFoundRoutePoint->m_bPtIsSelected =
false;
8091 m_pFoundRoutePoint = NULL;
8099bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8107 event.GetPosition(&x, &y);
8113 SelectRadius = g_Platform->GetSelectRadiusPix() /
8114 (m_true_scale_ppm * 1852 * 60);
8121 if (event.LeftDClick() && (cursor_region == CENTER)) {
8122 m_DoubleClickTimer->Start();
8123 singleClickEventIsValid =
false;
8127 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8132 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8135 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8136 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8137 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8143 SelectableItemList rpSelList =
8144 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8145 wxSelectableItemListNode *node = rpSelList.GetFirst();
8146 bool b_onRPtarget =
false;
8150 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8151 b_onRPtarget =
true;
8154 node = node->GetNext();
8159 if (m_pRoutePointEditTarget) {
8161 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8164 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8165 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8167 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8170 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8171 m_pRoutePointEditTarget = NULL;
8172 RefreshRect(wp_rect,
true);
8176 node = rpSelList.GetFirst();
8181 wxArrayPtrVoid *proute_array =
8186 bool brp_viz =
false;
8188 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8190 if (pr->IsVisible()) {
8195 delete proute_array;
8199 brp_viz = frp->IsVisible();
8201 brp_viz = frp->IsVisible();
8204 ShowMarkPropertiesDialog(frp);
8212 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8216 if (pr->IsVisible()) {
8217 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8222 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8226 if (pt->IsVisible()) {
8227 ShowTrackPropertiesDialog(pt);
8234 ShowObjectQueryWindow(x, y, zlat, zlon);
8239 if (event.LeftDown()) {
8255 bool appending =
false;
8256 bool inserting =
false;
8259 SetCursor(*pCursorPencil);
8263 m_bRouteEditing =
true;
8265 if (m_routeState == 1) {
8266 m_pMouseRoute =
new Route();
8267 pRouteList->Append(m_pMouseRoute);
8276 double nearby_radius_meters =
8277 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8280 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8281 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8282 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8283 wxArrayPtrVoid *proute_array =
8288 bool brp_viz =
false;
8290 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8292 if (pr->IsVisible()) {
8297 delete proute_array;
8299 pNearbyPoint->IsShared())
8302 pNearbyPoint->IsVisible();
8304 brp_viz = pNearbyPoint->IsVisible();
8307 wxString msg = _(
"Use nearby waypoint?");
8309 const bool noname(pNearbyPoint->GetName() ==
"");
8312 _(
"Use nearby nameless waypoint and name it M with"
8313 " a unique number?");
8316 m_FinishRouteOnKillFocus =
false;
8318 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8319 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8320 m_FinishRouteOnKillFocus =
true;
8321 if (dlg_return == wxID_YES) {
8323 if (m_pMouseRoute) {
8324 int last_wp_num = m_pMouseRoute->GetnPoints();
8326 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8327 wxString wp_name = wxString::Format(
8328 "M%002i-%s", last_wp_num + 1, guid_short);
8329 pNearbyPoint->SetName(wp_name);
8331 pNearbyPoint->SetName(
"WPXX");
8333 pMousePoint = pNearbyPoint;
8336 if (m_routeState > 1)
8337 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8338 Undo_HasParent, NULL);
8341 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8342 bool procede =
false;
8346 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8352 m_FinishRouteOnKillFocus =
false;
8358 _(
"Insert first part of this route in the new route?");
8359 if (tail->GetIndexOf(pMousePoint) ==
8362 dmsg = _(
"Insert this route in the new route?");
8364 if (tail->GetIndexOf(pMousePoint) != 1) {
8365 dlg_return = OCPNMessageBox(
8366 this, dmsg, _(
"OpenCPN Route Create"),
8367 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8368 m_FinishRouteOnKillFocus =
true;
8370 if (dlg_return == wxID_YES) {
8377 _(
"Append last part of this route to the new route?");
8378 if (tail->GetIndexOf(pMousePoint) == 1)
8380 "Append this route to the new route?");
8385 if (tail->GetLastPoint() != pMousePoint) {
8386 dlg_return = OCPNMessageBox(
8387 this, dmsg, _(
"OpenCPN Route Create"),
8388 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8389 m_FinishRouteOnKillFocus =
true;
8391 if (dlg_return == wxID_YES) {
8402 if (!FindRouteContainingWaypoint(pMousePoint))
8403 pMousePoint->SetShared(
true);
8408 if (NULL == pMousePoint) {
8409 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8410 _T(
""), wxEmptyString);
8411 pMousePoint->SetNameShown(
false);
8413 pConfig->AddNewWayPoint(pMousePoint, -1);
8414 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8416 if (m_routeState > 1)
8417 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8418 Undo_IsOrphanded, NULL);
8421 if (m_pMouseRoute) {
8422 if (m_routeState == 1) {
8424 m_pMouseRoute->AddPoint(pMousePoint);
8427 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8428 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8429 &rhumbBearing, &rhumbDist);
8430 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8431 rlat, &gcDist, &gcBearing, NULL);
8432 double gcDistNM = gcDist / 1852.0;
8435 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8436 pow(rhumbDist - gcDistNM - 1, 0.5);
8439 msg << _(
"For this leg the Great Circle route is ")
8440 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8441 << _(
" shorter than rhumbline.\n\n")
8442 << _(
"Would you like include the Great Circle routing points "
8445 m_FinishRouteOnKillFocus =
false;
8446 m_disable_edge_pan =
true;
8449 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8450 wxYES_NO | wxNO_DEFAULT);
8452 m_disable_edge_pan =
false;
8453 m_FinishRouteOnKillFocus =
true;
8455 if (answer == wxID_YES) {
8457 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8458 wxRealPoint gcCoord;
8460 for (
int i = 1; i <= segmentCount; i++) {
8461 double fraction = (double)i * (1.0 / (
double)segmentCount);
8462 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8463 gcDist * fraction, gcBearing,
8464 &gcCoord.x, &gcCoord.y, NULL);
8466 if (i < segmentCount) {
8467 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8468 _T(
""), wxEmptyString);
8469 gcPoint->SetNameShown(
false);
8470 pConfig->AddNewWayPoint(gcPoint, -1);
8471 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8474 gcPoint = pMousePoint;
8477 m_pMouseRoute->AddPoint(gcPoint);
8478 pSelect->AddSelectableRouteSegment(
8479 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8480 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8481 prevGcPoint = gcPoint;
8484 undo->CancelUndoableAction(
true);
8487 m_pMouseRoute->AddPoint(pMousePoint);
8488 pSelect->AddSelectableRouteSegment(
8489 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8490 pMousePoint, m_pMouseRoute);
8491 undo->AfterUndoableAction(m_pMouseRoute);
8495 m_pMouseRoute->AddPoint(pMousePoint);
8496 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8497 rlon, m_prev_pMousePoint,
8498 pMousePoint, m_pMouseRoute);
8499 undo->AfterUndoableAction(m_pMouseRoute);
8505 m_prev_pMousePoint = pMousePoint;
8513 int connect = tail->GetIndexOf(pMousePoint);
8518 int length = tail->GetnPoints();
8523 start = connect + 1;
8528 m_pMouseRoute->RemovePoint(
8532 for (i = start; i <= stop; i++) {
8533 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8536 m_pMouseRoute->GetnPoints();
8538 gFrame->RefreshAllCanvas();
8542 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8544 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8545 m_pMouseRoute->FinalizeForRendering();
8547 gFrame->RefreshAllCanvas();
8551 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8553 SetCursor(*pCursorPencil);
8555 if (!m_pMeasureRoute) {
8556 m_pMeasureRoute =
new Route();
8557 pRouteList->Append(m_pMeasureRoute);
8560 if (m_nMeasureState == 1) {
8566 wxString(_T (
"circle" )),
8567 wxEmptyString, wxEmptyString);
8568 pMousePoint->m_bShowName =
false;
8569 pMousePoint->SetShowWaypointRangeRings(
false);
8571 m_pMeasureRoute->AddPoint(pMousePoint);
8575 m_prev_pMousePoint = pMousePoint;
8579 gFrame->RefreshAllCanvas();
8584 FindRoutePointsAtCursor(SelectRadius,
true);
8589 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8597 if (ret)
return true;
8600 if (event.Dragging()) {
8605 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8607 SelectableItemList SelList = pSelect->FindSelectionList(
8609 wxSelectableItemListNode *node = SelList.GetFirst();
8611 pFind = node->GetData();
8613 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8614 node = node->GetNext();
8619 if (m_pRoutePointEditTarget &&
8620 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8622 SelectableItemList SelList = pSelect->FindSelectionList(
8624 wxSelectableItemListNode *node = SelList.GetFirst();
8626 pFind = node->GetData();
8628 if (m_pRoutePointEditTarget == frp) {
8629 m_bIsInRadius =
true;
8632 node = node->GetNext();
8635 if (!m_dragoffsetSet) {
8637 .PresetDragOffset(
this, mouse_x, mouse_y);
8638 m_dragoffsetSet =
true;
8643 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8644 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8646 if (NULL == g_pMarkInfoDialog) {
8647 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8648 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8649 DraggingAllowed =
false;
8651 if (m_pRoutePointEditTarget &&
8652 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8653 DraggingAllowed =
false;
8655 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8657 if (DraggingAllowed) {
8658 if (!undo->InUndoableAction()) {
8659 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8660 Undo_NeedsCopy, m_pFoundPoint);
8666 if (!g_bopengl && m_pEditRouteArray) {
8667 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8668 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8673 if (g_pRouteMan->IsRouteValid(pr)) {
8675 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8676 pre_rect.Union(route_rect);
8684 if (CheckEdgePan(x, y,
true, 5, 2))
8692 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8694 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8695 m_pRoutePointEditTarget,
8696 SELTYPE_DRAGHANDLE);
8697 m_pFoundPoint->m_slat =
8698 m_pRoutePointEditTarget->m_lat;
8699 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8701 m_pRoutePointEditTarget->m_lat =
8703 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8704 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8705 m_pFoundPoint->m_slat =
8707 m_pFoundPoint->m_slon = new_cursor_lon;
8711 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8712 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8713 g_pMarkInfoDialog->UpdateProperties(
true);
8723 if (m_pEditRouteArray) {
8724 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8726 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8727 if (g_pRouteMan->IsRouteValid(pr)) {
8729 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8730 post_rect.Union(route_rect);
8736 pre_rect.Union(post_rect);
8737 RefreshRect(pre_rect,
false);
8739 gFrame->RefreshCanvasOther(
this);
8740 m_bRoutePoinDragging =
true;
8745 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8746 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8748 if (NULL == g_pMarkInfoDialog) {
8749 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8750 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8751 DraggingAllowed =
false;
8753 if (m_pRoutePointEditTarget &&
8754 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8755 DraggingAllowed =
false;
8757 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8759 if (DraggingAllowed) {
8760 if (!undo->InUndoableAction()) {
8761 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8762 Undo_NeedsCopy, m_pFoundPoint);
8770 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8771 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8773 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8774 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8776 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8782 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8783 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8784 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8785 (
int)(lppmax - (pre_rect.height / 2)));
8793 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8796 m_pRoutePointEditTarget,
8797 SELTYPE_DRAGHANDLE);
8798 m_pFoundPoint->m_slat =
8799 m_pRoutePointEditTarget->m_lat;
8800 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8802 m_pRoutePointEditTarget->m_lat =
8805 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8811 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8812 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8813 g_pMarkInfoDialog->UpdateProperties(
true);
8818 if (!g_btouch) InvalidateGL();
8824 .CalculateDCRect(m_dc_route,
this, &post_rect);
8825 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8826 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8827 (
int)(lppmax - (post_rect.height / 2)));
8830 pre_rect.Union(post_rect);
8831 RefreshRect(pre_rect,
false);
8833 gFrame->RefreshCanvasOther(
this);
8834 m_bRoutePoinDragging =
true;
8839 if (ret)
return true;
8842 if (event.LeftUp()) {
8843 bool b_startedit_route =
false;
8844 m_dragoffsetSet =
false;
8847 m_bChartDragging =
false;
8848 m_bIsInRadius =
false;
8853 m_bedge_pan =
false;
8858 bool appending =
false;
8859 bool inserting =
false;
8865 if (m_pRoutePointEditTarget) {
8866 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8867 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8871 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8872 RefreshRect(wp_rect,
true);
8874 m_pRoutePointEditTarget = NULL;
8876 m_bRouteEditing =
true;
8878 if (m_routeState == 1) {
8879 m_pMouseRoute =
new Route();
8880 m_pMouseRoute->SetHiLite(50);
8881 pRouteList->Append(m_pMouseRoute);
8890 double nearby_radius_meters =
8891 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8894 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8895 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8896 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8899 m_FinishRouteOnKillFocus =
8901 dlg_return = OCPNMessageBox(
8902 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8903 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8904 m_FinishRouteOnKillFocus =
true;
8906 dlg_return = wxID_YES;
8908 if (dlg_return == wxID_YES) {
8909 pMousePoint = pNearbyPoint;
8912 if (m_routeState > 1)
8913 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8914 Undo_HasParent, NULL);
8915 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8917 bool procede =
false;
8921 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8927 m_FinishRouteOnKillFocus =
false;
8928 if (m_routeState == 1) {
8932 _(
"Insert first part of this route in the new route?");
8933 if (tail->GetIndexOf(pMousePoint) ==
8936 dmsg = _(
"Insert this route in the new route?");
8938 if (tail->GetIndexOf(pMousePoint) != 1) {
8940 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8941 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8942 m_FinishRouteOnKillFocus =
true;
8944 if (dlg_return == wxID_YES) {
8951 _(
"Append last part of this route to the new route?");
8952 if (tail->GetIndexOf(pMousePoint) == 1)
8954 "Append this route to the new route?");
8958 if (tail->GetLastPoint() != pMousePoint) {
8960 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8961 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8962 m_FinishRouteOnKillFocus =
true;
8964 if (dlg_return == wxID_YES) {
8975 if (!FindRouteContainingWaypoint(pMousePoint))
8976 pMousePoint->SetShared(
true);
8980 if (NULL == pMousePoint) {
8981 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8982 _T(
""), wxEmptyString);
8983 pMousePoint->SetNameShown(
false);
8985 pConfig->AddNewWayPoint(pMousePoint, -1);
8986 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8988 if (m_routeState > 1)
8989 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8990 Undo_IsOrphanded, NULL);
8993 if (m_routeState == 1) {
8995 m_pMouseRoute->AddPoint(pMousePoint);
8998 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8999 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9000 &rhumbBearing, &rhumbDist);
9001 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9002 &gcDist, &gcBearing, NULL);
9003 double gcDistNM = gcDist / 1852.0;
9006 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9007 pow(rhumbDist - gcDistNM - 1, 0.5);
9010 msg << _(
"For this leg the Great Circle route is ")
9011 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
9012 << _(
" shorter than rhumbline.\n\n")
9013 << _(
"Would you like include the Great Circle routing points "
9017 m_FinishRouteOnKillFocus =
false;
9018 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9019 wxYES_NO | wxNO_DEFAULT);
9020 m_FinishRouteOnKillFocus =
true;
9022 int answer = wxID_NO;
9025 if (answer == wxID_YES) {
9027 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9028 wxRealPoint gcCoord;
9030 for (
int i = 1; i <= segmentCount; i++) {
9031 double fraction = (double)i * (1.0 / (
double)segmentCount);
9032 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9033 gcDist * fraction, gcBearing,
9034 &gcCoord.x, &gcCoord.y, NULL);
9036 if (i < segmentCount) {
9037 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
9038 _T(
""), wxEmptyString);
9039 gcPoint->SetNameShown(
false);
9040 pConfig->AddNewWayPoint(gcPoint, -1);
9041 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9044 gcPoint = pMousePoint;
9047 m_pMouseRoute->AddPoint(gcPoint);
9048 pSelect->AddSelectableRouteSegment(
9049 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9050 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9051 prevGcPoint = gcPoint;
9054 undo->CancelUndoableAction(
true);
9057 m_pMouseRoute->AddPoint(pMousePoint);
9058 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9059 rlon, m_prev_pMousePoint,
9060 pMousePoint, m_pMouseRoute);
9061 undo->AfterUndoableAction(m_pMouseRoute);
9065 m_pMouseRoute->AddPoint(pMousePoint);
9066 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9067 rlon, m_prev_pMousePoint,
9068 pMousePoint, m_pMouseRoute);
9069 undo->AfterUndoableAction(m_pMouseRoute);
9075 m_prev_pMousePoint = pMousePoint;
9082 int connect = tail->GetIndexOf(pMousePoint);
9087 int length = tail->GetnPoints();
9092 start = connect + 1;
9097 m_pMouseRoute->RemovePoint(
9101 for (i = start; i <= stop; i++) {
9102 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9105 m_pMouseRoute->GetnPoints();
9107 gFrame->RefreshAllCanvas();
9111 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9113 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9114 m_pMouseRoute->FinalizeForRendering();
9119 }
else if (m_bMeasure_Active && m_nMeasureState)
9122 m_bedge_pan =
false;
9126 if (m_nMeasureState == 1) {
9127 m_pMeasureRoute =
new Route();
9128 pRouteList->Append(m_pMeasureRoute);
9133 if (m_pMeasureRoute) {
9136 wxEmptyString, wxEmptyString);
9137 pMousePoint->m_bShowName =
false;
9139 m_pMeasureRoute->AddPoint(pMousePoint);
9143 m_prev_pMousePoint = pMousePoint;
9145 m_pMeasureRoute->GetnPoints();
9149 CancelMeasureRoute();
9155 bool bSelectAllowed =
true;
9156 if (NULL == g_pMarkInfoDialog) {
9157 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9158 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9159 bSelectAllowed =
false;
9166 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9168 if (bSelectAllowed) {
9169 bool b_was_editing_mark = m_bMarkEditing;
9170 bool b_was_editing_route = m_bRouteEditing;
9171 FindRoutePointsAtCursor(SelectRadius,
9177 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->m_bIsInLayer)
9178 m_pRoutePointEditTarget = NULL;
9180 if (!b_was_editing_route) {
9181 if (m_pEditRouteArray) {
9182 b_startedit_route =
true;
9186 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9187 m_pTrackRolloverWin->IsActive(
false);
9189 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9190 m_pRouteRolloverWin->IsActive(
false);
9194 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9196 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9201 if (g_pRouteMan->IsRouteValid(pr)) {
9204 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9205 pre_rect.Union(route_rect);
9208 RefreshRect(pre_rect,
true);
9211 b_startedit_route =
false;
9215 if (m_pRoutePointEditTarget) {
9216 if (b_was_editing_mark ||
9217 b_was_editing_route) {
9218 if (m_lastRoutePointEditTarget) {
9219 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9220 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9222 .EnableDragHandle(
false);
9223 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9224 SELTYPE_DRAGHANDLE);
9228 if (m_pRoutePointEditTarget) {
9229 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
true;
9230 m_pRoutePointEditTarget->m_bPtIsSelected =
true;
9231 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9232 wxPoint2DDouble dragHandlePoint =
9234 .GetDragHandlePoint(
this);
9235 pSelect->AddSelectablePoint(
9236 dragHandlePoint.m_y, dragHandlePoint.m_x,
9237 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9240 if (m_lastRoutePointEditTarget) {
9241 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9242 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
9244 .EnableDragHandle(
false);
9245 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9246 SELTYPE_DRAGHANDLE);
9249 wxArrayPtrVoid *lastEditRouteArray =
9251 m_lastRoutePointEditTarget);
9252 if (lastEditRouteArray) {
9253 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9255 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9256 if (g_pRouteMan->IsRouteValid(pr)) {
9260 delete lastEditRouteArray;
9271 if (m_lastRoutePointEditTarget) {
9274 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9275 RefreshRect(wp_rect,
true);
9278 if (m_pRoutePointEditTarget) {
9281 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9282 RefreshRect(wp_rect,
true);
9291 bool b_start_rollover =
false;
9292 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9293 SelectItem *pFind = pSelectAIS->FindSelection(
9295 if (pFind) b_start_rollover =
true;
9298 if (!b_start_rollover && !b_startedit_route) {
9299 SelectableItemList SelList = pSelect->FindSelectionList(
9301 wxSelectableItemListNode *node = SelList.GetFirst();
9307 if (pr && pr->IsVisible()) {
9308 b_start_rollover =
true;
9311 node = node->GetNext();
9315 if (!b_start_rollover && !b_startedit_route) {
9316 SelectableItemList SelList = pSelect->FindSelectionList(
9318 wxSelectableItemListNode *node = SelList.GetFirst();
9324 if (tr && tr->IsVisible()) {
9325 b_start_rollover =
true;
9328 node = node->GetNext();
9332 if (b_start_rollover)
9333 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9337 bool appending =
false;
9338 bool inserting =
false;
9340 if (m_bRouteEditing ) {
9342 if (m_pRoutePointEditTarget) {
9348 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9349 double nearby_radius_meters =
9350 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9351 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9352 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9353 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9354 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9355 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9359 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9361 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9376 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9381 OCPNMessageBox(
this,
9382 _(
"Replace this RoutePoint by the nearby "
9384 _(
"OpenCPN RoutePoint change"),
9385 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9386 if (dlg_return == wxID_YES) {
9391 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9394 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9396 if (tail && current && (tail != current)) {
9398 connect = tail->GetIndexOf(pNearbyPoint);
9399 int index_current_route =
9400 current->GetIndexOf(m_pRoutePointEditTarget);
9401 index_last = current->GetIndexOf(current->GetLastPoint());
9402 dlg_return1 = wxID_NO;
9404 index_current_route) {
9406 if (connect != tail->GetnPoints()) {
9409 _(
"Last part of route to be appended to dragged "
9413 _(
"Full route to be appended to dragged route?");
9415 dlg_return1 = OCPNMessageBox(
9416 this, dmsg, _(
"OpenCPN Route Create"),
9417 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9418 if (dlg_return1 == wxID_YES) {
9422 }
else if (index_current_route ==
9427 _(
"First part of route to be inserted into dragged "
9429 if (connect == tail->GetnPoints())
9431 "Full route to be inserted into dragged route?");
9433 dlg_return1 = OCPNMessageBox(
9434 this, dmsg, _(
"OpenCPN Route Create"),
9435 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9436 if (dlg_return1 == wxID_YES) {
9443 if (m_pRoutePointEditTarget->IsShared()) {
9445 dlg_return = OCPNMessageBox(
9447 _(
"Do you really want to delete and replace this "
9449 _T(
"\n") + _(
"which has been created manually?"),
9450 (
"OpenCPN RoutePoint warning"),
9451 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9454 if (dlg_return == wxID_YES) {
9455 pMousePoint = pNearbyPoint;
9457 pMousePoint->SetShared(
true);
9461 pMousePoint->m_bIsInRoute =
true;
9467 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9469 if (m_pEditRouteArray) {
9470 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9472 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9473 if (g_pRouteMan->IsRouteValid(pr)) {
9479 pSelect->DeleteAllSelectableRoutePoints(pr);
9480 pSelect->DeleteAllSelectableRouteSegments(pr);
9485 pSelect->AddAllSelectableRouteSegments(pr);
9486 pSelect->AddAllSelectableRoutePoints(pr);
9488 pr->FinalizeForRendering();
9489 pr->UpdateSegmentDistances();
9490 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9496 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9497 if (m_pEditRouteArray) {
9498 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9500 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9501 if (g_pRouteMan->IsRouteValid(pr)) {
9502 if (pRoutePropDialog->GetRoute() == pr) {
9503 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9518 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9521 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9522 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9523 g_pMarkInfoDialog->Hide();
9525 delete m_pRoutePointEditTarget;
9526 m_lastRoutePointEditTarget = NULL;
9527 m_pRoutePointEditTarget = NULL;
9528 undo->AfterUndoableAction(pMousePoint);
9529 undo->InvalidateUndo();
9534 else if (m_bMarkEditing) {
9535 if (m_pRoutePointEditTarget)
9536 if (m_bRoutePoinDragging)
9537 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9540 if (m_pRoutePointEditTarget)
9541 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9543 if (!m_pRoutePointEditTarget) {
9544 delete m_pEditRouteArray;
9545 m_pEditRouteArray = NULL;
9546 m_bRouteEditing =
false;
9548 m_bRoutePoinDragging =
false;
9555 int length = tail->GetnPoints();
9556 for (
int i = connect + 1; i <= length; i++) {
9557 current->AddPointAndSegment(tail->GetPoint(i),
false);
9560 gFrame->RefreshAllCanvas();
9563 current->FinalizeForRendering();
9566 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9569 pSelect->DeleteAllSelectableRoutePoints(current);
9570 pSelect->DeleteAllSelectableRouteSegments(current);
9571 for (
int i = 1; i < connect; i++) {
9572 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9574 pSelect->AddAllSelectableRouteSegments(current);
9575 pSelect->AddAllSelectableRoutePoints(current);
9576 current->FinalizeForRendering();
9578 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9582 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9583 if (m_pEditRouteArray) {
9584 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9585 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9586 if (g_pRouteMan->IsRouteValid(pr)) {
9587 if (pRoutePropDialog->GetRoute() == pr) {
9588 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9598 if (m_bRouteEditing) {
9601 bool appending =
false;
9602 bool inserting =
false;
9605 if (m_pRoutePointEditTarget) {
9606 m_pRoutePointEditTarget->m_bBlink =
false;
9610 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9611 double nearby_radius_meters =
9612 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9613 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9614 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9615 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9616 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9617 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9618 bool duplicate =
false;
9620 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9622 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9637 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9642 OCPNMessageBox(
this,
9643 _(
"Replace this RoutePoint by the nearby "
9645 _(
"OpenCPN RoutePoint change"),
9646 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9647 if (dlg_return == wxID_YES) {
9651 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9654 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9656 if (tail && current && (tail != current)) {
9658 connect = tail->GetIndexOf(pNearbyPoint);
9659 int index_current_route =
9660 current->GetIndexOf(m_pRoutePointEditTarget);
9661 index_last = current->GetIndexOf(current->GetLastPoint());
9662 dlg_return1 = wxID_NO;
9664 index_current_route) {
9666 if (connect != tail->GetnPoints()) {
9669 _(
"Last part of route to be appended to dragged "
9673 _(
"Full route to be appended to dragged route?");
9675 dlg_return1 = OCPNMessageBox(
9676 this, dmsg, _(
"OpenCPN Route Create"),
9677 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9678 if (dlg_return1 == wxID_YES) {
9682 }
else if (index_current_route ==
9687 _(
"First part of route to be inserted into dragged "
9689 if (connect == tail->GetnPoints())
9691 "Full route to be inserted into dragged route?");
9693 dlg_return1 = OCPNMessageBox(
9694 this, dmsg, _(
"OpenCPN Route Create"),
9695 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9696 if (dlg_return1 == wxID_YES) {
9703 if (m_pRoutePointEditTarget->IsShared()) {
9704 dlg_return = wxID_NO;
9705 dlg_return = OCPNMessageBox(
9707 _(
"Do you really want to delete and replace this "
9709 _T(
"\n") + _(
"which has been created manually?"),
9710 (
"OpenCPN RoutePoint warning"),
9711 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9714 if (dlg_return == wxID_YES) {
9715 pMousePoint = pNearbyPoint;
9717 pMousePoint->SetShared(
true);
9721 pMousePoint->m_bIsInRoute =
true;
9727 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9729 if (m_pEditRouteArray) {
9730 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9732 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9733 if (g_pRouteMan->IsRouteValid(pr)) {
9738 pSelect->DeleteAllSelectableRoutePoints(pr);
9739 pSelect->DeleteAllSelectableRouteSegments(pr);
9744 pSelect->AddAllSelectableRouteSegments(pr);
9745 pSelect->AddAllSelectableRoutePoints(pr);
9747 pr->FinalizeForRendering();
9748 pr->UpdateSegmentDistances();
9751 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9763 int length = tail->GetnPoints();
9764 for (
int i = connect + 1; i <= length; i++) {
9765 current->AddPointAndSegment(tail->GetPoint(i),
false);
9769 gFrame->RefreshAllCanvas();
9772 current->FinalizeForRendering();
9775 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9778 pSelect->DeleteAllSelectableRoutePoints(current);
9779 pSelect->DeleteAllSelectableRouteSegments(current);
9780 for (
int i = 1; i < connect; i++) {
9781 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9783 pSelect->AddAllSelectableRouteSegments(current);
9784 pSelect->AddAllSelectableRoutePoints(current);
9785 current->FinalizeForRendering();
9787 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9791 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9792 if (m_pEditRouteArray) {
9793 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9795 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9796 if (g_pRouteMan->IsRouteValid(pr)) {
9797 if (pRoutePropDialog->GetRoute() == pr) {
9798 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9806 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9809 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9810 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9811 g_pMarkInfoDialog->Hide();
9813 delete m_pRoutePointEditTarget;
9814 m_lastRoutePointEditTarget = NULL;
9815 undo->AfterUndoableAction(pMousePoint);
9816 undo->InvalidateUndo();
9818 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9819 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9821 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9824 delete m_pEditRouteArray;
9825 m_pEditRouteArray = NULL;
9829 m_bRouteEditing =
false;
9830 m_pRoutePointEditTarget = NULL;
9836 else if (m_bMarkEditing) {
9837 if (m_pRoutePointEditTarget) {
9838 if (m_bRoutePoinDragging)
9839 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9840 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9841 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9845 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9846 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9847 RefreshRect(wp_rect,
true);
9850 m_pRoutePointEditTarget = NULL;
9851 m_bMarkEditing =
false;
9856 else if (leftIsDown) {
9861 if (!m_bChartDragging && !m_bMeasure_Active) {
9863 m_bChartDragging =
false;
9867 m_bRoutePoinDragging =
false;
9870 if (ret)
return true;
9873 if (event.RightDown()) {
9884 m_FinishRouteOnKillFocus =
false;
9885 CallPopupMenu(mx, my);
9886 m_FinishRouteOnKillFocus =
true;
9897 if (event.ShiftDown()) {
9901 event.GetPosition(&x, &y);
9903 x *= m_displayScale;
9904 y *= m_displayScale;
9910 int wheel_dir =
event.GetWheelRotation();
9913 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9914 wheel_dir = wheel_dir > 0 ? 1 : -1;
9916 double factor = g_mouse_zoom_sensitivity;
9917 if (wheel_dir < 0) factor = 1 / factor;
9919 if (g_bsmoothpanzoom) {
9920 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9921 if (wheel_dir == m_last_wheel_dir) {
9922 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9927 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9928 m_wheelstopwatch.Start(0);
9933 m_last_wheel_dir = wheel_dir;
9938 if (event.LeftDown()) {
9945 last_drag.x = x, last_drag.y = y;
9946 panleftIsDown =
true;
9949 if (event.LeftUp()) {
9950 if (panleftIsDown) {
9952 panleftIsDown =
false;
9955 if (!m_bChartDragging && !m_bMeasure_Active) {
9956 switch (cursor_region) {
9978 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
9983 m_bChartDragging =
false;
9989 if (event.Dragging() && event.LeftIsDown()) {
10007 struct timespec now;
10008 clock_gettime(CLOCK_MONOTONIC, &now);
10009 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10011 if (
false == m_bChartDragging) {
10013 last_drag.x = x, last_drag.y = y;
10014 m_bChartDragging =
true;
10015 m_chart_drag_total_time = 0;
10016 m_chart_drag_total_x = 0;
10017 m_chart_drag_total_y = 0;
10018 m_inertia_last_drag_x = x;
10019 m_inertia_last_drag_y = y;
10020 m_drag_vec_x.clear();
10021 m_drag_vec_y.clear();
10022 m_drag_vec_t.clear();
10023 m_last_drag_time = tnow;
10027 uint64_t delta_t = tnow - m_last_drag_time;
10028 double delta_tf = delta_t / 1e9;
10030 m_chart_drag_total_time += delta_tf;
10031 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10032 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10034 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10035 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10036 m_drag_vec_t.push_back(delta_tf);
10038 m_inertia_last_drag_x = x;
10039 m_inertia_last_drag_y = y;
10040 m_last_drag_time = tnow;
10042 if ((last_drag.x != x) || (last_drag.y != y)) {
10043 if (!m_routeState) {
10046 m_bChartDragging =
true;
10047 StartTimedMovement();
10048 m_pan_drag.x += last_drag.x - x;
10049 m_pan_drag.y += last_drag.y - y;
10050 last_drag.x = x, last_drag.y = y;
10054 if ((last_drag.x != x) || (last_drag.y != y)) {
10055 if (!m_routeState) {
10058 m_bChartDragging =
true;
10059 StartTimedMovement();
10060 m_pan_drag.x += last_drag.x - x;
10061 m_pan_drag.y += last_drag.y - y;
10062 last_drag.x = x, last_drag.y = y;
10069 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10071 m_DoubleClickTimer->Start();
10072 singleClickEventIsValid =
false;
10080void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10081 if (MouseEventOverlayWindows(event))
return;
10088void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10091 wxCursor *ptarget_cursor = pCursorArrow;
10092 if (!pPlugIn_Cursor) {
10093 ptarget_cursor = pCursorArrow;
10094 if ((!m_routeState) &&
10095 (!m_bMeasure_Active) ) {
10096 if (cursor_region == MID_RIGHT) {
10097 ptarget_cursor = pCursorRight;
10098 }
else if (cursor_region == MID_LEFT) {
10099 ptarget_cursor = pCursorLeft;
10100 }
else if (cursor_region == MID_TOP) {
10101 ptarget_cursor = pCursorDown;
10102 }
else if (cursor_region == MID_BOT) {
10103 ptarget_cursor = pCursorUp;
10105 ptarget_cursor = pCursorArrow;
10107 }
else if (m_bMeasure_Active ||
10109 ptarget_cursor = pCursorPencil;
10111 ptarget_cursor = pPlugIn_Cursor;
10114 SetCursor(*ptarget_cursor);
10117void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10118 SetCursor(*pCursorArrow);
10121void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10125 wxArrayString files;
10127 ChartBase *target_chart = GetChartAtCursor();
10128 if (target_chart) {
10129 file.Assign(target_chart->GetFullPath());
10130 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10131 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10134 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10136 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10137 unsigned int im = stackIndexArray.size();
10138 int scale = 2147483647;
10139 if (VPoint.b_quilt && im > 0) {
10140 for (
unsigned int is = 0; is < im; is++) {
10141 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
10142 CHART_TYPE_MBTILES) {
10143 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10145 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10146 if (ChartData->GetChartTableEntry(stackIndexArray[is])
10148 .Contains(lat, lon)) {
10149 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10152 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10153 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
10161 std::vector<Ais8_001_22 *> area_notices;
10163 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10166 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10167 auto target_data = target.second;
10168 if (!target_data->area_notices.empty()) {
10169 for (
auto &ani : target_data->area_notices) {
10174 for (Ais8_001_22_SubAreaList::iterator sa =
10175 area_notice.sub_areas.begin();
10176 sa != area_notice.sub_areas.end(); ++sa) {
10177 switch (sa->shape) {
10178 case AIS8_001_22_SHAPE_CIRCLE: {
10179 wxPoint target_point;
10181 bbox.Expand(target_point);
10182 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10185 case AIS8_001_22_SHAPE_RECT: {
10186 wxPoint target_point;
10188 bbox.Expand(target_point);
10189 if (sa->e_dim_m > sa->n_dim_m)
10190 bbox.EnLarge(sa->e_dim_m * vp_scale);
10192 bbox.EnLarge(sa->n_dim_m * vp_scale);
10195 case AIS8_001_22_SHAPE_POLYGON:
10196 case AIS8_001_22_SHAPE_POLYLINE: {
10197 for (
int i = 0; i < 4; ++i) {
10198 double lat = sa->latitude;
10199 double lon = sa->longitude;
10200 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10202 wxPoint target_point;
10204 bbox.Expand(target_point);
10208 case AIS8_001_22_SHAPE_SECTOR: {
10209 double lat1 = sa->latitude;
10210 double lon1 = sa->longitude;
10212 wxPoint target_point;
10214 bbox.Expand(target_point);
10215 for (
int i = 0; i < 18; ++i) {
10218 sa->left_bound_deg +
10219 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10220 sa->radius_m / 1852.0, &lat, &lon);
10222 bbox.Expand(target_point);
10224 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10227 bbox.Expand(target_point);
10233 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10234 area_notices.push_back(&area_notice);
10241 if (target_chart || !area_notices.empty() || file.HasName()) {
10243 int sel_rad_pix = 5;
10244 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10249 SetCursor(wxCURSOR_WAIT);
10250 bool lightsVis = m_encShowLights;
10251 if (!lightsVis) SetShowENCLights(
true);
10254 ListOfObjRazRules *rule_list = NULL;
10255 ListOfPI_S57Obj *pi_rule_list = NULL;
10258 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10259 else if (target_plugin_chart)
10260 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10261 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10263 ListOfObjRazRules *overlay_rule_list = NULL;
10264 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10267 if (CHs57_Overlay) {
10268 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10269 zlat, zlon, SelectRadius, &GetVP());
10272 if (!lightsVis) SetShowENCLights(
false);
10275 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10276 wxString face = dFont->GetFaceName();
10278 if (NULL == g_pObjectQueryDialog) {
10279 g_pObjectQueryDialog =
10280 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10281 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10284 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10285 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10289 fg = g_pObjectQueryDialog->GetForegroundColour();
10293 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
10294 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10297 int points = dFont->GetPointSize();
10299 int points = dFont->GetPointSize() + 1;
10303 for (
int i = -2; i < 5; i++) {
10304 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10306 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10308 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
10310 if (overlay_rule_list && CHs57_Overlay) {
10311 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10312 objText << _T(
"<hr noshade>");
10315 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10316 an != area_notices.end(); ++an) {
10317 objText << _T(
"<b>AIS Area Notice:</b> " );
10318 objText << ais8_001_22_notice_names[(*an)->notice_type];
10319 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10320 (*an)->sub_areas.begin();
10321 sa != (*an)->sub_areas.end(); ++sa)
10322 if (!sa->text.empty()) objText << sa->text;
10323 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10324 objText << _T(
"<hr noshade>" );
10328 objText << Chs57->CreateObjDescriptions(rule_list);
10329 else if (target_plugin_chart)
10330 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10333 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
10336 wxString AddFiles, filenameOK;
10338 if (!target_plugin_chart) {
10341 AddFiles = wxString::Format(
10342 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
10344 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
10345 _T(
"cellpadding=3>"),
10346 file.GetFullName());
10348 file.Assign(file.GetPath(), wxT(
""));
10349 wxDir dir(file.GetFullPath());
10351 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10353 file.Assign(dir.GetNameWithSep().append(filename));
10354 wxString FormatString =
10355 _T(
"<td valign=top><font size=-2><a ")
10356 _T("href=\"%s\">%s</a></font></td>");
10357 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10358 filenameOK = file.GetFullPath();
10360 if (3 * ((
int)filecount / 3) == filecount)
10361 FormatString.Prepend(_T(
"<tr>"));
10363 FormatString.Prepend(
10364 _T(
"<td>  </td>"));
10367 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10368 file.GetFullName());
10371 cont = dir.GetNext(&filename);
10373 objText << AddFiles << _T(
"</table>");
10375 objText << _T(
"</font>");
10376 objText << _T(
"</body></html>");
10378 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10379 g_pObjectQueryDialog->SetHTMLPage(objText);
10380 g_pObjectQueryDialog->Show();
10382 if ((!Chs57 && filecount == 1)) {
10384 wxHtmlLinkInfo hli(filenameOK);
10385 wxHtmlLinkEvent hle(1, hli);
10386 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10389 if (rule_list) rule_list->Clear();
10392 if (overlay_rule_list) overlay_rule_list->Clear();
10393 delete overlay_rule_list;
10395 if (pi_rule_list) pi_rule_list->Clear();
10396 delete pi_rule_list;
10398 SetCursor(wxCURSOR_ARROW);
10402void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10404 if (!g_pMarkInfoDialog) {
10411 wxSize canvas_size = GetSize();
10414 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10416 g_pMarkInfoDialog->Layout();
10418 wxPoint canvas_pos = GetPosition();
10419 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10421 bool newFit =
false;
10422 if (canvas_size.x < fitted_size.x) {
10423 fitted_size.x = canvas_size.x - 40;
10424 if (canvas_size.y < fitted_size.y)
10425 fitted_size.y -= 40;
10427 if (canvas_size.y < fitted_size.y) {
10428 fitted_size.y = canvas_size.y - 40;
10429 if (canvas_size.x < fitted_size.x)
10430 fitted_size.x -= 40;
10434 g_pMarkInfoDialog->SetSize(fitted_size);
10435 g_pMarkInfoDialog->Centre();
10439 markPoint->m_bRPIsBeingEdited =
false;
10441 wxString title_base = _(
"Mark Properties");
10442 if (markPoint->m_bIsInRoute) {
10443 title_base = _(
"Waypoint Properties");
10445 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10446 g_pMarkInfoDialog->UpdateProperties();
10447 if (markPoint->m_bIsInLayer) {
10448 wxString caption(wxString::Format(_T(
"%s, %s: %s"), title_base, _(
"Layer"),
10449 GetLayerName(markPoint->m_LayerID)));
10450 g_pMarkInfoDialog->SetDialogTitle(caption);
10452 g_pMarkInfoDialog->SetDialogTitle(title_base);
10454 g_pMarkInfoDialog->Show();
10455 g_pMarkInfoDialog->Raise();
10456 g_pMarkInfoDialog->InitialFocus();
10457 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10460void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10461 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10462 pRoutePropDialog->SetRouteAndUpdate(selected);
10464 pRoutePropDialog->Show();
10465 pRoutePropDialog->Raise();
10467 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10471 wxSize canvas_size = GetSize();
10472 wxPoint canvas_pos = GetPosition();
10473 wxSize fitted_size = pRoutePropDialog->GetSize();
10476 if (canvas_size.x < fitted_size.x) {
10477 fitted_size.x = canvas_size.x;
10478 if (canvas_size.y < fitted_size.y)
10479 fitted_size.y -= 20;
10481 if (canvas_size.y < fitted_size.y) {
10482 fitted_size.y = canvas_size.y;
10483 if (canvas_size.x < fitted_size.x)
10484 fitted_size.x -= 20;
10487 pRoutePropDialog->SetSize(fitted_size);
10488 pRoutePropDialog->Centre();
10493 wxPoint xxp = ClientToScreen(canvas_pos);
10497 pRoutePropDialog->SetRouteAndUpdate(selected);
10499 pRoutePropDialog->Show();
10504void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10505 pTrackPropDialog = TrackPropDlg::getInstance(
10508 pTrackPropDialog->SetTrackAndUpdate(selected);
10511 pTrackPropDialog->Show();
10516void pupHandler_PasteWaypoint() {
10519 int pasteBuffer = kml.ParsePasteBuffer();
10520 RoutePoint *pasted = kml.GetParsedRoutePoint();
10521 if (!pasted)
return;
10523 double nearby_radius_meters =
10524 g_Platform->GetSelectRadiusPix() /
10525 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10527 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10528 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10530 int answer = wxID_NO;
10531 if (nearPoint && !nearPoint->m_bIsInLayer) {
10534 "There is an existing waypoint at the same location as the one you are "
10535 "pasting. Would you like to merge the pasted data with it?\n\n");
10536 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10537 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10538 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10541 if (answer == wxID_YES) {
10542 nearPoint->SetName(pasted->GetName());
10543 nearPoint->m_MarkDescription = pasted->m_MarkDescription;
10544 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10545 pRouteManagerDialog->UpdateWptListCtrl();
10548 if (answer == wxID_NO) {
10551 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10553 pConfig->AddNewWayPoint(newPoint, -1);
10555 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10556 pRouteManagerDialog->UpdateWptListCtrl();
10557 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10558 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10561 gFrame->InvalidateAllGL();
10562 gFrame->RefreshAllCanvas(
false);
10565void pupHandler_PasteRoute() {
10568 int pasteBuffer = kml.ParsePasteBuffer();
10569 Route *pasted = kml.GetParsedRoute();
10570 if (!pasted)
return;
10572 double nearby_radius_meters =
10573 g_Platform->GetSelectRadiusPix() /
10574 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10580 bool mergepoints =
false;
10581 bool createNewRoute =
true;
10582 int existingWaypointCounter = 0;
10584 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10585 curPoint = pasted->GetPoint(i);
10586 nearPoint = pWayPointMan->GetNearbyWaypoint(
10587 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10589 mergepoints =
true;
10590 existingWaypointCounter++;
10594 curPoint->m_bPtIsSelected =
true;
10598 int answer = wxID_NO;
10602 "There are existing waypoints at the same location as some of the ones "
10603 "you are pasting. Would you like to just merge the pasted data into "
10605 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10606 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10607 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10609 if (answer == wxID_CANCEL) {
10616 if (mergepoints && answer == wxID_YES &&
10617 existingWaypointCounter == pasted->GetnPoints()) {
10618 wxRouteListNode *route_node = pRouteList->GetFirst();
10619 while (route_node) {
10620 Route *proute = route_node->GetData();
10623 createNewRoute =
false;
10626 route_node = route_node->GetNext();
10630 Route *newRoute = 0;
10633 if (createNewRoute) {
10634 newRoute =
new Route();
10638 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10639 curPoint = pasted->GetPoint(i);
10640 if (answer == wxID_YES && curPoint->m_bPtIsSelected) {
10641 curPoint->m_bPtIsSelected =
false;
10642 newPoint = pWayPointMan->GetNearbyWaypoint(
10643 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10644 newPoint->SetName(curPoint->GetName());
10645 newPoint->m_MarkDescription = curPoint->m_MarkDescription;
10647 if (createNewRoute) newRoute->AddPoint(newPoint);
10649 curPoint->m_bPtIsSelected =
false;
10653 newPoint->SetIconName(_T(
"circle"));
10654 newPoint->m_bIsVisible =
true;
10655 newPoint->m_bShowName =
false;
10656 newPoint->SetShared(
false);
10658 newRoute->AddPoint(newPoint);
10659 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10661 pConfig->AddNewWayPoint(newPoint, -1);
10664 if (i > 1 && createNewRoute)
10665 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10666 curPoint->m_lat, curPoint->m_lon,
10667 prevPoint, newPoint, newRoute);
10668 prevPoint = newPoint;
10671 if (createNewRoute) {
10672 pRouteList->Append(newRoute);
10673 pConfig->AddNewRoute(newRoute);
10675 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10676 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10679 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10680 pRouteManagerDialog->UpdateRouteListCtrl();
10681 pRouteManagerDialog->UpdateWptListCtrl();
10683 gFrame->InvalidateAllGL();
10684 gFrame->RefreshAllCanvas(
false);
10686 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10687 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10690void pupHandler_PasteTrack() {
10693 int pasteBuffer = kml.ParsePasteBuffer();
10694 Track *pasted = kml.GetParsedTrack();
10695 if (!pasted)
return;
10703 newTrack->SetName(pasted->GetName());
10705 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10706 curPoint = pasted->GetPoint(i);
10710 wxDateTime now = wxDateTime::Now();
10713 newTrack->AddPoint(newPoint);
10716 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10717 newPoint->m_lat, newPoint->m_lon,
10718 prevPoint, newPoint, newTrack);
10720 prevPoint = newPoint;
10723 g_TrackList.push_back(newTrack);
10724 pConfig->AddNewTrack(newTrack);
10726 gFrame->InvalidateAllGL();
10727 gFrame->RefreshAllCanvas(
false);
10730bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10732 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10733 m_pIDXCandidate, m_nmea_log);
10736 wxEVT_COMMAND_MENU_SELECTED,
10737 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10739 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10742 wxEVT_COMMAND_MENU_SELECTED,
10743 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10745 delete m_canvasMenu;
10746 m_canvasMenu = NULL;
10756void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10759 if (m_canvasMenu) {
10760 m_canvasMenu->PopupMenuHandler(event);
10765void ChartCanvas::StartRoute(
void) {
10767 if (g_brouteCreating)
return;
10769 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10771 g_brouteCreating =
true;
10773 m_bDrawingRoute =
false;
10774 SetCursor(*pCursorPencil);
10776 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10778 HideGlobalToolbar();
10781 androidSetRouteAnnunciator(
true);
10785void ChartCanvas::FinishRoute(
void) {
10787 m_prev_pMousePoint = NULL;
10788 m_bDrawingRoute =
false;
10791 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10793 androidSetRouteAnnunciator(
false);
10796 SetCursor(*pCursorArrow);
10798 if (m_pMouseRoute) {
10799 if (m_bAppendingRoute)
10800 pConfig->UpdateRoute(m_pMouseRoute);
10802 if (m_pMouseRoute->GetnPoints() > 1) {
10803 pConfig->AddNewRoute(m_pMouseRoute);
10806 NavObjectChanges::getInstance());
10807 m_pMouseRoute = NULL;
10810 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10812 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10813 (pRoutePropDialog->IsShown())) {
10814 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10817 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10818 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10819 pRouteManagerDialog->UpdateRouteListCtrl();
10822 m_bAppendingRoute =
false;
10823 m_pMouseRoute = NULL;
10825 m_pSelectedRoute = NULL;
10827 undo->InvalidateUndo();
10828 gFrame->RefreshAllCanvas(
true);
10830 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10832 ShowGlobalToolbar();
10834 g_brouteCreating =
false;
10837void ChartCanvas::HideGlobalToolbar() {
10838 if (m_canvasIndex == 0) {
10839 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10843void ChartCanvas::ShowGlobalToolbar() {
10844 if (m_canvasIndex == 0) {
10845 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10849void ChartCanvas::ShowAISTargetList(
void) {
10850 if (NULL == g_pAISTargetList) {
10854 g_pAISTargetList->UpdateAISTargetList();
10857void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10858 if (!m_bShowOutlines)
return;
10860 if (!ChartData)
return;
10862 int nEntry = ChartData->GetChartTableEntries();
10864 for (
int i = 0; i < nEntry; i++) {
10868 bool b_group_draw =
false;
10869 if (m_groupIndex > 0) {
10870 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10871 int index = pt->GetGroupArray()[ig];
10872 if (m_groupIndex == index) {
10873 b_group_draw =
true;
10878 b_group_draw =
true;
10880 if (b_group_draw) RenderChartOutline(dc, i, vp);
10886 if (VPoint.b_quilt) {
10887 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10888 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10892 }
else if (m_singleChart &&
10893 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10897 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10900 if (zoom_factor > 8.0) {
10901 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10904 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10908 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
10912void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10914 if (g_bopengl && m_glcc) {
10916 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10921 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10922 if (!ChartData->IsChartAvailable(dbIndex))
return;
10925 float plylat, plylon;
10926 float plylat1, plylon1;
10928 int pixx, pixy, pixx1, pixy1;
10931 ChartData->GetDBBoundingBox(dbIndex, box);
10935 if (box.GetLonRange() == 360)
return;
10937 double lon_bias = 0;
10939 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10941 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10943 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10944 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10946 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10947 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10950 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10953 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10954 if (0 == nAuxPlyEntries)
10958 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10959 plylon += lon_bias;
10965 for (
int i = 0; i < nPly - 1; i++) {
10966 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
10967 plylon1 += lon_bias;
10973 int pixxs1 = pixx1;
10974 int pixys1 = pixy1;
10976 bool b_skip =
false;
10980 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
10981 pow((
double)(pixy1 - pixy), 2)) /
10987 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10992 if (fabs(dist - distgc) > 10000. * 1852.)
10998 ClipResult res = cohen_sutherland_line_clip_i(
11000 if (res != Invisible && !b_skip)
11001 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11009 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11010 plylon1 += lon_bias;
11016 ClipResult res = cohen_sutherland_line_clip_i(
11018 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11025 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
11026 for (
int j = 0; j < nAuxPlyEntries; j++) {
11028 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11033 for (
int i = 0; i < nAuxPly - 1; i++) {
11034 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11040 int pixxs1 = pixx1;
11041 int pixys1 = pixy1;
11043 bool b_skip =
false;
11047 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11048 ((pixy1 - pixy) * (pixy1 - pixy))) /
11053 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11058 if (fabs(dist - distgc) > 10000. * 1852.)
11064 ClipResult res = cohen_sutherland_line_clip_i(
11066 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11074 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11079 ClipResult res = cohen_sutherland_line_clip_i(
11081 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11086static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11087 const wxString &second) {
11088 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11090 int pointsize = dFont->GetPointSize();
11094 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11095 false, dFont->GetFaceName());
11097 dc.SetFont(*psRLI_font);
11105 int hilite_offset = 3;
11108 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11109 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11111 dc.GetTextExtent(first, &w1, &h1);
11112 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11118 w = wxMax(w1, w2) + (h1 / 2);
11123 xp = ref_point.x - w;
11125 yp += hilite_offset;
11127 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11129 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11130 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11132 dc.DrawText(first, xp, yp);
11133 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11136void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11137 if (!g_bAllowShipToActive)
return;
11139 Route *rt = g_pRouteMan->GetpActiveRoute();
11142 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11143 wxPoint2DDouble pa, pb;
11149 g_pRouteMan->GetRoutePen()->GetWidth();
11150 if (rt->
m_width != wxPENSTYLE_INVALID)
11152 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11153 g_shipToActiveStyle, 5)];
11154 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11156 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11158 g_pRouteMan->GetActiveRoutePen()->GetColour();
11159 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11162 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11165 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11166 (
int)pb.m_y, GetVP(),
true);
11170#ifdef USE_ANDROID_GLES2
11171 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11173 if (style != wxPENSTYLE_SOLID) {
11174 if (glChartCanvas::dash_map.find(style) !=
11175 glChartCanvas::dash_map.end()) {
11176 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11180 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11183 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11184 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11190void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11192 if (m_routeState >= 2) route = m_pMouseRoute;
11193 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11194 route = m_pMeasureRoute;
11196 if (!route)
return;
11199 if (!g_pRouteMan->IsRouteValid(route))
return;
11204 int np = route->GetnPoints();
11206 if (g_btouch && (np > 1)) np--;
11208 render_lat = rp.m_lat;
11209 render_lon = rp.m_lon;
11212 double rhumbBearing, rhumbDist;
11214 &rhumbBearing, &rhumbDist);
11215 double brg = rhumbBearing;
11216 double dist = rhumbDist;
11220 double gcBearing, gcBearing2, gcDist;
11221 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11224 double gcDistm = gcDist / 1852.0;
11227 rhumbBearing = 90.;
11229 wxPoint destPoint, lastPoint;
11232 int milesDiff = rhumbDist - gcDistm;
11233 if (milesDiff > 1) {
11244 for (
int i = 1; i <= milesDiff; i++) {
11245 double p = (double)i * (1.0 / (
double)milesDiff);
11247 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11248 &pLon, &pLat, &gcBearing2);
11250 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11252 lastPoint = destPoint;
11255 if (r_rband.x && r_rband.y) {
11256 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11258 if (m_bMeasure_DistCircle) {
11259 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11260 powf((
float)(r_rband.y - lastPoint.y), 2));
11262 dc.SetPen(*g_pRouteMan->GetRoutePen());
11263 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11264 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11270 wxString routeInfo;
11272 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11278 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11280 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11281 (
int)varBrg, 0x00B0);
11284 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
11288 s0.Append(_(
"Route") + _T(
": "));
11290 s0.Append(_(
"Layer Route: "));
11293 if (!g_btouch) disp_length += dist;
11294 s0 += FormatDistanceAdaptive(disp_length);
11296 RouteLegInfo(dc, r_rband, routeInfo, s0);
11298 m_brepaint_piano =
true;
11301void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11302 if (!m_bShowVisibleSectors)
return;
11304 if (g_bDeferredInitDone) {
11306 double rhumbBearing, rhumbDist;
11307 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11308 &rhumbBearing, &rhumbDist);
11310 if (rhumbDist > 0.05)
11312 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11313 m_sectorlegsVisible);
11314 m_sector_glat = gLat;
11315 m_sector_glon = gLon;
11317 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11321void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11329void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11330 if (!ps52plib)
return;
11332 if (VPoint.b_quilt) {
11333 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11335 if (m_pQuilt->IsQuiltVector()) {
11336 if (ps52plib->GetStateHash() != m_s52StateHash) {
11338 m_s52StateHash = ps52plib->GetStateHash();
11342 if (ps52plib->GetStateHash() != m_s52StateHash) {
11344 m_s52StateHash = ps52plib->GetStateHash();
11349 bool bSendPlibState =
true;
11350 if (VPoint.b_quilt) {
11351 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11354 if (bSendPlibState) {
11356 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
11357 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
11358 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
11359 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
11360 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
11363 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
11364 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
11365 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
11366 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] = m_encShowAnchor;
11367 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] = GetShowENCDataQual();
11368 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
11369 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
11373 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
11374 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
11378 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
11379 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
11380 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
11381 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] =
11382 ps52plib->m_bShowS57ImportantTextOnly;
11383 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
11384 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
11385 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
11386 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
11387 v[_T(
"OpenCPN S52PLIB ColorShades")] =
11388 S52_getMarinerParam(S52_MAR_TWO_SHADES);
11391 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
11392 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
11393 v[_T(
"OpenCPN Scale Factor Exp")] =
11394 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11395 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
11401 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11402 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11403 g_lastS52PLIBPluginMessage = out;
11409void ChartCanvas::OnPaint(wxPaintEvent &event) {
11410 wxPaintDC dc(
this);
11420 if (!m_b_paint_enable) {
11425 UpdateCanvasS52PLIBConfig();
11428 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11430 if (m_glcc && g_bopengl) {
11431 if (!s_in_update) {
11441 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11443 wxRegion ru = GetUpdateRegion();
11445 int rx, ry, rwidth, rheight;
11446 ru.GetBox(rx, ry, rwidth, rheight);
11450#ifdef ocpnUSE_DIBSECTION
11453 wxMemoryDC temp_dc;
11461 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11462 height += m_Piano->GetHeight();
11464 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11468 int thumbx, thumby, thumbsx, thumbsy;
11469 pthumbwin->GetPosition(&thumbx, &thumby);
11470 pthumbwin->GetSize(&thumbsx, &thumbsy);
11471 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11473 if (pthumbwin->IsShown()) {
11474 rgn_chart.Subtract(rgn_thumbwin);
11475 ru.Subtract(rgn_thumbwin);
11481 wxRegion rgn_blit = ru;
11482 if (g_bShowChartBar) {
11483 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11484 GetClientSize().x, m_Piano->GetHeight());
11487 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11488 if (style->chartStatusWindowTransparent)
11489 m_brepaint_piano =
true;
11491 ru.Subtract(chart_bar_rect);
11495 if (m_Compass && m_Compass->IsShown()) {
11496 wxRect compassRect = m_Compass->
GetRect();
11497 if (ru.Contains(compassRect) != wxOutRegion) {
11498 ru.Subtract(compassRect);
11502 wxRect noteRect = m_notification_button->
GetRect();
11503 if (ru.Contains(noteRect) != wxOutRegion) {
11504 ru.Subtract(noteRect);
11508 bool b_newview =
true;
11513 m_cache_vp.IsValid()) {
11519 bool b_rcache_ok =
false;
11520 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11521 b_rcache_ok = !b_newview;
11524 if (VPoint.b_MercatorProjectionOverride)
11525 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11539 if (b_rcache_ok) chart_get_region.Clear();
11542 if (VPoint.b_quilt)
11544 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11546 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11551 AbstractPlatform::ShowBusySpinner();
11555 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11556 (m_working_bm.GetHeight() != svp.
pix_height))
11560 if (fabs(VPoint.
rotation) < 0.01) {
11561 bool b_save =
true;
11563 if (g_SencThreadManager) {
11564 if (g_SencThreadManager->GetJobCount()) {
11566 m_cache_vp.Invalidate();
11580 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11585 int dy = c_new.y - c_old.y;
11586 int dx = c_new.x - c_old.x;
11591 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11595 temp_dc.SelectObject(m_working_bm);
11597 wxMemoryDC cache_dc;
11598 cache_dc.SelectObject(m_cached_chart_bm);
11602 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11605 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11611 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11614 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11622 update_region.Union(
11625 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11630 update_region.Union(
11633 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11637 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11639 cache_dc.SelectObject(wxNullBitmap);
11643 temp_dc.SelectObject(m_cached_chart_bm);
11646 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11650 temp_dc.SelectObject(m_working_bm);
11651 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11656 temp_dc.SelectObject(m_cached_chart_bm);
11661 temp_dc.SelectObject(m_working_bm);
11662 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11675 wxMemoryDC scratch_dc_0;
11676 scratch_dc_0.SelectObject(m_cached_chart_bm);
11679 scratch_dc_0.SelectObject(wxNullBitmap);
11688 temp_dc.SelectObject(m_working_bm);
11691 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11692 chart_get_all_region);
11695 AbstractPlatform::HideBusySpinner();
11701 if (!m_singleChart) {
11702 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11707 if (!chart_get_region.IsEmpty()) {
11708 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11712 if (temp_dc.IsOk()) {
11717 if (!VPoint.b_quilt) {
11720 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11721 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11728 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11729 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11732 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11734 temp_dc.DestroyClippingRegion();
11739 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11741 if (!backgroundRegion.IsEmpty()) {
11747 wxColour water = pWorldBackgroundChart->water;
11748 if (water.IsOk()) {
11749 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11750 temp_dc.SetBrush(wxBrush(water));
11752 while (upd.HaveRects()) {
11753 wxRect rect = upd.GetRect();
11754 temp_dc.DrawRectangle(rect);
11759 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11760 temp_dc.SetDeviceClippingRegion(*clip_region);
11761 delete clip_region;
11765 SetVPRotation(VPoint.
skew);
11768 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11774 wxMemoryDC *pChartDC = &temp_dc;
11775 wxMemoryDC rotd_dc;
11777 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11779 if (!b_rcache_ok) {
11781 wxMemoryDC tbase_dc;
11783 tbase_dc.SelectObject(bm_base);
11785 tbase_dc.SelectObject(wxNullBitmap);
11787 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11790 wxImage base_image;
11791 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11799 bool b_rot_ok =
false;
11800 if (base_image.IsOk()) {
11803 m_b_rot_hidef =
false;
11807 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11808 m_b_rot_hidef, &m_roffset);
11813 rot_vp.IsValid() && (ri.IsOk())) {
11820 m_prot_bm =
new wxBitmap(ri);
11823 m_roffset.x += VPoint.rv_rect.x;
11824 m_roffset.y += VPoint.rv_rect.y;
11827 if (m_prot_bm && m_prot_bm->IsOk()) {
11828 rotd_dc.SelectObject(*m_prot_bm);
11829 pChartDC = &rotd_dc;
11831 pChartDC = &temp_dc;
11832 m_roffset = wxPoint(0, 0);
11835 pChartDC = &temp_dc;
11836 m_roffset = wxPoint(0, 0);
11839 wxPoint offset = m_roffset;
11842 m_cache_vp = VPoint;
11845 wxMemoryDC mscratch_dc;
11846 mscratch_dc.SelectObject(*pscratch_bm);
11848 mscratch_dc.ResetBoundingBox();
11849 mscratch_dc.DestroyClippingRegion();
11850 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11853 wxRegionIterator upd(rgn_blit);
11855 wxRect rect = upd.GetRect();
11857 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11858 rect.x - offset.x, rect.y - offset.y);
11864 if (m_show_focus_bar && (g_canvasConfig != 0)) {
11865 if (
this == wxWindow::FindFocus()) {
11866 g_focusCanvas =
this;
11868 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11869 mscratch_dc.SetPen(wxPen(colour));
11870 mscratch_dc.SetBrush(wxBrush(colour));
11872 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11873 mscratch_dc.DrawRectangle(activeRect);
11878 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11879 unsigned int im = stackIndexArray.size();
11880 if (VPoint.b_quilt && im > 0) {
11881 std::vector<int> tiles_to_show;
11882 for (
unsigned int is = 0; is < im; is++) {
11884 ChartData->GetChartTableEntry(stackIndexArray[is]);
11885 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11888 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11889 tiles_to_show.push_back(stackIndexArray[is]);
11893 if (tiles_to_show.size())
11894 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11901 ocpnDC scratch_dc(mscratch_dc);
11902 DrawOverlayObjects(scratch_dc, ru);
11905 RebuildTideSelectList(GetVP().GetBBox());
11906 DrawAllTidesInBBox(scratch_dc, GetVP().GetBBox());
11909 if (m_bShowCurrent) {
11910 RebuildCurrentSelectList(GetVP().GetBBox());
11911 DrawAllCurrentsInBBox(scratch_dc, GetVP().GetBBox());
11914 if (m_brepaint_piano && g_bShowChartBar) {
11915 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), mscratch_dc);
11918 if (m_Compass) m_Compass->Paint(scratch_dc);
11920 if (!g_CanvasHideNotificationIcon) {
11921 auto ¬eman = NotificationManager::GetInstance();
11922 if (noteman.GetNotificationCount()) {
11923 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
11924 if (m_notification_button->UpdateStatus()) Refresh();
11925 m_notification_button->Show(
true);
11926 m_notification_button->Paint(scratch_dc);
11928 m_notification_button->Show(
false);
11931 RenderAlertMessage(mscratch_dc, GetVP());
11936#ifdef ocpnUSE_DIBSECTION
11941 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11942 q_dc.SelectObject(qbm);
11945 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11948 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11949 q_dc.SetBrush(qbr);
11950 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11953 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11956 q_dc.SelectObject(wxNullBitmap);
11963 if( VPoint.b_quilt ) {
11964 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11965 ChartBase *chart = m_pQuilt->GetRefChart();
11966 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11971 ChPI->ClearPLIBTextList();
11974 ps52plib->ClearTextList();
11978 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11980 wxColor maskBackground = wxColour(1,0,0);
11981 t_dc.SelectObject( qbm );
11982 t_dc.SetBackground(wxBrush(maskBackground));
11986 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
11989 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
11990 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
11993 wxRegionIterator upd_final( ru );
11994 while( upd_final ) {
11995 wxRect rect = upd_final.GetRect();
11996 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12000 t_dc.SelectObject( wxNullBitmap );
12006 if (VPoint.b_quilt) {
12007 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12008 ChartBase *chart = m_pQuilt->GetRefChart();
12009 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12013 ChPI->ClearPLIBTextList();
12015 if (ps52plib) ps52plib->ClearTextList();
12020 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12022 if (g_bShowChartBar && m_Piano) {
12023 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12024 GetVP().pix_width, m_Piano->GetHeight());
12027 if (!style->chartStatusWindowTransparent)
12028 chart_all_text_region.Subtract(chart_bar_rect);
12031 if (m_Compass && m_Compass->IsShown()) {
12032 wxRect compassRect = m_Compass->
GetRect();
12033 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12034 chart_all_text_region.Subtract(compassRect);
12038 mscratch_dc.DestroyClippingRegion();
12040 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12041 chart_all_text_region);
12047 wxRegionIterator upd_final(rgn_blit);
12048 while (upd_final) {
12049 wxRect rect = upd_final.GetRect();
12050 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12071 temp_dc.SelectObject(wxNullBitmap);
12073 mscratch_dc.SelectObject(wxNullBitmap);
12075 dc.DestroyClippingRegion();
12080void ChartCanvas::PaintCleanup() {
12092 m_bTCupdate =
false;
12096 WarpPointer(warp_x, warp_y);
12103 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12104 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12108wxColour GetErrorGraphicColor(
double val)
12127 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
12128 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
12129 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
12130 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
12131 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
12132 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
12133 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
12134 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
12135 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
12136 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
12137 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
12138 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
12139 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
12140 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
12141 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
12142 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
12143 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
12144 else if( val >= 48) c.Set(_T(
"#410000"));
12149void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12152 gr_image.InitAlpha();
12154 double maxval = -10000;
12155 double minval = 10000;
12172 maxval = wxMax(maxval, (glat - rlat));
12173 minval = wxMin(minval, (glat - rlat));
12190 double f = ((glat - rlat)-minval)/(maxval - minval);
12192 double dy = (f * 40);
12194 wxColour c = GetErrorGraphicColor(dy);
12195 unsigned char r = c.Red();
12196 unsigned char g = c.Green();
12197 unsigned char b = c.Blue();
12199 gr_image.SetRGB(j, i, r,g,b);
12200 if((glat - rlat )!= 0)
12201 gr_image.SetAlpha(j, i, 128);
12203 gr_image.SetAlpha(j, i, 255);
12210 wxBitmap *pbm =
new wxBitmap(gr_image);
12211 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12212 pbm->SetMask(gr_mask);
12214 pmdc->DrawBitmap(*pbm, 0,0);
12222void ChartCanvas::CancelMouseRoute() {
12224 m_pMouseRoute = NULL;
12225 m_bDrawingRoute =
false;
12228int ChartCanvas::GetNextContextMenuId() {
12229 return CanvasMenuHandler::GetNextContextMenuId();
12232bool ChartCanvas::SetCursor(
const wxCursor &c) {
12234 if (g_bopengl && m_glcc)
12235 return m_glcc->SetCursor(c);
12238 return wxWindow::SetCursor(c);
12241void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12242 if (g_bquiting)
return;
12252 if (!m_RolloverPopupTimer.IsRunning() &&
12253 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12254 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12255 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12256 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12259 if (m_glcc && g_bopengl) {
12262 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12264 m_glcc->Refresh(eraseBackground,
12275 if (pthumbwin && pthumbwin->IsShown()) {
12276 pthumbwin->Raise();
12277 pthumbwin->Refresh(
false);
12281 if (m_pCIWin && m_pCIWin->IsShown()) {
12283 m_pCIWin->Refresh(
false);
12291 wxWindow::Refresh(eraseBackground, rect);
12294void ChartCanvas::Update() {
12295 if (m_glcc && g_bopengl) {
12300 wxWindow::Update();
12304 if (!pemboss)
return;
12305 int x = pemboss->x, y = pemboss->y;
12306 const double factor = 200;
12308 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
12309 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12310 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
12313 wxMemoryDC snip_dc;
12314 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12315 snip_dc.SelectObject(snip_bmp);
12317 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12318 snip_dc.SelectObject(wxNullBitmap);
12320 wxImage snip_img = snip_bmp.ConvertToImage();
12323 unsigned char *pdata = snip_img.GetData();
12325 for (
int y = 0; y < pemboss->height; y++) {
12326 int map_index = (y * pemboss->width);
12327 for (
int x = 0; x < pemboss->width; x++) {
12328 double val = (pemboss->pmap[map_index] * factor) / 256.;
12330 int nred = (int)((*pdata) + val);
12331 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12332 *pdata++ = (
unsigned char)nred;
12334 int ngreen = (int)((*pdata) + val);
12335 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12336 *pdata++ = (
unsigned char)ngreen;
12338 int nblue = (int)((*pdata) + val);
12339 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12340 *pdata++ = (
unsigned char)nblue;
12348 wxBitmap emb_bmp(snip_img);
12351 wxMemoryDC result_dc;
12352 result_dc.SelectObject(emb_bmp);
12355 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12357 result_dc.SelectObject(wxNullBitmap);
12363 if (GetQuiltMode()) {
12365 int refIndex = GetQuiltRefChartdbIndex();
12366 if (refIndex >= 0) {
12367 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
12368 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12369 if (current_type == CHART_TYPE_MBTILES) {
12370 ChartBase *pChart = m_pQuilt->GetRefChart();
12373 zoom_factor = ptc->GetZoomFactor();
12378 if (zoom_factor <= 3.9)
return NULL;
12380 if (m_singleChart) {
12381 if (zoom_factor <= 3.9)
return NULL;
12386 if (m_pEM_OverZoom) {
12387 m_pEM_OverZoom->x = 4;
12388 m_pEM_OverZoom->y = 0;
12389 if (g_MainToolbar && IsPrimaryCanvas()) {
12390 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12391 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12394 return m_pEM_OverZoom;
12397void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12407 g_overlayCanvas =
this;
12409 if (g_pi_manager) {
12410 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12411 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12415 AISDrawAreaNotices(dc, GetVP(),
this);
12417 wxDC *pdc = dc.GetDC();
12419 pdc->DestroyClippingRegion();
12420 wxDCClipper(*pdc, ru);
12423 if (m_bShowNavobjects) {
12424 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12425 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12426 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12427 DrawAnchorWatchPoints(dc);
12429 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12430 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12433 AISDraw(dc, GetVP(),
this);
12437 RenderVisibleSectorLights(dc);
12439 RenderAllChartOutlines(dc, GetVP());
12440 RenderRouteLegs(dc);
12441 RenderShipToActive(dc,
false);
12443 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12444 if (g_pi_manager) {
12445 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12446 OVERLAY_OVER_SHIPS);
12449 DrawEmboss(dc, EmbossDepthScale());
12450 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12451 if (g_pi_manager) {
12452 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12453 OVERLAY_OVER_EMBOSS);
12455 if (!g_PrintingInProgress) {
12456 if (IsPrimaryCanvas()) {
12457 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12460 if (IsPrimaryCanvas()) {
12461 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12464 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12466 if (m_pTrackRolloverWin) {
12467 m_pTrackRolloverWin->Draw(dc);
12468 m_brepaint_piano =
true;
12471 if (m_pRouteRolloverWin) {
12472 m_pRouteRolloverWin->Draw(dc);
12473 m_brepaint_piano =
true;
12476 if (m_pAISRolloverWin) {
12477 m_pAISRolloverWin->Draw(dc);
12478 m_brepaint_piano =
true;
12481 if (g_pi_manager) {
12482 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12488 if (!m_bShowDepthUnits)
return NULL;
12490 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12492 if (GetQuiltMode()) {
12493 wxString s = m_pQuilt->GetQuiltDepthUnit();
12495 if (s == _T(
"FEET"))
12496 depth_unit_type = DEPTH_UNIT_FEET;
12497 else if (s.StartsWith(_T(
"FATHOMS")))
12498 depth_unit_type = DEPTH_UNIT_FATHOMS;
12499 else if (s.StartsWith(_T(
"METERS")))
12500 depth_unit_type = DEPTH_UNIT_METERS;
12501 else if (s.StartsWith(_T(
"METRES")))
12502 depth_unit_type = DEPTH_UNIT_METERS;
12503 else if (s.StartsWith(_T(
"METRIC")))
12504 depth_unit_type = DEPTH_UNIT_METERS;
12505 else if (s.StartsWith(_T(
"METER")))
12506 depth_unit_type = DEPTH_UNIT_METERS;
12509 if (m_singleChart) {
12510 depth_unit_type = m_singleChart->GetDepthUnitType();
12511 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12512 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12517 switch (depth_unit_type) {
12518 case DEPTH_UNIT_FEET:
12521 case DEPTH_UNIT_METERS:
12522 ped = m_pEM_Meters;
12524 case DEPTH_UNIT_FATHOMS:
12525 ped = m_pEM_Fathoms;
12531 ped->x = (GetVP().
pix_width - ped->width);
12533 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12534 wxRect r = m_Compass->
GetRect();
12535 ped->y = r.y + r.height;
12542void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12545 if (style->embossFont == wxEmptyString) {
12546 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12548 font.SetPointSize(60);
12549 font.SetWeight(wxFONTWEIGHT_BOLD);
12551 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12552 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12554 int emboss_width = 500;
12555 int emboss_height = 200;
12559 delete m_pEM_Meters;
12560 delete m_pEM_Fathoms;
12564 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12566 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12568 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12571#define OVERZOOM_TEXT _("OverZoom")
12573void ChartCanvas::SetOverzoomFont() {
12578 if (style->embossFont == wxEmptyString) {
12579 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12581 font.SetPointSize(40);
12582 font.SetWeight(wxFONTWEIGHT_BOLD);
12584 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12585 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12587 wxClientDC dc(
this);
12589 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12591 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12592 font.SetPointSize(font.GetPointSize() - 1);
12594 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12596 m_overzoomFont = font;
12597 m_overzoomTextWidth = w;
12598 m_overzoomTextHeight = h;
12601void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12602 delete m_pEM_OverZoom;
12604 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12606 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12607 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12610emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12611 int height,
const wxString &str,
12616 wxBitmap bmp(width, height, -1);
12619 wxMemoryDC temp_dc;
12620 temp_dc.SelectObject(bmp);
12623 temp_dc.SetBackground(*wxWHITE_BRUSH);
12624 temp_dc.SetTextBackground(*wxWHITE);
12625 temp_dc.SetTextForeground(*wxBLACK);
12629 temp_dc.SetFont(font);
12632 temp_dc.GetTextExtent(str, &str_w, &str_h);
12634 temp_dc.DrawText(str, 1, 1);
12637 temp_dc.SelectObject(wxNullBitmap);
12640 wxImage img = bmp.ConvertToImage();
12642 int image_width = str_w * 105 / 100;
12643 int image_height = str_h * 105 / 100;
12644 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12645 wxMin(image_height, img.GetHeight()));
12646 wxImage imgs = img.GetSubImage(r);
12650 case GLOBAL_COLOR_SCHEME_DAY:
12654 case GLOBAL_COLOR_SCHEME_DUSK:
12657 case GLOBAL_COLOR_SCHEME_NIGHT:
12664 const int w = imgs.GetWidth();
12665 const int h = imgs.GetHeight();
12666 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12671 for (
int y = 1; y < h - 1; y++) {
12672 for (
int x = 1; x < w - 1; x++) {
12674 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12675 val = (int)(val * val_factor);
12676 index = (y * w) + x;
12689void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12690 Track *active_track = NULL;
12691 for (
Track *pTrackDraw : g_TrackList) {
12692 if (g_pActiveTrack == pTrackDraw) {
12693 active_track = pTrackDraw;
12697 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12700 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12703void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12704 Track *active_track = NULL;
12705 for (
Track *pTrackDraw : g_TrackList) {
12706 if (g_pActiveTrack == pTrackDraw) {
12707 active_track = pTrackDraw;
12711 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12714void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12715 Route *active_route = NULL;
12717 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12718 node = node->GetNext()) {
12719 Route *pRouteDraw = node->GetData();
12720 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12721 active_route = pRouteDraw;
12726 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12731 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12734void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12735 Route *active_route = NULL;
12737 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12738 node = node->GetNext()) {
12739 Route *pRouteDraw = node->GetData();
12740 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12741 active_route = pRouteDraw;
12745 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12748void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12749 if (!pWayPointMan)
return;
12751 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12756 if (pWP->m_bIsInRoute) {
12757 node = node->GetNext();
12762 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12766 if (pWP->GetShowWaypointRangeRings() &&
12767 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12768 double factor = 1.00;
12769 if (pWP->GetWaypointRangeRingsStepUnits() ==
12771 factor = 1 / 1.852;
12773 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12774 pWP->GetWaypointRangeRingsStep() / 60.;
12778 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12779 pWP->m_lat + radius, pWP->m_lon + radius);
12780 if (!BltBBox.IntersectOut(radar_box)) {
12787 node = node->GetNext();
12791void ChartCanvas::DrawBlinkObjects(
void) {
12793 wxRect update_rect;
12795 if (!pWayPointMan)
return;
12797 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12802 if (pWP->m_bBlink) {
12803 update_rect.Union(pWP->CurrentRect_in_DC);
12807 node = node->GetNext();
12809 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12812void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12815 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12817 wxPoint lAnchorPoint1, lAnchorPoint2;
12820 if (pAnchorWatchPoint1) {
12821 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12825 if (pAnchorWatchPoint2) {
12826 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12831 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12832 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12834 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12835 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12836 dc.SetBrush(*ppBrush);
12840 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12845 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12850 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12855 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12860double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12863 wxPoint lAnchorPoint;
12866 double tlat1, tlon1;
12868 if (pAnchorWatchPoint) {
12869 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12870 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12871 dabs = fabs(d1 / 1852.);
12872 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12877 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12878 pow((
double)(lAnchorPoint.y - r1.y), 2));
12881 if (d1 < 0) lpp = -lpp;
12889void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12890 if (!ptcmgr)
return;
12892 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12894 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12895 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12900 if ((type ==
't') || (type ==
'T')) {
12901 if (BBox.Contains(lat, lon)) {
12903 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12909extern wxDateTime gTimeSource;
12911void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12912 if (!ptcmgr)
return;
12914 wxDateTime this_now = gTimeSource;
12915 bool cur_time = !gTimeSource.IsValid();
12916 if (cur_time) this_now = wxDateTime::Now();
12917 time_t t_this_now = this_now.GetTicks();
12919 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12920 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12921 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12922 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12924 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12925 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12928 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12929 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12932 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12933 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12934 wxBRUSHSTYLE_SOLID);
12935 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12936 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12937 wxBRUSHSTYLE_SOLID);
12939 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
12940 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12941 int font_size = wxMax(10, dFont->GetPointSize());
12944 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
12945 false, dFont->GetFaceName());
12947 dc.SetPen(*pblack_pen);
12948 dc.SetBrush(*pgreen_brush);
12952 case GLOBAL_COLOR_SCHEME_DAY:
12955 case GLOBAL_COLOR_SCHEME_DUSK:
12958 case GLOBAL_COLOR_SCHEME_NIGHT:
12959 bm = m_bmTideNight;
12966 int bmw = bm.GetWidth();
12967 int bmh = bm.GetHeight();
12969 float scale_factor = 1.0;
12973 float icon_pixelRefDim = 45;
12977 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
12978 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
12979 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12993 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
12995 float nominal_icon_size_pixels = 48;
12996 float pix_factor = (2 * height) / nominal_icon_size_pixels;
13006 double targetHeight0 = 16.0;
13009 double displaySize = m_display_size_mm;
13010 displaySize = wxMax(displaySize, 100);
13012 float targetHeight = wxMin(targetHeight0, displaySize / 15);
13014 double pix_factor = targetHeight / symHeight;
13017 scale_factor *= pix_factor;
13019 float user_scale_factor = g_ChartScaleFactorExp;
13020 if (g_ChartScaleFactorExp > 1.0)
13021 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13024 scale_factor *= user_scale_factor;
13025 scale_factor *= GetContentScaleFactor();
13028 double marge = 0.05;
13029 std::vector<LLBBox> drawn_boxes;
13030 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13031 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13034 if ((type ==
't') || (type ==
'T'))
13039 if (BBox.ContainsMarge(lat, lon, marge)) {
13041 if (GetVP().chart_scale < 500000) {
13042 bool bdrawn =
false;
13043 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13044 if (drawn_boxes[i].Contains(lat, lon)) {
13049 if (bdrawn)
continue;
13052 this_box.Set(lat, lon, lat, lon);
13053 this_box.EnLarge(.005);
13054 drawn_boxes.push_back(this_box);
13060 if (GetVP().chart_scale > 500000) {
13061 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13065 dc.SetFont(*plabelFont);
13077 if (ptcmgr->GetTideFlowSens(
13078 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13082 ptcmgr->GetHightOrLowTide(
13083 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13084 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13096 if (tctime > t_this_now)
13097 ptcmgr->GetHightOrLowTide(
13098 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13099 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13103 ptcmgr->GetHightOrLowTide(
13104 t_this_now, FORWARD_TEN_MINUTES_STEP,
13105 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13119 int width = (int)(12 * scale_factor + 0.5);
13120 int height = (int)(45 * scale_factor + 0.5);
13121 int linew = wxMax(1, (
int)(scale_factor));
13122 int xDraw = r.x - (width / 2);
13123 int yDraw = r.y - (height / 2);
13126 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13127 int hs = (httime > lttime) ? -4 : 4;
13128 hs *= (int)(scale_factor + 0.5);
13129 if (ts > 0.995 || ts < 0.005) hs = 0;
13130 int ht_y = (int)(height * ts);
13133 pblack_pen->SetWidth(linew);
13134 dc.SetPen(*pblack_pen);
13135 dc.SetBrush(*pyelo_brush);
13136 dc.DrawRectangle(xDraw, yDraw, width, height);
13140 dc.SetPen(*pblue_pen);
13141 dc.SetBrush(*pblue_brush);
13142 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13143 (width - (4 * linew)), height - ht_y);
13149 arrow[0].x = xDraw + 2 * linew;
13150 arrow[1].x = xDraw + width / 2;
13151 arrow[2].x = xDraw + width - 2 * linew;
13152 pyelo_pen->SetWidth(linew);
13153 pblue_pen->SetWidth(linew);
13154 if (ts > 0.35 || ts < 0.15)
13156 hl = (int)(height * 0.25) + yDraw;
13158 arrow[1].y = hl + hs;
13161 dc.SetPen(*pyelo_pen);
13163 dc.SetPen(*pblue_pen);
13164 dc.DrawLines(3, arrow);
13166 if (ts > 0.60 || ts < 0.40)
13168 hl = (int)(height * 0.5) + yDraw;
13170 arrow[1].y = hl + hs;
13173 dc.SetPen(*pyelo_pen);
13175 dc.SetPen(*pblue_pen);
13176 dc.DrawLines(3, arrow);
13178 if (ts < 0.65 || ts > 0.85)
13180 hl = (int)(height * 0.75) + yDraw;
13182 arrow[1].y = hl + hs;
13185 dc.SetPen(*pyelo_pen);
13187 dc.SetPen(*pblue_pen);
13188 dc.DrawLines(3, arrow);
13192 s.Printf(_T(
"%3.1f"), nowlev);
13194 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13196 dc.GetTextExtent(s, &wx1, NULL);
13198 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13213void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13214 if (!ptcmgr)
return;
13216 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13218 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13219 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13224 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13225 if ((BBox.Contains(lat, lon))) {
13227 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13233void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13234 if (!ptcmgr)
return;
13236 float tcvalue, dir;
13240 double lon_last = 0.;
13241 double lat_last = 0.;
13243 double marge = 0.2;
13244 bool cur_time = !gTimeSource.IsValid();
13246 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13247 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13249 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13250 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13251 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13252 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13254 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13255 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13256 wxBRUSHSTYLE_SOLID);
13257 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13258 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13259 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13260 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13262 double skew_angle = GetVPRotation();
13264 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13265 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13266 int font_size = wxMax(10, dFont->GetPointSize());
13269 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13270 false, dFont->GetFaceName());
13272 float scale_factor = 1.0;
13279 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
13280 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
13281 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
13287 float nominal_icon_size_pixels = 6;
13288 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
13295 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13297 float nominal_icon_size_pixels = 15;
13298 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13305 float icon_pixelRefDim = 5;
13310 double targetHeight0 = 2.0;
13313 double displaySize = m_display_size_mm;
13314 displaySize = wxMax(displaySize, 100);
13316 float targetHeight = wxMin(targetHeight0, displaySize / 50);
13317 double pix_factor = targetHeight / symHeight;
13320 scale_factor *= pix_factor;
13322 float user_scale_factor = g_ChartScaleFactorExp;
13323 if (g_ChartScaleFactorExp > 1.0)
13324 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13327 scale_factor *= user_scale_factor;
13329 scale_factor *= GetContentScaleFactor();
13332 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13333 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13338 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13339 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13344 int dd = (int)(5.0 * scale_factor + 0.5);
13355 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13356 dc.SetPen(*pblack_pen);
13357 dc.SetBrush(*porange_brush);
13358 dc.DrawPolygon(4, d);
13361 dc.SetBrush(*pblack_brush);
13362 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13366 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13380 double a1 = fabs(tcvalue) * 10.;
13382 a1 = wxMax(1.0, a1);
13383 double a2 = log10(a1);
13385 float cscale = scale_factor * a2 * 0.4;
13387 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13388 dc.SetPen(*porange_pen);
13389 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13393 if (bDrawCurrentValues) {
13394 dc.SetFont(*pTCFont);
13395 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13396 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13417void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
13418 pCwin =
new TCWin(
this, x, y, pvIDX);
13421#define NUM_CURRENT_ARROW_POINTS 9
13422static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13423 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13424 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13425 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13427void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13429 if (
scale > 1e-2) {
13430 float sin_rot = sin(rot_angle * PI / 180.);
13431 float cos_rot = cos(rot_angle * PI / 180.);
13435 float xt = CurrentArrowArray[0].x;
13436 float yt = CurrentArrowArray[0].y;
13438 float xp = (xt * cos_rot) - (yt * sin_rot);
13439 float yp = (xt * sin_rot) + (yt * cos_rot);
13440 int x1 = (int)(xp *
scale);
13441 int y1 = (int)(yp *
scale);
13444 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13445 xt = CurrentArrowArray[ip].x;
13446 yt = CurrentArrowArray[ip].y;
13448 float xp = (xt * cos_rot) - (yt * sin_rot);
13449 float yp = (xt * sin_rot) + (yt * cos_rot);
13450 int x2 = (int)(xp *
scale);
13451 int y2 = (int)(yp *
scale);
13453 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13461wxString ChartCanvas::FindValidUploadPort() {
13464 if (!g_uploadConnection.IsEmpty() &&
13465 g_uploadConnection.StartsWith(_T(
"Serial"))) {
13466 port = g_uploadConnection;
13472 for (
auto *cp : TheConnectionParams()) {
13473 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13474 port << _T(
"Serial:") << cp->Port;
13480void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13483 if (NULL == g_pais_query_dialog_active) {
13484 int pos_x = g_ais_query_dialog_x;
13485 int pos_y = g_ais_query_dialog_y;
13487 if (g_pais_query_dialog_active) {
13488 g_pais_query_dialog_active->Destroy();
13494 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13495 wxPoint(pos_x, pos_y));
13497 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13499 g_pais_query_dialog_active->SetMMSI(mmsi);
13500 g_pais_query_dialog_active->UpdateText();
13501 wxSize sz = g_pais_query_dialog_active->GetSize();
13503 bool b_reset_pos =
false;
13508 RECT frame_title_rect;
13509 frame_title_rect.left = pos_x;
13510 frame_title_rect.top = pos_y;
13511 frame_title_rect.right = pos_x + sz.x;
13512 frame_title_rect.bottom = pos_y + 30;
13514 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13515 b_reset_pos =
true;
13520 wxRect window_title_rect;
13521 window_title_rect.x = pos_x;
13522 window_title_rect.y = pos_y;
13523 window_title_rect.width = sz.x;
13524 window_title_rect.height = 30;
13526 wxRect ClientRect = wxGetClientDisplayRect();
13527 ClientRect.Deflate(
13529 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13533 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13536 g_pais_query_dialog_active->SetMMSI(mmsi);
13537 g_pais_query_dialog_active->UpdateText();
13540 g_pais_query_dialog_active->Show();
13543void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13544 bool cur_mode = GetQuiltMode();
13546 if (!GetQuiltMode())
13547 SetQuiltMode(
true);
13548 else if (GetQuiltMode()) {
13549 SetQuiltMode(
false);
13550 g_sticky_chart = GetQuiltReferenceChartIndex();
13553 if (cur_mode != GetQuiltMode()) {
13554 SetupCanvasQuiltMode();
13563 if (ps52plib) ps52plib->GenerateStateHash();
13565 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13566 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13569void ChartCanvas::DoCanvasStackDelta(
int direction) {
13570 if (!GetQuiltMode()) {
13571 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13572 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13573 if ((current_stack_index + direction) < 0)
return;
13575 if (m_bpersistent_quilt ) {
13577 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13579 if (IsChartQuiltableRef(new_dbIndex)) {
13580 ToggleCanvasQuiltMode();
13581 SelectQuiltRefdbChart(new_dbIndex);
13582 m_bpersistent_quilt =
false;
13585 SelectChartFromStack(current_stack_index + direction);
13588 std::vector<int> piano_chart_index_array =
13589 GetQuiltExtendedStackdbIndexArray();
13590 int refdb = GetQuiltRefChartdbIndex();
13593 int current_index = -1;
13594 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13595 if (refdb == piano_chart_index_array[i]) {
13600 if (current_index == -1)
return;
13603 int target_family = ctet.GetChartFamily();
13605 int new_index = -1;
13606 int check_index = current_index + direction;
13607 bool found =
false;
13608 int check_dbIndex = -1;
13609 int new_dbIndex = -1;
13613 (
unsigned int)check_index < piano_chart_index_array.size() &&
13614 (check_index >= 0)) {
13615 check_dbIndex = piano_chart_index_array[check_index];
13616 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13617 if (target_family == cte.GetChartFamily()) {
13619 new_index = check_index;
13620 new_dbIndex = check_dbIndex;
13624 check_index += direction;
13627 if (!found)
return;
13629 if (!IsChartQuiltableRef(new_dbIndex)) {
13630 ToggleCanvasQuiltMode();
13631 SelectdbChart(new_dbIndex);
13632 m_bpersistent_quilt =
true;
13634 SelectQuiltRefChart(new_index);
13638 gFrame->UpdateGlobalMenuItems();
13640 SetQuiltChartHiLiteIndex(-1);
13651void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13654 switch (event.GetId()) {
13668 DoCanvasStackDelta(1);
13673 DoCanvasStackDelta(-1);
13683 ShowCurrents(!GetbShowCurrent());
13690 ShowTides(!GetbShowTide());
13697 if (0 == m_routeState) {
13704 androidSetRouteAnnunciator(m_routeState == 1);
13710 SetAISCanvasDisplayStyle(-1);
13722void ChartCanvas::SetShowAIS(
bool show) {
13724 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13725 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13728void ChartCanvas::SetAttenAIS(
bool show) {
13729 m_bShowAISScaled = show;
13730 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13731 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13734void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13737 bool bShowAIS_Array[3] = {
true,
true,
false};
13738 bool bShowScaled_Array[3] = {
false,
true,
true};
13739 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13740 _(
"Attenuate less critical AIS targets"),
13741 _(
"Hide AIS Targets")};
13742 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13743 _T(
"AIS_Disabled")};
13745 int AIS_Toolbar_Switch = 0;
13746 if (StyleIndx == -1) {
13748 for (
int i = 1; i < ArraySize; i++) {
13749 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13750 (bShowScaled_Array[i] == m_bShowAISScaled))
13751 AIS_Toolbar_Switch = i;
13753 AIS_Toolbar_Switch++;
13754 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13755 AIS_Toolbar_Switch++;
13758 AIS_Toolbar_Switch = StyleIndx;
13761 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13763 int AIS_Toolbar_Switch_Next =
13764 AIS_Toolbar_Switch + 1;
13765 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13766 AIS_Toolbar_Switch_Next++;
13767 if (AIS_Toolbar_Switch_Next >= ArraySize)
13768 AIS_Toolbar_Switch_Next = 0;
13771 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13772 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13775void ChartCanvas::TouchAISToolActive(
void) {}
13777void ChartCanvas::UpdateAISTBTool(
void) {}
13785void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13787 bool b_update =
false;
13788 int cc1_edge_comp = 2;
13789 wxRect rect = m_Compass->
GetRect();
13790 wxSize parent_size = GetSize();
13792 parent_size *= m_displayScale;
13796 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
13797 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13798 wxRect compass_rect(compass_pt, rect.GetSize());
13800 m_Compass->Move(compass_pt);
13802 if (m_Compass && m_Compass->IsShown())
13803 m_Compass->UpdateStatus(b_force_new | b_update);
13805 wxPoint note_point =
13806 wxPoint(compass_rect.x - compass_rect.width, compass_rect.y);
13807 m_notification_button->Move(note_point);
13809 m_notification_button->UpdateStatus();
13810 if (b_force_new | b_update) Refresh();
13813void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13814 ChartTypeEnum New_Type,
13815 ChartFamilyEnum New_Family) {
13816 if (!GetpCurrentStack())
return;
13817 if (!ChartData)
return;
13819 if (index < GetpCurrentStack()->nEntry) {
13822 pTentative_Chart = ChartData->OpenStackChartConditional(
13823 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13825 if (pTentative_Chart) {
13826 if (m_singleChart) m_singleChart->Deactivate();
13828 m_singleChart = pTentative_Chart;
13829 m_singleChart->Activate();
13831 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13832 GetpCurrentStack(), m_singleChart->GetFullPath());
13845 double best_scale_ppm = GetBestVPScale(m_singleChart);
13846 double rotation = GetVPRotation();
13847 double oldskew = GetVPSkew();
13848 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13850 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13851 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13852 if (fabs(newskew) > 0.0001) rotation = newskew;
13855 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13857 UpdateGPSCompassStatusBox(
true);
13861 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13862 if (idx < 0)
return;
13864 std::vector<int> piano_active_chart_index_array;
13865 piano_active_chart_index_array.push_back(
13866 GetpCurrentStack()->GetCurrentEntrydbIndex());
13867 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13870void ChartCanvas::SelectdbChart(
int dbindex) {
13871 if (!GetpCurrentStack())
return;
13872 if (!ChartData)
return;
13874 if (dbindex >= 0) {
13877 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13879 if (pTentative_Chart) {
13880 if (m_singleChart) m_singleChart->Deactivate();
13882 m_singleChart = pTentative_Chart;
13883 m_singleChart->Activate();
13885 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13886 GetpCurrentStack(), m_singleChart->GetFullPath());
13899 double best_scale_ppm = GetBestVPScale(m_singleChart);
13903 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13913void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13916 if (!GetQuiltMode()) {
13917 if (GetpCurrentStack()) {
13918 int stack_index = -1;
13919 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13920 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13921 if (check_dbIndex < 0)
continue;
13923 ChartData->GetChartTableEntry(check_dbIndex);
13924 if (type == cte.GetChartType()) {
13927 }
else if (family == cte.GetChartFamily()) {
13933 if (stack_index >= 0) {
13934 SelectChartFromStack(stack_index);
13938 int sel_dbIndex = -1;
13939 std::vector<int> piano_chart_index_array =
13940 GetQuiltExtendedStackdbIndexArray();
13941 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13942 int check_dbIndex = piano_chart_index_array[i];
13943 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13944 if (type == cte.GetChartType()) {
13945 if (IsChartQuiltableRef(check_dbIndex)) {
13946 sel_dbIndex = check_dbIndex;
13949 }
else if (family == cte.GetChartFamily()) {
13950 if (IsChartQuiltableRef(check_dbIndex)) {
13951 sel_dbIndex = check_dbIndex;
13957 if (sel_dbIndex >= 0) {
13958 SelectQuiltRefdbChart(sel_dbIndex,
false);
13960 AdjustQuiltRefChart();
13967 SetQuiltChartHiLiteIndex(-1);
13972bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
13973 return std::find(m_tile_yesshow_index_array.begin(),
13974 m_tile_yesshow_index_array.end(),
13975 index) != m_tile_yesshow_index_array.end();
13978bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
13979 return std::find(m_tile_noshow_index_array.begin(),
13980 m_tile_noshow_index_array.end(),
13981 index) != m_tile_noshow_index_array.end();
13984void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
13985 if (std::find(m_tile_noshow_index_array.begin(),
13986 m_tile_noshow_index_array.end(),
13987 index) == m_tile_noshow_index_array.end()) {
13988 m_tile_noshow_index_array.push_back(index);
13998void ChartCanvas::HandlePianoClick(
13999 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14000 if (g_options && g_options->IsShown())
14002 if (!m_pCurrentStack)
return;
14003 if (!ChartData)
return;
14018 double distance = 25000;
14019 int closest_index = -1;
14020 for (
int chart_index : selected_dbIndex_array) {
14021 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
14022 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14023 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14026 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14027 if (test_distance < distance) {
14028 distance = test_distance;
14029 closest_index = chart_index;
14033 int selected_dbIndex = selected_dbIndex_array[0];
14034 if (closest_index >= 0) selected_dbIndex = closest_index;
14036 if (!GetQuiltMode()) {
14037 if (m_bpersistent_quilt ) {
14038 if (IsChartQuiltableRef(selected_dbIndex)) {
14039 ToggleCanvasQuiltMode();
14040 SelectQuiltRefdbChart(selected_dbIndex);
14041 m_bpersistent_quilt =
false;
14043 SelectChartFromStack(selected_index);
14046 SelectChartFromStack(selected_index);
14047 g_sticky_chart = selected_dbIndex;
14051 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14055 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
14056 bool bfound =
false;
14057 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14058 if (m_tile_noshow_index_array[i] ==
14059 selected_dbIndex) {
14060 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14067 m_tile_noshow_index_array.push_back(selected_dbIndex);
14071 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14072 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14076 if (IsChartQuiltableRef(selected_dbIndex)) {
14082 bool set_scale =
false;
14083 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
14084 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14090 SelectQuiltRefdbChart(selected_dbIndex,
true);
14092 SelectQuiltRefdbChart(selected_dbIndex,
false);
14097 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14099 double proposed_scale_onscreen =
14102 if (g_bPreserveScaleOnX) {
14103 proposed_scale_onscreen =
14104 wxMin(proposed_scale_onscreen,
14106 GetCanvasWidth()));
14108 proposed_scale_onscreen =
14109 wxMin(proposed_scale_onscreen,
14111 GetCanvasWidth()));
14113 proposed_scale_onscreen =
14114 wxMax(proposed_scale_onscreen,
14123 ToggleCanvasQuiltMode();
14124 SelectdbChart(selected_dbIndex);
14125 m_bpersistent_quilt =
true;
14130 SetQuiltChartHiLiteIndex(-1);
14131 gFrame->UpdateGlobalMenuItems();
14133 HideChartInfoWindow();
14138void ChartCanvas::HandlePianoRClick(
14139 int x,
int y,
int selected_index,
14140 const std::vector<int> &selected_dbIndex_array) {
14141 if (g_options && g_options->IsShown())
14143 if (!GetpCurrentStack())
return;
14145 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14146 UpdateCanvasControlBar();
14148 SetQuiltChartHiLiteIndex(-1);
14151void ChartCanvas::HandlePianoRollover(
14152 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14153 int n_charts,
int scale) {
14154 if (g_options && g_options->IsShown())
14156 if (!GetpCurrentStack())
return;
14157 if (!ChartData)
return;
14159 if (ChartData->IsBusy())
return;
14161 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14163 if (!GetQuiltMode()) {
14164 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14167 std::vector<int> piano_chart_index_array;
14168 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14169 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14170 if ((GetpCurrentStack()->nEntry > 1) ||
14171 (piano_chart_index_array.size() >= 1)) {
14172 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14174 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14176 }
else if (GetpCurrentStack()->nEntry == 1) {
14178 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14179 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14180 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14182 }
else if ((-1 == selected_index) &&
14183 (0 == selected_dbIndex_array.size())) {
14184 ShowChartInfoWindow(key_location.x, -1);
14188 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14190 if ((GetpCurrentStack()->nEntry > 1) ||
14191 (piano_chart_index_array.size() >= 1)) {
14193 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14194 selected_dbIndex_array);
14195 else if (n_charts == 1)
14196 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14198 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14205void ChartCanvas::ClearPianoRollover() {
14206 ClearQuiltChartHiLiteIndexArray();
14207 ShowChartInfoWindow(0, -1);
14208 std::vector<int> vec;
14209 ShowCompositeInfoWindow(0, 0, 0, vec);
14213void ChartCanvas::UpdateCanvasControlBar(
void) {
14214 if (m_pianoFrozen)
return;
14216 if (!GetpCurrentStack())
return;
14217 if (!ChartData)
return;
14218 if (!g_bShowChartBar)
return;
14221 int sel_family = -1;
14223 std::vector<int> piano_chart_index_array;
14224 std::vector<int> empty_piano_chart_index_array;
14226 wxString old_hash = m_Piano->GetStoredHash();
14228 if (GetQuiltMode()) {
14229 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14230 GetQuiltFullScreendbIndexArray());
14232 std::vector<int> piano_active_chart_index_array =
14233 GetQuiltCandidatedbIndexArray();
14234 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14236 std::vector<int> piano_eclipsed_chart_index_array =
14237 GetQuiltEclipsedStackdbIndexArray();
14238 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14240 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14241 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14243 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14244 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14246 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
14247 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14250 if (m_singleChart) {
14251 sel_type = m_singleChart->GetChartType();
14252 sel_family = m_singleChart->GetChartFamily();
14257 std::vector<int> piano_skew_chart_index_array;
14258 std::vector<int> piano_tmerc_chart_index_array;
14259 std::vector<int> piano_poly_chart_index_array;
14261 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14263 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14264 double skew_norm = ctei.GetChartSkew();
14265 if (skew_norm > 180.) skew_norm -= 360.;
14267 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14268 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14271 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14272 if (fabs(skew_norm) > 1.)
14273 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14275 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14276 }
else if (fabs(skew_norm) > 1.)
14277 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14279 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14280 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14281 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14283 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14284 if (new_hash != old_hash) {
14285 m_Piano->FormatKeys();
14286 HideChartInfoWindow();
14287 m_Piano->ResetRollover();
14288 SetQuiltChartHiLiteIndex(-1);
14289 m_brepaint_piano =
true;
14295 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14297 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14298 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14299 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14300 if (e == CHART_FAMILY_RASTER) mask |= 1;
14301 if (e == CHART_FAMILY_VECTOR) {
14302 if (t == CHART_TYPE_CM93COMP)
14309 wxString s_indicated;
14310 if (sel_type == CHART_TYPE_CM93COMP)
14311 s_indicated = _T(
"cm93");
14313 if (sel_family == CHART_FAMILY_RASTER)
14314 s_indicated = _T(
"raster");
14315 else if (sel_family == CHART_FAMILY_VECTOR)
14316 s_indicated = _T(
"vector");
14319 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14322void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14324void ChartCanvas::PianoPopupMenu(
14325 int x,
int y,
int selected_index,
14326 const std::vector<int> &selected_dbIndex_array) {
14327 if (!GetpCurrentStack())
return;
14330 if (!GetQuiltMode())
return;
14332 m_piano_ctx_menu =
new wxMenu();
14334 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14344 menu_selected_dbIndex = selected_dbIndex_array[0];
14345 menu_selected_index = selected_index;
14348 bool b_is_in_noshow =
false;
14349 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14350 if (m_quilt_noshow_index_array[i] ==
14351 menu_selected_dbIndex)
14353 b_is_in_noshow =
true;
14358 if (b_is_in_noshow) {
14359 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14360 _(
"Show This Chart"));
14361 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14362 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14363 }
else if (GetpCurrentStack()->nEntry > 1) {
14364 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14365 _(
"Hide This Chart"));
14366 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14367 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14371 wxPoint pos = wxPoint(x, y - 30);
14374 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14375 PopupMenu(m_piano_ctx_menu, pos);
14377 delete m_piano_ctx_menu;
14378 m_piano_ctx_menu = NULL;
14380 HideChartInfoWindow();
14381 m_Piano->ResetRollover();
14383 SetQuiltChartHiLiteIndex(-1);
14384 ClearQuiltChartHiLiteIndexArray();
14389void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14390 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14391 if (m_quilt_noshow_index_array[i] ==
14392 menu_selected_dbIndex)
14394 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14400void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14401 if (!GetpCurrentStack())
return;
14402 if (!ChartData)
return;
14404 RemoveChartFromQuilt(menu_selected_dbIndex);
14408 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14409 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
14411 int i = menu_selected_index + 1;
14412 bool b_success =
false;
14413 while (i < GetpCurrentStack()->nEntry - 1) {
14414 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14415 if (type == ChartData->GetDBChartType(dbIndex)) {
14416 SelectQuiltRefChart(i);
14426 i = menu_selected_index - 1;
14428 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14429 if (type == ChartData->GetDBChartType(dbIndex)) {
14430 SelectQuiltRefChart(i);
14440void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14442 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14443 if (m_quilt_noshow_index_array[i] ==
14446 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14451 m_quilt_noshow_index_array.push_back(dbIndex);
14454bool ChartCanvas::UpdateS52State() {
14455 bool retval =
false;
14459 ps52plib->SetShowS57Text(m_encShowText);
14460 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14461 ps52plib->m_bShowSoundg = m_encShowDepth;
14462 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14463 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14466 if (!m_encShowLights)
14467 ps52plib->AddObjNoshow(
"LIGHTS");
14469 ps52plib->RemoveObjNoshow(
"LIGHTS");
14470 ps52plib->SetLightsOff(!m_encShowLights);
14471 ps52plib->m_bExtendLightSectors =
true;
14474 ps52plib->SetAnchorOn(m_encShowAnchor);
14475 ps52plib->SetQualityOfData(m_encShowDataQual);
14481void ChartCanvas::SetShowENCDataQual(
bool show) {
14482 m_encShowDataQual = show;
14483 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14484 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14486 m_s52StateHash = 0;
14489void ChartCanvas::SetShowENCText(
bool show) {
14490 m_encShowText = show;
14491 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14492 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14494 m_s52StateHash = 0;
14497void ChartCanvas::SetENCDisplayCategory(
int category) {
14498 m_encDisplayCategory = category;
14499 m_s52StateHash = 0;
14502void ChartCanvas::SetShowENCDepth(
bool show) {
14503 m_encShowDepth = show;
14504 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14505 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14507 m_s52StateHash = 0;
14510void ChartCanvas::SetShowENCLightDesc(
bool show) {
14511 m_encShowLightDesc = show;
14512 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14513 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14515 m_s52StateHash = 0;
14518void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14519 m_encShowBuoyLabels = show;
14520 m_s52StateHash = 0;
14523void ChartCanvas::SetShowENCLights(
bool show) {
14524 m_encShowLights = show;
14525 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14526 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14528 m_s52StateHash = 0;
14531void ChartCanvas::SetShowENCAnchor(
bool show) {
14532 m_encShowAnchor = show;
14533 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14534 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14536 m_s52StateHash = 0;
14539wxRect ChartCanvas::GetMUIBarRect() {
14542 rv = m_muiBar->GetRect();
14548void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14549 if (!GetAlertString().IsEmpty()) {
14550 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14551 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14553 dc.SetFont(*pfont);
14554 dc.SetPen(*wxTRANSPARENT_PEN);
14556 dc.SetBrush(wxColour(243, 229, 47));
14558 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14562 wxRect sbr = GetScaleBarRect();
14563 int xp = sbr.x + sbr.width + 10;
14564 int yp = (sbr.y + sbr.height) - h;
14566 int wdraw = w + 10;
14567 dc.DrawRectangle(xp, yp, wdraw, h);
14568 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14569 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14579#define BRIGHT_XCALIB
14580#define __OPCPN_USEICC__
14583#ifdef __OPCPN_USEICC__
14584int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14585 double co_green,
double co_blue);
14587wxString temp_file_name;
14591class ocpnCurtain:
public wxDialog
14593 DECLARE_CLASS( ocpnCurtain )
14594 DECLARE_EVENT_TABLE()
14597 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14599 bool ProcessEvent(wxEvent& event);
14603IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14605BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14608ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14610 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14613ocpnCurtain::~ocpnCurtain()
14617bool ocpnCurtain::ProcessEvent(wxEvent& event)
14619 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14620 return GetParent()->GetEventHandler()->ProcessEvent(event);
14625#include <windows.h>
14628typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14629typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14630SetDeviceGammaRamp_ptr_type
14631 g_pSetDeviceGammaRamp;
14632GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14634WORD *g_pSavedGammaMap;
14638int InitScreenBrightness(
void) {
14641 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14645 if (NULL == hGDI32DLL) {
14646 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14648 if (NULL != hGDI32DLL) {
14650 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14651 hGDI32DLL,
"SetDeviceGammaRamp");
14652 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14653 hGDI32DLL,
"GetDeviceGammaRamp");
14656 if ((NULL == g_pSetDeviceGammaRamp) ||
14657 (NULL == g_pGetDeviceGammaRamp)) {
14658 FreeLibrary(hGDI32DLL);
14667 if (!g_pSavedGammaMap) {
14668 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14671 bbr = g_pGetDeviceGammaRamp(
14672 hDC, g_pSavedGammaMap);
14673 ReleaseDC(NULL, hDC);
14678 wxRegKey *pRegKey =
new wxRegKey(
14679 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14680 _T(
"NT\\CurrentVersion\\ICM"));
14681 if (!pRegKey->Exists()) pRegKey->Create();
14682 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14684 g_brightness_init =
true;
14690 if (NULL == g_pcurtain) {
14691 if (gFrame->CanSetTransparent()) {
14693 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14694 wxPoint(0, 0), ::wxGetDisplaySize(),
14695 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14696 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14703 g_pcurtain->Hide();
14705 HWND hWnd = GetHwndOf(g_pcurtain);
14706 SetWindowLong(hWnd, GWL_EXSTYLE,
14707 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14708 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14709 g_pcurtain->SetTransparent(0);
14711 g_pcurtain->Maximize();
14712 g_pcurtain->Show();
14715 g_pcurtain->Enable();
14716 g_pcurtain->Disable();
14723 g_brightness_init =
true;
14729 wxString cmd(_T (
"xcalib -version" ));
14731 wxArrayString output;
14732 long r = wxExecute(cmd, output);
14735 _T(
" External application \"xcalib\" not found. Screen brightness ")
14736 _T(
"not changed."));
14738 g_brightness_init =
true;
14743int RestoreScreenBrightness(
void) {
14746 if (g_pSavedGammaMap) {
14747 HDC hDC = GetDC(NULL);
14748 g_pSetDeviceGammaRamp(hDC,
14750 ReleaseDC(NULL, hDC);
14752 free(g_pSavedGammaMap);
14753 g_pSavedGammaMap = NULL;
14757 g_pcurtain->Close();
14758 g_pcurtain->Destroy();
14762 g_brightness_init =
false;
14767#ifdef BRIGHT_XCALIB
14768 if (g_brightness_init) {
14770 cmd = _T(
"xcalib -clear");
14771 wxExecute(cmd, wxEXEC_ASYNC);
14772 g_brightness_init =
false;
14782int SetScreenBrightness(
int brightness) {
14789 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14791 g_pcurtain->Close();
14792 g_pcurtain->Destroy();
14796 InitScreenBrightness();
14798 if (NULL == hGDI32DLL) {
14800 wchar_t wdll_name[80];
14801 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14802 LPCWSTR cstr = wdll_name;
14804 hGDI32DLL = LoadLibrary(cstr);
14806 if (NULL != hGDI32DLL) {
14808 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14809 hGDI32DLL,
"SetDeviceGammaRamp");
14810 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14811 hGDI32DLL,
"GetDeviceGammaRamp");
14814 if ((NULL == g_pSetDeviceGammaRamp) ||
14815 (NULL == g_pGetDeviceGammaRamp)) {
14816 FreeLibrary(hGDI32DLL);
14823 HDC hDC = GetDC(NULL);
14834 int increment = brightness * 256 / 100;
14837 WORD GammaTable[3][256];
14840 for (
int i = 0; i < 256; i++) {
14841 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14842 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14843 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14845 table_val += increment;
14847 if (table_val > 65535) table_val = 65535;
14850 g_pSetDeviceGammaRamp(hDC, GammaTable);
14851 ReleaseDC(NULL, hDC);
14858 if (g_pSavedGammaMap) {
14859 HDC hDC = GetDC(NULL);
14860 g_pSetDeviceGammaRamp(hDC,
14862 ReleaseDC(NULL, hDC);
14865 if (brightness < 100) {
14866 if (NULL == g_pcurtain) InitScreenBrightness();
14869 int sbrite = wxMax(1, brightness);
14870 sbrite = wxMin(100, sbrite);
14872 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14876 g_pcurtain->Close();
14877 g_pcurtain->Destroy();
14887#ifdef BRIGHT_XCALIB
14889 if (!g_brightness_init) {
14890 last_brightness = 100;
14891 g_brightness_init =
true;
14892 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14893 InitScreenBrightness();
14896#ifdef __OPCPN_USEICC__
14899 if (!CreateSimpleICCProfileFile(
14900 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14901 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14902 wxString cmd(_T (
"xcalib " ));
14903 cmd += temp_file_name;
14905 wxExecute(cmd, wxEXEC_ASYNC);
14914 if (brightness > last_brightness) {
14916 cmd = _T(
"xcalib -clear");
14917 wxExecute(cmd, wxEXEC_ASYNC);
14919 ::wxMilliSleep(10);
14921 int brite_adj = wxMax(1, brightness);
14922 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14923 wxExecute(cmd, wxEXEC_ASYNC);
14925 int brite_adj = wxMax(1, brightness);
14926 int factor = (brite_adj * 100) / last_brightness;
14927 factor = wxMax(1, factor);
14929 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14930 wxExecute(cmd, wxEXEC_ASYNC);
14935 last_brightness = brightness;
14942#ifdef __OPCPN_USEICC__
14944#define MLUT_TAG 0x6d4c5554L
14945#define VCGT_TAG 0x76636774L
14947int GetIntEndian(
unsigned char *s) {
14952 p = (
unsigned char *)&ret;
14955 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14957 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14962unsigned short GetShortEndian(
unsigned char *s) {
14963 unsigned short ret;
14967 p = (
unsigned char *)&ret;
14970 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
14972 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
14978int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14979 double co_green,
double co_blue) {
14983 fp = fopen(file_name,
"wb");
14984 if (!fp)
return -1;
14990 for (
int i = 0; i < 128; i++) header[i] = 0;
14992 fwrite(header, 128, 1, fp);
14996 int numTags = GetIntEndian((
unsigned char *)&numTags0);
14997 fwrite(&numTags, 1, 4, fp);
14999 int tagName0 = VCGT_TAG;
15000 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15001 fwrite(&tagName, 1, 4, fp);
15003 int tagOffset0 = 128 + 4 *
sizeof(int);
15004 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15005 fwrite(&tagOffset, 1, 4, fp);
15008 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15009 fwrite(&tagSize, 1, 4, fp);
15011 fwrite(&tagName, 1, 4, fp);
15013 fwrite(&tagName, 1, 4, fp);
15018 int gammatype0 = 0;
15019 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15020 fwrite(&gammatype, 1, 4, fp);
15022 int numChannels0 = 3;
15023 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15024 fwrite(&numChannels, 1, 2, fp);
15026 int numEntries0 = 256;
15027 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15028 fwrite(&numEntries, 1, 2, fp);
15030 int entrySize0 = 1;
15031 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15032 fwrite(&entrySize, 1, 2, fp);
15034 unsigned char ramp[256];
15037 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15038 fwrite(ramp, 256, 1, fp);
15041 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15042 fwrite(ramp, 256, 1, fp);
15045 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15046 fwrite(ramp, 256, 1, fp);
bool g_bresponsive
Flag to control adaptive UI scaling.
Global state for AIS decoder.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Represents an active track that is currently being recorded.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
void DoZoomCanvas(double factor, bool can_zoom_to_cursor=true)
Internal function that implements the actual zoom operation.
double GetCanvasTrueScale()
Return the physical pixels per meter at chart center, accounting for latitude distortion.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Set the viewport center point.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Manages the chart database and provides access to chart data.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
Primary navigation console display for route and vessel tracking.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Gets a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute, 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.