35#include <wx/graphics.h>
36#include <wx/clipbrd.h>
37#include <wx/aui/aui.h>
41#include "o_sound/o_sound.h"
48#include "model/geodesic.h"
54#include "model/nav_object_database.h"
113#include "tide_time.h"
120#include "s57_ocpn_utils.h"
123#include "androidUTIL.h"
133#include <wx/msw/msvcrt.h>
142#define printf printf2
144int __cdecl printf2(
const char *format, ...) {
148 va_start(argptr, format);
149 int ret = vsnprintf(str,
sizeof(str), format, argptr);
151 OutputDebugStringA(str);
156#if defined(__MSVC__) && (_MSC_VER < 1700)
157#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
163#define OCPN_ALT_MENUBAR 1
171extern ColorScheme global_color_scheme;
172extern wxColor GetDimColor(wxColor c);
174static bool g_bSmoothRecenter =
true;
175static bool bDrawCurrentValues;
196static bool mouse_leftisdown;
197static bool g_brouteCreating;
198static int r_gamma_mult;
199static int g_gamma_mult;
200static int b_gamma_mult;
201static int gamma_state;
202static bool g_brightness_init;
203static int last_brightness;
204static wxGLContext *g_pGLcontext;
207static wxDialog *g_pcurtain;
209static wxString g_lastS52PLIBPluginMessage;
212#define MAX_BRIGHT 100
219EVT_ACTIVATE(ChartCanvas::OnActivate)
220EVT_SIZE(ChartCanvas::OnSize)
221#ifndef HAVE_WX_GESTURE_EVENTS
222EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
224EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
225EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
226EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
227EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
228EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
229EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
230EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
231EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
232EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
233EVT_KEY_UP(ChartCanvas::OnKeyUp)
234EVT_CHAR(ChartCanvas::OnKeyChar)
235EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
236EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
237EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
238EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
239EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
240EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
241EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
242EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
243EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
244EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
250 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
251 m_nmea_log(nmea_log) {
252 parent_frame = (
MyFrame *)frame;
253 m_canvasIndex = canvasIndex;
257 SetBackgroundColour(wxColour(0, 0, 0));
258 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
262 m_bDrawingRoute =
false;
263 m_bRouteEditing =
false;
264 m_bMarkEditing =
false;
265 m_bRoutePoinDragging =
false;
266 m_bIsInRadius =
false;
267 m_bMayToggleMenuBar =
true;
270 m_bShowNavobjects =
true;
272 m_bAppendingRoute =
false;
273 pThumbDIBShow = NULL;
274 m_bShowCurrent =
false;
276 bShowingCurrent =
false;
280 m_b_paint_enable =
true;
283 pss_overlay_bmp = NULL;
284 pss_overlay_mask = NULL;
285 m_bChartDragging =
false;
286 m_bMeasure_Active =
false;
287 m_bMeasure_DistCircle =
false;
288 m_pMeasureRoute = NULL;
289 m_pTrackRolloverWin = NULL;
290 m_pRouteRolloverWin = NULL;
291 m_pAISRolloverWin = NULL;
293 m_disable_edge_pan =
false;
294 m_dragoffsetSet =
false;
298 m_singleChart = NULL;
299 m_upMode = NORTH_UP_MODE;
301 m_bShowAISScaled =
false;
302 m_timed_move_vp_active =
false;
304 m_disable_adjust_on_zoom =
false;
311 m_pSelectedRoute = NULL;
312 m_pSelectedTrack = NULL;
313 m_pRoutePointEditTarget = NULL;
314 m_pFoundPoint = NULL;
315 m_pMouseRoute = NULL;
316 m_prev_pMousePoint = NULL;
317 m_pEditRouteArray = NULL;
318 m_pFoundRoutePoint = NULL;
319 m_FinishRouteOnKillFocus =
true;
321 m_pRolloverRouteSeg = NULL;
322 m_pRolloverTrackSeg = NULL;
323 m_bsectors_shown =
false;
325 m_bbrightdir =
false;
330 m_pos_image_user_day = NULL;
331 m_pos_image_user_dusk = NULL;
332 m_pos_image_user_night = NULL;
333 m_pos_image_user_grey_day = NULL;
334 m_pos_image_user_grey_dusk = NULL;
335 m_pos_image_user_grey_night = NULL;
338 m_rotation_speed = 0;
344 m_pos_image_user_yellow_day = NULL;
345 m_pos_image_user_yellow_dusk = NULL;
346 m_pos_image_user_yellow_night = NULL;
348 SetOwnShipState(SHIP_INVALID);
350 undo =
new Undo(
this);
356 m_focus_indicator_pix = 1;
358 m_pCurrentStack = NULL;
359 m_bpersistent_quilt =
false;
360 m_piano_ctx_menu = NULL;
362 m_NotificationsList = NULL;
363 m_notification_button = NULL;
365 g_ChartNotRenderScaleFactor = 2.0;
366 m_bShowScaleInStatusBar =
true;
369 m_bShowScaleInStatusBar =
false;
370 m_show_focus_bar =
true;
372 m_bShowOutlines =
false;
373 m_bDisplayGrid =
false;
374 m_bShowDepthUnits =
true;
375 m_encDisplayCategory = (int)STANDARD;
377 m_encShowLights =
true;
378 m_encShowAnchor =
true;
379 m_encShowDataQual =
false;
381 m_pQuilt =
new Quilt(
this);
386 g_PrintingInProgress =
false;
388#ifdef HAVE_WX_GESTURE_EVENTS
389 m_oldVPSScale = -1.0;
390 m_popupWanted =
false;
393 m_inLongPress =
false;
396 m_sw_left_down.Start();
397 m_sw_left_up.Start();
401 singleClickEventIsValid =
false;
410 pCursorPencil = NULL;
415 SetCursor(*pCursorArrow);
417 pPanTimer =
new wxTimer(
this, m_MouseDragging);
420 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
421 pMovementTimer->Stop();
423 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
424 pMovementStopTimer->Stop();
426 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
427 pRotDefTimer->Stop();
429 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
430 m_DoubleClickTimer->Stop();
432 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
433 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
434 m_chart_drag_inertia_active =
false;
436 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
437 m_animationActive =
false;
438 m_menuTimer.SetOwner(
this, MENU_TIMER);
439 m_tap_timer.SetOwner(
this, TAP_TIMER);
443 m_panx_target_final = m_pany_target_final = 0;
444 m_panx_target_now = m_pany_target_now = 0;
447 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
448 pCurTrackTimer->Stop();
449 m_curtrack_timer_msec = 10;
451 m_wheelzoom_stop_oneshot = 0;
452 m_last_wheel_dir = 0;
454 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
456 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
458 m_rollover_popup_timer_msec = 20;
460 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
462 m_b_rot_hidef =
true;
467 m_upMode = NORTH_UP_MODE;
468 m_bLookAhead =
false;
472 m_cs = GLOBAL_COLOR_SCHEME_DAY;
475 VPoint.view_scale_ppm = 1;
478 m_ignore_next_leftup =
false;
480 m_canvas_scale_factor = 1.;
482 m_canvas_width = 1000;
484 m_overzoomTextWidth = 0;
485 m_overzoomTextHeight = 0;
494 m_pEM_Fathoms = NULL;
496 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
498 m_pEM_OverZoom = NULL;
500 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
508 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
511 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
514 double factor_dusk = 0.5;
515 double factor_night = 0.25;
518 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
520 int rimg_width = m_os_image_red_day.GetWidth();
521 int rimg_height = m_os_image_red_day.GetHeight();
523 m_os_image_red_dusk = m_os_image_red_day.Copy();
524 m_os_image_red_night = m_os_image_red_day.Copy();
526 for (
int iy = 0; iy < rimg_height; iy++) {
527 for (
int ix = 0; ix < rimg_width; ix++) {
528 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
529 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
530 m_os_image_red_day.GetGreen(ix, iy),
531 m_os_image_red_day.GetBlue(ix, iy));
532 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
533 hsv.value = hsv.value * factor_dusk;
534 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
535 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
537 hsv = wxImage::RGBtoHSV(rgb);
538 hsv.value = hsv.value * factor_night;
539 nrgb = wxImage::HSVtoRGB(hsv);
540 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
546 m_os_image_grey_day =
547 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
549 int gimg_width = m_os_image_grey_day.GetWidth();
550 int gimg_height = m_os_image_grey_day.GetHeight();
552 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
553 m_os_image_grey_night = m_os_image_grey_day.Copy();
555 for (
int iy = 0; iy < gimg_height; iy++) {
556 for (
int ix = 0; ix < gimg_width; ix++) {
557 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
558 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
559 m_os_image_grey_day.GetGreen(ix, iy),
560 m_os_image_grey_day.GetBlue(ix, iy));
561 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
562 hsv.value = hsv.value * factor_dusk;
563 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
564 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
566 hsv = wxImage::RGBtoHSV(rgb);
567 hsv.value = hsv.value * factor_night;
568 nrgb = wxImage::HSVtoRGB(hsv);
569 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
575 m_os_image_yellow_day = m_os_image_red_day.Copy();
577 gimg_width = m_os_image_yellow_day.GetWidth();
578 gimg_height = m_os_image_yellow_day.GetHeight();
580 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
581 m_os_image_yellow_night = m_os_image_red_day.Copy();
583 for (
int iy = 0; iy < gimg_height; iy++) {
584 for (
int ix = 0; ix < gimg_width; ix++) {
585 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
586 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
587 m_os_image_yellow_day.GetGreen(ix, iy),
588 m_os_image_yellow_day.GetBlue(ix, iy));
589 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
590 hsv.hue += 60. / 360.;
591 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
592 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
594 hsv = wxImage::RGBtoHSV(rgb);
595 hsv.value = hsv.value * factor_dusk;
596 hsv.hue += 60. / 360.;
597 nrgb = wxImage::HSVtoRGB(hsv);
598 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
600 hsv = wxImage::RGBtoHSV(rgb);
601 hsv.hue += 60. / 360.;
602 hsv.value = hsv.value * factor_night;
603 nrgb = wxImage::HSVtoRGB(hsv);
604 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
610 m_pos_image_red = &m_os_image_red_day;
611 m_pos_image_yellow = &m_os_image_yellow_day;
612 m_pos_image_grey = &m_os_image_grey_day;
616 m_pBrightPopup = NULL;
619 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
624 m_Piano =
new Piano(
this);
626 m_bShowCompassWin =
true;
628 m_Compass->SetScaleFactor(g_compass_scalefactor);
629 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
631 if (IsPrimaryCanvas()) {
633 m_notification_button->SetScaleFactor(g_compass_scalefactor);
634 m_notification_button->Show(
true);
637 m_pianoFrozen =
false;
639 SetMinSize(wxSize(200, 200));
641 m_displayScale = 1.0;
642#if defined(__WXOSX__) || defined(__WXGTK3__)
644 m_displayScale = GetContentScaleFactor();
646 VPoint.SetPixelScale(m_displayScale);
648#ifdef HAVE_WX_GESTURE_EVENTS
651 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
652 wxLogError(
"Failed to enable touch events");
657 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
658 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
660 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
661 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
663 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
664 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
666 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
667 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
672 auto ¬eman = NotificationManager::GetInstance();
674 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
675 evt_notificationlist_change_listener.Listen(
676 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
677 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
678 if (m_NotificationsList && m_NotificationsList->IsShown()) {
679 m_NotificationsList->ReloadNotificationList();
685ChartCanvas::~ChartCanvas() {
686 delete pThumbDIBShow;
694 delete pCursorPencil;
698 delete pMovementTimer;
699 delete pMovementStopTimer;
700 delete pCurTrackTimer;
702 delete m_DoubleClickTimer;
704 delete m_pTrackRolloverWin;
705 delete m_pRouteRolloverWin;
706 delete m_pAISRolloverWin;
707 delete m_pBrightPopup;
713 m_dc_route.SelectObject(wxNullBitmap);
716 delete pWorldBackgroundChart;
717 delete pss_overlay_bmp;
721 delete m_pEM_Fathoms;
723 delete m_pEM_OverZoom;
728 delete m_pos_image_user_day;
729 delete m_pos_image_user_dusk;
730 delete m_pos_image_user_night;
731 delete m_pos_image_user_grey_day;
732 delete m_pos_image_user_grey_dusk;
733 delete m_pos_image_user_grey_night;
734 delete m_pos_image_user_yellow_day;
735 delete m_pos_image_user_yellow_dusk;
736 delete m_pos_image_user_yellow_night;
740 if (!g_bdisable_opengl) {
743#if wxCHECK_VERSION(2, 9, 0)
744 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
751 MUIBar *muiBar = m_muiBar;
755 delete m_pCurrentStack;
760void ChartCanvas::SetupGridFont() {
761 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
763 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
765 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
766 FALSE, wxString(
"Arial"));
769void ChartCanvas::RebuildCursors() {
775 delete pCursorPencil;
779 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
783 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
784 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
785 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
786 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
787 wxImage ICursorPencil =
788 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
789 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
791#if !defined(__WXMSW__) && !defined(__WXQT__)
792 ICursorLeft.ConvertAlphaToMask(128);
793 ICursorRight.ConvertAlphaToMask(128);
794 ICursorUp.ConvertAlphaToMask(128);
795 ICursorDown.ConvertAlphaToMask(128);
796 ICursorPencil.ConvertAlphaToMask(10);
797 ICursorCross.ConvertAlphaToMask(10);
800 if (ICursorLeft.Ok()) {
801 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
802 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
803 pCursorLeft =
new wxCursor(ICursorLeft);
805 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
807 if (ICursorRight.Ok()) {
808 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
809 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
810 pCursorRight =
new wxCursor(ICursorRight);
812 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
814 if (ICursorUp.Ok()) {
815 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
816 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
817 pCursorUp =
new wxCursor(ICursorUp);
819 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
821 if (ICursorDown.Ok()) {
822 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
823 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
824 pCursorDown =
new wxCursor(ICursorDown);
826 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
828 if (ICursorPencil.Ok()) {
829 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
830 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
831 pCursorPencil =
new wxCursor(ICursorPencil);
833 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
835 if (ICursorCross.Ok()) {
836 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
837 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
838 pCursorCross =
new wxCursor(ICursorCross);
840 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
842 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
843 pPlugIn_Cursor = NULL;
846void ChartCanvas::CanvasApplyLocale() {
847 CreateDepthUnitEmbossMaps(m_cs);
848 CreateOZEmbossMapData(m_cs);
851void ChartCanvas::SetupGlCanvas() {
854 if (!g_bdisable_opengl) {
856 wxLogMessage(
"Creating glChartCanvas");
861 if (IsPrimaryCanvas()) {
868 wxGLContext *pctx =
new wxGLContext(m_glcc);
869 m_glcc->SetContext(pctx);
873 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
875 m_glcc->SetContext(g_pGLcontext);
885 if (!g_bdisable_opengl) {
888 wxLogMessage(
"Creating glChartCanvas");
892 if (IsPrimaryCanvas()) {
893 qDebug() <<
"Creating Primary glChartCanvas";
901 wxGLContext *pctx =
new wxGLContext(m_glcc);
902 m_glcc->SetContext(pctx);
904 m_glcc->m_pParentCanvas =
this;
907 qDebug() <<
"Creating Secondary glChartCanvas";
913 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
916 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
917 m_glcc->SetContext(pwxctx);
918 m_glcc->m_pParentCanvas =
this;
926void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
927 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
942 if (m_routeState && m_FinishRouteOnKillFocus)
943 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
945 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
949void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
950 m_routeFinishTimer.Stop();
954 gFrame->UpdateGlobalMenuItems(
this);
956 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
959void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
960 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
963#ifdef HAVE_WX_GESTURE_EVENTS
964void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
971 m_popupWanted =
true;
973 m_inLongPress = !g_bhide_context_menus;
976 m_menuPos =
event.GetPosition();
977 wxMouseEvent ev(wxEVT_LEFT_UP);
978 ev.m_x = m_menuPos.x;
979 ev.m_y = m_menuPos.y;
980 wxPostEvent(
this, ev);
984 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
985 ev_right_click.m_x = m_menuPos.x;
986 ev_right_click.m_y = m_menuPos.y;
987 MouseEvent(ev_right_click);
992void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
996void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
998void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1000void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1002 long dt = m_sw_left_up.Time() - m_sw_up_time;
1003 m_sw_up_time = m_sw_left_up.Time();
1014 wxPoint pos =
event.GetPosition();
1018 if (!m_popupWanted) {
1019 wxMouseEvent ev(wxEVT_LEFT_UP);
1026 m_popupWanted =
false;
1028 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1035void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1040 long dt = m_sw_left_down.Time() - m_sw_down_time;
1041 m_sw_down_time = m_sw_left_down.Time();
1065 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1067 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1068 m_lastTapPos.y - max_double_click_distance,
1069 max_double_click_distance * 2, max_double_click_distance * 2);
1072 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1078 m_lastTapPos =
event.GetPosition();
1079 m_tap_timer.StartOnce(
1083 if (m_tap_count == 2) {
1087 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1100void ChartCanvas::OnMotion(wxMouseEvent &event) {
1105 event.m_leftDown = m_leftdown;
1109void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1111 if (event.IsGestureEnd())
return;
1113 double factor =
event.GetZoomFactor();
1115 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1120 double wanted_factor = m_oldVPSScale / current_vps * factor;
1125 if (event.IsGestureStart()) {
1126 m_zoomStartPoint =
event.GetPosition();
1128 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1130 m_zoomStartPoint =
event.GetPosition();
1134void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1136void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1137 DoRotateCanvas(0.0);
1141void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1146void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1147 m_FinishRouteOnKillFocus =
false;
1148 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1149 m_FinishRouteOnKillFocus =
true;
1152void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1157 m_restore_dbindex = pcc->DBindex;
1159 if (pcc->GroupID < 0) pcc->GroupID = 0;
1164 m_groupIndex = pcc->GroupID;
1166 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1180 m_encDisplayCategory = pcc->nENCDisplayCategory;
1181 m_encShowDepth = pcc->bShowENCDepths;
1182 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1183 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1184 m_encShowLights = pcc->bShowENCLights;
1185 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1186 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1187 m_encShowDataQual = pcc->bShowENCDataQuality;
1191 m_upMode = NORTH_UP_MODE;
1193 m_upMode = COURSE_UP_MODE;
1195 m_upMode = HEAD_UP_MODE;
1199 m_singleChart = NULL;
1202void ChartCanvas::ApplyGlobalSettings() {
1205 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1206 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1208 if (m_notification_button) m_notification_button->UpdateStatus();
1211void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1212 bool groupOK = CheckGroup(m_groupIndex);
1215 SetGroupIndex(m_groupIndex,
true);
1219void ChartCanvas::SetShowGPS(
bool bshow) {
1220 if (m_bShowGPS != bshow) {
1223 m_Compass->SetScaleFactor(g_compass_scalefactor);
1224 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1229void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1230 m_bShowCompassWin = bshow;
1232 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1233 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1237int ChartCanvas::GetPianoHeight() {
1239 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1244void ChartCanvas::ConfigureChartBar() {
1247 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1248 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1250 if (GetQuiltMode()) {
1251 m_Piano->SetRoundedRectangles(
true);
1253 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1254 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1255 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1258void ChartCanvas::ShowTides(
bool bShow) {
1259 gFrame->LoadHarmonics();
1262 SetbShowTide(bShow);
1264 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1266 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1267 SetbShowTide(
false);
1268 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1271 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1272 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1283void ChartCanvas::ShowCurrents(
bool bShow) {
1284 gFrame->LoadHarmonics();
1287 SetbShowCurrent(bShow);
1288 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1290 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1291 SetbShowCurrent(
false);
1292 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1295 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1296 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1313void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1315void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1318 int new_index = index;
1321 bool bgroup_override =
false;
1322 int old_group_index = new_index;
1324 if (!CheckGroup(new_index)) {
1326 bgroup_override =
true;
1329 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1333 int current_chart_native_scale = GetCanvasChartNativeScale();
1336 m_groupIndex = new_index;
1342 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1346 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1350 g_sticky_chart = -1;
1354 UpdateCanvasOnGroupChange();
1357 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1359 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1362 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1363 double best_scale = GetBestStartScale(dbi_hint, vp);
1367 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1371 canvasChartsRefresh(dbi_hint);
1373 UpdateCanvasControlBar();
1375 if (!autoSwitch && bgroup_override) {
1377 wxString msg(_(
"Group \""));
1380 msg += pGroup->m_group_name;
1382 msg += _(
"\" is empty.");
1384 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1391 if (bgroup_override) {
1392 wxString msg(_(
"Group \""));
1395 msg += pGroup->m_group_name;
1397 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1399 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1403bool ChartCanvas::CheckGroup(
int igroup) {
1406 if (igroup == 0)
return true;
1413 if (pGroup->m_element_array.empty())
1417 for (
const auto &elem : pGroup->m_element_array) {
1418 for (
unsigned int ic = 0;
1419 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1421 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1423 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1428 for (
const auto &elem : pGroup->m_element_array) {
1429 const wxString &element_root = elem.m_element_name;
1430 wxString test_string =
"GSHH";
1431 if (element_root.Upper().Contains(test_string))
return true;
1437void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1440 AbstractPlatform::ShowBusySpinner();
1444 SetQuiltRefChart(-1);
1446 m_singleChart = NULL;
1452 if (!m_pCurrentStack) {
1454 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1457 if (-1 != dbi_hint) {
1458 if (GetQuiltMode()) {
1459 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1460 SetQuiltRefChart(dbi_hint);
1464 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1466 if (pTentative_Chart) {
1469 if (m_singleChart) m_singleChart->Deactivate();
1471 m_singleChart = pTentative_Chart;
1472 m_singleChart->Activate();
1474 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1475 GetpCurrentStack(), m_singleChart->GetFullPath());
1483 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1484 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1485 SetQuiltRefChart(selected_index);
1489 SetupCanvasQuiltMode();
1490 if (!GetQuiltMode() && m_singleChart == 0) {
1492 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1493 m_singleChart = pDummyChart;
1499 UpdateCanvasControlBar();
1500 UpdateGPSCompassStatusBox(
true);
1502 SetCursor(wxCURSOR_ARROW);
1504 AbstractPlatform::HideBusySpinner();
1507bool ChartCanvas::DoCanvasUpdate() {
1509 double vpLat, vpLon;
1510 bool blong_jump =
false;
1511 meters_to_shift = 0;
1514 bool bNewChart =
false;
1515 bool bNewView =
false;
1516 bool bCanvasChartAutoOpen =
true;
1518 bool bNewPiano =
false;
1519 bool bOpenSpecified;
1525 if (bDBUpdateInProgress)
return false;
1529 if (m_chart_drag_inertia_active)
return false;
1555 double dx = m_OSoffsetx;
1556 double dy = m_OSoffsety;
1560 if (GetUpMode() == NORTH_UP_MODE) {
1561 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1563 double offset_angle = atan2(d_north, d_east);
1564 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1565 double chart_angle = GetVPRotation();
1566 double target_angle = chart_angle + offset_angle;
1567 double d_east_mod = offset_distance * cos(target_angle);
1568 double d_north_mod = offset_distance * sin(target_angle);
1569 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1573 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1574 double cog_to_use =
gCog;
1576 (fabs(
gCog - gCog_gt) > 20)) {
1577 cog_to_use = gCog_gt;
1580 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1582 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1584 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1585 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1587 double pixel_delta_tent =
1588 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1590 double pixel_delta = 0;
1595 if (!std::isnan(
gSog)) {
1599 pixel_delta = pixel_delta_tent;
1602 meters_to_shift = 0;
1604 if (!std::isnan(
gCog)) {
1605 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1606 dir_to_shift = cog_to_use;
1607 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1613 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1627 if (GetQuiltMode()) {
1628 int current_db_index = -1;
1629 if (m_pCurrentStack)
1632 ->GetCurrentEntrydbIndex();
1640 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1642 if (m_pCurrentStack->nEntry) {
1643 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1645 SelectQuiltRefdbChart(new_dbIndex,
true);
1646 m_bautofind =
false;
1650 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1651 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1656 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1662 double proposed_scale_onscreen =
1665 int initial_db_index = m_restore_dbindex;
1666 if (initial_db_index < 0) {
1667 if (m_pCurrentStack->nEntry) {
1669 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1674 if (m_pCurrentStack->nEntry) {
1675 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1680 if (!IsChartQuiltableRef(initial_db_index)) {
1684 int stack_index = 0;
1686 if (stack_index >= 0) {
1687 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1688 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1689 if (IsChartQuiltableRef(test_db_index) &&
1691 ChartData->GetDBChartType(initial_db_index))) {
1692 initial_db_index = test_db_index;
1702 SetQuiltRefChart(initial_db_index);
1703 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1711 0, GetVPRotation());
1716 bool super_jump =
false;
1718 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1719 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1720 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1723 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1725 if (blong_jump) nstep = 20;
1726 StartTimedMovementVP(vpLat, vpLon, nstep);
1737 pLast_Ch = m_singleChart;
1738 ChartTypeEnum new_open_type;
1739 ChartFamilyEnum new_open_family;
1741 new_open_type = pLast_Ch->GetChartType();
1742 new_open_family = pLast_Ch->GetChartFamily();
1744 new_open_type = CHART_TYPE_KAP;
1745 new_open_family = CHART_FAMILY_RASTER;
1748 bOpenSpecified = m_bFirstAuto;
1751 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1754 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1756 if (NULL == pDummyChart) {
1762 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1764 m_singleChart = pDummyChart;
1769 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1771 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1774 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1775 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1782 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1788 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1793 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1796 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1801 if (NULL != m_singleChart)
1802 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1803 m_singleChart->GetFullPath());
1806 m_pCurrentStack->CurrentStackEntry = tEntry;
1816 if (bCanvasChartAutoOpen) {
1817 bool search_direction =
1819 int start_index = 0;
1823 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1824 (LastStack.nEntry == 0)) {
1825 search_direction =
true;
1826 start_index = m_pCurrentStack->nEntry - 1;
1830 if (bOpenSpecified) {
1831 search_direction =
false;
1833 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1836 new_open_type = CHART_TYPE_DONTCARE;
1839 pProposed =
ChartData->OpenStackChartConditional(
1840 m_pCurrentStack, start_index, search_direction, new_open_type,
1844 if (NULL == pProposed)
1845 pProposed =
ChartData->OpenStackChartConditional(
1846 m_pCurrentStack, start_index, search_direction,
1847 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1849 if (NULL == pProposed)
1850 pProposed =
ChartData->OpenStackChartConditional(
1851 m_pCurrentStack, start_index, search_direction,
1852 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1863 if (NULL == pProposed) {
1864 if (NULL == pDummyChart) {
1870 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1872 pProposed = pDummyChart;
1876 if (m_singleChart) m_singleChart->Deactivate();
1877 m_singleChart = pProposed;
1879 if (m_singleChart) {
1880 m_singleChart->Activate();
1881 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1882 m_pCurrentStack, m_singleChart->GetFullPath());
1887 if (NULL != m_singleChart) {
1893 if (!GetVP().IsValid())
1894 set_scale = 1. / 20000.;
1896 double proposed_scale_onscreen;
1899 double new_scale_ppm =
1900 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1908 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1909 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1910 double equivalent_vp_scale =
1912 double new_scale_ppm =
1913 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1918 proposed_scale_onscreen =
1919 wxMin(proposed_scale_onscreen,
1922 proposed_scale_onscreen =
1923 wxMax(proposed_scale_onscreen,
1932 m_singleChart->GetChartSkew() * PI / 180.,
1939 if ((m_bFollow) && m_singleChart)
1941 m_singleChart->GetChartSkew() * PI / 180.,
1950 m_bFirstAuto =
false;
1954 if (bNewChart && !bNewView) Refresh(
false);
1959 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1962 return bNewChart | bNewView;
1965void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1966 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1968 SetQuiltRefChart(db_index);
1973 double best_scale_ppm = GetBestVPScale(pc);
1977 SetQuiltRefChart(-1);
1979 SetQuiltRefChart(-1);
1982void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1983 std::vector<int> piano_chart_index_array =
1984 GetQuiltExtendedStackdbIndexArray();
1985 int current_db_index = piano_chart_index_array[selected_index];
1987 SelectQuiltRefdbChart(current_db_index);
1990double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1994 if ((g_bPreserveScaleOnX) ||
1995 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2001 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2002 double equivalent_vp_scale =
2004 double new_scale_ppm =
2005 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2012 double max_underzoom_multiplier = 2.0;
2013 if (GetVP().b_quilt) {
2014 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2015 pchart->GetChartType(),
2016 pchart->GetChartFamily());
2017 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2020 proposed_scale_onscreen = wxMin(
2021 proposed_scale_onscreen,
2023 max_underzoom_multiplier);
2026 proposed_scale_onscreen =
2027 wxMax(proposed_scale_onscreen,
2035void ChartCanvas::SetupCanvasQuiltMode() {
2040 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2044 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2045 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2046 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2047 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2049 m_Piano->SetRoundedRectangles(
true);
2052 int target_new_dbindex = -1;
2053 if (m_pCurrentStack) {
2054 target_new_dbindex =
2055 GetQuiltReferenceChartIndex();
2057 if (-1 != target_new_dbindex) {
2058 if (!IsChartQuiltableRef(target_new_dbindex)) {
2059 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2060 int type =
ChartData->GetDBChartType(target_new_dbindex);
2063 int stack_index = m_pCurrentStack->CurrentStackEntry;
2065 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2066 (stack_index >= 0)) {
2067 int proj_tent =
ChartData->GetDBChartProj(
2068 m_pCurrentStack->GetDBIndex(stack_index));
2069 int type_tent =
ChartData->GetDBChartType(
2070 m_pCurrentStack->GetDBIndex(stack_index));
2072 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2073 if ((proj == proj_tent) && (type_tent == type)) {
2074 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2084 if (IsChartQuiltableRef(target_new_dbindex))
2085 SelectQuiltRefdbChart(target_new_dbindex,
2088 SelectQuiltRefdbChart(-1,
false);
2090 m_singleChart = NULL;
2093 AdjustQuiltRefChart();
2101 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2105 std::vector<int> empty_array;
2106 m_Piano->SetActiveKeyArray(empty_array);
2107 m_Piano->SetNoshowIndexArray(empty_array);
2108 m_Piano->SetEclipsedIndexArray(empty_array);
2111 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2112 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2113 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2114 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2116 m_Piano->SetRoundedRectangles(
false);
2122 if (!GetQuiltMode()) {
2127 if (m_bFollow ==
true) {
2135 if (!m_singleChart) {
2138 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2146 int cur_max_scale = (int)1e8;
2148 ChartBase *pChart = GetFirstQuiltChart();
2152 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2154 if (pChart->GetNativeScale() < cur_max_scale) {
2155 Candidate_Chart = pChart;
2156 cur_max_scale = pChart->GetNativeScale();
2159 pChart = GetNextQuiltChart();
2162 m_singleChart = Candidate_Chart;
2166 if (NULL == m_singleChart) {
2167 m_singleChart =
ChartData->OpenStackChartConditional(
2168 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2169 CHART_FAMILY_DONTCARE);
2175 InvalidateAllQuiltPatchs();
2177 if (m_singleChart) {
2178 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2179 std::vector<int> one_array;
2180 one_array.push_back(dbi);
2181 m_Piano->SetActiveKeyArray(one_array);
2184 if (m_singleChart) {
2185 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2189 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2193bool ChartCanvas::IsTempMenuBarEnabled() {
2196 wxGetOsVersion(&major);
2204double ChartCanvas::GetCanvasRangeMeters() {
2206 GetSize(&width, &height);
2207 int minDimension = wxMin(width, height);
2210 range *= cos(GetVP().clat * PI / 180.);
2214void ChartCanvas::SetCanvasRangeMeters(
double range) {
2216 GetSize(&width, &height);
2217 int minDimension = wxMin(width, height);
2219 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2223bool ChartCanvas::SetUserOwnship() {
2227 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2228 double factor_dusk = 0.5;
2229 double factor_night = 0.25;
2231 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2232 m_pos_image_user_day =
new wxImage;
2233 *m_pos_image_user_day = pbmp->ConvertToImage();
2234 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2236 int gimg_width = m_pos_image_user_day->GetWidth();
2237 int gimg_height = m_pos_image_user_day->GetHeight();
2240 m_pos_image_user_dusk =
new wxImage;
2241 m_pos_image_user_night =
new wxImage;
2243 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2244 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2246 for (
int iy = 0; iy < gimg_height; iy++) {
2247 for (
int ix = 0; ix < gimg_width; ix++) {
2248 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2249 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2250 m_pos_image_user_day->GetGreen(ix, iy),
2251 m_pos_image_user_day->GetBlue(ix, iy));
2252 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2253 hsv.value = hsv.value * factor_dusk;
2254 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2255 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2258 hsv = wxImage::RGBtoHSV(rgb);
2259 hsv.value = hsv.value * factor_night;
2260 nrgb = wxImage::HSVtoRGB(hsv);
2261 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2268 m_pos_image_user_grey_day =
new wxImage;
2269 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2271 m_pos_image_user_grey_dusk =
new wxImage;
2272 m_pos_image_user_grey_night =
new wxImage;
2274 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2275 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2277 for (
int iy = 0; iy < gimg_height; iy++) {
2278 for (
int ix = 0; ix < gimg_width; ix++) {
2279 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2280 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2281 m_pos_image_user_grey_day->GetGreen(ix, iy),
2282 m_pos_image_user_grey_day->GetBlue(ix, iy));
2283 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2284 hsv.value = hsv.value * factor_dusk;
2285 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2286 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2289 hsv = wxImage::RGBtoHSV(rgb);
2290 hsv.value = hsv.value * factor_night;
2291 nrgb = wxImage::HSVtoRGB(hsv);
2292 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2299 m_pos_image_user_yellow_day =
new wxImage;
2300 m_pos_image_user_yellow_dusk =
new wxImage;
2301 m_pos_image_user_yellow_night =
new wxImage;
2303 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2304 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2305 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2307 for (
int iy = 0; iy < gimg_height; iy++) {
2308 for (
int ix = 0; ix < gimg_width; ix++) {
2309 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2310 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2311 m_pos_image_user_grey_day->GetGreen(ix, iy),
2312 m_pos_image_user_grey_day->GetBlue(ix, iy));
2316 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2317 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2318 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2320 hsv = wxImage::RGBtoHSV(rgb);
2321 hsv.value = hsv.value * factor_dusk;
2322 nrgb = wxImage::HSVtoRGB(hsv);
2323 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2325 hsv = wxImage::RGBtoHSV(rgb);
2326 hsv.value = hsv.value * factor_night;
2327 nrgb = wxImage::HSVtoRGB(hsv);
2328 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2340 m_display_size_mm = size;
2347 double horizontal = sd.x;
2351 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2352 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2356 ps52plib->SetPPMM(m_pix_per_mm);
2361 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2363 m_display_size_mm, sd.x, sd.y);
2369 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2372 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2375void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2377 wxString msg(event.m_string.c_str(), wxConvUTF8);
2379 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2380 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2383 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2385 compress_msg_array.RemoveAt(event.thread);
2386 compress_msg_array.Insert( msg, event.thread);
2389 compress_msg_array.Add(msg);
2392 wxString combined_msg;
2393 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2394 combined_msg += compress_msg_array[i];
2395 combined_msg +=
"\n";
2399 pprog->Update(pprog_count, combined_msg, &skip );
2400 pprog->SetSize(pprog_size);
2405void ChartCanvas::InvalidateGL() {
2406 if (!m_glcc)
return;
2408 if (g_bopengl) m_glcc->Invalidate();
2410 if (m_Compass) m_Compass->UpdateStatus(
true);
2413int ChartCanvas::GetCanvasChartNativeScale() {
2415 if (!VPoint.b_quilt) {
2416 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2418 ret = (int)m_pQuilt->GetRefNativeScale();
2423ChartBase *ChartCanvas::GetChartAtCursor() {
2425 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2426 target_chart = m_singleChart;
2427 else if (VPoint.b_quilt)
2428 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2430 target_chart = NULL;
2431 return target_chart;
2434ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2438 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2440 target_chart = NULL;
2441 return target_chart;
2444int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2445 int new_dbIndex = -1;
2446 if (!VPoint.b_quilt) {
2447 if (m_pCurrentStack) {
2448 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2449 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2451 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2461 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2463 for (
unsigned int is = 0; is < im; is++) {
2465 m_pQuilt->GetExtendedStackIndexArray()[is]);
2468 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2478void ChartCanvas::EnablePaint(
bool b_enable) {
2479 m_b_paint_enable = b_enable;
2481 if (m_glcc) m_glcc->EnablePaint(b_enable);
2485bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2487void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2489std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2490 return m_pQuilt->GetQuiltIndexArray();
2494void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2495 VPoint.b_quilt = b_quilt;
2496 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2499bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2501int ChartCanvas::GetQuiltReferenceChartIndex() {
2502 return m_pQuilt->GetRefChartdbIndex();
2505void ChartCanvas::InvalidateAllQuiltPatchs() {
2506 m_pQuilt->InvalidateAllQuiltPatchs();
2509ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2510 return m_pQuilt->GetLargestScaleChart();
2513ChartBase *ChartCanvas::GetFirstQuiltChart() {
2514 return m_pQuilt->GetFirstChart();
2517ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2519int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2521void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2522 m_pQuilt->SetHiliteIndex(dbIndex);
2525void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2526 m_pQuilt->SetHiliteIndexArray(hilite_array);
2529void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2530 m_pQuilt->ClearHiliteIndexArray();
2533std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2535 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2538int ChartCanvas::GetQuiltRefChartdbIndex() {
2539 return m_pQuilt->GetRefChartdbIndex();
2542std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2543 return m_pQuilt->GetExtendedStackIndexArray();
2546std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2547 return m_pQuilt->GetFullscreenIndexArray();
2550std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2551 return m_pQuilt->GetEclipsedStackIndexArray();
2554void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2556double ChartCanvas::GetQuiltMaxErrorFactor() {
2557 return m_pQuilt->GetMaxErrorFactor();
2560bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2561 return m_pQuilt->IsChartQuiltableRef(db_index);
2565 double chartMaxScale =
2567 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2570void ChartCanvas::StartMeasureRoute() {
2571 if (!m_routeState) {
2572 if (m_bMeasure_Active) {
2574 m_pMeasureRoute = NULL;
2577 m_bMeasure_Active =
true;
2578 m_nMeasureState = 1;
2579 m_bDrawingRoute =
false;
2581 SetCursor(*pCursorPencil);
2586void ChartCanvas::CancelMeasureRoute() {
2587 m_bMeasure_Active =
false;
2588 m_nMeasureState = 0;
2589 m_bDrawingRoute =
false;
2592 m_pMeasureRoute = NULL;
2594 SetCursor(*pCursorArrow);
2597ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2599void ChartCanvas::SetVP(
ViewPort &vp) {
2610void ChartCanvas::TriggerDeferredFocus() {
2613 m_deferredFocusTimer.Start(20,
true);
2615#if defined(__WXGTK__) || defined(__WXOSX__)
2626void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2631void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2632 if (SendKeyEventToPlugins(event))
2636 int key_char =
event.GetKeyCode();
2639 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2645 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2650 if (g_benable_rotate) {
2671void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2672 if (SendKeyEventToPlugins(event))
2676 bool b_handled =
false;
2678 m_modkeys =
event.GetModifiers();
2680 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2682#ifdef OCPN_ALT_MENUBAR
2688 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2690 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2691 if (!g_bTempShowMenuBar) {
2692 g_bTempShowMenuBar =
true;
2693 parent_frame->ApplyGlobalSettings(
false);
2695 m_bMayToggleMenuBar =
false;
2701 if (event.GetKeyCode() != WXK_ALT) {
2702 m_bMayToggleMenuBar =
false;
2709 switch (event.GetKeyCode()) {
2716 event.GetPosition(&x, &y);
2717 m_FinishRouteOnKillFocus =
false;
2718 CallPopupMenu(x, y);
2719 m_FinishRouteOnKillFocus =
true;
2723 m_modkeys |= wxMOD_ALT;
2727 m_modkeys |= wxMOD_CONTROL;
2732 case WXK_RAW_CONTROL:
2733 m_modkeys |= wxMOD_RAW_CONTROL;
2738 if (m_modkeys == wxMOD_CONTROL)
2739 parent_frame->DoStackDown(
this);
2741 StartTimedMovement();
2751 StartTimedMovement();
2759 if (m_modkeys == wxMOD_CONTROL)
2760 parent_frame->DoStackUp(
this);
2762 StartTimedMovement();
2772 StartTimedMovement();
2784 SetShowENCText(!GetShowENCText());
2790 if (!m_bMeasure_Active) {
2791 if (event.ShiftDown())
2792 m_bMeasure_DistCircle =
true;
2794 m_bMeasure_DistCircle =
false;
2796 StartMeasureRoute();
2798 CancelMeasureRoute();
2800 SetCursor(*pCursorArrow);
2810 parent_frame->ToggleColorScheme();
2812 TriggerDeferredFocus();
2816 int mod = m_modkeys & wxMOD_SHIFT;
2817 if (mod != m_brightmod) {
2819 m_bbrightdir = !m_bbrightdir;
2822 if (!m_bbrightdir) {
2823 g_nbrightness -= 10;
2824 if (g_nbrightness <= MIN_BRIGHT) {
2825 g_nbrightness = MIN_BRIGHT;
2826 m_bbrightdir =
true;
2829 g_nbrightness += 10;
2830 if (g_nbrightness >= MAX_BRIGHT) {
2831 g_nbrightness = MAX_BRIGHT;
2832 m_bbrightdir =
false;
2836 SetScreenBrightness(g_nbrightness);
2837 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2846 parent_frame->DoStackDown(
this);
2850 parent_frame->DoStackUp(
this);
2855 ToggleCanvasQuiltMode();
2861 parent_frame->ToggleFullScreen();
2866 if (m_modkeys == wxMOD_ALT) {
2869 ToggleChartOutlines();
2875 parent_frame->ActivateMOB();
2879 case WXK_NUMPAD_ADD:
2884 case WXK_NUMPAD_SUBTRACT:
2885 case WXK_PAGEDOWN: {
2886 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2891 if (m_bMeasure_Active) {
2892 if (m_nMeasureState > 2) {
2893 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2895 m_pMeasureRoute->GetnPoints();
2897 gFrame->RefreshAllCanvas();
2899 CancelMeasureRoute();
2900 StartMeasureRoute();
2908 if (event.GetKeyCode() < 128)
2910 int key_char =
event.GetKeyCode();
2914 if (!g_b_assume_azerty) {
2916 if (g_benable_rotate) {
2948 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2955 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2956 m_modkeys & wxMOD_RAW_CONTROL) {
2957 parent_frame->ToggleFullScreen();
2962 if (event.ControlDown()) key_char -= 64;
2964 if (key_char >=
'0' && key_char <=
'9')
2965 SetGroupIndex(key_char -
'0');
2970 SetShowENCAnchor(!GetShowENCAnchor());
2976 parent_frame->ToggleColorScheme();
2981 event.GetPosition(&x, &y);
2982 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2983 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2986 if (VPoint.b_quilt) {
2988 if (m_pQuilt->GetChartAtPix(
2993 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2995 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3000 if (m_singleChart) {
3001 ChartType = m_singleChart->GetChartType();
3002 ChartFam = m_singleChart->GetChartFamily();
3006 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3007 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3009 this, -1, ChartType, ChartFam,
3010 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3011 wxDefaultSize, wxSIMPLE_BORDER,
"");
3024 m_nmea_log->Raise();
3028 SetShowENCLights(!GetShowENCLights());
3034 if (event.ShiftDown())
3035 m_bMeasure_DistCircle =
true;
3037 m_bMeasure_DistCircle =
false;
3039 StartMeasureRoute();
3043 if (g_bInlandEcdis && ps52plib) {
3044 SetENCDisplayCategory((_DisCat)STANDARD);
3049 ToggleChartOutlines();
3053 ToggleCanvasQuiltMode();
3057 parent_frame->ToggleTestPause();
3060 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3061 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3062 g_iNavAidRadarRingsNumberVisible = 1;
3063 else if (!g_bNavAidRadarRingsShown &&
3064 g_iNavAidRadarRingsNumberVisible == 1)
3065 g_iNavAidRadarRingsNumberVisible = 0;
3068 SetShowENCDepth(!m_encShowDepth);
3073 SetShowENCText(!GetShowENCText());
3078 SetShowENCDataQual(!GetShowENCDataQual());
3083 m_bShowNavobjects = !m_bShowNavobjects;
3098 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3103 if (event.ControlDown()) gFrame->DropMarker(
false);
3110 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3111 if ((indexActive + 1) <= r->GetnPoints()) {
3122 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3128 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3134 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3141 parent_frame->DoSettings();
3145 parent_frame->Close();
3161 if (undo->AnythingToRedo()) {
3162 undo->RedoNextAction();
3169 if (event.ShiftDown()) {
3170 if (undo->AnythingToRedo()) {
3171 undo->RedoNextAction();
3176 if (undo->AnythingToUndo()) {
3177 undo->UndoLastAction();
3186 if (m_bMeasure_Active) {
3187 CancelMeasureRoute();
3189 SetCursor(*pCursorArrow);
3192 gFrame->RefreshAllCanvas();
3206 switch (gamma_state) {
3226 SetScreenBrightness(g_nbrightness);
3231 if (event.ControlDown()) {
3232 m_bShowCompassWin = !m_bShowCompassWin;
3233 SetShowGPSCompassWindow(m_bShowCompassWin);
3250void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3251 if (SendKeyEventToPlugins(event))
3255 switch (event.GetKeyCode()) {
3257 parent_frame->SwitchKBFocus(
this);
3263 if (!m_pany) m_panspeed = 0;
3269 if (!m_panx) m_panspeed = 0;
3272 case WXK_NUMPAD_ADD:
3273 case WXK_NUMPAD_SUBTRACT:
3282 m_modkeys &= ~wxMOD_ALT;
3283#ifdef OCPN_ALT_MENUBAR
3288 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3289 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3290 parent_frame->ApplyGlobalSettings(
false);
3292 m_bMayToggleMenuBar =
true;
3298 m_modkeys &= ~wxMOD_CONTROL;
3302 if (event.GetKeyCode() < 128)
3304 int key_char =
event.GetKeyCode();
3308 if (!g_b_assume_azerty) {
3323 m_rotation_speed = 0;
3341void ChartCanvas::ToggleChartOutlines() {
3342 m_bShowOutlines = !m_bShowOutlines;
3348 if (g_bopengl) InvalidateGL();
3352void ChartCanvas::ToggleLookahead() {
3353 m_bLookAhead = !m_bLookAhead;
3358void ChartCanvas::SetUpMode(
int mode) {
3361 if (mode != NORTH_UP_MODE) {
3364 if (!std::isnan(
gCog)) stuff =
gCog;
3367 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3370 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3372 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3373 SetVPRotation(GetVPSkew());
3378 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3379 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3381 UpdateGPSCompassStatusBox(
true);
3382 gFrame->DoChartUpdate();
3385bool ChartCanvas::DoCanvasCOGSet() {
3386 if (GetUpMode() == NORTH_UP_MODE)
return false;
3388 if (g_btenhertz) cog_use =
gCog;
3390 double rotation = 0;
3391 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3392 rotation = -
gHdt * PI / 180.;
3393 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3394 rotation = -cog_use * PI / 180.;
3396 SetVPRotation(rotation);
3400double easeOutCubic(
double t) {
3402 return 1.0 - pow(1.0 - t, 3.0);
3405void ChartCanvas::StartChartDragInertia() {
3406 m_bChartDragging =
false;
3409 m_chart_drag_inertia_time = 750;
3410 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3415 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3419 size_t length = m_drag_vec_t.size();
3420 for (
size_t i = 0; i < n_vel; i++) {
3421 xacc += m_drag_vec_x.at(length - 1 - i);
3422 yacc += m_drag_vec_y.at(length - 1 - i);
3423 tacc += m_drag_vec_t.at(length - 1 - i);
3426 if (tacc == 0)
return;
3428 double drag_velocity_x = xacc / tacc;
3429 double drag_velocity_y = yacc / tacc;
3435 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3437 m_chart_drag_velocity_x = drag_velocity_x;
3438 m_chart_drag_velocity_y = drag_velocity_y;
3440 m_chart_drag_inertia_active =
true;
3442 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3445void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3446 if (!m_chart_drag_inertia_active)
return;
3448 wxLongLong now = wxGetLocalTimeMillis();
3449 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3450 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3451 if (t > 1.0) t = 1.0;
3452 double e = 1.0 - easeOutCubic(t);
3455 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3457 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3459 m_last_elapsed = elapsed;
3463 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3464 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3465 double inertia_lat, inertia_lon;
3469 if (!IsOwnshipOnScreen()) {
3471 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3472 UpdateFollowButtonState();
3483 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3484 m_chart_drag_inertia_timer.Stop();
3487 m_target_lat = GetVP().
clat;
3488 m_target_lon = GetVP().
clon;
3489 m_pan_drag.x = m_pan_drag.y = 0;
3490 m_panx = m_pany = 0;
3491 m_chart_drag_inertia_active =
false;
3495 int target_redraw_interval = 40;
3496 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3500void ChartCanvas::StopMovement() {
3501 m_panx = m_pany = 0;
3504 m_rotation_speed = 0;
3507#if !defined(__WXGTK__) && !defined(__WXQT__)
3518bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3520 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3522 if (!pMovementTimer->IsRunning()) {
3523 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3526 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3531 m_last_movement_time = wxDateTime::UNow();
3535void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3538 m_target_lat = target_lat;
3539 m_target_lon = target_lon;
3542 m_start_lat = GetVP().
clat;
3543 m_start_lon = GetVP().
clon;
3545 m_VPMovementTimer.Start(1,
true);
3546 m_timed_move_vp_active =
true;
3548 m_timedVP_step = nstep;
3551void ChartCanvas::DoTimedMovementVP() {
3552 if (!m_timed_move_vp_active)
return;
3553 if (m_stvpc++ > m_timedVP_step * 2) {
3560 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3575 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3576 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3578 m_run_lat = new_lat;
3579 m_run_lon = new_lon;
3584void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3586void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3588void ChartCanvas::StartTimedMovementTarget() {}
3590void ChartCanvas::DoTimedMovementTarget() {}
3592void ChartCanvas::StopMovementTarget() {}
3595void ChartCanvas::DoTimedMovement() {
3596 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3600 wxDateTime now = wxDateTime::UNow();
3602 if (m_last_movement_time.IsValid())
3603 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3605 m_last_movement_time = now;
3615 if (dt == 0) dt = 1;
3618 if (m_mustmove < 0) m_mustmove = 0;
3621 if (m_pan_drag.x || m_pan_drag.y) {
3623 m_pan_drag.x = m_pan_drag.y = 0;
3626 if (m_panx || m_pany) {
3627 const double slowpan = .1, maxpan = 2;
3628 if (m_modkeys == wxMOD_ALT)
3629 m_panspeed = slowpan;
3631 m_panspeed += (double)dt / 500;
3632 m_panspeed = wxMin(maxpan, m_panspeed);
3634 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3637 if (m_zoom_factor != 1) {
3638 double alpha = 400, beta = 1.5;
3639 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3641 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3643 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3648 if (zoom_factor > 1) {
3649 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3653 else if (zoom_factor < 1) {
3654 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3659 if (fabs(zoom_factor - 1) > 1e-4) {
3660 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3665 if (m_wheelzoom_stop_oneshot > 0) {
3666 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3667 m_wheelzoom_stop_oneshot = 0;
3672 if (zoom_factor > 1) {
3674 m_wheelzoom_stop_oneshot = 0;
3677 }
else if (zoom_factor < 1) {
3679 m_wheelzoom_stop_oneshot = 0;
3686 if (m_rotation_speed) {
3687 double speed = m_rotation_speed;
3688 if (m_modkeys == wxMOD_ALT) speed /= 10;
3689 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3693void ChartCanvas::SetColorScheme(ColorScheme cs) {
3698 case GLOBAL_COLOR_SCHEME_DAY:
3699 m_pos_image_red = &m_os_image_red_day;
3700 m_pos_image_grey = &m_os_image_grey_day;
3701 m_pos_image_yellow = &m_os_image_yellow_day;
3702 m_pos_image_user = m_pos_image_user_day;
3703 m_pos_image_user_grey = m_pos_image_user_grey_day;
3704 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3705 m_cTideBitmap = m_bmTideDay;
3706 m_cCurrentBitmap = m_bmCurrentDay;
3709 case GLOBAL_COLOR_SCHEME_DUSK:
3710 m_pos_image_red = &m_os_image_red_dusk;
3711 m_pos_image_grey = &m_os_image_grey_dusk;
3712 m_pos_image_yellow = &m_os_image_yellow_dusk;
3713 m_pos_image_user = m_pos_image_user_dusk;
3714 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3715 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3716 m_cTideBitmap = m_bmTideDusk;
3717 m_cCurrentBitmap = m_bmCurrentDusk;
3719 case GLOBAL_COLOR_SCHEME_NIGHT:
3720 m_pos_image_red = &m_os_image_red_night;
3721 m_pos_image_grey = &m_os_image_grey_night;
3722 m_pos_image_yellow = &m_os_image_yellow_night;
3723 m_pos_image_user = m_pos_image_user_night;
3724 m_pos_image_user_grey = m_pos_image_user_grey_night;
3725 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3726 m_cTideBitmap = m_bmTideNight;
3727 m_cCurrentBitmap = m_bmCurrentNight;
3730 m_pos_image_red = &m_os_image_red_day;
3731 m_pos_image_grey = &m_os_image_grey_day;
3732 m_pos_image_yellow = &m_os_image_yellow_day;
3733 m_pos_image_user = m_pos_image_user_day;
3734 m_pos_image_user_grey = m_pos_image_user_grey_day;
3735 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3736 m_cTideBitmap = m_bmTideDay;
3737 m_cCurrentBitmap = m_bmCurrentDay;
3741 CreateDepthUnitEmbossMaps(cs);
3742 CreateOZEmbossMapData(cs);
3745 m_fog_color = wxColor(
3749 case GLOBAL_COLOR_SCHEME_DUSK:
3752 case GLOBAL_COLOR_SCHEME_NIGHT:
3758 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3759 m_fog_color.Blue() * dim);
3763 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3764 SetBackgroundColour( wxColour(0,0,0) );
3766 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3769 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3771 SetBackgroundColour( wxNullColour );
3778 m_Piano->SetColorScheme(cs);
3780 m_Compass->SetColorScheme(cs);
3782 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3784 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3786 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3787 if (m_notification_button) {
3788 m_notification_button->SetColorScheme(cs);
3792 if (g_bopengl && m_glcc) {
3793 m_glcc->SetColorScheme(cs);
3799 m_brepaint_piano =
true;
3806wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3807 wxImage img = Bitmap.ConvertToImage();
3808 int sx = img.GetWidth();
3809 int sy = img.GetHeight();
3811 wxImage new_img(img);
3813 for (
int i = 0; i < sx; i++) {
3814 for (
int j = 0; j < sy; j++) {
3815 if (!img.IsTransparent(i, j)) {
3816 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3817 (
unsigned char)(img.GetGreen(i, j) * factor),
3818 (
unsigned char)(img.GetBlue(i, j) * factor));
3823 wxBitmap ret = wxBitmap(new_img);
3828void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3831 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3833 if (!m_pBrightPopup) {
3836 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3840 m_pBrightPopup->SetSize(x, y);
3841 m_pBrightPopup->Move(120, 120);
3844 int bmpsx = m_pBrightPopup->GetSize().x;
3845 int bmpsy = m_pBrightPopup->GetSize().y;
3847 wxBitmap bmp(bmpsx, bmpsx);
3848 wxMemoryDC mdc(bmp);
3850 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3851 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3852 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3853 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3856 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3858 mdc.SetFont(*pfont);
3861 if (brightness == max)
3863 else if (brightness == min)
3866 val.Printf(
"%3d", brightness);
3868 mdc.DrawText(val, 0, 0);
3870 mdc.SelectObject(wxNullBitmap);
3872 m_pBrightPopup->SetBitmap(bmp);
3873 m_pBrightPopup->Show();
3874 m_pBrightPopup->Refresh();
3877void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3878 m_b_rot_hidef =
true;
3882void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3885 bool b_need_refresh =
false;
3887 wxSize win_size = GetSize() * m_displayScale;
3891 bool showAISRollover =
false;
3893 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3897 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3898 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3901 showAISRollover =
true;
3903 if (NULL == m_pAISRolloverWin) {
3905 m_pAISRolloverWin->IsActive(
false);
3906 b_need_refresh =
true;
3907 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3908 m_AISRollover_MMSI != FoundAIS_MMSI) {
3914 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3915 m_pAISRolloverWin->IsActive(
false);
3916 m_AISRollover_MMSI = 0;
3921 m_AISRollover_MMSI = FoundAIS_MMSI;
3923 if (!m_pAISRolloverWin->IsActive()) {
3924 wxString s = ptarget->GetRolloverString();
3925 m_pAISRolloverWin->SetString(s);
3927 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3928 AIS_ROLLOVER, win_size);
3929 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3930 m_pAISRolloverWin->IsActive(
true);
3931 b_need_refresh =
true;
3935 m_AISRollover_MMSI = 0;
3936 showAISRollover =
false;
3941 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3942 m_pAISRolloverWin->IsActive(
false);
3943 m_AISRollover_MMSI = 0;
3944 b_need_refresh =
true;
3949 bool showRouteRollover =
false;
3951 if (NULL == m_pRolloverRouteSeg) {
3955 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3956 SelectableItemList SelList =
pSelect->FindSelectionList(
3958 auto node = SelList.begin();
3959 while (node != SelList.end()) {
3964 if (pr && pr->IsVisible()) {
3965 m_pRolloverRouteSeg = pFindSel;
3966 showRouteRollover =
true;
3968 if (NULL == m_pRouteRolloverWin) {
3970 m_pRouteRolloverWin->IsActive(
false);
3973 if (!m_pRouteRolloverWin->IsActive()) {
3981 DistanceBearingMercator(
3982 segShow_point_b->m_lat, segShow_point_b->m_lon,
3983 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3985 if (!pr->m_bIsInLayer)
3986 s.Append(_(
"Route") +
": ");
3988 s.Append(_(
"Layer Route: "));
3990 if (pr->m_RouteNameString.IsEmpty())
3991 s.Append(_(
"(unnamed)"));
3993 s.Append(pr->m_RouteNameString);
3998 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3999 << segShow_point_b->GetName() <<
"\n";
4002 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4003 (
int)floor(brg + 0.5), 0x00B0);
4006 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4008 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4009 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4011 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4012 (
int)floor(varBrg + 0.5), 0x00B0);
4020 double shiptoEndLeg = 0.;
4021 bool validActive =
false;
4022 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4025 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4026 auto node = pr->pRoutePointList->begin();
4028 float dist_to_endleg = 0;
4031 for (++node; node != pr->pRoutePointList->end(); ++node) {
4038 if (prp->IsSame(segShow_point_a))
break;
4046 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4049 ->GetCurrentRngToActivePoint();
4058 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4063 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4064 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4066 << wxString(ttg_sec > SECONDS_PER_DAY
4067 ? ttg_span.Format(_(
"%Dd %H:%M"))
4068 : ttg_span.Format(_(
"%H:%M")));
4069 wxDateTime dtnow, eta;
4070 eta = dtnow.SetToCurrent().Add(ttg_span);
4071 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4072 << eta.Format(
" %d %H:%M");
4076 m_pRouteRolloverWin->SetString(s);
4078 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4079 LEG_ROLLOVER, win_size);
4080 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4081 m_pRouteRolloverWin->IsActive(
true);
4082 b_need_refresh =
true;
4083 showRouteRollover =
true;
4092 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4094 m_pRolloverRouteSeg))
4095 showRouteRollover =
false;
4096 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4097 showRouteRollover =
false;
4099 showRouteRollover =
true;
4103 if (m_routeState) showRouteRollover =
false;
4106 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4107 showRouteRollover =
false;
4109 if (m_pRouteRolloverWin &&
4110 !showRouteRollover) {
4111 m_pRouteRolloverWin->IsActive(
false);
4112 m_pRolloverRouteSeg = NULL;
4113 m_pRouteRolloverWin->Destroy();
4114 m_pRouteRolloverWin = NULL;
4115 b_need_refresh =
true;
4116 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4117 m_pRouteRolloverWin->IsActive(
true);
4118 b_need_refresh =
true;
4123 bool showTrackRollover =
false;
4125 if (NULL == m_pRolloverTrackSeg) {
4129 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4130 SelectableItemList SelList =
pSelect->FindSelectionList(
4133 auto node = SelList.begin();
4134 while (node != SelList.end()) {
4139 if (pt && pt->IsVisible()) {
4140 m_pRolloverTrackSeg = pFindSel;
4141 showTrackRollover =
true;
4143 if (NULL == m_pTrackRolloverWin) {
4145 m_pTrackRolloverWin->IsActive(
false);
4148 if (!m_pTrackRolloverWin->IsActive()) {
4156 DistanceBearingMercator(
4157 segShow_point_b->m_lat, segShow_point_b->m_lon,
4158 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4160 if (!pt->m_bIsInLayer)
4161 s.Append(_(
"Track") +
": ");
4163 s.Append(_(
"Layer Track: "));
4165 if (pt->GetName().IsEmpty())
4166 s.Append(_(
"(unnamed)"));
4168 s.Append(pt->GetName());
4169 double tlenght = pt->Length();
4171 if (pt->GetLastPoint()->GetTimeString() &&
4172 pt->GetPoint(0)->GetTimeString()) {
4173 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4174 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4175 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4176 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4177 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4178 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4179 << getUsrSpeedUnit();
4180 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4181 : ttime.Format(
" %H:%M"));
4185 if (g_bShowTrackPointTime &&
4186 strlen(segShow_point_b->GetTimeString())) {
4187 wxString stamp = segShow_point_b->GetTimeString();
4188 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4189 if (timestamp.IsValid()) {
4193 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4195 s <<
"\n" << _(
"Segment Created: ") << stamp;
4200 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4205 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4207 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4208 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4210 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4216 if (segShow_point_a->GetTimeString() &&
4217 segShow_point_b->GetTimeString()) {
4218 wxDateTime apoint = segShow_point_a->GetCreateTime();
4219 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4220 if (apoint.IsValid() && bpoint.IsValid()) {
4221 double segmentSpeed = toUsrSpeed(
4222 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4223 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4224 << getUsrSpeedUnit();
4228 m_pTrackRolloverWin->SetString(s);
4230 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4231 LEG_ROLLOVER, win_size);
4232 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4233 m_pTrackRolloverWin->IsActive(
true);
4234 b_need_refresh =
true;
4235 showTrackRollover =
true;
4244 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4246 m_pRolloverTrackSeg))
4247 showTrackRollover =
false;
4248 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4249 showTrackRollover =
false;
4251 showTrackRollover =
true;
4255 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4256 showTrackRollover =
false;
4259 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4260 showTrackRollover =
false;
4266 if (m_pTrackRolloverWin &&
4267 !showTrackRollover) {
4268 m_pTrackRolloverWin->IsActive(
false);
4269 m_pRolloverTrackSeg = NULL;
4270 m_pTrackRolloverWin->Destroy();
4271 m_pTrackRolloverWin = NULL;
4272 b_need_refresh =
true;
4273 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4274 m_pTrackRolloverWin->IsActive(
true);
4275 b_need_refresh =
true;
4278 if (b_need_refresh) Refresh();
4281void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4282 if ((GetShowENCLights() || m_bsectors_shown) &&
4283 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4284 extendedSectorLegs)) {
4285 if (!m_bsectors_shown) {
4287 m_bsectors_shown =
true;
4290 if (m_bsectors_shown) {
4292 m_bsectors_shown =
false;
4300#if defined(__WXGTK__) || defined(__WXQT__)
4305 double cursor_lat, cursor_lon;
4308 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4309 while (cursor_lon < -180.) cursor_lon += 360.;
4311 while (cursor_lon > 180.) cursor_lon -= 360.;
4313 SetCursorStatus(cursor_lat, cursor_lon);
4319void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4320 if (!parent_frame->m_pStatusBar)
return;
4324 s1 += toSDMM(1, cursor_lat);
4326 s1 += toSDMM(2, cursor_lon);
4328 if (STAT_FIELD_CURSOR_LL >= 0)
4329 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4331 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4336 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4337 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4338 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4340 wxString s = st + sm;
4353 if (g_bShowLiveETA) {
4356 float boatSpeedDefault = g_defaultBoatSpeed;
4361 if (!std::isnan(
gSog)) {
4363 if (boatSpeed < 0.5) {
4366 realTimeETA = dist / boatSpeed * 60;
4375 s << minutesToHoursDays(realTimeETA);
4380 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4381 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4383 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4388 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4396wxString minutesToHoursDays(
float timeInMinutes) {
4399 if (timeInMinutes == 0) {
4404 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4405 s << wxString::Format(
"%d", (
int)timeInMinutes);
4410 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4413 hours = (int)timeInMinutes / 60;
4414 min = (int)timeInMinutes % 60;
4417 s << wxString::Format(
"%d", hours);
4420 s << wxString::Format(
"%d", hours);
4422 s << wxString::Format(
"%d", min);
4429 else if (timeInMinutes > 24 * 60) {
4432 days = (int)(timeInMinutes / 60) / 24;
4433 hours = (int)(timeInMinutes / 60) % 24;
4436 s << wxString::Format(
"%d", days);
4439 s << wxString::Format(
"%d", days);
4441 s << wxString::Format(
"%d", hours);
4453void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4461 wxPoint2DDouble *r) {
4466 double rlon, wxPoint2DDouble *r) {
4477 if (!g_bopengl && m_singleChart &&
4478 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4479 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4480 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4481 (m_singleChart->GetChartProjectionType() !=
4482 PROJECTION_TRANSVERSE_MERCATOR) &&
4483 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4484 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4485 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4499 Cur_BSB_Ch->SetVPRasterParms(vp);
4500 double rpixxd, rpixyd;
4501 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4527 if (std::isnan(p.m_x)) {
4528 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4532 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4533 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4535 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4554 if (!g_bopengl && m_singleChart &&
4555 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4556 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4557 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4558 (m_singleChart->GetChartProjectionType() !=
4559 PROJECTION_TRANSVERSE_MERCATOR) &&
4560 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4561 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4562 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4573 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4576 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4581 else if (slon > 180.)
4592 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4598 DoZoomCanvas(factor,
false);
4599 extendedSectorLegs.clear();
4604 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4607 if (StartTimedMovement(stoptimer)) {
4609 m_zoom_factor = factor;
4614 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4616 DoZoomCanvas(factor, can_zoom_to_cursor);
4619 extendedSectorLegs.clear();
4622void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4625 if (!m_pCurrentStack)
return;
4631 if (m_bzooming)
return;
4640 double proposed_scale_onscreen =
4643 bool b_do_zoom =
false;
4652 if (!VPoint.b_quilt) {
4655 if (!m_disable_adjust_on_zoom) {
4656 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4657 if (new_db_index >= 0)
4658 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4662 int current_ref_stack_index = -1;
4663 if (m_pCurrentStack->nEntry) {
4665 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4666 m_pQuilt->SetReferenceChart(trial_index);
4667 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4668 if (new_db_index >= 0)
4669 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4673 if (m_pCurrentStack)
4674 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4685 double min_allowed_scale =
4688 if (proposed_scale_onscreen < min_allowed_scale) {
4693 proposed_scale_onscreen = min_allowed_scale;
4697 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4700 }
else if (factor < 1) {
4705 bool b_smallest =
false;
4707 if (!VPoint.b_quilt) {
4712 LLBBox viewbox = VPoint.GetBBox();
4714 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4715 double max_allowed_scale;
4729 if (proposed_scale_onscreen > max_allowed_scale) {
4731 proposed_scale_onscreen = max_allowed_scale;
4736 if (!m_disable_adjust_on_zoom) {
4738 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4739 if (new_db_index >= 0)
4740 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4742 if (m_pCurrentStack)
4743 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4746 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4748 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4749 proposed_scale_onscreen =
4750 wxMin(proposed_scale_onscreen,
4756 m_absolute_min_scale_ppm)
4757 proposed_scale_onscreen =
4766 bool b_allow_ztc =
true;
4767 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4768 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4770 double brg, distance;
4771 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4774 meters_to_shift = distance * 1852;
4782 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4785 if (m_bFollow) DoCanvasUpdate();
4792void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4794 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4798void ChartCanvas::RotateCanvas(
double dir) {
4802 if (StartTimedMovement()) {
4804 m_rotation_speed = dir * 60;
4807 double speed = dir * 10;
4808 if (m_modkeys == wxMOD_ALT) speed /= 20;
4809 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4813void ChartCanvas::DoRotateCanvas(
double rotation) {
4814 while (rotation < 0) rotation += 2 * PI;
4815 while (rotation > 2 * PI) rotation -= 2 * PI;
4817 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4819 SetVPRotation(rotation);
4820 parent_frame->UpdateRotationState(VPoint.
rotation);
4823void ChartCanvas::DoTiltCanvas(
double tilt) {
4824 while (tilt < 0) tilt = 0;
4825 while (tilt > .95) tilt = .95;
4827 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4833void ChartCanvas::TogglebFollow() {
4840void ChartCanvas::ClearbFollow() {
4843 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4845 UpdateFollowButtonState();
4849 parent_frame->SetChartUpdatePeriod();
4852void ChartCanvas::SetbFollow() {
4855 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4856 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4864 p.m_x += m_OSoffsetx;
4865 p.m_y -= m_OSoffsety;
4874 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4875 UpdateFollowButtonState();
4877 if (!g_bSmoothRecenter) {
4881 parent_frame->SetChartUpdatePeriod();
4884void ChartCanvas::UpdateFollowButtonState() {
4887 m_muiBar->SetFollowButtonState(0);
4890 m_muiBar->SetFollowButtonState(2);
4892 m_muiBar->SetFollowButtonState(1);
4898 androidSetFollowTool(0);
4901 androidSetFollowTool(2);
4903 androidSetFollowTool(1);
4910 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4911 if (pic->m_enabled && pic->m_init_state) {
4912 switch (pic->m_api_version) {
4915 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4926void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4927 if (g_bSmoothRecenter && !m_routeState) {
4928 if (StartSmoothJump(lat, lon, scale_ppm))
4932 double gcDist, gcBearingEnd;
4933 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4935 gcBearingEnd += 180;
4936 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4939 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4940 double new_lat = lat + (lat_offset / (1852 * 60));
4941 double new_lon = lon + (lon_offset / (1852 * 60));
4944 StartSmoothJump(lat, lon, scale_ppm);
4949 if (lon > 180.0) lon -= 360.0;
4955 if (!GetQuiltMode()) {
4957 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4958 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4962 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4963 AdjustQuiltRefChart();
4970 UpdateFollowButtonState();
4978bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4983 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4984 double distance_pixels = gcDist *
GetVPScale();
4985 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4991 m_startLat = m_vLat;
4992 m_startLon = m_vLon;
4997 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4998 m_endScale = scale_ppm;
5001 m_animationDuration = 600;
5002 m_animationStart = wxGetLocalTimeMillis();
5009 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5010 m_animationActive =
true;
5015void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5017 wxLongLong now = wxGetLocalTimeMillis();
5018 double elapsed = (now - m_animationStart).ToDouble();
5019 double t = elapsed / m_animationDuration.ToDouble();
5020 if (t > 1.0) t = 1.0;
5023 double e = easeOutCubic(t);
5026 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5027 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5028 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5033 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5039 m_animationActive =
false;
5040 UpdateFollowButtonState();
5049 extendedSectorLegs.clear();
5058 if (iters++ > 5)
return false;
5059 if (!std::isnan(dlat))
break;
5062 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5068 else if (dlat < -90)
5071 if (dlon > 360.) dlon -= 360.;
5072 if (dlon < -360.) dlon += 360.;
5087 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5091 if (VPoint.b_quilt) {
5092 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5093 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5097 double tweak_scale_ppm =
5103 if (new_ref_dbIndex == -1) {
5104#pragma GCC diagnostic push
5105#pragma GCC diagnostic ignored "-Warray-bounds"
5112 int trial_index = -1;
5113 if (m_pCurrentStack->nEntry) {
5115 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5118 if (trial_index < 0) {
5119 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5120 if (full_screen_array.size())
5121 trial_index = full_screen_array[full_screen_array.size() - 1];
5124 if (trial_index >= 0) {
5125 m_pQuilt->SetReferenceChart(trial_index);
5130#pragma GCC diagnostic pop
5137 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5139 double offset_angle = atan2(offy, offx);
5140 double offset_distance = sqrt((offy * offy) + (offx * offx));
5141 double chart_angle = GetVPRotation();
5142 double target_angle = chart_angle - offset_angle;
5143 double d_east_mod = offset_distance * cos(target_angle);
5144 double d_north_mod = offset_distance * sin(target_angle);
5149 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5150 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5152 UpdateFollowButtonState();
5158 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5163bool ChartCanvas::IsOwnshipOnScreen() {
5166 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5167 ((r.y > 0) && r.y < GetCanvasHeight()))
5173void ChartCanvas::ReloadVP(
bool b_adjust) {
5174 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5176 LoadVP(VPoint, b_adjust);
5179void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5181 if (g_bopengl && m_glcc) {
5182 m_glcc->Invalidate();
5183 if (m_glcc->GetSize() != GetSize()) {
5184 m_glcc->SetSize(GetSize());
5189 m_cache_vp.Invalidate();
5190 m_bm_cache_vp.Invalidate();
5193 VPoint.Invalidate();
5195 if (m_pQuilt) m_pQuilt->Invalidate();
5204 vp.m_projection_type, b_adjust);
5207void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5208 m_pQuilt->SetReferenceChart(dbIndex);
5209 VPoint.Invalidate();
5210 m_pQuilt->Invalidate();
5213double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5215 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5222int ChartCanvas::AdjustQuiltRefChart() {
5227 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5229 double min_ref_scale =
5230 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5231 double max_ref_scale =
5232 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5235 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5236 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5237 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5239 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5242 int target_stack_index = wxNOT_FOUND;
5244 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5245 if (index == m_pQuilt->GetRefChartdbIndex()) {
5246 target_stack_index = il;
5251 if (wxNOT_FOUND == target_stack_index)
5252 target_stack_index = 0;
5254 int ref_family = pc->GetChartFamily();
5255 int extended_array_count =
5256 m_pQuilt->GetExtendedStackIndexArray().size();
5257 while ((!brender_ok) &&
5258 ((
int)target_stack_index < (extended_array_count - 1))) {
5259 target_stack_index++;
5261 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5263 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5264 IsChartQuiltableRef(test_db_index)) {
5267 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5269 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5276 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5277 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5278 IsChartQuiltableRef(new_db_index)) {
5279 m_pQuilt->SetReferenceChart(new_db_index);
5282 ret = m_pQuilt->GetRefChartdbIndex();
5284 ret = m_pQuilt->GetRefChartdbIndex();
5287 ret = m_pQuilt->GetRefChartdbIndex();
5296void ChartCanvas::UpdateCanvasOnGroupChange() {
5297 delete m_pCurrentStack;
5309bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5310 double latNE,
double lonNE) {
5312 double latc = (latSW + latNE) / 2.0;
5313 double lonc = (lonSW + lonNE) / 2.0;
5316 double ne_easting, ne_northing;
5317 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5319 double sw_easting, sw_northing;
5320 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5322 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5329 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5332bool ChartCanvas::SetVPProjection(
int projection) {
5338 double prev_true_scale_ppm = m_true_scale_ppm;
5343 m_absolute_min_scale_ppm));
5351bool ChartCanvas::SetVPRotation(
double angle) {
5353 VPoint.
skew, angle);
5356 double skew,
double rotation,
int projection,
5357 bool b_adjust,
bool b_refresh) {
5362 if (VPoint.IsValid()) {
5363 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5364 (fabs(VPoint.
skew - skew) < 1e-9) &&
5365 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5366 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5367 (VPoint.m_projection_type == projection ||
5368 projection == PROJECTION_UNKNOWN))
5371 if (VPoint.m_projection_type != projection)
5372 VPoint.InvalidateTransformCache();
5382 if (projection != PROJECTION_UNKNOWN)
5383 VPoint.SetProjectionType(projection);
5384 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5385 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5388 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5389 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5390 if (VPoint.
clat > 89.5)
5392 else if (VPoint.
clat < -89.5)
5393 VPoint.
clat = -89.5;
5398 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5399 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5411 bool bwasValid = VPoint.IsValid();
5416 m_cache_vp.Invalidate();
5421 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5425 int mouseX = mouse_x;
5426 int mouseY = mouse_y;
5427 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5433 SendCursorLatLonToAllPlugIns(lat, lon);
5436 if (!VPoint.b_quilt && m_singleChart) {
5441 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5445 if ((!m_cache_vp.IsValid()) ||
5450 wxPoint cp_last, cp_this;
5454 if (cp_last != cp_this) {
5460 if (m_pCurrentStack) {
5462 int current_db_index;
5464 m_pCurrentStack->GetCurrentEntrydbIndex();
5466 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5468 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5471 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5475 if (VPoint.b_quilt) {
5479 m_pQuilt->InvalidateAllQuiltPatchs();
5483 if (!m_pCurrentStack)
return false;
5485 int current_db_index;
5487 m_pCurrentStack->GetCurrentEntrydbIndex();
5489 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5490 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5493 int current_ref_stack_index = -1;
5494 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5495 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5496 current_ref_stack_index = i;
5499 if (g_bFullScreenQuilt) {
5500 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5504 bool b_needNewRef =
false;
5507 if ((-1 == current_ref_stack_index) &&
5508 (m_pQuilt->GetRefChartdbIndex() >= 0))
5509 b_needNewRef =
true;
5516 bool renderable =
true;
5518 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5519 if (referenceChart) {
5520 double chartMaxScale = referenceChart->GetNormalScaleMax(
5522 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5524 if (!renderable) b_needNewRef =
true;
5527 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5529 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5530 int target_scale = cte_ref.GetScale();
5531 int target_type = cte_ref.GetChartType();
5532 int candidate_stack_index;
5539 candidate_stack_index = 0;
5540 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5542 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5543 int candidate_scale = cte_candidate.GetScale();
5544 int candidate_type = cte_candidate.GetChartType();
5546 if ((candidate_scale >= target_scale) &&
5547 (candidate_type == target_type)) {
5548 bool renderable =
true;
5550 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5551 if (tentative_referenceChart) {
5552 double chartMaxScale =
5553 tentative_referenceChart->GetNormalScaleMax(
5555 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5558 if (renderable)
break;
5561 candidate_stack_index++;
5566 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5567 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5568 while (candidate_stack_index >= 0) {
5569 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5573 int candidate_scale = cte_candidate.GetScale();
5574 int candidate_type = cte_candidate.GetChartType();
5576 if ((candidate_scale <= target_scale) &&
5577 (candidate_type == target_type))
5580 candidate_stack_index--;
5585 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5586 (candidate_stack_index < 0))
5587 candidate_stack_index = 0;
5589 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5591 m_pQuilt->SetReferenceChart(new_ref_index);
5597 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5602 bool renderable =
true;
5604 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5605 if (referenceChart) {
5606 double chartMaxScale = referenceChart->GetNormalScaleMax(
5608 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5609 proj =
ChartData->GetDBChartProj(ref_db_index);
5611 proj = PROJECTION_MERCATOR;
5613 VPoint.b_MercatorProjectionOverride =
5614 (m_pQuilt->GetnCharts() == 0 || !renderable);
5616 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5618 VPoint.SetProjectionType(proj);
5623 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5628 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5648 m_pQuilt->Invalidate();
5665 if (b_refresh) Refresh(
false);
5672 }
else if (!g_bopengl) {
5673 OcpnProjType projection = PROJECTION_UNKNOWN;
5676 projection = m_singleChart->GetChartProjectionType();
5677 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5678 VPoint.SetProjectionType(projection);
5682 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5683 m_cache_vp.Invalidate();
5687 UpdateCanvasControlBar();
5691 if (VPoint.GetBBox().GetValid()) {
5694 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5703 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5706 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5713 wxPoint2DDouble r, r1;
5715 double delta_check =
5719 double check_point = wxMin(89., VPoint.
clat);
5721 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5724 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5725 VPoint.
clon, 0, &rhumbDist);
5730 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5731 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5733 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5737 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5743 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5745 if (m_true_scale_ppm)
5746 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5751 double round_factor = 1000.;
5755 round_factor = 100.;
5757 round_factor = 1000.;
5760 double retina_coef = 1;
5764 retina_coef = GetContentScaleFactor();
5775 double true_scale_display =
5776 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5781 if (m_displayed_scale_factor > 10.0)
5782 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5783 m_displayed_scale_factor);
5784 else if (m_displayed_scale_factor > 1.0)
5785 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5786 m_displayed_scale_factor);
5787 else if (m_displayed_scale_factor > 0.1) {
5788 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5789 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5790 }
else if (m_displayed_scale_factor > 0.01) {
5791 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5792 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5795 "%s %4.0f (---)", _(
"Scale"),
5796 true_scale_display);
5799 m_scaleValue = true_scale_display;
5801 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5803 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5804 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5806 bool b_noshow =
false;
5810 wxClientDC dc(parent_frame->GetStatusBar());
5812 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5813 dc.SetFont(*templateFont);
5814 dc.GetTextExtent(text, &w, &h);
5819 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5820 if (w && w > rect.width) {
5821 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5825 dc.GetTextExtent(text, &w, &h);
5827 if (w && w > rect.width) {
5833 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5838 m_vLat = VPoint.
clat;
5839 m_vLon = VPoint.
clon;
5853static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5857static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5858 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5860wxColour ChartCanvas::PredColor() {
5863 if (SHIP_NORMAL == m_ownship_state)
5864 return GetGlobalColor(
"URED");
5866 else if (SHIP_LOWACCURACY == m_ownship_state)
5867 return GetGlobalColor(
"YELO1");
5869 return GetGlobalColor(
"NODTA");
5872wxColour ChartCanvas::ShipColor() {
5876 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5878 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5880 return GetGlobalColor(
"URED");
5883void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5884 wxPoint2DDouble lShipMidPoint) {
5885 dc.SetPen(wxPen(PredColor(), 2));
5887 if (SHIP_NORMAL == m_ownship_state)
5888 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5890 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5892 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5893 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5895 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5897 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5898 lShipMidPoint.m_y + 12);
5901void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5902 wxPoint GPSOffsetPixels,
5903 wxPoint2DDouble lGPSPoint) {
5908 float ref_dim = m_display_size_mm / 24;
5909 ref_dim = wxMin(ref_dim, 12);
5910 ref_dim = wxMax(ref_dim, 6);
5913 cPred.Set(g_cog_predictor_color);
5914 if (cPred == wxNullColour) cPred = PredColor();
5921 double nominal_line_width_pix = wxMax(
5923 floor(m_pix_per_mm / 2));
5927 if (nominal_line_width_pix > g_cog_predictor_width)
5928 g_cog_predictor_width = nominal_line_width_pix;
5931 wxPoint lPredPoint, lHeadPoint;
5933 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5934 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5936 double pred_lat, pred_lon;
5937 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5938 &pred_lat, &pred_lon);
5949 float ndelta_pix = 10.;
5950 double hdg_pred_lat, hdg_pred_lon;
5951 bool b_render_hdt =
false;
5952 if (!std::isnan(
gHdt)) {
5954 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5957 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5958 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5959 if (dist > ndelta_pix ) {
5960 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5961 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5966 wxPoint lShipMidPoint;
5967 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5968 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5969 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5970 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5972 if (lpp >= img_height / 2) {
5973 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
5974 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
5975 !std::isnan(
gSog)) {
5977 float dash_length = ref_dim;
5978 wxDash dash_long[2];
5980 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5981 g_cog_predictor_width);
5982 dash_long[1] = dash_long[0] / 2.0;
5986 if (dash_length > 250.) {
5987 dash_long[0] = 250. / g_cog_predictor_width;
5988 dash_long[1] = dash_long[0] / 2;
5991 wxPen ppPen2(cPred, g_cog_predictor_width,
5992 (wxPenStyle)g_cog_predictor_style);
5993 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5994 ppPen2.SetDashes(2, dash_long);
5997 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5998 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6000 if (g_cog_predictor_width > 1) {
6001 float line_width = g_cog_predictor_width / 3.;
6003 wxDash dash_long3[2];
6004 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6005 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6007 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6008 (wxPenStyle)g_cog_predictor_style);
6009 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6010 ppPen3.SetDashes(2, dash_long3);
6012 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6013 lGPSPoint.m_y + GPSOffsetPixels.y,
6014 lPredPoint.x + GPSOffsetPixels.x,
6015 lPredPoint.y + GPSOffsetPixels.y);
6018 if (g_cog_predictor_endmarker) {
6020 double png_pred_icon_scale_factor = .4;
6021 if (g_ShipScaleFactorExp > 1.0)
6022 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6023 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6027 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6028 (
float)(lPredPoint.x - lShipMidPoint.x));
6029 cog_rad += (float)PI;
6031 for (
int i = 0; i < 4; i++) {
6033 double pxa = (double)(s_png_pred_icon[j]);
6034 double pya = (double)(s_png_pred_icon[j + 1]);
6036 pya *= png_pred_icon_scale_factor;
6037 pxa *= png_pred_icon_scale_factor;
6039 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6040 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6042 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6043 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6047 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6050 dc.SetBrush(wxBrush(cPred));
6052 dc.StrokePolygon(4, icon);
6059 float hdt_dash_length = ref_dim * 0.4;
6061 cPred.Set(g_ownship_HDTpredictor_color);
6062 if (cPred == wxNullColour) cPred = PredColor();
6064 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6065 : g_cog_predictor_width * 0.8);
6066 wxDash dash_short[2];
6068 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6071 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6074 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6075 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6076 ppPen2.SetDashes(2, dash_short);
6080 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6081 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6083 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6085 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6087 if (g_ownship_HDTpredictor_endmarker) {
6088 double nominal_circle_size_pixels = wxMax(
6089 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6092 if (g_ShipScaleFactorExp > 1.0)
6093 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6095 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6096 lHeadPoint.y + GPSOffsetPixels.y,
6097 nominal_circle_size_pixels / 2);
6102 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6103 double factor = 1.00;
6104 if (g_pNavAidRadarRingsStepUnits == 1)
6106 else if (g_pNavAidRadarRingsStepUnits == 2) {
6107 if (std::isnan(
gSog))
6112 factor *= g_fNavAidRadarRingsStep;
6116 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6119 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6120 pow((
double)(lGPSPoint.m_y - r.y), 2));
6121 int pix_radius = (int)lpp;
6123 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6125 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6128 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6130 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6131 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6135void ChartCanvas::ComputeShipScaleFactor(
6136 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6137 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6138 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6139 float screenResolution = m_pix_per_mm;
6142 double ship_bow_lat, ship_bow_lon;
6143 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6144 &ship_bow_lat, &ship_bow_lon);
6145 wxPoint lShipBowPoint;
6146 wxPoint2DDouble b_point =
6150 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6151 powf((
float)(b_point.m_y - a_point.m_y), 2));
6154 float shipLength_mm = shipLength_px / screenResolution;
6157 float ownship_min_mm = g_n_ownship_min_mm;
6158 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6161 float hdt_ant = icon_hdt + 180.;
6162 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6163 float dx = g_n_gps_antenna_offset_x / 1852.;
6164 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6172 if (shipLength_mm < ownship_min_mm) {
6173 dy /= shipLength_mm / ownship_min_mm;
6174 dx /= shipLength_mm / ownship_min_mm;
6177 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6179 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6180 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6186 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6187 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6189 float scale_factor = shipLength_px / ownShipLength;
6192 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6195 scale_factor = wxMax(scale_factor, scale_factor_min);
6197 scale_factor_y = scale_factor;
6198 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6199 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6202void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6203 if (!GetVP().IsValid())
return;
6205 wxPoint GPSOffsetPixels(0, 0);
6206 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6209 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6210 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6214 lShipMidPoint = lGPSPoint;
6218 float icon_hdt = pCog;
6219 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6222 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6226 double osd_head_lat, osd_head_lon;
6227 wxPoint osd_head_point;
6229 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6234 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6235 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6236 icon_rad += (float)PI;
6238 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6242 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6246 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6247 if (GetVP().chart_scale >
6250 ShipDrawLargeScale(dc, lShipMidPoint);
6256 if (m_pos_image_user)
6257 pos_image = m_pos_image_user->Copy();
6258 else if (SHIP_NORMAL == m_ownship_state)
6259 pos_image = m_pos_image_red->Copy();
6260 if (SHIP_LOWACCURACY == m_ownship_state)
6261 pos_image = m_pos_image_yellow->Copy();
6262 else if (SHIP_NORMAL != m_ownship_state)
6263 pos_image = m_pos_image_grey->Copy();
6266 if (m_pos_image_user) {
6267 pos_image = m_pos_image_user->Copy();
6269 if (SHIP_LOWACCURACY == m_ownship_state)
6270 pos_image = m_pos_image_user_yellow->Copy();
6271 else if (SHIP_NORMAL != m_ownship_state)
6272 pos_image = m_pos_image_user_grey->Copy();
6275 img_height = pos_image.GetHeight();
6277 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6278 g_OwnShipIconType > 0)
6280 int ownShipWidth = 22;
6281 int ownShipLength = 84;
6282 if (g_OwnShipIconType == 1) {
6283 ownShipWidth = pos_image.GetWidth();
6284 ownShipLength = pos_image.GetHeight();
6287 float scale_factor_x, scale_factor_y;
6288 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6289 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6290 scale_factor_x, scale_factor_y);
6292 if (g_OwnShipIconType == 1) {
6293 pos_image.Rescale(ownShipWidth * scale_factor_x,
6294 ownShipLength * scale_factor_y,
6295 wxIMAGE_QUALITY_HIGH);
6296 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6298 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6301 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6302 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6303 if (rot_image.GetAlpha(ip, jp) > 64)
6304 rot_image.SetAlpha(ip, jp, 255);
6306 wxBitmap os_bm(rot_image);
6308 int w = os_bm.GetWidth();
6309 int h = os_bm.GetHeight();
6312 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6313 lShipMidPoint.m_y - h / 2,
true);
6316 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6317 lShipMidPoint.m_y - h / 2);
6318 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6319 lShipMidPoint.m_y - h / 2 + h);
6322 else if (g_OwnShipIconType == 2) {
6323 wxPoint ownship_icon[10];
6325 for (
int i = 0; i < 10; i++) {
6327 float pxa = (float)(s_ownship_icon[j]);
6328 float pya = (float)(s_ownship_icon[j + 1]);
6329 pya *= scale_factor_y;
6330 pxa *= scale_factor_x;
6332 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6333 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6335 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6336 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6339 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6341 dc.SetBrush(wxBrush(ShipColor()));
6343 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6346 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6348 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6352 img_height = ownShipLength * scale_factor_y;
6356 if (m_pos_image_user) circle_rad = 1;
6358 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6359 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6360 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6363 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6365 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6368 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6369 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6370 if (rot_image.GetAlpha(ip, jp) > 64)
6371 rot_image.SetAlpha(ip, jp, 255);
6373 wxBitmap os_bm(rot_image);
6375 if (g_ShipScaleFactorExp > 1) {
6376 wxImage scaled_image = os_bm.ConvertToImage();
6377 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6379 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6380 scaled_image.GetHeight() * factor,
6381 wxIMAGE_QUALITY_HIGH));
6383 int w = os_bm.GetWidth();
6384 int h = os_bm.GetHeight();
6387 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6388 lShipMidPoint.m_y - h / 2,
true);
6392 if (m_pos_image_user) circle_rad = 1;
6394 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6395 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6396 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6399 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6400 lShipMidPoint.m_y - h / 2);
6401 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6402 lShipMidPoint.m_y - h / 2 + h);
6407 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6420void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6421 float &MinorSpacing) {
6426 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6427 {.000001f, 45.0f, 15.0f},
6428 {.0002f, 30.0f, 10.0f},
6429 {.0003f, 10.0f, 2.0f},
6430 {.0008f, 5.0f, 1.0f},
6431 {.001f, 2.0f, 30.0f / 60.0f},
6432 {.003f, 1.0f, 20.0f / 60.0f},
6433 {.006f, 0.5f, 10.0f / 60.0f},
6434 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6435 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6436 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6437 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6438 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6439 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6440 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6441 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6444 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6445 if (view_scale_ppm < lltab[tabi][0])
break;
6446 MajorSpacing = lltab[tabi][1];
6447 MinorSpacing = lltab[tabi][2];
6461wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6462 int deg = (int)fabs(latlon);
6463 float min = fabs((fabs(latlon) - deg) * 60.0);
6473 }
else if (latlon < 0.0) {
6485 if (spacing >= 1.0) {
6486 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6487 }
else if (spacing >= (1.0 / 60.0)) {
6488 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6490 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6507void ChartCanvas::GridDraw(
ocpnDC &dc) {
6508 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6510 double nlat, elon, slat, wlon;
6513 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6515 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6517 if (!m_pgridFont) SetupGridFont();
6518 dc.SetFont(*m_pgridFont);
6519 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6522 h = m_canvas_height;
6533 dlon = dlon + 360.0;
6536 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6539 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6542 while (lat < nlat) {
6545 CalcGridText(lat, gridlatMajor,
true);
6547 dc.
DrawLine(0, r.y, w, r.y,
false);
6548 dc.DrawText(st, 0, r.y);
6549 lat = lat + gridlatMajor;
6551 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6555 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6558 while (lat < nlat) {
6561 dc.
DrawLine(0, r.y, 10, r.y,
false);
6562 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6563 lat = lat + gridlatMinor;
6567 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6570 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6573 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6575 wxString st = CalcGridText(lon, gridlonMajor,
false);
6577 dc.
DrawLine(r.x, 0, r.x, h,
false);
6578 dc.DrawText(st, r.x, 0);
6579 lon = lon + gridlonMajor;
6584 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6588 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6590 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6593 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6594 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6595 lon = lon + gridlonMinor;
6602void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6604 double blat, blon, tlat, tlon;
6607 int x_origin = m_bDisplayGrid ? 60 : 20;
6608 int y_origin = m_canvas_height - 50;
6614 if (GetVP().chart_scale > 80000)
6618 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6619 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6624 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6625 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6629 double rotation = -VPoint.
rotation;
6631 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6633 int l1 = (y_origin - r.y) / count;
6635 for (
int i = 0; i < count; i++) {
6642 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6645 double blat, blon, tlat, tlon;
6652 int y_origin = m_canvas_height - chartbar_height - 5;
6656 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6663 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6668 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6669 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6673 float places = floor(logdist), rem = logdist - places;
6674 dist = pow(10, places);
6681 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6682 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6683 double rotation = -VPoint.
rotation;
6689 int l1 = r.x - x_origin;
6691 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6696 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6697 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6698 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6700 if (!m_pgridFont) SetupGridFont();
6701 dc.SetFont(*m_pgridFont);
6702 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6704 dc.GetTextExtent(s, &w, &h);
6710 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6714void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6719 double ra_max = 40.;
6721 wxPen pen_save = dc.GetPen();
6723 wxDateTime now = wxDateTime::Now();
6729 x0 = x1 = x + radius;
6734 while (angle < 360.) {
6735 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6738 if (angle > 360.) angle = 360.;
6740 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6748 x1 = (int)(x + cos(angle * PI / 180.) * r);
6749 y1 = (int)(y + sin(angle * PI / 180.) * r);
6759 dc.
DrawLine(x + radius, y, x1, y1);
6761 dc.SetPen(pen_save);
6764static bool bAnchorSoundPlaying =
false;
6766static void onAnchorSoundFinished(
void *ptr) {
6767 o_sound::g_anchorwatch_sound->UnLoad();
6768 bAnchorSoundPlaying =
false;
6771void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6772 using namespace o_sound;
6774 bool play_sound =
false;
6776 if (AnchorAlertOn1) {
6777 wxPoint TargetPoint;
6780 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6781 TargetPoint.y, 100);
6785 AnchorAlertOn1 =
false;
6788 if (AnchorAlertOn2) {
6789 wxPoint TargetPoint;
6792 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6793 TargetPoint.y, 100);
6797 AnchorAlertOn2 =
false;
6800 if (!bAnchorSoundPlaying) {
6801 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6802 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6803 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6804 if (g_anchorwatch_sound->IsOk()) {
6805 bAnchorSoundPlaying =
true;
6806 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6807 g_anchorwatch_sound->Play();
6813void ChartCanvas::UpdateShips() {
6816 wxClientDC dc(
this);
6817 if (!dc.IsOk())
return;
6819 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6820 if (!test_bitmap.IsOk())
return;
6822 wxMemoryDC temp_dc(test_bitmap);
6824 temp_dc.ResetBoundingBox();
6825 temp_dc.DestroyClippingRegion();
6826 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6837 ocpndc.CalcBoundingBox(px.x, px.y);
6842 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6843 temp_dc.MaxY() - temp_dc.MinY());
6845 wxRect own_ship_update_rect = ship_draw_rect;
6847 if (!own_ship_update_rect.IsEmpty()) {
6850 own_ship_update_rect.Union(ship_draw_last_rect);
6851 own_ship_update_rect.Inflate(2);
6854 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6856 ship_draw_last_rect = ship_draw_rect;
6858 temp_dc.SelectObject(wxNullBitmap);
6861void ChartCanvas::UpdateAlerts() {
6866 wxClientDC dc(
this);
6870 dc.GetSize(&sx, &sy);
6873 wxBitmap test_bitmap(sx, sy, -1);
6877 temp_dc.SelectObject(test_bitmap);
6879 temp_dc.ResetBoundingBox();
6880 temp_dc.DestroyClippingRegion();
6881 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6888 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6889 temp_dc.MaxX() - temp_dc.MinX(),
6890 temp_dc.MaxY() - temp_dc.MinY());
6892 if (!alert_rect.IsEmpty())
6893 alert_rect.Inflate(2);
6895 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6898 wxRect alert_update_rect = alert_draw_rect;
6899 alert_update_rect.Union(alert_rect);
6902 RefreshRect(alert_update_rect,
false);
6906 alert_draw_rect = alert_rect;
6908 temp_dc.SelectObject(wxNullBitmap);
6911void ChartCanvas::UpdateAIS() {
6917 wxClientDC dc(
this);
6921 dc.GetSize(&sx, &sy);
6929 if (
g_pAIS->GetTargetList().size() > 10) {
6930 ais_rect = wxRect(0, 0, sx, sy);
6933 wxBitmap test_bitmap(sx, sy, -1);
6937 temp_dc.SelectObject(test_bitmap);
6939 temp_dc.ResetBoundingBox();
6940 temp_dc.DestroyClippingRegion();
6941 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6945 AISDraw(ocpndc, GetVP(),
this);
6946 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6950 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6951 temp_dc.MaxY() - temp_dc.MinY());
6953 if (!ais_rect.IsEmpty())
6954 ais_rect.Inflate(2);
6956 temp_dc.SelectObject(wxNullBitmap);
6959 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6962 wxRect ais_update_rect = ais_draw_rect;
6963 ais_update_rect.Union(ais_rect);
6966 RefreshRect(ais_update_rect,
false);
6970 ais_draw_rect = ais_rect;
6973void ChartCanvas::ToggleCPAWarn() {
6974 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6980 g_bTCPA_Max =
false;
6984 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6985 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6987 if (!g_AisFirstTimeUse) {
6988 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
6989 _(
"CPA") +
" " + mess, 4, 4);
6994void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6996void ChartCanvas::OnSize(wxSizeEvent &event) {
6997 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6999 GetClientSize(&m_canvas_width, &m_canvas_height);
7003 m_displayScale = GetContentScaleFactor();
7007 m_canvas_width *= m_displayScale;
7008 m_canvas_height *= m_displayScale;
7021 m_absolute_min_scale_ppm =
7023 (1.2 * WGS84_semimajor_axis_meters * PI);
7026 gFrame->ProcessCanvasResize();
7036 SetMUIBarPosition();
7037 UpdateFollowButtonState();
7038 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7042 xr_margin = m_canvas_width * 95 / 100;
7043 xl_margin = m_canvas_width * 5 / 100;
7044 yt_margin = m_canvas_height * 5 / 100;
7045 yb_margin = m_canvas_height * 95 / 100;
7048 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7053 m_brepaint_piano =
true;
7056 m_dc_route.SelectObject(wxNullBitmap);
7059 m_dc_route.SelectObject(*proute_bm);
7073 m_glcc->OnSize(event);
7082void ChartCanvas::ProcessNewGUIScale() {
7090void ChartCanvas::CreateMUIBar() {
7091 if (g_useMUI && !m_muiBar) {
7092 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7093 m_muiBar->SetColorScheme(m_cs);
7094 m_muiBarHOSize = m_muiBar->m_size;
7102 SetMUIBarPosition();
7103 UpdateFollowButtonState();
7104 m_muiBar->UpdateDynamicValues();
7105 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7109void ChartCanvas::SetMUIBarPosition() {
7113 int pianoWidth = GetClientSize().x * 0.6f;
7118 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7119 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7121 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7122 m_muiBar->SetColorScheme(m_cs);
7126 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7127 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7129 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7130 m_muiBar->SetColorScheme(m_cs);
7134 m_muiBar->SetBestPosition();
7138void ChartCanvas::DestroyMuiBar() {
7145void ChartCanvas::ShowCompositeInfoWindow(
7146 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7148 if (NULL == m_pCIWin) {
7153 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7156 s = _(
"Composite of ");
7159 s1.Printf(
"%d ", n_charts);
7167 s1.Printf(_(
"Chart scale"));
7170 s2.Printf(
"1:%d\n",
scale);
7174 s1 = _(
"Zoom in for more information");
7178 int char_width = s1.Length();
7179 int char_height = 3;
7181 if (g_bChartBarEx) {
7184 for (
int i : index_vector) {
7186 wxString path = cte.GetFullSystemPath();
7190 char_width = wxMax(char_width, path.Length());
7191 if (j++ >= 9)
break;
7194 s +=
" .\n .\n .\n";
7203 m_pCIWin->SetString(s);
7205 m_pCIWin->FitToChars(char_width, char_height);
7208 p.x = x / GetContentScaleFactor();
7209 if ((p.x + m_pCIWin->GetWinSize().x) >
7210 (m_canvas_width / GetContentScaleFactor()))
7211 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7212 m_pCIWin->GetWinSize().x) /
7215 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7216 4 - m_pCIWin->GetWinSize().y;
7218 m_pCIWin->dbIndex = 0;
7219 m_pCIWin->chart_scale = 0;
7220 m_pCIWin->SetPosition(p);
7221 m_pCIWin->SetBitmap();
7222 m_pCIWin->Refresh();
7226 HideChartInfoWindow();
7230void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7232 if (NULL == m_pCIWin) {
7237 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7246 dbIndex, FULL_INIT);
7248 int char_width, char_height;
7249 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7250 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7252 m_pCIWin->SetString(s);
7253 m_pCIWin->FitToChars(char_width, char_height);
7256 p.x = x / GetContentScaleFactor();
7257 if ((p.x + m_pCIWin->GetWinSize().x) >
7258 (m_canvas_width / GetContentScaleFactor()))
7259 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7260 m_pCIWin->GetWinSize().x) /
7263 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7264 4 - m_pCIWin->GetWinSize().y;
7266 m_pCIWin->dbIndex = dbIndex;
7267 m_pCIWin->SetPosition(p);
7268 m_pCIWin->SetBitmap();
7269 m_pCIWin->Refresh();
7273 HideChartInfoWindow();
7277void ChartCanvas::HideChartInfoWindow() {
7280 m_pCIWin->Destroy();
7284 androidForceFullRepaint();
7289void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7290 wxMouseEvent ev(wxEVT_MOTION);
7293 ev.m_leftDown = mouse_leftisdown;
7295 wxEvtHandler *evthp = GetEventHandler();
7297 ::wxPostEvent(evthp, ev);
7300void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7301 if ((m_panx_target_final - m_panx_target_now) ||
7302 (m_pany_target_final - m_pany_target_now)) {
7303 DoTimedMovementTarget();
7308void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7310bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7312 if (m_disable_edge_pan)
return false;
7315 int pan_margin = m_canvas_width * margin / 100;
7316 int pan_timer_set = 200;
7317 double pan_delta = GetVP().
pix_width * delta / 100;
7321 if (x > m_canvas_width - pan_margin) {
7326 else if (x < pan_margin) {
7331 if (y < pan_margin) {
7336 else if (y > m_canvas_height - pan_margin) {
7345 wxMouseState state = ::wxGetMouseState();
7346#if wxCHECK_VERSION(3, 0, 0)
7347 if (!state.LeftIsDown())
7349 if (!state.LeftDown())
7354 if ((bft) && !pPanTimer->IsRunning()) {
7356 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7362 if ((!bft) && pPanTimer->IsRunning()) {
7372void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7373 bool setBeingEdited) {
7374 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7375 m_pRoutePointEditTarget = NULL;
7376 m_pFoundPoint = NULL;
7379 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7380 SelectableItemList SelList =
pSelect->FindSelectionList(
7390 bool brp_viz =
false;
7391 if (m_pEditRouteArray) {
7392 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7393 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7394 if (pr->IsVisible()) {
7400 brp_viz = frp->IsVisible();
7404 if (m_pEditRouteArray)
7406 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7407 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7410 m_bRouteEditing = setBeingEdited;
7413 frp->m_bRPIsBeingEdited = setBeingEdited;
7414 m_bMarkEditing = setBeingEdited;
7417 m_pRoutePointEditTarget = frp;
7418 m_pFoundPoint = pFind;
7423std::shared_ptr<HostApi121::PiPointContext>
7424ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7438 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7439 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7440 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7441 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7442 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7446 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7449 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7454 int FoundAIS_MMSI = 0;
7456 FoundAIS_MMSI = pFindAIS->GetUserData();
7459 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7460 seltype |= SELTYPE_AISTARGET;
7466 Route *SelectedRoute = NULL;
7472 Route *pSelectedActiveRoute = NULL;
7473 Route *pSelectedVizRoute = NULL;
7476 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7477 SelectableItemList SelList =
7478 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7486 bool brp_viz =
false;
7488 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7490 if (pr->IsVisible()) {
7495 if (!brp_viz && prp->IsShared())
7497 brp_viz = prp->IsVisible();
7500 brp_viz = prp->IsVisible();
7502 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7508 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7511 pSelectedActiveRoute = pr;
7512 pFoundActiveRoutePoint = prp;
7517 if (NULL == pSelectedVizRoute) {
7518 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7520 if (pr->IsVisible()) {
7521 pSelectedVizRoute = pr;
7522 pFoundVizRoutePoint = prp;
7528 delete proute_array;
7533 if (pFoundActiveRoutePoint) {
7534 FoundRoutePoint = pFoundActiveRoutePoint;
7535 SelectedRoute = pSelectedActiveRoute;
7536 }
else if (pFoundVizRoutePoint) {
7537 FoundRoutePoint = pFoundVizRoutePoint;
7538 SelectedRoute = pSelectedVizRoute;
7541 FoundRoutePoint = pFirstVizPoint;
7543 if (SelectedRoute) {
7544 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7545 }
else if (FoundRoutePoint) {
7546 seltype |= SELTYPE_MARKPOINT;
7551 if (m_pFoundRoutePoint) {
7555 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7556 RefreshRect(wp_rect,
true);
7565 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7566 SelectableItemList SelList =
7567 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7569 if (NULL == SelectedRoute)
7574 if (pr->IsVisible()) {
7581 if (SelectedRoute) {
7582 if (NULL == FoundRoutePoint)
7583 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7586 seltype |= SELTYPE_ROUTESEGMENT;
7590 if (pFindTrackSeg) {
7591 m_pSelectedTrack = NULL;
7592 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7593 SelectableItemList SelList =
7594 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7599 if (pt->IsVisible()) {
7600 m_pSelectedTrack = pt;
7604 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7607 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7610 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7611 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7612 rstruct->object_ident =
"";
7614 if (seltype == SELTYPE_AISTARGET) {
7615 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7617 val.Printf(
"%d", FoundAIS_MMSI);
7618 rstruct->object_ident = val.ToStdString();
7619 }
else if (seltype & SELTYPE_MARKPOINT) {
7620 if (FoundRoutePoint) {
7621 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7622 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7624 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7625 if (SelectedRoute) {
7626 rstruct->object_type =
7627 HostApi121::PiContextObjectType::kObjectRoutesegment;
7628 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7630 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7631 if (m_pSelectedTrack) {
7632 rstruct->object_type =
7633 HostApi121::PiContextObjectType::kObjectTracksegment;
7634 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7641void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7642 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7643 singleClickEventIsValid =
false;
7644 m_DoubleClickTimer->Stop();
7649bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7650 if (!m_bChartDragging && !m_bDrawingRoute) {
7655 if (m_Compass && m_Compass->IsShown()) {
7657 bool isInCompass = logicalRect.Contains(event.GetPosition());
7658 if (isInCompass || m_mouseWasInCompass) {
7659 if (m_Compass->MouseEvent(event)) {
7660 cursor_region = CENTER;
7661 if (!g_btouch) SetCanvasCursor(event);
7662 m_mouseWasInCompass = isInCompass;
7666 m_mouseWasInCompass = isInCompass;
7669 if (m_notification_button && m_notification_button->IsShown()) {
7671 bool isinButton = logicalRect.Contains(event.GetPosition());
7673 SetCursor(*pCursorArrow);
7674 if (event.LeftDown()) HandleNotificationMouseClick();
7679 if (MouseEventToolbar(event))
return true;
7681 if (MouseEventChartBar(event))
return true;
7683 if (MouseEventMUIBar(event))
return true;
7685 if (MouseEventIENCBar(event))
return true;
7690void ChartCanvas::HandleNotificationMouseClick() {
7691 if (!m_NotificationsList) {
7695 m_NotificationsList->RecalculateSize();
7696 m_NotificationsList->Hide();
7699 if (m_NotificationsList->IsShown()) {
7700 m_NotificationsList->Hide();
7702 m_NotificationsList->RecalculateSize();
7703 m_NotificationsList->ReloadNotificationList();
7704 m_NotificationsList->Show();
7707bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7708 if (!g_bShowChartBar)
return false;
7710 if (!m_Piano->MouseEvent(event))
return false;
7712 cursor_region = CENTER;
7713 if (!g_btouch) SetCanvasCursor(event);
7717bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7718 if (!IsPrimaryCanvas())
return false;
7727 cursor_region = CENTER;
7728 if (!g_btouch) SetCanvasCursor(event);
7732bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7733 if (!IsPrimaryCanvas())
return false;
7746bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7748 if (!m_muiBar->MouseEvent(event))
return false;
7751 cursor_region = CENTER;
7752 if (!g_btouch) SetCanvasCursor(event);
7764 event.GetPosition(&x, &y);
7766 x *= m_displayScale;
7767 y *= m_displayScale;
7769 m_MouseDragging =
event.Dragging();
7775 if (event.Dragging()) {
7776 if ((x == mouse_x) && (y == mouse_y))
return true;
7782 mouse_leftisdown =
event.LeftDown();
7786 cursor_region = CENTER;
7790 if (m_Compass && m_Compass->IsShown() &&
7791 m_Compass->
GetRect().Contains(event.GetPosition())) {
7792 cursor_region = CENTER;
7793 }
else if (x > xr_margin) {
7794 cursor_region = MID_RIGHT;
7795 }
else if (x < xl_margin) {
7796 cursor_region = MID_LEFT;
7797 }
else if (y > yb_margin - chartbar_height &&
7798 y < m_canvas_height - chartbar_height) {
7799 cursor_region = MID_TOP;
7800 }
else if (y < yt_margin) {
7801 cursor_region = MID_BOT;
7803 cursor_region = CENTER;
7806 if (!g_btouch) SetCanvasCursor(event);
7810 leftIsDown =
event.LeftDown();
7813 if (event.LeftDown()) {
7814 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7817 g_bTempShowMenuBar =
false;
7818 parent_frame->ApplyGlobalSettings(
false);
7826 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7827 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7831 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7832 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7835 event.SetEventObject(
this);
7836 if (SendMouseEventToPlugins(event))
7843 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7844 StartChartDragInertia();
7847 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7848 !singleClickEventIsValid) {
7850 if (m_DoubleClickTimer->IsRunning()) {
7851 m_DoubleClickTimer->Stop();
7856 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7857 singleClickEvent = event;
7858 singleClickEventIsValid =
true;
7867 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7868 if (g_click_stop > 0) {
7876 if (GetUpMode() == COURSE_UP_MODE) {
7877 m_b_rot_hidef =
false;
7878 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7880 pRotDefTimer->Stop();
7883 bool bRoll = !g_btouch;
7888 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7889 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7890 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7891 m_RolloverPopupTimer.Start(
7895 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7899 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7908#if !defined(__WXGTK__) && !defined(__WXQT__)
7916 if ((x >= 0) && (y >= 0))
7921 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7922 wxPoint p = ClientToScreen(wxPoint(x, y));
7928 if (m_routeState >= 2) {
7931 m_bDrawingRoute =
true;
7933 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7938 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7941 m_bDrawingRoute =
true;
7943 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7956#if defined(__WXMAC__) || defined(__ANDROID__)
7960 wxClientDC cdc(GetParent());
7972 if (m_pSelectedRoute) {
7974 m_pSelectedRoute->DeSelectRoute();
7976 if (g_bopengl && m_glcc) {
7981 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7984 if (m_pFoundRoutePoint) {
7992 if (g_btouch && m_pRoutePointEditTarget) {
7995 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7999 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8000 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8001 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8002 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8003 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8007 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8010 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8016 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8019 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8020 seltype |= SELTYPE_AISTARGET;
8025 m_pFoundRoutePoint = NULL;
8030 Route *pSelectedActiveRoute = NULL;
8031 Route *pSelectedVizRoute = NULL;
8034 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8035 SelectableItemList SelList =
8036 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8044 bool brp_viz =
false;
8046 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8048 if (pr->IsVisible()) {
8053 if (!brp_viz && prp->IsShared())
8055 brp_viz = prp->IsVisible();
8058 brp_viz = prp->IsVisible();
8060 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8065 m_pSelectedRoute = NULL;
8067 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8070 pSelectedActiveRoute = pr;
8071 pFoundActiveRoutePoint = prp;
8076 if (NULL == pSelectedVizRoute) {
8077 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8079 if (pr->IsVisible()) {
8080 pSelectedVizRoute = pr;
8081 pFoundVizRoutePoint = prp;
8087 delete proute_array;
8092 if (pFoundActiveRoutePoint) {
8093 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8094 m_pSelectedRoute = pSelectedActiveRoute;
8095 }
else if (pFoundVizRoutePoint) {
8096 m_pFoundRoutePoint = pFoundVizRoutePoint;
8097 m_pSelectedRoute = pSelectedVizRoute;
8100 m_pFoundRoutePoint = pFirstVizPoint;
8102 if (m_pSelectedRoute) {
8103 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8104 }
else if (m_pFoundRoutePoint) {
8105 seltype |= SELTYPE_MARKPOINT;
8109 if (m_pFoundRoutePoint) {
8113 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8114 RefreshRect(wp_rect,
true);
8122 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8123 SelectableItemList SelList =
8124 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8126 if (NULL == m_pSelectedRoute)
8131 if (pr->IsVisible()) {
8132 m_pSelectedRoute = pr;
8138 if (m_pSelectedRoute) {
8139 if (NULL == m_pFoundRoutePoint)
8140 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8145 if (g_bopengl && m_glcc) {
8150 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8152 seltype |= SELTYPE_ROUTESEGMENT;
8156 if (pFindTrackSeg) {
8157 m_pSelectedTrack = NULL;
8158 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8159 SelectableItemList SelList =
8160 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8165 if (pt->IsVisible()) {
8166 m_pSelectedTrack = pt;
8170 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8176 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8177 seltype |= SELTYPE_CURRENTPOINT;
8180 else if (pFindTide) {
8181 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8182 seltype |= SELTYPE_TIDEPOINT;
8187 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8192IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8202 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8203 SelectableItemList SelList =
8204 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8207 pFind = *SelList.begin();
8208 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8210 auto node = SelList.begin();
8211 if (SelList.size() > 1) {
8212 for (++node; node != SelList.end(); ++node) {
8215 if (pIDX_candidate->
IDX_type ==
'c') {
8216 pIDX_best_candidate = pIDX_candidate;
8221 pFind = *SelList.begin();
8222 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8225 return pIDX_best_candidate;
8227void ChartCanvas::CallPopupMenu(
int x,
int y) {
8231 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8239 if (SELTYPE_CURRENTPOINT == seltype) {
8245 if (SELTYPE_TIDEPOINT == seltype) {
8251 InvokeCanvasMenu(x, y, seltype);
8254 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8258 m_pSelectedRoute = NULL;
8260 if (m_pFoundRoutePoint) {
8261 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8264 m_pFoundRoutePoint = NULL;
8270bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8278 event.GetPosition(&x, &y);
8284 SelectRadius = g_Platform->GetSelectRadiusPix() /
8285 (m_true_scale_ppm * 1852 * 60);
8292 if (event.LeftDClick() && (cursor_region == CENTER)) {
8293 m_DoubleClickTimer->Start();
8294 singleClickEventIsValid =
false;
8300 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8303 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8306 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8307 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8308 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8314 SelectableItemList rpSelList =
8315 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8316 bool b_onRPtarget =
false;
8319 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8320 b_onRPtarget =
true;
8328 std::unique_ptr<HostApi> host_api =
GetHostApi();
8329 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8331 if (m_pRoutePointEditTarget) {
8333 if ((api_121->GetContextMenuMask() &
8334 api_121->kContextMenuDisableWaypoint))
8336 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8342 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8345 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8346 m_pRoutePointEditTarget = NULL;
8347 RefreshRect(wp_rect,
true);
8351 auto node = rpSelList.begin();
8352 if (node != rpSelList.end()) {
8356 wxArrayPtrVoid *proute_array =
8361 bool brp_viz =
false;
8363 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8365 if (pr->IsVisible()) {
8370 delete proute_array;
8374 brp_viz = frp->IsVisible();
8376 brp_viz = frp->IsVisible();
8379 if ((api_121->GetContextMenuMask() &
8380 api_121->kContextMenuDisableWaypoint))
8383 ShowMarkPropertiesDialog(frp);
8392 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8394 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8397 if (pr->IsVisible()) {
8398 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8403 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8405 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8408 if (pt->IsVisible()) {
8409 ShowTrackPropertiesDialog(pt);
8418 if (m_bShowCurrent) {
8420 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8422 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8430 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8432 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8440 ShowObjectQueryWindow(x, y, zlat, zlon);
8445 if (event.LeftDown()) {
8461 bool appending =
false;
8462 bool inserting =
false;
8465 SetCursor(*pCursorPencil);
8469 m_bRouteEditing =
true;
8471 if (m_routeState == 1) {
8472 m_pMouseRoute =
new Route();
8473 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8483 double nearby_radius_meters =
8484 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8487 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8488 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8489 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8490 wxArrayPtrVoid *proute_array =
8495 bool brp_viz =
false;
8497 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8499 if (pr->IsVisible()) {
8504 delete proute_array;
8506 pNearbyPoint->IsShared())
8509 pNearbyPoint->IsVisible();
8511 brp_viz = pNearbyPoint->IsVisible();
8514 wxString msg = _(
"Use nearby waypoint?");
8516 const bool noname(pNearbyPoint->GetName() ==
"");
8519 _(
"Use nearby nameless waypoint and name it M with"
8520 " a unique number?");
8523 m_FinishRouteOnKillFocus =
false;
8525 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8526 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8527 m_FinishRouteOnKillFocus =
true;
8528 if (dlg_return == wxID_YES) {
8530 if (m_pMouseRoute) {
8531 int last_wp_num = m_pMouseRoute->GetnPoints();
8533 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8534 wxString wp_name = wxString::Format(
8535 "M%002i-%s", last_wp_num + 1, guid_short);
8536 pNearbyPoint->SetName(wp_name);
8538 pNearbyPoint->SetName(
"WPXX");
8540 pMousePoint = pNearbyPoint;
8543 if (m_routeState > 1)
8544 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8545 Undo_HasParent, NULL);
8548 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8549 bool procede =
false;
8553 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8559 m_FinishRouteOnKillFocus =
false;
8565 _(
"Insert first part of this route in the new route?");
8566 if (tail->GetIndexOf(pMousePoint) ==
8569 dmsg = _(
"Insert this route in the new route?");
8571 if (tail->GetIndexOf(pMousePoint) != 1) {
8572 dlg_return = OCPNMessageBox(
8573 this, dmsg, _(
"OpenCPN Route Create"),
8574 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8575 m_FinishRouteOnKillFocus =
true;
8577 if (dlg_return == wxID_YES) {
8584 _(
"Append last part of this route to the new route?");
8585 if (tail->GetIndexOf(pMousePoint) == 1)
8587 "Append this route to the new route?");
8592 if (tail->GetLastPoint() != pMousePoint) {
8593 dlg_return = OCPNMessageBox(
8594 this, dmsg, _(
"OpenCPN Route Create"),
8595 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8596 m_FinishRouteOnKillFocus =
true;
8598 if (dlg_return == wxID_YES) {
8609 if (!FindRouteContainingWaypoint(pMousePoint))
8610 pMousePoint->SetShared(
true);
8615 if (NULL == pMousePoint) {
8616 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8618 pMousePoint->SetNameShown(
false);
8622 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8624 if (m_routeState > 1)
8625 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8626 Undo_IsOrphanded, NULL);
8629 if (m_pMouseRoute) {
8630 if (m_routeState == 1) {
8632 m_pMouseRoute->AddPoint(pMousePoint);
8636 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8637 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8638 &rhumbBearing, &rhumbDist);
8639 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8640 rlat, &gcDist, &gcBearing, NULL);
8641 double gcDistNM = gcDist / 1852.0;
8644 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8645 pow(rhumbDist - gcDistNM - 1, 0.5);
8648 msg << _(
"For this leg the Great Circle route is ")
8650 << _(
" shorter than rhumbline.\n\n")
8651 << _(
"Would you like include the Great Circle routing points "
8654 m_FinishRouteOnKillFocus =
false;
8655 m_disable_edge_pan =
true;
8658 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8659 wxYES_NO | wxNO_DEFAULT);
8661 m_disable_edge_pan =
false;
8662 m_FinishRouteOnKillFocus =
true;
8664 if (answer == wxID_YES) {
8666 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8667 wxRealPoint gcCoord;
8669 for (
int i = 1; i <= segmentCount; i++) {
8670 double fraction = (double)i * (1.0 / (
double)segmentCount);
8671 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8672 gcDist * fraction, gcBearing,
8673 &gcCoord.x, &gcCoord.y, NULL);
8675 if (i < segmentCount) {
8676 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8678 gcPoint->SetNameShown(
false);
8680 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8682 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8685 gcPoint = pMousePoint;
8688 m_pMouseRoute->AddPoint(gcPoint);
8689 pSelect->AddSelectableRouteSegment(
8690 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8691 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8692 prevGcPoint = gcPoint;
8695 undo->CancelUndoableAction(
true);
8698 m_pMouseRoute->AddPoint(pMousePoint);
8699 pSelect->AddSelectableRouteSegment(
8700 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8701 pMousePoint, m_pMouseRoute);
8702 undo->AfterUndoableAction(m_pMouseRoute);
8706 m_pMouseRoute->AddPoint(pMousePoint);
8707 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8708 rlon, m_prev_pMousePoint,
8709 pMousePoint, m_pMouseRoute);
8710 undo->AfterUndoableAction(m_pMouseRoute);
8716 m_prev_pMousePoint = pMousePoint;
8724 int connect = tail->GetIndexOf(pMousePoint);
8729 int length = tail->GetnPoints();
8734 start = connect + 1;
8739 m_pMouseRoute->RemovePoint(
8743 for (i = start; i <= stop; i++) {
8744 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8747 m_pMouseRoute->GetnPoints();
8749 gFrame->RefreshAllCanvas();
8753 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8755 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8756 m_pMouseRoute->FinalizeForRendering();
8758 gFrame->RefreshAllCanvas();
8762 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8764 SetCursor(*pCursorPencil);
8766 if (!m_pMeasureRoute) {
8767 m_pMeasureRoute =
new Route();
8771 if (m_nMeasureState == 1) {
8778 wxEmptyString, wxEmptyString);
8780 pMousePoint->SetShowWaypointRangeRings(
false);
8782 m_pMeasureRoute->AddPoint(pMousePoint);
8786 m_prev_pMousePoint = pMousePoint;
8790 gFrame->RefreshAllCanvas();
8795 FindRoutePointsAtCursor(SelectRadius,
true);
8799 m_last_touch_down_pos =
event.GetPosition();
8801 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8809 if (ret)
return true;
8812 if (event.Dragging()) {
8815 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8817 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8819 SelectableItemList SelList =
pSelect->FindSelectionList(
8823 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8828 if (m_pRoutePointEditTarget &&
8829 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8831 SelectableItemList SelList =
pSelect->FindSelectionList(
8835 if (m_pRoutePointEditTarget == frp) {
8836 m_bIsInRadius =
true;
8841 if (!m_dragoffsetSet) {
8843 .PresetDragOffset(
this, mouse_x, mouse_y);
8844 m_dragoffsetSet =
true;
8849 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8850 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8853 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8855 DraggingAllowed =
false;
8857 if (m_pRoutePointEditTarget &&
8858 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8859 DraggingAllowed =
false;
8861 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8863 if (DraggingAllowed) {
8864 if (!undo->InUndoableAction()) {
8865 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8866 Undo_NeedsCopy, m_pFoundPoint);
8872 if (!g_bopengl && m_pEditRouteArray) {
8873 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8874 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8881 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8882 pre_rect.Union(route_rect);
8890 if (CheckEdgePan(x, y,
true, 5, 2))
8898 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8900 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8901 m_pRoutePointEditTarget,
8902 SELTYPE_DRAGHANDLE);
8903 m_pFoundPoint->m_slat =
8904 m_pRoutePointEditTarget->m_lat;
8905 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8907 m_pRoutePointEditTarget->m_lat =
8909 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8910 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8911 m_pFoundPoint->m_slat =
8913 m_pFoundPoint->m_slon = new_cursor_lon;
8929 if (m_pEditRouteArray) {
8930 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8932 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8935 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8936 post_rect.Union(route_rect);
8942 pre_rect.Union(post_rect);
8943 RefreshRect(pre_rect,
false);
8945 gFrame->RefreshCanvasOther(
this);
8946 m_bRoutePoinDragging =
true;
8951 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8952 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8955 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8957 DraggingAllowed =
false;
8959 if (m_pRoutePointEditTarget &&
8960 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8961 DraggingAllowed =
false;
8963 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8965 if (DraggingAllowed) {
8966 if (!undo->InUndoableAction()) {
8967 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8968 Undo_NeedsCopy, m_pFoundPoint);
8982 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8988 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8989 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8990 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8991 (
int)(lppmax - (pre_rect.height / 2)));
8999 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9002 m_pRoutePointEditTarget,
9003 SELTYPE_DRAGHANDLE);
9004 m_pFoundPoint->m_slat =
9005 m_pRoutePointEditTarget->m_lat;
9006 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9008 m_pRoutePointEditTarget->m_lat =
9011 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9024 if (!g_btouch) InvalidateGL();
9030 .CalculateDCRect(m_dc_route,
this, &post_rect);
9031 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9032 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9033 (
int)(lppmax - (post_rect.height / 2)));
9036 pre_rect.Union(post_rect);
9037 RefreshRect(pre_rect,
false);
9039 gFrame->RefreshCanvasOther(
this);
9040 m_bRoutePoinDragging =
true;
9042 ret = g_btouch ? m_bRoutePoinDragging :
true;
9045 if (ret)
return true;
9048 if (event.LeftUp()) {
9049 bool b_startedit_route =
false;
9050 m_dragoffsetSet =
false;
9053 m_bChartDragging =
false;
9054 m_bIsInRadius =
false;
9058 if (m_ignore_next_leftup) {
9059 m_ignore_next_leftup =
false;
9064 m_bedge_pan =
false;
9069 bool appending =
false;
9070 bool inserting =
false;
9076 if (m_pRoutePointEditTarget) {
9082 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9083 RefreshRect(wp_rect,
true);
9085 m_pRoutePointEditTarget = NULL;
9087 m_bRouteEditing =
true;
9089 if (m_routeState == 1) {
9090 m_pMouseRoute =
new Route();
9091 m_pMouseRoute->SetHiLite(50);
9095 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9102 double nearby_radius_meters =
9103 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9106 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9107 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9108 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9111 m_FinishRouteOnKillFocus =
9113 dlg_return = OCPNMessageBox(
9114 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9115 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9116 m_FinishRouteOnKillFocus =
true;
9118 dlg_return = wxID_YES;
9120 if (dlg_return == wxID_YES) {
9121 pMousePoint = pNearbyPoint;
9124 if (m_routeState > 1)
9125 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9126 Undo_HasParent, NULL);
9127 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9129 bool procede =
false;
9133 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9139 m_FinishRouteOnKillFocus =
false;
9140 if (m_routeState == 1) {
9144 _(
"Insert first part of this route in the new route?");
9145 if (tail->GetIndexOf(pMousePoint) ==
9148 dmsg = _(
"Insert this route in the new route?");
9150 if (tail->GetIndexOf(pMousePoint) != 1) {
9152 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9153 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9154 m_FinishRouteOnKillFocus =
true;
9156 if (dlg_return == wxID_YES) {
9163 _(
"Append last part of this route to the new route?");
9164 if (tail->GetIndexOf(pMousePoint) == 1)
9166 "Append this route to the new route?");
9170 if (tail->GetLastPoint() != pMousePoint) {
9172 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9173 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9174 m_FinishRouteOnKillFocus =
true;
9176 if (dlg_return == wxID_YES) {
9187 if (!FindRouteContainingWaypoint(pMousePoint))
9188 pMousePoint->SetShared(
true);
9192 if (NULL == pMousePoint) {
9193 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9195 pMousePoint->SetNameShown(
false);
9197 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9199 if (m_routeState > 1)
9200 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9201 Undo_IsOrphanded, NULL);
9204 if (m_routeState == 1) {
9206 m_pMouseRoute->AddPoint(pMousePoint);
9207 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9211 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9212 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9213 &rhumbBearing, &rhumbDist);
9214 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9215 &gcDist, &gcBearing, NULL);
9216 double gcDistNM = gcDist / 1852.0;
9219 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9220 pow(rhumbDist - gcDistNM - 1, 0.5);
9223 msg << _(
"For this leg the Great Circle route is ")
9225 << _(
" shorter than rhumbline.\n\n")
9226 << _(
"Would you like include the Great Circle routing points "
9230 m_FinishRouteOnKillFocus =
false;
9231 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9232 wxYES_NO | wxNO_DEFAULT);
9233 m_FinishRouteOnKillFocus =
true;
9235 int answer = wxID_NO;
9238 if (answer == wxID_YES) {
9240 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9241 wxRealPoint gcCoord;
9243 for (
int i = 1; i <= segmentCount; i++) {
9244 double fraction = (double)i * (1.0 / (
double)segmentCount);
9245 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9246 gcDist * fraction, gcBearing,
9247 &gcCoord.x, &gcCoord.y, NULL);
9249 if (i < segmentCount) {
9250 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9252 gcPoint->SetNameShown(
false);
9253 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9256 gcPoint = pMousePoint;
9259 m_pMouseRoute->AddPoint(gcPoint);
9260 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9262 pSelect->AddSelectableRouteSegment(
9263 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9264 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9265 prevGcPoint = gcPoint;
9268 undo->CancelUndoableAction(
true);
9271 m_pMouseRoute->AddPoint(pMousePoint);
9272 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9273 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9274 rlon, m_prev_pMousePoint,
9275 pMousePoint, m_pMouseRoute);
9276 undo->AfterUndoableAction(m_pMouseRoute);
9280 m_pMouseRoute->AddPoint(pMousePoint);
9281 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9283 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9284 rlon, m_prev_pMousePoint,
9285 pMousePoint, m_pMouseRoute);
9286 undo->AfterUndoableAction(m_pMouseRoute);
9292 m_prev_pMousePoint = pMousePoint;
9299 int connect = tail->GetIndexOf(pMousePoint);
9304 int length = tail->GetnPoints();
9309 start = connect + 1;
9314 m_pMouseRoute->RemovePoint(
9318 for (i = start; i <= stop; i++) {
9319 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9322 m_pMouseRoute->GetnPoints();
9324 gFrame->RefreshAllCanvas();
9328 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9330 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9331 m_pMouseRoute->FinalizeForRendering();
9336 }
else if (m_bMeasure_Active && m_nMeasureState)
9339 m_bedge_pan =
false;
9343 if (m_nMeasureState == 1) {
9344 m_pMeasureRoute =
new Route();
9350 if (m_pMeasureRoute) {
9353 wxEmptyString, wxEmptyString);
9356 m_pMeasureRoute->AddPoint(pMousePoint);
9360 m_prev_pMousePoint = pMousePoint;
9362 m_pMeasureRoute->GetnPoints();
9366 CancelMeasureRoute();
9372 bool bSelectAllowed =
true;
9374 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9376 bSelectAllowed =
false;
9380 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9381 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9382 significant_drag) ||
9383 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9384 significant_drag)) {
9385 bSelectAllowed =
false;
9393 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9395 if (bSelectAllowed) {
9396 bool b_was_editing_mark = m_bMarkEditing;
9397 bool b_was_editing_route = m_bRouteEditing;
9398 FindRoutePointsAtCursor(SelectRadius,
9404 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9405 m_pRoutePointEditTarget = NULL;
9407 if (!b_was_editing_route) {
9408 if (m_pEditRouteArray) {
9409 b_startedit_route =
true;
9413 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9414 m_pTrackRolloverWin->IsActive(
false);
9416 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9417 m_pRouteRolloverWin->IsActive(
false);
9421 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9423 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9431 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9432 pre_rect.Union(route_rect);
9435 RefreshRect(pre_rect,
true);
9438 b_startedit_route =
false;
9442 if (m_pRoutePointEditTarget) {
9443 if (b_was_editing_mark ||
9444 b_was_editing_route) {
9445 if (m_lastRoutePointEditTarget) {
9449 .EnableDragHandle(
false);
9450 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9451 SELTYPE_DRAGHANDLE);
9455 if (m_pRoutePointEditTarget) {
9458 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9459 wxPoint2DDouble dragHandlePoint =
9461 .GetDragHandlePoint(
this);
9463 dragHandlePoint.m_y, dragHandlePoint.m_x,
9464 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9467 if (m_lastRoutePointEditTarget) {
9471 .EnableDragHandle(
false);
9472 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9473 SELTYPE_DRAGHANDLE);
9476 wxArrayPtrVoid *lastEditRouteArray =
9478 m_lastRoutePointEditTarget);
9479 if (lastEditRouteArray) {
9480 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9482 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9487 delete lastEditRouteArray;
9498 if (m_lastRoutePointEditTarget) {
9501 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9502 RefreshRect(wp_rect,
true);
9505 if (m_pRoutePointEditTarget) {
9508 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9509 RefreshRect(wp_rect,
true);
9517 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9518 bool b_start_rollover =
false;
9522 if (pFind) b_start_rollover =
true;
9525 if (!b_start_rollover && !b_startedit_route) {
9526 SelectableItemList SelList =
pSelect->FindSelectionList(
9530 if (pr && pr->IsVisible()) {
9531 b_start_rollover =
true;
9537 if (!b_start_rollover && !b_startedit_route) {
9538 SelectableItemList SelList =
pSelect->FindSelectionList(
9542 if (tr && tr->IsVisible()) {
9543 b_start_rollover =
true;
9549 if (b_start_rollover)
9550 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9554 bool appending =
false;
9555 bool inserting =
false;
9557 if (m_bRouteEditing ) {
9559 if (m_pRoutePointEditTarget) {
9565 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9566 double nearby_radius_meters =
9567 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9568 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9569 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9570 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9572 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9576 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9578 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9582 std::find(list->begin(), list->end(), pNearbyPoint);
9583 if (pos != list->end()) {
9595 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9600 OCPNMessageBox(
this,
9601 _(
"Replace this RoutePoint by the nearby "
9603 _(
"OpenCPN RoutePoint change"),
9604 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9605 if (dlg_return == wxID_YES) {
9610 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9613 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9615 if (tail && current && (tail != current)) {
9617 connect = tail->GetIndexOf(pNearbyPoint);
9618 int index_current_route =
9619 current->GetIndexOf(m_pRoutePointEditTarget);
9620 index_last = current->GetIndexOf(current->GetLastPoint());
9621 dlg_return1 = wxID_NO;
9623 index_current_route) {
9625 if (connect != tail->GetnPoints()) {
9628 _(
"Last part of route to be appended to dragged "
9632 _(
"Full route to be appended to dragged route?");
9634 dlg_return1 = OCPNMessageBox(
9635 this, dmsg, _(
"OpenCPN Route Create"),
9636 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9637 if (dlg_return1 == wxID_YES) {
9641 }
else if (index_current_route ==
9646 _(
"First part of route to be inserted into dragged "
9648 if (connect == tail->GetnPoints())
9650 "Full route to be inserted into dragged route?");
9652 dlg_return1 = OCPNMessageBox(
9653 this, dmsg, _(
"OpenCPN Route Create"),
9654 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9655 if (dlg_return1 == wxID_YES) {
9662 if (m_pRoutePointEditTarget->IsShared()) {
9664 dlg_return = OCPNMessageBox(
9666 _(
"Do you really want to delete and replace this "
9668 "\n" + _(
"which has been created manually?"),
9669 (
"OpenCPN RoutePoint warning"),
9670 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9673 if (dlg_return == wxID_YES) {
9674 pMousePoint = pNearbyPoint;
9676 pMousePoint->SetShared(
true);
9686 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9688 if (m_pEditRouteArray) {
9689 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9691 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9696 auto pos = std::find(list->begin(), list->end(),
9697 m_pRoutePointEditTarget);
9699 pSelect->DeleteAllSelectableRoutePoints(pr);
9700 pSelect->DeleteAllSelectableRouteSegments(pr);
9703 pos = std::find(list->begin(), list->end(),
9704 m_pRoutePointEditTarget);
9707 pSelect->AddAllSelectableRouteSegments(pr);
9708 pSelect->AddAllSelectableRoutePoints(pr);
9710 pr->FinalizeForRendering();
9711 pr->UpdateSegmentDistances();
9712 if (m_bRoutePoinDragging) {
9714 NavObj_dB::GetInstance().UpdateRoute(pr);
9722 if (m_pEditRouteArray) {
9723 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9725 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9744 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9751 delete m_pRoutePointEditTarget;
9752 m_lastRoutePointEditTarget = NULL;
9753 m_pRoutePointEditTarget = NULL;
9754 undo->AfterUndoableAction(pMousePoint);
9755 undo->InvalidateUndo();
9760 else if (m_bMarkEditing) {
9761 if (m_pRoutePointEditTarget)
9762 if (m_bRoutePoinDragging) {
9764 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9768 if (m_pRoutePointEditTarget)
9769 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9771 if (!m_pRoutePointEditTarget) {
9772 delete m_pEditRouteArray;
9773 m_pEditRouteArray = NULL;
9774 m_bRouteEditing =
false;
9776 m_bRoutePoinDragging =
false;
9783 int length = tail->GetnPoints();
9784 for (
int i = connect + 1; i <= length; i++) {
9785 current->AddPointAndSegment(tail->GetPoint(i),
false);
9788 gFrame->RefreshAllCanvas();
9791 current->FinalizeForRendering();
9797 pSelect->DeleteAllSelectableRoutePoints(current);
9798 pSelect->DeleteAllSelectableRouteSegments(current);
9799 for (
int i = 1; i < connect; i++) {
9800 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9802 pSelect->AddAllSelectableRouteSegments(current);
9803 pSelect->AddAllSelectableRoutePoints(current);
9804 current->FinalizeForRendering();
9811 if (m_pEditRouteArray) {
9812 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9813 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9826 if (m_bRouteEditing) {
9829 bool appending =
false;
9830 bool inserting =
false;
9833 if (m_pRoutePointEditTarget) {
9834 m_pRoutePointEditTarget->
m_bBlink =
false;
9838 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9839 double nearby_radius_meters =
9840 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9841 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9842 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9843 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9845 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9846 bool duplicate =
false;
9848 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9850 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9854 std::find(list->begin(), list->end(), pNearbyPoint);
9855 if (pos != list->end()) {
9867 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9872 OCPNMessageBox(
this,
9873 _(
"Replace this RoutePoint by the nearby "
9875 _(
"OpenCPN RoutePoint change"),
9876 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9877 if (dlg_return == wxID_YES) {
9881 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9884 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9886 if (tail && current && (tail != current)) {
9888 connect = tail->GetIndexOf(pNearbyPoint);
9889 int index_current_route =
9890 current->GetIndexOf(m_pRoutePointEditTarget);
9891 index_last = current->GetIndexOf(current->GetLastPoint());
9892 dlg_return1 = wxID_NO;
9894 index_current_route) {
9896 if (connect != tail->GetnPoints()) {
9899 _(
"Last part of route to be appended to dragged "
9903 _(
"Full route to be appended to dragged route?");
9905 dlg_return1 = OCPNMessageBox(
9906 this, dmsg, _(
"OpenCPN Route Create"),
9907 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9908 if (dlg_return1 == wxID_YES) {
9912 }
else if (index_current_route ==
9917 _(
"First part of route to be inserted into dragged "
9919 if (connect == tail->GetnPoints())
9921 "Full route to be inserted into dragged route?");
9923 dlg_return1 = OCPNMessageBox(
9924 this, dmsg, _(
"OpenCPN Route Create"),
9925 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9926 if (dlg_return1 == wxID_YES) {
9933 if (m_pRoutePointEditTarget->IsShared()) {
9934 dlg_return = wxID_NO;
9935 dlg_return = OCPNMessageBox(
9937 _(
"Do you really want to delete and replace this "
9939 "\n" + _(
"which has been created manually?"),
9940 (
"OpenCPN RoutePoint warning"),
9941 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9944 if (dlg_return == wxID_YES) {
9945 pMousePoint = pNearbyPoint;
9947 pMousePoint->SetShared(
true);
9957 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9959 if (m_pEditRouteArray) {
9960 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9962 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9966 auto pos = std::find(list->begin(), list->end(),
9967 m_pRoutePointEditTarget);
9969 pSelect->DeleteAllSelectableRoutePoints(pr);
9970 pSelect->DeleteAllSelectableRouteSegments(pr);
9973 pos = std::find(list->begin(), list->end(),
9974 m_pRoutePointEditTarget);
9975 if (pos != list->end()) list->erase(pos);
9978 pSelect->AddAllSelectableRouteSegments(pr);
9979 pSelect->AddAllSelectableRoutePoints(pr);
9981 pr->FinalizeForRendering();
9982 pr->UpdateSegmentDistances();
9985 if (m_bRoutePoinDragging) {
9990 NavObj_dB::GetInstance().UpdateRoutePoint(
9991 m_pRoutePointEditTarget);
9993 NavObj_dB::GetInstance().UpdateRoute(pr);
10005 int length = tail->GetnPoints();
10006 for (
int i = connect + 1; i <= length; i++) {
10007 current->AddPointAndSegment(tail->GetPoint(i),
false);
10011 gFrame->RefreshAllCanvas();
10014 current->FinalizeForRendering();
10020 pSelect->DeleteAllSelectableRoutePoints(current);
10021 pSelect->DeleteAllSelectableRouteSegments(current);
10022 for (
int i = 1; i < connect; i++) {
10023 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10025 pSelect->AddAllSelectableRouteSegments(current);
10026 pSelect->AddAllSelectableRoutePoints(current);
10027 current->FinalizeForRendering();
10034 if (m_pEditRouteArray) {
10035 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10037 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10049 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10056 delete m_pRoutePointEditTarget;
10057 m_lastRoutePointEditTarget = NULL;
10058 undo->AfterUndoableAction(pMousePoint);
10059 undo->InvalidateUndo();
10064 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10067 delete m_pEditRouteArray;
10068 m_pEditRouteArray = NULL;
10072 m_bRouteEditing =
false;
10073 m_pRoutePointEditTarget = NULL;
10079 else if (m_bMarkEditing) {
10080 if (m_pRoutePointEditTarget) {
10081 if (m_bRoutePoinDragging) {
10083 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10085 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10090 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10092 RefreshRect(wp_rect,
true);
10095 m_pRoutePointEditTarget = NULL;
10096 m_bMarkEditing =
false;
10101 else if (leftIsDown) {
10102 leftIsDown =
false;
10106 if (!m_bChartDragging && !m_bMeasure_Active) {
10108 m_bChartDragging =
false;
10112 m_bRoutePoinDragging =
false;
10115 if (ret)
return true;
10118 if (event.RightDown()) {
10129 m_FinishRouteOnKillFocus =
false;
10130 CallPopupMenu(mx, my);
10131 m_FinishRouteOnKillFocus =
true;
10141 if (event.ShiftDown()) {
10145 event.GetPosition(&x, &y);
10147 x *= m_displayScale;
10148 y *= m_displayScale;
10154 int wheel_dir =
event.GetWheelRotation();
10157 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10158 wheel_dir = wheel_dir > 0 ? 1 : -1;
10160 double factor = g_mouse_zoom_sensitivity;
10161 if (wheel_dir < 0) factor = 1 / factor;
10164 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10165 if (wheel_dir == m_last_wheel_dir) {
10166 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10171 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10172 m_wheelstopwatch.Start(0);
10177 m_last_wheel_dir = wheel_dir;
10182 if (event.LeftDown()) {
10188 last_drag.x = x, last_drag.y = y;
10189 panleftIsDown =
true;
10192 if (event.LeftUp()) {
10193 if (panleftIsDown) {
10195 panleftIsDown =
false;
10198 if (!m_bChartDragging && !m_bMeasure_Active) {
10199 switch (cursor_region) {
10221 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10226 m_bChartDragging =
false;
10232 if (event.Dragging() && event.LeftIsDown()) {
10248 if (g_btouch && !m_inPinch) {
10249 struct timespec now;
10250 clock_gettime(CLOCK_MONOTONIC, &now);
10251 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10253 bool trigger_hold =
false;
10254 if (
false == m_bChartDragging) {
10255 if (m_DragTrigger < 0) {
10258 m_DragTriggerStartTime = tnow;
10259 trigger_hold =
true;
10261 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10262 m_DragTrigger = -1;
10267 if (trigger_hold)
return true;
10269 if (
false == m_bChartDragging) {
10272 last_drag.x = x - 1, last_drag.y = y - 1;
10273 m_bChartDragging =
true;
10274 m_chart_drag_total_time = 0;
10275 m_chart_drag_total_x = 0;
10276 m_chart_drag_total_y = 0;
10277 m_inertia_last_drag_x = x;
10278 m_inertia_last_drag_y = y;
10279 m_drag_vec_x.clear();
10280 m_drag_vec_y.clear();
10281 m_drag_vec_t.clear();
10282 m_last_drag_time = tnow;
10286 uint64_t delta_t = tnow - m_last_drag_time;
10287 double delta_tf = delta_t / 1e9;
10289 m_chart_drag_total_time += delta_tf;
10290 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10291 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10293 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10294 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10295 m_drag_vec_t.push_back(delta_tf);
10297 m_inertia_last_drag_x = x;
10298 m_inertia_last_drag_y = y;
10299 m_last_drag_time = tnow;
10301 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10302 m_bChartDragging =
true;
10303 StartTimedMovement();
10304 m_pan_drag.x += last_drag.x - x;
10305 m_pan_drag.y += last_drag.y - y;
10306 last_drag.x = x, last_drag.y = y;
10308 }
else if (!g_btouch) {
10309 if ((last_drag.x != x) || (last_drag.y != y)) {
10310 if (!m_routeState) {
10313 m_bChartDragging =
true;
10314 StartTimedMovement();
10315 m_pan_drag.x += last_drag.x - x;
10316 m_pan_drag.y += last_drag.y - y;
10317 last_drag.x = x, last_drag.y = y;
10324 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10326 m_ignore_next_leftup =
true;
10327 m_DoubleClickTimer->Start();
10328 singleClickEventIsValid =
false;
10336void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10337 if (MouseEventOverlayWindows(event))
return;
10341 bool nm = MouseEventProcessObjects(event);
10345void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10348 wxCursor *ptarget_cursor = pCursorArrow;
10349 if (!pPlugIn_Cursor) {
10350 ptarget_cursor = pCursorArrow;
10351 if ((!m_routeState) &&
10352 (!m_bMeasure_Active) ) {
10353 if (cursor_region == MID_RIGHT) {
10354 ptarget_cursor = pCursorRight;
10355 }
else if (cursor_region == MID_LEFT) {
10356 ptarget_cursor = pCursorLeft;
10357 }
else if (cursor_region == MID_TOP) {
10358 ptarget_cursor = pCursorDown;
10359 }
else if (cursor_region == MID_BOT) {
10360 ptarget_cursor = pCursorUp;
10362 ptarget_cursor = pCursorArrow;
10364 }
else if (m_bMeasure_Active ||
10366 ptarget_cursor = pCursorPencil;
10368 ptarget_cursor = pPlugIn_Cursor;
10371 SetCursor(*ptarget_cursor);
10374void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10375 SetCursor(*pCursorArrow);
10378void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10382 wxArrayString files;
10384 ChartBase *target_chart = GetChartAtCursor();
10385 if (target_chart) {
10386 file.Assign(target_chart->GetFullPath());
10387 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10388 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10391 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10393 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10394 unsigned int im = stackIndexArray.size();
10395 int scale = 2147483647;
10396 if (VPoint.b_quilt && im > 0) {
10397 for (
unsigned int is = 0; is < im; is++) {
10398 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10399 CHART_TYPE_MBTILES) {
10400 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10402 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10403 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10405 .Contains(lat, lon)) {
10406 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10409 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10410 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10418 std::vector<Ais8_001_22 *> area_notices;
10420 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10423 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10424 auto target_data = target.second;
10425 if (!target_data->area_notices.empty()) {
10426 for (
auto &ani : target_data->area_notices) {
10431 for (Ais8_001_22_SubAreaList::iterator sa =
10432 area_notice.sub_areas.begin();
10433 sa != area_notice.sub_areas.end(); ++sa) {
10434 switch (sa->shape) {
10435 case AIS8_001_22_SHAPE_CIRCLE: {
10436 wxPoint target_point;
10438 bbox.Expand(target_point);
10439 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10442 case AIS8_001_22_SHAPE_RECT: {
10443 wxPoint target_point;
10445 bbox.Expand(target_point);
10446 if (sa->e_dim_m > sa->n_dim_m)
10447 bbox.EnLarge(sa->e_dim_m * vp_scale);
10449 bbox.EnLarge(sa->n_dim_m * vp_scale);
10452 case AIS8_001_22_SHAPE_POLYGON:
10453 case AIS8_001_22_SHAPE_POLYLINE: {
10454 for (
int i = 0; i < 4; ++i) {
10455 double lat = sa->latitude;
10456 double lon = sa->longitude;
10457 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10459 wxPoint target_point;
10461 bbox.Expand(target_point);
10465 case AIS8_001_22_SHAPE_SECTOR: {
10466 double lat1 = sa->latitude;
10467 double lon1 = sa->longitude;
10469 wxPoint target_point;
10471 bbox.Expand(target_point);
10472 for (
int i = 0; i < 18; ++i) {
10475 sa->left_bound_deg +
10476 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10477 sa->radius_m / 1852.0, &lat, &lon);
10479 bbox.Expand(target_point);
10481 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10484 bbox.Expand(target_point);
10490 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10491 area_notices.push_back(&area_notice);
10498 if (target_chart || !area_notices.empty() || file.HasName()) {
10500 int sel_rad_pix = 5;
10501 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10506 SetCursor(wxCURSOR_WAIT);
10507 bool lightsVis = m_encShowLights;
10508 if (!lightsVis) SetShowENCLights(
true);
10511 ListOfObjRazRules *rule_list = NULL;
10512 ListOfPI_S57Obj *pi_rule_list = NULL;
10515 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10516 else if (target_plugin_chart)
10517 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10518 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10520 ListOfObjRazRules *overlay_rule_list = NULL;
10521 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10524 if (CHs57_Overlay) {
10525 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10526 zlat, zlon, SelectRadius, &GetVP());
10529 if (!lightsVis) SetShowENCLights(
false);
10532 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10533 wxString face = dFont->GetFaceName();
10537 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10538 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10542 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10550 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10551 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10554 int points = dFont->GetPointSize();
10556 int points = dFont->GetPointSize() + 1;
10560 for (
int i = -2; i < 5; i++) {
10561 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10565 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10567 if (overlay_rule_list && CHs57_Overlay) {
10568 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10569 objText <<
"<hr noshade>";
10572 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10573 an != area_notices.end(); ++an) {
10574 objText <<
"<b>AIS Area Notice:</b> ";
10575 objText << ais8_001_22_notice_names[(*an)->notice_type];
10576 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10577 (*an)->sub_areas.begin();
10578 sa != (*an)->sub_areas.end(); ++sa)
10579 if (!sa->text.empty()) objText << sa->text;
10580 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10581 objText <<
"<hr noshade>";
10585 objText << Chs57->CreateObjDescriptions(rule_list);
10586 else if (target_plugin_chart)
10587 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10590 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10593 wxString AddFiles, filenameOK;
10595 if (!target_plugin_chart) {
10598 AddFiles = wxString::Format(
10599 "<hr noshade><br><b>Additional info files attached to: </b> "
10601 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10603 file.GetFullName());
10605 file.Assign(file.GetPath(),
"");
10606 wxDir dir(file.GetFullPath());
10608 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10610 file.Assign(dir.GetNameWithSep().append(filename));
10611 wxString FormatString =
10612 "<td valign=top><font size=-2><a "
10613 "href=\"%s\">%s</a></font></td>";
10614 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10615 filenameOK = file.GetFullPath();
10617 if (3 * ((
int)filecount / 3) == filecount)
10618 FormatString.Prepend(
"<tr>");
10620 FormatString.Prepend(
10621 "<td>  </td>");
10624 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10625 file.GetFullName());
10628 cont = dir.GetNext(&filename);
10630 objText << AddFiles <<
"</table>";
10632 objText <<
"</font>";
10633 objText <<
"</body></html>";
10635 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10639 if ((!Chs57 && filecount == 1)) {
10641 wxHtmlLinkInfo hli(filenameOK);
10642 wxHtmlLinkEvent hle(1, hli);
10646 if (rule_list) rule_list->Clear();
10649 if (overlay_rule_list) overlay_rule_list->Clear();
10650 delete overlay_rule_list;
10652 if (pi_rule_list) pi_rule_list->Clear();
10653 delete pi_rule_list;
10655 SetCursor(wxCURSOR_ARROW);
10659void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10668 wxSize canvas_size = GetSize();
10675 wxPoint canvas_pos = GetPosition();
10678 bool newFit =
false;
10679 if (canvas_size.x < fitted_size.x) {
10680 fitted_size.x = canvas_size.x - 40;
10681 if (canvas_size.y < fitted_size.y)
10682 fitted_size.y -= 40;
10684 if (canvas_size.y < fitted_size.y) {
10685 fitted_size.y = canvas_size.y - 40;
10686 if (canvas_size.x < fitted_size.x)
10687 fitted_size.x -= 40;
10698 wxString title_base = _(
"Mark Properties");
10700 title_base = _(
"Waypoint Properties");
10705 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10717void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10727 if (g_bresponsive) {
10728 wxSize canvas_size = GetSize();
10729 wxPoint canvas_pos = GetPosition();
10733 if (canvas_size.x < fitted_size.x) {
10734 fitted_size.x = canvas_size.x;
10735 if (canvas_size.y < fitted_size.y)
10736 fitted_size.y -= 20;
10738 if (canvas_size.y < fitted_size.y) {
10739 fitted_size.y = canvas_size.y;
10740 if (canvas_size.x < fitted_size.x)
10741 fitted_size.x -= 20;
10750 wxPoint xxp = ClientToScreen(canvas_pos);
10761void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10773void pupHandler_PasteWaypoint() {
10776 int pasteBuffer = kml.ParsePasteBuffer();
10777 RoutePoint *pasted = kml.GetParsedRoutePoint();
10778 if (!pasted)
return;
10780 double nearby_radius_meters =
10781 g_Platform->GetSelectRadiusPix() /
10782 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10784 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10785 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10787 int answer = wxID_NO;
10791 "There is an existing waypoint at the same location as the one you are "
10792 "pasting. Would you like to merge the pasted data with it?\n\n");
10793 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10794 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10795 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10798 if (answer == wxID_YES) {
10799 nearPoint->SetName(pasted->GetName());
10801 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10802 pRouteManagerDialog->UpdateWptListCtrl();
10805 if (answer == wxID_NO) {
10808 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10811 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10814 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10815 pRouteManagerDialog->UpdateWptListCtrl();
10820 gFrame->InvalidateAllGL();
10821 gFrame->RefreshAllCanvas(
false);
10824void pupHandler_PasteRoute() {
10827 int pasteBuffer = kml.ParsePasteBuffer();
10828 Route *pasted = kml.GetParsedRoute();
10829 if (!pasted)
return;
10831 double nearby_radius_meters =
10832 g_Platform->GetSelectRadiusPix() /
10833 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10839 bool mergepoints =
false;
10840 bool createNewRoute =
true;
10841 int existingWaypointCounter = 0;
10843 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10844 curPoint = pasted->GetPoint(i);
10845 nearPoint = pWayPointMan->GetNearbyWaypoint(
10846 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10848 mergepoints =
true;
10849 existingWaypointCounter++;
10857 int answer = wxID_NO;
10861 "There are existing waypoints at the same location as some of the ones "
10862 "you are pasting. Would you like to just merge the pasted data into "
10864 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10865 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10866 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10868 if (answer == wxID_CANCEL) {
10875 if (mergepoints && answer == wxID_YES &&
10876 existingWaypointCounter == pasted->GetnPoints()) {
10879 createNewRoute =
false;
10885 Route *newRoute = 0;
10888 if (createNewRoute) {
10889 newRoute =
new Route();
10893 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10894 curPoint = pasted->GetPoint(i);
10897 newPoint = pWayPointMan->GetNearbyWaypoint(
10898 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10899 newPoint->SetName(curPoint->GetName());
10902 if (createNewRoute) newRoute->AddPoint(newPoint);
10908 newPoint->SetIconName(
"circle");
10911 newPoint->SetShared(
false);
10913 newRoute->AddPoint(newPoint);
10914 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10917 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10920 if (i > 1 && createNewRoute)
10921 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10922 curPoint->m_lat, curPoint->m_lon,
10923 prevPoint, newPoint, newRoute);
10924 prevPoint = newPoint;
10927 if (createNewRoute) {
10930 NavObj_dB::GetInstance().InsertRoute(newRoute);
10936 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10937 pRouteManagerDialog->UpdateRouteListCtrl();
10938 pRouteManagerDialog->UpdateWptListCtrl();
10940 gFrame->InvalidateAllGL();
10941 gFrame->RefreshAllCanvas(
false);
10947void pupHandler_PasteTrack() {
10950 int pasteBuffer = kml.ParsePasteBuffer();
10951 Track *pasted = kml.GetParsedTrack();
10952 if (!pasted)
return;
10960 newTrack->SetName(pasted->GetName());
10962 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10963 curPoint = pasted->GetPoint(i);
10967 wxDateTime now = wxDateTime::Now();
10970 newTrack->AddPoint(newPoint);
10973 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10974 newPoint->m_lat, newPoint->m_lon,
10975 prevPoint, newPoint, newTrack);
10977 prevPoint = newPoint;
10982 NavObj_dB::GetInstance().InsertTrack(newTrack);
10984 gFrame->InvalidateAllGL();
10985 gFrame->RefreshAllCanvas(
false);
10988bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10991 v[
"CursorPosition_x"] = x;
10992 v[
"CursorPosition_y"] = y;
10995 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
10996 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
10997 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11002 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11004 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11007#define SELTYPE_UNKNOWN 0x0001
11008#define SELTYPE_ROUTEPOINT 0x0002
11009#define SELTYPE_ROUTESEGMENT 0x0004
11010#define SELTYPE_TIDEPOINT 0x0008
11011#define SELTYPE_CURRENTPOINT 0x0010
11012#define SELTYPE_ROUTECREATE 0x0020
11013#define SELTYPE_AISTARGET 0x0040
11014#define SELTYPE_MARKPOINT 0x0080
11015#define SELTYPE_TRACKSEGMENT 0x0100
11016#define SELTYPE_DRAGHANDLE 0x0200
11019 if (g_bhide_context_menus)
return true;
11021 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11022 m_pIDXCandidate, m_nmea_log);
11025 wxEVT_COMMAND_MENU_SELECTED,
11026 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11032 if (m_inLongPress) {
11033 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11034 m_inLongPress =
false;
11038 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11041 wxEVT_COMMAND_MENU_SELECTED,
11042 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11044 delete m_canvasMenu;
11045 m_canvasMenu = NULL;
11055void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11058 if (m_canvasMenu) {
11059 m_canvasMenu->PopupMenuHandler(event);
11064void ChartCanvas::StartRoute() {
11066 if (g_brouteCreating)
return;
11070 g_brouteCreating =
true;
11072 m_bDrawingRoute =
false;
11073 SetCursor(*pCursorPencil);
11075 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11077 HideGlobalToolbar();
11080 androidSetRouteAnnunciator(
true);
11084wxString ChartCanvas::FinishRoute() {
11086 m_prev_pMousePoint = NULL;
11087 m_bDrawingRoute =
false;
11089 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11092 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11094 androidSetRouteAnnunciator(
false);
11097 SetCursor(*pCursorArrow);
11099 if (m_pMouseRoute) {
11100 if (m_bAppendingRoute) {
11102 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11104 if (m_pMouseRoute->GetnPoints() > 1) {
11106 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11109 m_pMouseRoute = NULL;
11112 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11119 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11120 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11121 pRouteManagerDialog->UpdateRouteListCtrl();
11124 m_bAppendingRoute =
false;
11125 m_pMouseRoute = NULL;
11127 m_pSelectedRoute = NULL;
11129 undo->InvalidateUndo();
11130 gFrame->RefreshAllCanvas(
true);
11134 ShowGlobalToolbar();
11136 g_brouteCreating =
false;
11141void ChartCanvas::HideGlobalToolbar() {
11142 if (m_canvasIndex == 0) {
11143 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11147void ChartCanvas::ShowGlobalToolbar() {
11148 if (m_canvasIndex == 0) {
11149 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11153void ChartCanvas::ShowAISTargetList() {
11154 if (NULL == g_pAISTargetList) {
11158 g_pAISTargetList->UpdateAISTargetList();
11161void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11162 if (!m_bShowOutlines)
return;
11166 int nEntry =
ChartData->GetChartTableEntries();
11168 for (
int i = 0; i < nEntry; i++) {
11172 bool b_group_draw =
false;
11173 if (m_groupIndex > 0) {
11174 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11175 int index = pt->GetGroupArray()[ig];
11176 if (m_groupIndex == index) {
11177 b_group_draw =
true;
11182 b_group_draw =
true;
11184 if (b_group_draw) RenderChartOutline(dc, i, vp);
11190 if (VPoint.b_quilt) {
11191 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11192 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11196 }
else if (m_singleChart &&
11197 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11201 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11204 if (zoom_factor > 8.0) {
11205 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11208 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11212 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11216void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11218 if (g_bopengl && m_glcc) {
11220 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11225 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11226 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11229 float plylat, plylon;
11230 float plylat1, plylon1;
11232 int pixx, pixy, pixx1, pixy1;
11235 ChartData->GetDBBoundingBox(dbIndex, box);
11239 if (box.GetLonRange() == 360)
return;
11241 double lon_bias = 0;
11243 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11245 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11247 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11248 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11250 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11251 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11254 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11257 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11258 if (0 == nAuxPlyEntries)
11262 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11263 plylon += lon_bias;
11269 for (
int i = 0; i < nPly - 1; i++) {
11270 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11271 plylon1 += lon_bias;
11277 int pixxs1 = pixx1;
11278 int pixys1 = pixy1;
11280 bool b_skip =
false;
11284 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11285 pow((
double)(pixy1 - pixy), 2)) /
11291 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11296 if (fabs(dist - distgc) > 10000. * 1852.)
11302 ClipResult res = cohen_sutherland_line_clip_i(
11304 if (res != Invisible && !b_skip)
11305 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11313 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11314 plylon1 += lon_bias;
11320 ClipResult res = cohen_sutherland_line_clip_i(
11322 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11329 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11330 for (
int j = 0; j < nAuxPlyEntries; j++) {
11332 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11337 for (
int i = 0; i < nAuxPly - 1; i++) {
11338 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11344 int pixxs1 = pixx1;
11345 int pixys1 = pixy1;
11347 bool b_skip =
false;
11351 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11352 ((pixy1 - pixy) * (pixy1 - pixy))) /
11357 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11362 if (fabs(dist - distgc) > 10000. * 1852.)
11368 ClipResult res = cohen_sutherland_line_clip_i(
11370 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11378 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11383 ClipResult res = cohen_sutherland_line_clip_i(
11385 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11390static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11391 const wxString &second) {
11392 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11394 int pointsize = dFont->GetPointSize();
11398 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11399 false, dFont->GetFaceName());
11401 dc.SetFont(*psRLI_font);
11409 int hilite_offset = 3;
11412 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11413 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11415 dc.GetTextExtent(first, &w1, &h1);
11416 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11422 w = wxMax(w1, w2) + (h1 / 2);
11427 xp = ref_point.x - w;
11429 yp += hilite_offset;
11431 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11433 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11434 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11436 dc.DrawText(first, xp, yp);
11437 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11440void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11441 if (!g_bAllowShipToActive)
return;
11447 wxPoint2DDouble pa, pb;
11454 if (rt->
m_width != wxPENSTYLE_INVALID)
11456 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11457 g_shipToActiveStyle, 5)];
11458 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11460 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11463 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11466 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11469 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11470 (
int)pb.m_y, GetVP(),
true);
11474#ifdef USE_ANDROID_GLES2
11475 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11477 if (style != wxPENSTYLE_SOLID) {
11478 if (glChartCanvas::dash_map.find(style) !=
11479 glChartCanvas::dash_map.end()) {
11480 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11484 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11487 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11488 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11494void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11496 if (m_routeState >= 2) route = m_pMouseRoute;
11497 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11498 route = m_pMeasureRoute;
11500 if (!route)
return;
11508 int np = route->GetnPoints();
11510 if (g_btouch && (np > 1)) np--;
11512 render_lat = rp.m_lat;
11513 render_lon = rp.m_lon;
11516 double rhumbBearing, rhumbDist;
11518 &rhumbBearing, &rhumbDist);
11519 double brg = rhumbBearing;
11520 double dist = rhumbDist;
11524 double gcBearing, gcBearing2, gcDist;
11525 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11528 double gcDistm = gcDist / 1852.0;
11531 rhumbBearing = 90.;
11533 wxPoint destPoint, lastPoint;
11536 int milesDiff = rhumbDist - gcDistm;
11537 if (milesDiff > 1) {
11548 for (
int i = 1; i <= milesDiff; i++) {
11549 double p = (double)i * (1.0 / (
double)milesDiff);
11551 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11552 &pLon, &pLat, &gcBearing2);
11554 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11556 lastPoint = destPoint;
11559 if (r_rband.x && r_rband.y) {
11560 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11562 if (m_bMeasure_DistCircle) {
11563 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11564 powf((
float)(r_rband.y - lastPoint.y), 2));
11567 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11568 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11574 wxString routeInfo;
11577 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11583 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11585 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11586 (
int)varBrg, 0x00B0);
11593 routeInfo <<
"\nReverse: ";
11595 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11596 (
int)(brg + 180.) % 360, 0x00B0);
11598 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11599 (
int)(varBrg + 180.) % 360, 0x00B0);
11604 s0.Append(_(
"Route") +
": ");
11606 s0.Append(_(
"Layer Route: "));
11609 if (!g_btouch) disp_length += dist;
11612 RouteLegInfo(dc, r_rband, routeInfo, s0);
11614 m_brepaint_piano =
true;
11617void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11618 if (!m_bShowVisibleSectors)
return;
11620 if (g_bDeferredInitDone) {
11622 double rhumbBearing, rhumbDist;
11623 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11624 &rhumbBearing, &rhumbDist);
11626 if (rhumbDist > 0.05)
11628 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11629 m_sectorlegsVisible);
11630 m_sector_glat =
gLat;
11631 m_sector_glon =
gLon;
11633 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11637void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11645void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11646 if (!ps52plib)
return;
11648 if (VPoint.b_quilt) {
11649 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11651 if (m_pQuilt->IsQuiltVector()) {
11652 if (ps52plib->GetStateHash() != m_s52StateHash) {
11654 m_s52StateHash = ps52plib->GetStateHash();
11658 if (ps52plib->GetStateHash() != m_s52StateHash) {
11660 m_s52StateHash = ps52plib->GetStateHash();
11665 bool bSendPlibState =
true;
11666 if (VPoint.b_quilt) {
11667 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11670 if (bSendPlibState) {
11672 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11673 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11674 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11675 v[
"OpenCPN Version Date"] = VERSION_DATE;
11676 v[
"OpenCPN Version Full"] = VERSION_FULL;
11679 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11680 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11681 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11682 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11683 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11684 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11685 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11689 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11690 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11694 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11695 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11696 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11697 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11698 ps52plib->m_bShowS57ImportantTextOnly;
11699 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11700 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11701 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11702 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11703 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11706 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11707 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11708 v[
"OpenCPN Scale Factor Exp"] =
11709 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11716 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11717 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11718 g_lastS52PLIBPluginMessage = out;
11725 wxPaintDC dc(
this);
11735 if (!m_b_paint_enable) {
11743 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11745 if (m_glcc && g_bopengl) {
11746 if (!s_in_update) {
11756 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11758 wxRegion ru = GetUpdateRegion();
11760 int rx, ry, rwidth, rheight;
11761 ru.GetBox(rx, ry, rwidth, rheight);
11763#ifdef ocpnUSE_DIBSECTION
11766 wxMemoryDC temp_dc;
11774 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11775 height += m_Piano->GetHeight();
11777 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11781 int thumbx, thumby, thumbsx, thumbsy;
11782 pthumbwin->GetPosition(&thumbx, &thumby);
11783 pthumbwin->GetSize(&thumbsx, &thumbsy);
11784 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11787 rgn_chart.Subtract(rgn_thumbwin);
11788 ru.Subtract(rgn_thumbwin);
11794 wxRegion rgn_blit = ru;
11795 if (g_bShowChartBar) {
11796 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11797 GetClientSize().x, m_Piano->GetHeight());
11800 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11801 if (style->chartStatusWindowTransparent)
11802 m_brepaint_piano =
true;
11804 ru.Subtract(chart_bar_rect);
11808 if (m_Compass && m_Compass->IsShown()) {
11809 wxRect compassRect = m_Compass->
GetRect();
11810 if (ru.Contains(compassRect) != wxOutRegion) {
11811 ru.Subtract(compassRect);
11815 if (m_notification_button) {
11816 wxRect noteRect = m_notification_button->
GetRect();
11817 if (ru.Contains(noteRect) != wxOutRegion) {
11818 ru.Subtract(noteRect);
11823 bool b_newview =
true;
11828 m_cache_vp.IsValid()) {
11834 bool b_rcache_ok =
false;
11835 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11836 b_rcache_ok = !b_newview;
11839 if (VPoint.b_MercatorProjectionOverride)
11840 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11854 if (b_rcache_ok) chart_get_region.Clear();
11857 if (VPoint.b_quilt)
11859 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11861 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11866 AbstractPlatform::ShowBusySpinner();
11870 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11871 (m_working_bm.GetHeight() != svp.
pix_height))
11875 if (fabs(VPoint.
rotation) < 0.01) {
11876 bool b_save =
true;
11881 m_cache_vp.Invalidate();
11895 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11900 int dy = c_new.y - c_old.y;
11901 int dx = c_new.x - c_old.x;
11906 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11910 temp_dc.SelectObject(m_working_bm);
11912 wxMemoryDC cache_dc;
11913 cache_dc.SelectObject(m_cached_chart_bm);
11917 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11920 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11926 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11929 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11937 update_region.Union(
11940 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11945 update_region.Union(
11948 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11952 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11954 cache_dc.SelectObject(wxNullBitmap);
11958 temp_dc.SelectObject(m_cached_chart_bm);
11961 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11965 temp_dc.SelectObject(m_working_bm);
11966 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11971 temp_dc.SelectObject(m_cached_chart_bm);
11976 temp_dc.SelectObject(m_working_bm);
11977 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11990 wxMemoryDC scratch_dc_0;
11991 scratch_dc_0.SelectObject(m_cached_chart_bm);
11994 scratch_dc_0.SelectObject(wxNullBitmap);
12003 temp_dc.SelectObject(m_working_bm);
12006 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12007 chart_get_all_region);
12010 AbstractPlatform::HideBusySpinner();
12016 if (!m_singleChart) {
12017 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12022 if (!chart_get_region.IsEmpty()) {
12023 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12027 if (temp_dc.IsOk()) {
12032 if (!VPoint.b_quilt) {
12035 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12036 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12043 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12044 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12047 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12049 temp_dc.DestroyClippingRegion();
12054 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12056 if (!backgroundRegion.IsEmpty()) {
12062 wxColour water = pWorldBackgroundChart->water;
12063 if (water.IsOk()) {
12064 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12065 temp_dc.SetBrush(wxBrush(water));
12067 while (upd.HaveRects()) {
12068 wxRect rect = upd.GetRect();
12069 temp_dc.DrawRectangle(rect);
12074 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12075 temp_dc.SetDeviceClippingRegion(*clip_region);
12076 delete clip_region;
12080 SetVPRotation(VPoint.
skew);
12089 wxMemoryDC *pChartDC = &temp_dc;
12090 wxMemoryDC rotd_dc;
12092 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12094 if (!b_rcache_ok) {
12096 wxMemoryDC tbase_dc;
12098 tbase_dc.SelectObject(bm_base);
12100 tbase_dc.SelectObject(wxNullBitmap);
12102 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12105 wxImage base_image;
12106 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12114 bool b_rot_ok =
false;
12115 if (base_image.IsOk()) {
12118 m_b_rot_hidef =
false;
12122 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12123 m_b_rot_hidef, &m_roffset);
12128 rot_vp.IsValid() && (ri.IsOk())) {
12135 m_prot_bm =
new wxBitmap(ri);
12138 m_roffset.x += VPoint.rv_rect.x;
12139 m_roffset.y += VPoint.rv_rect.y;
12142 if (m_prot_bm && m_prot_bm->IsOk()) {
12143 rotd_dc.SelectObject(*m_prot_bm);
12144 pChartDC = &rotd_dc;
12146 pChartDC = &temp_dc;
12147 m_roffset = wxPoint(0, 0);
12150 pChartDC = &temp_dc;
12151 m_roffset = wxPoint(0, 0);
12154 wxPoint offset = m_roffset;
12157 m_cache_vp = VPoint;
12160 wxMemoryDC mscratch_dc;
12161 mscratch_dc.SelectObject(*pscratch_bm);
12163 mscratch_dc.ResetBoundingBox();
12164 mscratch_dc.DestroyClippingRegion();
12165 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12168 wxRegionIterator upd(rgn_blit);
12170 wxRect rect = upd.GetRect();
12172 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12173 rect.x - offset.x, rect.y - offset.y);
12179 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12180 if (
this == wxWindow::FindFocus()) {
12183 wxColour colour = GetGlobalColor(
"BLUE4");
12184 mscratch_dc.SetPen(wxPen(colour));
12185 mscratch_dc.SetBrush(wxBrush(colour));
12187 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12188 mscratch_dc.DrawRectangle(activeRect);
12193 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12194 unsigned int im = stackIndexArray.size();
12195 if (VPoint.b_quilt && im > 0) {
12196 std::vector<int> tiles_to_show;
12197 for (
unsigned int is = 0; is < im; is++) {
12199 ChartData->GetChartTableEntry(stackIndexArray[is]);
12200 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12203 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12204 tiles_to_show.push_back(stackIndexArray[is]);
12208 if (tiles_to_show.size())
12209 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12215 ocpnDC scratch_dc(mscratch_dc);
12216 RenderAlertMessage(mscratch_dc, GetVP());
12222#ifdef ocpnUSE_DIBSECTION
12227 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12228 q_dc.SelectObject(qbm);
12231 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12234 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12235 q_dc.SetBrush(qbr);
12236 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12239 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12242 q_dc.SelectObject(wxNullBitmap);
12251 if( VPoint.b_quilt ) {
12252 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12253 ChartBase *chart = m_pQuilt->GetRefChart();
12254 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12259 ChPI->ClearPLIBTextList();
12262 ps52plib->ClearTextList();
12266 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12268 wxColor maskBackground = wxColour(1,0,0);
12269 t_dc.SelectObject( qbm );
12270 t_dc.SetBackground(wxBrush(maskBackground));
12274 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12277 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12278 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12281 wxRegionIterator upd_final( ru );
12282 while( upd_final ) {
12283 wxRect rect = upd_final.GetRect();
12284 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12288 t_dc.SelectObject( wxNullBitmap );
12294 if (VPoint.b_quilt) {
12295 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12296 ChartBase *chart = m_pQuilt->GetRefChart();
12297 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12301 ChPI->ClearPLIBTextList();
12303 if (ps52plib) ps52plib->ClearTextList();
12308 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12310 if (g_bShowChartBar && m_Piano) {
12311 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12312 GetVP().pix_width, m_Piano->GetHeight());
12315 if (!style->chartStatusWindowTransparent)
12316 chart_all_text_region.Subtract(chart_bar_rect);
12319 if (m_Compass && m_Compass->IsShown()) {
12320 wxRect compassRect = m_Compass->
GetRect();
12321 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12322 chart_all_text_region.Subtract(compassRect);
12326 mscratch_dc.DestroyClippingRegion();
12328 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12329 chart_all_text_region);
12335 ocpnDC scratch_dc(mscratch_dc);
12336 DrawOverlayObjects(scratch_dc, ru);
12339 wxRegionIterator upd_final(rgn_blit);
12340 while (upd_final) {
12341 wxRect rect = upd_final.GetRect();
12342 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12349 temp_dc.SelectObject(wxNullBitmap);
12351 mscratch_dc.SelectObject(wxNullBitmap);
12353 dc.DestroyClippingRegion();
12358void ChartCanvas::PaintCleanup() {
12360 if (m_inPinch)
return;
12371 m_bTCupdate =
false;
12375 WarpPointer(warp_x, warp_y);
12382 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12383 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12387wxColour GetErrorGraphicColor(
double val)
12406 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12407 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12408 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12409 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12410 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12411 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12412 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12413 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12414 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12415 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12416 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12417 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12418 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12419 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12420 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12421 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12422 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12423 else if( val >= 48) c.Set(
"#410000");
12428void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12431 gr_image.InitAlpha();
12433 double maxval = -10000;
12434 double minval = 10000;
12451 maxval = wxMax(maxval, (glat - rlat));
12452 minval = wxMin(minval, (glat - rlat));
12469 double f = ((glat - rlat)-minval)/(maxval - minval);
12471 double dy = (f * 40);
12473 wxColour c = GetErrorGraphicColor(dy);
12474 unsigned char r = c.Red();
12475 unsigned char g = c.Green();
12476 unsigned char b = c.Blue();
12478 gr_image.SetRGB(j, i, r,g,b);
12479 if((glat - rlat )!= 0)
12480 gr_image.SetAlpha(j, i, 128);
12482 gr_image.SetAlpha(j, i, 255);
12489 wxBitmap *pbm =
new wxBitmap(gr_image);
12490 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12491 pbm->SetMask(gr_mask);
12493 pmdc->DrawBitmap(*pbm, 0,0);
12501void ChartCanvas::CancelMouseRoute() {
12503 m_pMouseRoute = NULL;
12504 m_bDrawingRoute =
false;
12507int ChartCanvas::GetNextContextMenuId() {
12508 return CanvasMenuHandler::GetNextContextMenuId();
12511bool ChartCanvas::SetCursor(
const wxCursor &c) {
12513 if (g_bopengl && m_glcc)
12514 return m_glcc->SetCursor(c);
12517 return wxWindow::SetCursor(c);
12520void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12521 if (g_bquiting)
return;
12531 if (!m_RolloverPopupTimer.IsRunning() &&
12532 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12533 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12534 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12535 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12538 if (m_glcc && g_bopengl) {
12541 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12543 m_glcc->Refresh(eraseBackground,
12560 if (m_pCIWin && m_pCIWin->IsShown()) {
12562 m_pCIWin->Refresh(
false);
12570 wxWindow::Refresh(eraseBackground, rect);
12573void ChartCanvas::Update() {
12574 if (m_glcc && g_bopengl) {
12579 wxWindow::Update();
12583 if (!pemboss)
return;
12584 int x = pemboss->x, y = pemboss->y;
12585 const double factor = 200;
12587 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12588 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12589 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12592 wxMemoryDC snip_dc;
12593 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12594 snip_dc.SelectObject(snip_bmp);
12596 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12597 snip_dc.SelectObject(wxNullBitmap);
12599 wxImage snip_img = snip_bmp.ConvertToImage();
12602 unsigned char *pdata = snip_img.GetData();
12604 for (
int y = 0; y < pemboss->height; y++) {
12605 int map_index = (y * pemboss->width);
12606 for (
int x = 0; x < pemboss->width; x++) {
12607 double val = (pemboss->pmap[map_index] * factor) / 256.;
12609 int nred = (int)((*pdata) + val);
12610 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12611 *pdata++ = (
unsigned char)nred;
12613 int ngreen = (int)((*pdata) + val);
12614 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12615 *pdata++ = (
unsigned char)ngreen;
12617 int nblue = (int)((*pdata) + val);
12618 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12619 *pdata++ = (
unsigned char)nblue;
12627 wxBitmap emb_bmp(snip_img);
12630 wxMemoryDC result_dc;
12631 result_dc.SelectObject(emb_bmp);
12634 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12636 result_dc.SelectObject(wxNullBitmap);
12642 if (GetQuiltMode()) {
12644 int refIndex = GetQuiltRefChartdbIndex();
12645 if (refIndex >= 0) {
12647 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12648 if (current_type == CHART_TYPE_MBTILES) {
12649 ChartBase *pChart = m_pQuilt->GetRefChart();
12652 zoom_factor = ptc->GetZoomFactor();
12657 if (zoom_factor <= 3.9)
return NULL;
12659 if (m_singleChart) {
12660 if (zoom_factor <= 3.9)
return NULL;
12665 if (m_pEM_OverZoom) {
12666 m_pEM_OverZoom->x = 4;
12667 m_pEM_OverZoom->y = 0;
12669 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12670 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12673 return m_pEM_OverZoom;
12676void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12689 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12690 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12694 AISDrawAreaNotices(dc, GetVP(),
this);
12696 wxDC *pdc = dc.GetDC();
12698 pdc->DestroyClippingRegion();
12699 wxDCClipper(*pdc, ru);
12702 if (m_bShowNavobjects) {
12703 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12704 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12705 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12706 DrawAnchorWatchPoints(dc);
12708 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12709 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12712 AISDraw(dc, GetVP(),
this);
12716 RenderVisibleSectorLights(dc);
12718 RenderAllChartOutlines(dc, GetVP());
12719 RenderRouteLegs(dc);
12720 RenderShipToActive(dc,
false);
12722 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12724 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12728 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12729 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12732 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12737 RebuildTideSelectList(GetVP().GetBBox());
12738 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12741 if (m_bShowCurrent) {
12742 RebuildCurrentSelectList(GetVP().GetBBox());
12743 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12746 if (!g_PrintingInProgress) {
12747 if (IsPrimaryCanvas()) {
12751 if (IsPrimaryCanvas()) {
12755 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12757 if (m_pTrackRolloverWin) {
12758 m_pTrackRolloverWin->Draw(dc);
12759 m_brepaint_piano =
true;
12762 if (m_pRouteRolloverWin) {
12763 m_pRouteRolloverWin->Draw(dc);
12764 m_brepaint_piano =
true;
12767 if (m_pAISRolloverWin) {
12768 m_pAISRolloverWin->Draw(dc);
12769 m_brepaint_piano =
true;
12771 if (m_brepaint_piano && g_bShowChartBar) {
12772 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12775 if (m_Compass) m_Compass->Paint(dc);
12777 if (!g_CanvasHideNotificationIcon) {
12778 if (IsPrimaryCanvas()) {
12779 auto ¬eman = NotificationManager::GetInstance();
12780 if (noteman.GetNotificationCount()) {
12781 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12782 if (m_notification_button->UpdateStatus()) Refresh();
12783 m_notification_button->Show(
true);
12784 m_notification_button->Paint(dc);
12786 m_notification_button->Show(
false);
12792 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12798 if (!m_bShowDepthUnits)
return NULL;
12800 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12802 if (GetQuiltMode()) {
12803 wxString s = m_pQuilt->GetQuiltDepthUnit();
12806 depth_unit_type = DEPTH_UNIT_FEET;
12807 else if (s.StartsWith(
"FATHOMS"))
12808 depth_unit_type = DEPTH_UNIT_FATHOMS;
12809 else if (s.StartsWith(
"METERS"))
12810 depth_unit_type = DEPTH_UNIT_METERS;
12811 else if (s.StartsWith(
"METRES"))
12812 depth_unit_type = DEPTH_UNIT_METERS;
12813 else if (s.StartsWith(
"METRIC"))
12814 depth_unit_type = DEPTH_UNIT_METERS;
12815 else if (s.StartsWith(
"METER"))
12816 depth_unit_type = DEPTH_UNIT_METERS;
12819 if (m_singleChart) {
12820 depth_unit_type = m_singleChart->GetDepthUnitType();
12821 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12822 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12827 switch (depth_unit_type) {
12828 case DEPTH_UNIT_FEET:
12831 case DEPTH_UNIT_METERS:
12832 ped = m_pEM_Meters;
12834 case DEPTH_UNIT_FATHOMS:
12835 ped = m_pEM_Fathoms;
12841 ped->x = (GetVP().
pix_width - ped->width);
12843 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12844 wxRect r = m_Compass->
GetRect();
12845 ped->y = r.y + r.height;
12852void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12855 if (style->embossFont == wxEmptyString) {
12856 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12858 font.SetPointSize(60);
12859 font.SetWeight(wxFONTWEIGHT_BOLD);
12861 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12862 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12864 int emboss_width = 500;
12865 int emboss_height = 200;
12869 delete m_pEM_Meters;
12870 delete m_pEM_Fathoms;
12874 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12876 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12878 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12881#define OVERZOOM_TEXT _("OverZoom")
12883void ChartCanvas::SetOverzoomFont() {
12888 if (style->embossFont == wxEmptyString) {
12889 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12891 font.SetPointSize(40);
12892 font.SetWeight(wxFONTWEIGHT_BOLD);
12894 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12895 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12897 wxClientDC dc(
this);
12899 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12901 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12902 font.SetPointSize(font.GetPointSize() - 1);
12904 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12906 m_overzoomFont = font;
12907 m_overzoomTextWidth = w;
12908 m_overzoomTextHeight = h;
12911void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12912 delete m_pEM_OverZoom;
12914 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12916 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12917 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12920emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12921 int height,
const wxString &str,
12926 wxBitmap bmp(width, height, -1);
12929 wxMemoryDC temp_dc;
12930 temp_dc.SelectObject(bmp);
12933 temp_dc.SetBackground(*wxWHITE_BRUSH);
12934 temp_dc.SetTextBackground(*wxWHITE);
12935 temp_dc.SetTextForeground(*wxBLACK);
12939 temp_dc.SetFont(font);
12942 temp_dc.GetTextExtent(str, &str_w, &str_h);
12944 temp_dc.DrawText(str, 1, 1);
12947 temp_dc.SelectObject(wxNullBitmap);
12950 wxImage img = bmp.ConvertToImage();
12952 int image_width = str_w * 105 / 100;
12953 int image_height = str_h * 105 / 100;
12954 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12955 wxMin(image_height, img.GetHeight()));
12956 wxImage imgs = img.GetSubImage(r);
12960 case GLOBAL_COLOR_SCHEME_DAY:
12964 case GLOBAL_COLOR_SCHEME_DUSK:
12967 case GLOBAL_COLOR_SCHEME_NIGHT:
12974 const int w = imgs.GetWidth();
12975 const int h = imgs.GetHeight();
12976 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12981 for (
int y = 1; y < h - 1; y++) {
12982 for (
int x = 1; x < w - 1; x++) {
12984 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12985 val = (int)(val * val_factor);
12986 index = (y * w) + x;
12999void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13000 Track *active_track = NULL;
13003 active_track = pTrackDraw;
13007 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13010 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13013void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13014 Track *active_track = NULL;
13017 active_track = pTrackDraw;
13021 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13024void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13025 Route *active_route = NULL;
13027 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13028 active_route = pRouteDraw;
13033 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13038 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13041void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13042 Route *active_route = NULL;
13045 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13046 active_route = pRouteDraw;
13050 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13053void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13054 if (!pWayPointMan)
return;
13056 auto node = pWayPointMan->GetWaypointList()->begin();
13058 while (node != pWayPointMan->GetWaypointList()->end()) {
13067 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13071 if (pWP->GetShowWaypointRangeRings() &&
13072 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13073 double factor = 1.00;
13074 if (pWP->GetWaypointRangeRingsStepUnits() ==
13076 factor = 1 / 1.852;
13078 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13079 pWP->GetWaypointRangeRingsStep() / 60.;
13083 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13084 pWP->m_lat + radius, pWP->m_lon + radius);
13085 if (!BltBBox.IntersectOut(radar_box)) {
13096void ChartCanvas::DrawBlinkObjects() {
13098 wxRect update_rect;
13100 if (!pWayPointMan)
return;
13102 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13109 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13112void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13117 wxPoint lAnchorPoint1, lAnchorPoint2;
13131 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13132 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13134 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13135 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13136 dc.SetBrush(*ppBrush);
13140 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13145 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13150 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13155 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13160double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13163 wxPoint lAnchorPoint;
13166 double tlat1, tlon1;
13168 if (pAnchorWatchPoint) {
13169 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13170 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13171 dabs = fabs(d1 / 1852.);
13172 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13177 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13178 pow((
double)(lAnchorPoint.y - r1.y), 2));
13181 if (d1 < 0) lpp = -lpp;
13189void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13192 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13194 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13200 if ((type ==
't') || (type ==
'T')) {
13201 if (BBox.Contains(lat, lon)) {
13203 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13209void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13212 wxDateTime this_now = gTimeSource;
13213 bool cur_time = !gTimeSource.IsValid();
13214 if (cur_time) this_now = wxDateTime::Now();
13215 time_t t_this_now = this_now.GetTicks();
13217 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13219 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13220 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13221 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13222 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13224 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13225 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13226 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13227 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13228 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13229 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13231 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13232 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13233 int font_size = wxMax(10, dFont->GetPointSize());
13236 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13237 false, dFont->GetFaceName());
13239 dc.SetPen(*pblack_pen);
13240 dc.SetBrush(*pgreen_brush);
13244 case GLOBAL_COLOR_SCHEME_DAY:
13247 case GLOBAL_COLOR_SCHEME_DUSK:
13250 case GLOBAL_COLOR_SCHEME_NIGHT:
13251 bm = m_bmTideNight;
13258 int bmw = bm.GetWidth();
13259 int bmh = bm.GetHeight();
13261 float scale_factor = 1.0;
13265 float icon_pixelRefDim = 45;
13270 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13272 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13274 scale_factor *= pix_factor;
13281 scale_factor *= user_scale_factor;
13282 scale_factor *= GetContentScaleFactor();
13285 double marge = 0.05;
13286 std::vector<LLBBox> drawn_boxes;
13287 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13291 if ((type ==
't') || (type ==
'T'))
13296 if (BBox.ContainsMarge(lat, lon, marge)) {
13298 if (GetVP().chart_scale < 500000) {
13299 bool bdrawn =
false;
13300 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13301 if (drawn_boxes[i].Contains(lat, lon)) {
13306 if (bdrawn)
continue;
13309 this_box.Set(lat, lon, lat, lon);
13310 this_box.EnLarge(.005);
13311 drawn_boxes.push_back(this_box);
13317 if (GetVP().chart_scale > 500000) {
13318 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13322 dc.SetFont(*plabelFont);
13334 if (
ptcmgr->GetTideFlowSens(
13335 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13339 ptcmgr->GetHightOrLowTide(
13340 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13341 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13353 if (tctime > t_this_now)
13354 ptcmgr->GetHightOrLowTide(
13355 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13356 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13360 ptcmgr->GetHightOrLowTide(
13361 t_this_now, FORWARD_TEN_MINUTES_STEP,
13362 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13376 int width = (int)(12 * scale_factor + 0.5);
13377 int height = (int)(45 * scale_factor + 0.5);
13378 int linew = wxMax(1, (
int)(scale_factor));
13379 int xDraw = r.x - (width / 2);
13380 int yDraw = r.y - (height / 2);
13383 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13384 int hs = (httime > lttime) ? -4 : 4;
13385 hs *= (int)(scale_factor + 0.5);
13386 if (ts > 0.995 || ts < 0.005) hs = 0;
13387 int ht_y = (int)(height * ts);
13390 pblack_pen->SetWidth(linew);
13391 dc.SetPen(*pblack_pen);
13392 dc.SetBrush(*pyelo_brush);
13393 dc.DrawRectangle(xDraw, yDraw, width, height);
13397 dc.SetPen(*pblue_pen);
13398 dc.SetBrush(*pblue_brush);
13399 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13400 (width - (4 * linew)), height - ht_y);
13406 arrow[0].x = xDraw + 2 * linew;
13407 arrow[1].x = xDraw + width / 2;
13408 arrow[2].x = xDraw + width - 2 * linew;
13409 pyelo_pen->SetWidth(linew);
13410 pblue_pen->SetWidth(linew);
13411 if (ts > 0.35 || ts < 0.15)
13413 hl = (int)(height * 0.25) + yDraw;
13415 arrow[1].y = hl + hs;
13418 dc.SetPen(*pyelo_pen);
13420 dc.SetPen(*pblue_pen);
13421 dc.DrawLines(3, arrow);
13423 if (ts > 0.60 || ts < 0.40)
13425 hl = (int)(height * 0.5) + yDraw;
13427 arrow[1].y = hl + hs;
13430 dc.SetPen(*pyelo_pen);
13432 dc.SetPen(*pblue_pen);
13433 dc.DrawLines(3, arrow);
13435 if (ts < 0.65 || ts > 0.85)
13437 hl = (int)(height * 0.75) + yDraw;
13439 arrow[1].y = hl + hs;
13442 dc.SetPen(*pyelo_pen);
13444 dc.SetPen(*pblue_pen);
13445 dc.DrawLines(3, arrow);
13449 s.Printf(
"%3.1f", nowlev);
13451 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13453 dc.GetTextExtent(s, &wx1, NULL);
13455 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13470void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13473 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13475 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13481 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13482 if ((BBox.Contains(lat, lon))) {
13484 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13490void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13493 float tcvalue, dir;
13497 double lon_last = 0.;
13498 double lat_last = 0.;
13500 double marge = 0.2;
13501 bool cur_time = !gTimeSource.IsValid();
13503 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13504 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13506 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13508 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13509 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13510 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13511 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13512 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13513 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13514 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13515 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13517 double skew_angle = GetVPRotation();
13519 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13520 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13521 int font_size = wxMax(10, dFont->GetPointSize());
13524 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13525 false, dFont->GetFaceName());
13527 float scale_factor = 1.0;
13533 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13535 float nominal_icon_size_pixels = 15;
13536 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13538 scale_factor *= pix_factor;
13545 scale_factor *= user_scale_factor;
13547 scale_factor *= GetContentScaleFactor();
13550 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13556 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13557 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13562 int dd = (int)(5.0 * scale_factor + 0.5);
13573 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13574 dc.SetPen(*pblack_pen);
13575 dc.SetBrush(*porange_brush);
13576 dc.DrawPolygon(4, d);
13579 dc.SetBrush(*pblack_brush);
13580 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13584 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13598 double a1 = fabs(tcvalue) * 10.;
13600 a1 = wxMax(1.0, a1);
13601 double a2 = log10(a1);
13603 float cscale = scale_factor * a2 * 0.3;
13605 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13606 dc.SetPen(*porange_pen);
13607 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13611 if (bDrawCurrentValues) {
13612 dc.SetFont(*pTCFont);
13613 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13614 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13640 if (!pvIDX)
return;
13645 if (pCwin && pCwin->IsShown()) {
13653 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13668 pCwin =
new TCWin(
this, x, y, pvIDX);
13686#define NUM_CURRENT_ARROW_POINTS 9
13687static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13688 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13689 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13690 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13692void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13694 if (
scale > 1e-2) {
13695 float sin_rot = sin(rot_angle * PI / 180.);
13696 float cos_rot = cos(rot_angle * PI / 180.);
13700 float xt = CurrentArrowArray[0].x;
13701 float yt = CurrentArrowArray[0].y;
13703 float xp = (xt * cos_rot) - (yt * sin_rot);
13704 float yp = (xt * sin_rot) + (yt * cos_rot);
13705 int x1 = (int)(xp *
scale);
13706 int y1 = (int)(yp *
scale);
13709 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13710 xt = CurrentArrowArray[ip].x;
13711 yt = CurrentArrowArray[ip].y;
13713 float xp = (xt * cos_rot) - (yt * sin_rot);
13714 float yp = (xt * sin_rot) + (yt * cos_rot);
13715 int x2 = (int)(xp *
scale);
13716 int y2 = (int)(yp *
scale);
13718 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13726wxString ChartCanvas::FindValidUploadPort() {
13729 if (!g_uploadConnection.IsEmpty() &&
13730 g_uploadConnection.StartsWith(
"Serial")) {
13731 port = g_uploadConnection;
13737 for (
auto *cp : TheConnectionParams()) {
13738 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13739 port <<
"Serial:" << cp->Port;
13745void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13748 if (NULL == g_pais_query_dialog_active) {
13749 int pos_x = g_ais_query_dialog_x;
13750 int pos_y = g_ais_query_dialog_y;
13752 if (g_pais_query_dialog_active) {
13753 g_pais_query_dialog_active->Destroy();
13759 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13760 wxPoint(pos_x, pos_y));
13762 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13763 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13764 g_pais_query_dialog_active->SetMMSI(mmsi);
13765 g_pais_query_dialog_active->UpdateText();
13766 wxSize sz = g_pais_query_dialog_active->GetSize();
13768 bool b_reset_pos =
false;
13773 RECT frame_title_rect;
13774 frame_title_rect.left = pos_x;
13775 frame_title_rect.top = pos_y;
13776 frame_title_rect.right = pos_x + sz.x;
13777 frame_title_rect.bottom = pos_y + 30;
13779 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13780 b_reset_pos =
true;
13785 wxRect window_title_rect;
13786 window_title_rect.x = pos_x;
13787 window_title_rect.y = pos_y;
13788 window_title_rect.width = sz.x;
13789 window_title_rect.height = 30;
13791 wxRect ClientRect = wxGetClientDisplayRect();
13792 ClientRect.Deflate(
13794 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13798 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13801 g_pais_query_dialog_active->SetMMSI(mmsi);
13802 g_pais_query_dialog_active->UpdateText();
13805 g_pais_query_dialog_active->Show();
13808void ChartCanvas::ToggleCanvasQuiltMode() {
13809 bool cur_mode = GetQuiltMode();
13811 if (!GetQuiltMode())
13812 SetQuiltMode(
true);
13813 else if (GetQuiltMode()) {
13814 SetQuiltMode(
false);
13815 g_sticky_chart = GetQuiltReferenceChartIndex();
13818 if (cur_mode != GetQuiltMode()) {
13819 SetupCanvasQuiltMode();
13828 if (ps52plib) ps52plib->GenerateStateHash();
13830 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13831 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13834void ChartCanvas::DoCanvasStackDelta(
int direction) {
13835 if (!GetQuiltMode()) {
13836 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13837 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13838 if ((current_stack_index + direction) < 0)
return;
13840 if (m_bpersistent_quilt ) {
13842 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13844 if (IsChartQuiltableRef(new_dbIndex)) {
13845 ToggleCanvasQuiltMode();
13846 SelectQuiltRefdbChart(new_dbIndex);
13847 m_bpersistent_quilt =
false;
13850 SelectChartFromStack(current_stack_index + direction);
13853 std::vector<int> piano_chart_index_array =
13854 GetQuiltExtendedStackdbIndexArray();
13855 int refdb = GetQuiltRefChartdbIndex();
13858 int current_index = -1;
13859 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13860 if (refdb == piano_chart_index_array[i]) {
13865 if (current_index == -1)
return;
13868 int target_family = ctet.GetChartFamily();
13870 int new_index = -1;
13871 int check_index = current_index + direction;
13872 bool found =
false;
13873 int check_dbIndex = -1;
13874 int new_dbIndex = -1;
13878 (
unsigned int)check_index < piano_chart_index_array.size() &&
13879 (check_index >= 0)) {
13880 check_dbIndex = piano_chart_index_array[check_index];
13882 if (target_family == cte.GetChartFamily()) {
13884 new_index = check_index;
13885 new_dbIndex = check_dbIndex;
13889 check_index += direction;
13892 if (!found)
return;
13894 if (!IsChartQuiltableRef(new_dbIndex)) {
13895 ToggleCanvasQuiltMode();
13896 SelectdbChart(new_dbIndex);
13897 m_bpersistent_quilt =
true;
13899 SelectQuiltRefChart(new_index);
13903 gFrame->UpdateGlobalMenuItems();
13905 SetQuiltChartHiLiteIndex(-1);
13916void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13919 switch (event.GetId()) {
13931 DoCanvasStackDelta(1);
13936 DoCanvasStackDelta(-1);
13946 ShowCurrents(!GetbShowCurrent());
13953 ShowTides(!GetbShowTide());
13960 if (0 == m_routeState) {
13967 androidSetRouteAnnunciator(m_routeState == 1);
13973 SetAISCanvasDisplayStyle(-1);
13985void ChartCanvas::SetShowAIS(
bool show) {
13987 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13988 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13991void ChartCanvas::SetAttenAIS(
bool show) {
13992 m_bShowAISScaled = show;
13993 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13994 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13997void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14000 bool bShowAIS_Array[3] = {
true,
true,
false};
14001 bool bShowScaled_Array[3] = {
false,
true,
true};
14002 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14003 _(
"Attenuate less critical AIS targets"),
14004 _(
"Hide AIS Targets")};
14005 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14007 int AIS_Toolbar_Switch = 0;
14008 if (StyleIndx == -1) {
14010 for (
int i = 1; i < ArraySize; i++) {
14011 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14012 (bShowScaled_Array[i] == m_bShowAISScaled))
14013 AIS_Toolbar_Switch = i;
14015 AIS_Toolbar_Switch++;
14016 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14017 AIS_Toolbar_Switch++;
14020 AIS_Toolbar_Switch = StyleIndx;
14023 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14025 int AIS_Toolbar_Switch_Next =
14026 AIS_Toolbar_Switch + 1;
14027 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14028 AIS_Toolbar_Switch_Next++;
14029 if (AIS_Toolbar_Switch_Next >= ArraySize)
14030 AIS_Toolbar_Switch_Next = 0;
14033 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14034 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14037void ChartCanvas::TouchAISToolActive() {}
14039void ChartCanvas::UpdateAISTBTool() {}
14047void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14049 bool b_update =
false;
14050 int cc1_edge_comp = 2;
14051 wxRect rect = m_Compass->
GetRect();
14052 wxSize parent_size = GetSize();
14054 parent_size *= m_displayScale;
14058 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14059 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14060 wxRect compass_rect(compass_pt, rect.GetSize());
14062 m_Compass->Move(compass_pt);
14064 if (m_Compass && m_Compass->IsShown())
14065 m_Compass->UpdateStatus(b_force_new | b_update);
14067 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14068 scaler = wxMax(scaler, 1.0);
14069 wxPoint note_point = wxPoint(
14070 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14071 if (m_notification_button) {
14072 m_notification_button->Move(note_point);
14073 m_notification_button->UpdateStatus();
14076 if (b_force_new | b_update) Refresh();
14079void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14080 ChartTypeEnum New_Type,
14081 ChartFamilyEnum New_Family) {
14082 if (!GetpCurrentStack())
return;
14085 if (index < GetpCurrentStack()->nEntry) {
14088 pTentative_Chart =
ChartData->OpenStackChartConditional(
14089 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14091 if (pTentative_Chart) {
14092 if (m_singleChart) m_singleChart->Deactivate();
14094 m_singleChart = pTentative_Chart;
14095 m_singleChart->Activate();
14097 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14098 GetpCurrentStack(), m_singleChart->GetFullPath());
14111 double best_scale_ppm = GetBestVPScale(m_singleChart);
14112 double rotation = GetVPRotation();
14113 double oldskew = GetVPSkew();
14114 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14116 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14117 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14118 if (fabs(newskew) > 0.0001) rotation = newskew;
14121 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14123 UpdateGPSCompassStatusBox(
true);
14127 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14128 if (idx < 0)
return;
14130 std::vector<int> piano_active_chart_index_array;
14131 piano_active_chart_index_array.push_back(
14132 GetpCurrentStack()->GetCurrentEntrydbIndex());
14133 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14136void ChartCanvas::SelectdbChart(
int dbindex) {
14137 if (!GetpCurrentStack())
return;
14140 if (dbindex >= 0) {
14143 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14145 if (pTentative_Chart) {
14146 if (m_singleChart) m_singleChart->Deactivate();
14148 m_singleChart = pTentative_Chart;
14149 m_singleChart->Activate();
14151 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14152 GetpCurrentStack(), m_singleChart->GetFullPath());
14165 double best_scale_ppm = GetBestVPScale(m_singleChart);
14169 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14179void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14182 if (!GetQuiltMode()) {
14183 if (GetpCurrentStack()) {
14184 int stack_index = -1;
14185 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14186 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14187 if (check_dbIndex < 0)
continue;
14189 ChartData->GetChartTableEntry(check_dbIndex);
14190 if (type == cte.GetChartType()) {
14193 }
else if (family == cte.GetChartFamily()) {
14199 if (stack_index >= 0) {
14200 SelectChartFromStack(stack_index);
14204 int sel_dbIndex = -1;
14205 std::vector<int> piano_chart_index_array =
14206 GetQuiltExtendedStackdbIndexArray();
14207 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14208 int check_dbIndex = piano_chart_index_array[i];
14210 if (type == cte.GetChartType()) {
14211 if (IsChartQuiltableRef(check_dbIndex)) {
14212 sel_dbIndex = check_dbIndex;
14215 }
else if (family == cte.GetChartFamily()) {
14216 if (IsChartQuiltableRef(check_dbIndex)) {
14217 sel_dbIndex = check_dbIndex;
14223 if (sel_dbIndex >= 0) {
14224 SelectQuiltRefdbChart(sel_dbIndex,
false);
14226 AdjustQuiltRefChart();
14233 SetQuiltChartHiLiteIndex(-1);
14238bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14239 return std::find(m_tile_yesshow_index_array.begin(),
14240 m_tile_yesshow_index_array.end(),
14241 index) != m_tile_yesshow_index_array.end();
14244bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14245 return std::find(m_tile_noshow_index_array.begin(),
14246 m_tile_noshow_index_array.end(),
14247 index) != m_tile_noshow_index_array.end();
14250void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14251 if (std::find(m_tile_noshow_index_array.begin(),
14252 m_tile_noshow_index_array.end(),
14253 index) == m_tile_noshow_index_array.end()) {
14254 m_tile_noshow_index_array.push_back(index);
14264void ChartCanvas::HandlePianoClick(
14265 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14268 if (!m_pCurrentStack)
return;
14284 double distance = 25000;
14285 int closest_index = -1;
14286 for (
int chart_index : selected_dbIndex_array) {
14288 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14289 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14292 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14293 if (test_distance < distance) {
14294 distance = test_distance;
14295 closest_index = chart_index;
14299 int selected_dbIndex = selected_dbIndex_array[0];
14300 if (closest_index >= 0) selected_dbIndex = closest_index;
14302 if (!GetQuiltMode()) {
14303 if (m_bpersistent_quilt ) {
14304 if (IsChartQuiltableRef(selected_dbIndex)) {
14305 ToggleCanvasQuiltMode();
14306 SelectQuiltRefdbChart(selected_dbIndex);
14307 m_bpersistent_quilt =
false;
14309 SelectChartFromStack(selected_index);
14312 SelectChartFromStack(selected_index);
14313 g_sticky_chart = selected_dbIndex;
14317 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14321 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14322 bool bfound =
false;
14323 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14324 if (m_tile_noshow_index_array[i] ==
14325 selected_dbIndex) {
14326 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14333 m_tile_noshow_index_array.push_back(selected_dbIndex);
14337 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14338 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14342 if (IsChartQuiltableRef(selected_dbIndex)) {
14348 bool set_scale =
false;
14349 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14350 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14356 SelectQuiltRefdbChart(selected_dbIndex,
true);
14358 SelectQuiltRefdbChart(selected_dbIndex,
false);
14363 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14365 double proposed_scale_onscreen =
14368 if (g_bPreserveScaleOnX) {
14369 proposed_scale_onscreen =
14370 wxMin(proposed_scale_onscreen,
14372 GetCanvasWidth()));
14374 proposed_scale_onscreen =
14375 wxMin(proposed_scale_onscreen,
14377 GetCanvasWidth()));
14379 proposed_scale_onscreen =
14380 wxMax(proposed_scale_onscreen,
14389 ToggleCanvasQuiltMode();
14390 SelectdbChart(selected_dbIndex);
14391 m_bpersistent_quilt =
true;
14396 SetQuiltChartHiLiteIndex(-1);
14397 gFrame->UpdateGlobalMenuItems();
14399 HideChartInfoWindow();
14404void ChartCanvas::HandlePianoRClick(
14405 int x,
int y,
int selected_index,
14406 const std::vector<int> &selected_dbIndex_array) {
14409 if (!GetpCurrentStack())
return;
14411 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14412 UpdateCanvasControlBar();
14414 SetQuiltChartHiLiteIndex(-1);
14417void ChartCanvas::HandlePianoRollover(
14418 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14419 int n_charts,
int scale) {
14422 if (!GetpCurrentStack())
return;
14427 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14429 if (!GetQuiltMode()) {
14430 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14433 std::vector<int> piano_chart_index_array;
14434 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14435 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14436 if ((GetpCurrentStack()->nEntry > 1) ||
14437 (piano_chart_index_array.size() >= 1)) {
14438 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14440 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14442 }
else if (GetpCurrentStack()->nEntry == 1) {
14444 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14445 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14446 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14448 }
else if ((-1 == selected_index) &&
14449 (0 == selected_dbIndex_array.size())) {
14450 ShowChartInfoWindow(key_location.x, -1);
14454 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14456 if ((GetpCurrentStack()->nEntry > 1) ||
14457 (piano_chart_index_array.size() >= 1)) {
14459 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14460 selected_dbIndex_array);
14461 else if (n_charts == 1)
14462 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14464 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14471void ChartCanvas::ClearPianoRollover() {
14472 ClearQuiltChartHiLiteIndexArray();
14473 ShowChartInfoWindow(0, -1);
14474 std::vector<int> vec;
14475 ShowCompositeInfoWindow(0, 0, 0, vec);
14479void ChartCanvas::UpdateCanvasControlBar() {
14480 if (m_pianoFrozen)
return;
14482 if (!GetpCurrentStack())
return;
14484 if (!g_bShowChartBar)
return;
14487 int sel_family = -1;
14489 std::vector<int> piano_chart_index_array;
14490 std::vector<int> empty_piano_chart_index_array;
14492 wxString old_hash = m_Piano->GetStoredHash();
14494 if (GetQuiltMode()) {
14495 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14496 GetQuiltFullScreendbIndexArray());
14498 std::vector<int> piano_active_chart_index_array =
14499 GetQuiltCandidatedbIndexArray();
14500 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14502 std::vector<int> piano_eclipsed_chart_index_array =
14503 GetQuiltEclipsedStackdbIndexArray();
14504 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14506 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14507 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14509 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14510 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14512 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14513 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14516 if (m_singleChart) {
14517 sel_type = m_singleChart->GetChartType();
14518 sel_family = m_singleChart->GetChartFamily();
14523 std::vector<int> piano_skew_chart_index_array;
14524 std::vector<int> piano_tmerc_chart_index_array;
14525 std::vector<int> piano_poly_chart_index_array;
14527 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14529 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14530 double skew_norm = ctei.GetChartSkew();
14531 if (skew_norm > 180.) skew_norm -= 360.;
14533 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14534 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14537 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14538 if (fabs(skew_norm) > 1.)
14539 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14541 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14542 }
else if (fabs(skew_norm) > 1.)
14543 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14545 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14546 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14547 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14549 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14550 if (new_hash != old_hash) {
14551 m_Piano->FormatKeys();
14552 HideChartInfoWindow();
14553 m_Piano->ResetRollover();
14554 SetQuiltChartHiLiteIndex(-1);
14555 m_brepaint_piano =
true;
14561 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14563 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14564 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14565 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14566 if (e == CHART_FAMILY_RASTER) mask |= 1;
14567 if (e == CHART_FAMILY_VECTOR) {
14568 if (t == CHART_TYPE_CM93COMP)
14575 wxString s_indicated;
14576 if (sel_type == CHART_TYPE_CM93COMP)
14577 s_indicated =
"cm93";
14579 if (sel_family == CHART_FAMILY_RASTER)
14580 s_indicated =
"raster";
14581 else if (sel_family == CHART_FAMILY_VECTOR)
14582 s_indicated =
"vector";
14585 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14588void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14590void ChartCanvas::PianoPopupMenu(
14591 int x,
int y,
int selected_index,
14592 const std::vector<int> &selected_dbIndex_array) {
14593 if (!GetpCurrentStack())
return;
14596 if (!GetQuiltMode())
return;
14598 m_piano_ctx_menu =
new wxMenu();
14600 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14610 menu_selected_dbIndex = selected_dbIndex_array[0];
14611 menu_selected_index = selected_index;
14614 bool b_is_in_noshow =
false;
14615 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14616 if (m_quilt_noshow_index_array[i] ==
14617 menu_selected_dbIndex)
14619 b_is_in_noshow =
true;
14624 if (b_is_in_noshow) {
14625 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14626 _(
"Show This Chart"));
14627 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14628 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14629 }
else if (GetpCurrentStack()->nEntry > 1) {
14630 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14631 _(
"Hide This Chart"));
14632 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14633 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14637 wxPoint pos = wxPoint(x, y - 30);
14640 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14641 PopupMenu(m_piano_ctx_menu, pos);
14643 delete m_piano_ctx_menu;
14644 m_piano_ctx_menu = NULL;
14646 HideChartInfoWindow();
14647 m_Piano->ResetRollover();
14649 SetQuiltChartHiLiteIndex(-1);
14650 ClearQuiltChartHiLiteIndexArray();
14655void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14656 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14657 if (m_quilt_noshow_index_array[i] ==
14658 menu_selected_dbIndex)
14660 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14666void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14667 if (!GetpCurrentStack())
return;
14670 RemoveChartFromQuilt(menu_selected_dbIndex);
14674 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14675 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14677 int i = menu_selected_index + 1;
14678 bool b_success =
false;
14679 while (i < GetpCurrentStack()->nEntry - 1) {
14680 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14681 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14682 SelectQuiltRefChart(i);
14692 i = menu_selected_index - 1;
14694 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14695 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14696 SelectQuiltRefChart(i);
14706void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14708 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14709 if (m_quilt_noshow_index_array[i] ==
14712 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14717 m_quilt_noshow_index_array.push_back(dbIndex);
14720bool ChartCanvas::UpdateS52State() {
14721 bool retval =
false;
14724 ps52plib->SetShowS57Text(m_encShowText);
14725 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14726 ps52plib->m_bShowSoundg = m_encShowDepth;
14727 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14728 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14731 if (!m_encShowLights)
14732 ps52plib->AddObjNoshow(
"LIGHTS");
14734 ps52plib->RemoveObjNoshow(
"LIGHTS");
14735 ps52plib->SetLightsOff(!m_encShowLights);
14736 ps52plib->m_bExtendLightSectors =
true;
14739 ps52plib->SetAnchorOn(m_encShowAnchor);
14740 ps52plib->SetQualityOfData(m_encShowDataQual);
14746void ChartCanvas::SetShowENCDataQual(
bool show) {
14747 m_encShowDataQual = show;
14748 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14749 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14751 m_s52StateHash = 0;
14754void ChartCanvas::SetShowENCText(
bool show) {
14755 m_encShowText = show;
14756 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14757 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14759 m_s52StateHash = 0;
14762void ChartCanvas::SetENCDisplayCategory(
int category) {
14763 m_encDisplayCategory = category;
14764 m_s52StateHash = 0;
14767void ChartCanvas::SetShowENCDepth(
bool show) {
14768 m_encShowDepth = show;
14769 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14770 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14772 m_s52StateHash = 0;
14775void ChartCanvas::SetShowENCLightDesc(
bool show) {
14776 m_encShowLightDesc = show;
14777 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14778 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14780 m_s52StateHash = 0;
14783void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14784 m_encShowBuoyLabels = show;
14785 m_s52StateHash = 0;
14788void ChartCanvas::SetShowENCLights(
bool show) {
14789 m_encShowLights = show;
14790 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14791 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14793 m_s52StateHash = 0;
14796void ChartCanvas::SetShowENCAnchor(
bool show) {
14797 m_encShowAnchor = show;
14798 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14799 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14801 m_s52StateHash = 0;
14804wxRect ChartCanvas::GetMUIBarRect() {
14807 rv = m_muiBar->GetRect();
14813void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14814 if (!GetAlertString().IsEmpty()) {
14815 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14816 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14818 dc.SetFont(*pfont);
14819 dc.SetPen(*wxTRANSPARENT_PEN);
14821 dc.SetBrush(wxColour(243, 229, 47));
14823 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14827 wxRect sbr = GetScaleBarRect();
14828 int xp = sbr.x + sbr.width + 10;
14829 int yp = (sbr.y + sbr.height) - h;
14831 int wdraw = w + 10;
14832 dc.DrawRectangle(xp, yp, wdraw, h);
14833 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14834 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14844#define BRIGHT_XCALIB
14845#define __OPCPN_USEICC__
14848#ifdef __OPCPN_USEICC__
14849int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14850 double co_green,
double co_blue);
14852wxString temp_file_name;
14856class ocpnCurtain:
public wxDialog
14858 DECLARE_CLASS( ocpnCurtain )
14859 DECLARE_EVENT_TABLE()
14862 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14864 bool ProcessEvent(wxEvent& event);
14868IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14870BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14873ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14875 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14878ocpnCurtain::~ocpnCurtain()
14882bool ocpnCurtain::ProcessEvent(wxEvent& event)
14884 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14885 return GetParent()->GetEventHandler()->ProcessEvent(event);
14890#include <windows.h>
14893typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14894typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14895SetDeviceGammaRamp_ptr_type
14896 g_pSetDeviceGammaRamp;
14897GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14899WORD *g_pSavedGammaMap;
14903int InitScreenBrightness() {
14906 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14910 if (NULL == hGDI32DLL) {
14911 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14913 if (NULL != hGDI32DLL) {
14915 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14916 hGDI32DLL,
"SetDeviceGammaRamp");
14917 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14918 hGDI32DLL,
"GetDeviceGammaRamp");
14921 if ((NULL == g_pSetDeviceGammaRamp) ||
14922 (NULL == g_pGetDeviceGammaRamp)) {
14923 FreeLibrary(hGDI32DLL);
14932 if (!g_pSavedGammaMap) {
14933 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14936 bbr = g_pGetDeviceGammaRamp(
14937 hDC, g_pSavedGammaMap);
14938 ReleaseDC(NULL, hDC);
14943 wxRegKey *pRegKey =
new wxRegKey(
14944 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14945 "NT\\CurrentVersion\\ICM");
14946 if (!pRegKey->Exists()) pRegKey->Create();
14947 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14949 g_brightness_init =
true;
14955 if (NULL == g_pcurtain) {
14956 if (gFrame->CanSetTransparent()) {
14958 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14959 wxPoint(0, 0), ::wxGetDisplaySize(),
14960 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14961 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14968 g_pcurtain->Hide();
14970 HWND hWnd = GetHwndOf(g_pcurtain);
14971 SetWindowLong(hWnd, GWL_EXSTYLE,
14972 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14973 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14974 g_pcurtain->SetTransparent(0);
14976 g_pcurtain->Maximize();
14977 g_pcurtain->Show();
14980 g_pcurtain->Enable();
14981 g_pcurtain->Disable();
14988 g_brightness_init =
true;
14994 wxString cmd(
"xcalib -version");
14996 wxArrayString output;
14997 long r = wxExecute(cmd, output);
15000 " External application \"xcalib\" not found. Screen brightness "
15003 g_brightness_init =
true;
15008int RestoreScreenBrightness() {
15011 if (g_pSavedGammaMap) {
15012 HDC hDC = GetDC(NULL);
15013 g_pSetDeviceGammaRamp(hDC,
15015 ReleaseDC(NULL, hDC);
15017 free(g_pSavedGammaMap);
15018 g_pSavedGammaMap = NULL;
15022 g_pcurtain->Close();
15023 g_pcurtain->Destroy();
15027 g_brightness_init =
false;
15032#ifdef BRIGHT_XCALIB
15033 if (g_brightness_init) {
15035 cmd =
"xcalib -clear";
15036 wxExecute(cmd, wxEXEC_ASYNC);
15037 g_brightness_init =
false;
15047int SetScreenBrightness(
int brightness) {
15054 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15056 g_pcurtain->Close();
15057 g_pcurtain->Destroy();
15061 InitScreenBrightness();
15063 if (NULL == hGDI32DLL) {
15065 wchar_t wdll_name[80];
15066 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15067 LPCWSTR cstr = wdll_name;
15069 hGDI32DLL = LoadLibrary(cstr);
15071 if (NULL != hGDI32DLL) {
15073 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15074 hGDI32DLL,
"SetDeviceGammaRamp");
15075 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15076 hGDI32DLL,
"GetDeviceGammaRamp");
15079 if ((NULL == g_pSetDeviceGammaRamp) ||
15080 (NULL == g_pGetDeviceGammaRamp)) {
15081 FreeLibrary(hGDI32DLL);
15088 HDC hDC = GetDC(NULL);
15099 int increment = brightness * 256 / 100;
15102 WORD GammaTable[3][256];
15105 for (
int i = 0; i < 256; i++) {
15106 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15107 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15108 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15110 table_val += increment;
15112 if (table_val > 65535) table_val = 65535;
15115 g_pSetDeviceGammaRamp(hDC, GammaTable);
15116 ReleaseDC(NULL, hDC);
15123 if (g_pSavedGammaMap) {
15124 HDC hDC = GetDC(NULL);
15125 g_pSetDeviceGammaRamp(hDC,
15127 ReleaseDC(NULL, hDC);
15130 if (brightness < 100) {
15131 if (NULL == g_pcurtain) InitScreenBrightness();
15134 int sbrite = wxMax(1, brightness);
15135 sbrite = wxMin(100, sbrite);
15137 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15141 g_pcurtain->Close();
15142 g_pcurtain->Destroy();
15152#ifdef BRIGHT_XCALIB
15154 if (!g_brightness_init) {
15155 last_brightness = 100;
15156 g_brightness_init =
true;
15157 temp_file_name = wxFileName::CreateTempFileName(
"");
15158 InitScreenBrightness();
15161#ifdef __OPCPN_USEICC__
15164 if (!CreateSimpleICCProfileFile(
15165 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15166 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15167 wxString cmd(
"xcalib ");
15168 cmd += temp_file_name;
15170 wxExecute(cmd, wxEXEC_ASYNC);
15179 if (brightness > last_brightness) {
15181 cmd =
"xcalib -clear";
15182 wxExecute(cmd, wxEXEC_ASYNC);
15184 ::wxMilliSleep(10);
15186 int brite_adj = wxMax(1, brightness);
15187 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15188 wxExecute(cmd, wxEXEC_ASYNC);
15190 int brite_adj = wxMax(1, brightness);
15191 int factor = (brite_adj * 100) / last_brightness;
15192 factor = wxMax(1, factor);
15194 cmd.Printf(
"xcalib -co %2d -a", factor);
15195 wxExecute(cmd, wxEXEC_ASYNC);
15200 last_brightness = brightness;
15207#ifdef __OPCPN_USEICC__
15209#define MLUT_TAG 0x6d4c5554L
15210#define VCGT_TAG 0x76636774L
15212int GetIntEndian(
unsigned char *s) {
15217 p = (
unsigned char *)&ret;
15220 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15222 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15227unsigned short GetShortEndian(
unsigned char *s) {
15228 unsigned short ret;
15232 p = (
unsigned char *)&ret;
15235 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15237 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15243int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15244 double co_green,
double co_blue) {
15248 fp = fopen(file_name,
"wb");
15249 if (!fp)
return -1;
15255 for (
int i = 0; i < 128; i++) header[i] = 0;
15257 fwrite(header, 128, 1, fp);
15261 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15262 fwrite(&numTags, 1, 4, fp);
15264 int tagName0 = VCGT_TAG;
15265 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15266 fwrite(&tagName, 1, 4, fp);
15268 int tagOffset0 = 128 + 4 *
sizeof(int);
15269 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15270 fwrite(&tagOffset, 1, 4, fp);
15273 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15274 fwrite(&tagSize, 1, 4, fp);
15276 fwrite(&tagName, 1, 4, fp);
15278 fwrite(&tagName, 1, 4, fp);
15283 int gammatype0 = 0;
15284 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15285 fwrite(&gammatype, 1, 4, fp);
15287 int numChannels0 = 3;
15288 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15289 fwrite(&numChannels, 1, 2, fp);
15291 int numEntries0 = 256;
15292 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15293 fwrite(&numEntries, 1, 2, fp);
15295 int entrySize0 = 1;
15296 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15297 fwrite(&entrySize, 1, 2, fp);
15299 unsigned char ramp[256];
15302 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15303 fwrite(ramp, 256, 1, fp);
15306 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15307 fwrite(ramp, 256, 1, fp);
15310 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15311 fwrite(ramp, 256, 1, fp);
Select * pSelectAIS
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetQueryDialog.
std::unique_ptr< HostApi > GetHostApi()
HostApi factory,.
Chart canvas configuration state
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
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.
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.
void CloseTideDialog()
Close any open tide dialog.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
void OnPaint(wxPaintEvent &event)
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void DoMovement(long dt)
Performs a step of smooth movement animation on the chart canvas.
void ShowSingleTideDialog(int x, int y, void *pvIDX)
Display tide/current dialog with single-instance management.
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.
int PrepareContextSelections(double lat, double lon)
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.
EventVar json_msg
Notified with message targeting all plugins.
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.
bool IsTideDialogOpen() const
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 DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
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)
Centers the view on a specific lat/lon position.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
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)
Get 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.
PluginLoader is a backend module without any direct GUI functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
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.
wxString m_GUID
Globally unique identifier for this 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)
Dialog for displaying query results of S57 objects.
IDX_entry * GetCurrentIDX() const
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.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
APConsole * console
Global instance.
Primary navigation console display for route and vessel tracking.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
bool g_bRollover
enable/disable mouse rollover GUI effects
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
double g_display_size_mm
Physical display width (mm)
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
GoToPositionDialog * pGoToPositionDialog
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Hooks into gui available in model.
size_t g_current_monitor
Current monitor displaying main application frame.
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
bool g_b_overzoom_x
Allow high overzoom.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Hotheys help dialog (the '?' button).
GUI constant definitions.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
MySQL based storage for routes, tracks, etc.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
User notifications manager.
Notification Manager GUI.
OCPN_AUIManager * g_pauimgr
Global instance.
Optimized wxBitmap Object.
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
int GetChartbarHeight()
Gets height of chart bar in pixels.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Layer to use wxDC or opengl.
options * g_options
Global instance.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
double gHdt
True heading in degrees (0-359.99).
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Purpose: Track and Trackpoint drawing stuff.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
RoutePoint * pAnchorWatchPoint2
Global instance.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RoutePoint * pAnchorWatchPoint1
Global instance.
float g_ChartScaleFactorExp
Global instance.
S57QueryDialog * g_pObjectQueryDialog
Global instance.
S57 object query result window.
Select * pSelect
Global instance.
Select * pSelectTC
Global instance.
Selected route, segment, waypoint, etc.
A single, selected generic item.
SENCThreadManager * g_SencThreadManager
Global instance.
ShapeBaseChartSet gShapeBasemap
global instance
Represents an entry in the chart table, containing information about a single chart.
Tide and currents window.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
Timer identification constants.
ActiveTrack * g_pActiveTrack
global instance
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Track and Trackpoint drawing stuff.
TrackPropDlg * pTrackPropDialog
Global instance.
Framework for Undo features.