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_ignore_next_leftup) {
9344 m_ignore_next_leftup =
false;
9348 if (m_nMeasureState == 1) {
9349 m_pMeasureRoute =
new Route();
9355 if (m_pMeasureRoute) {
9358 wxEmptyString, wxEmptyString);
9361 m_pMeasureRoute->AddPoint(pMousePoint);
9365 m_prev_pMousePoint = pMousePoint;
9367 m_pMeasureRoute->GetnPoints();
9371 CancelMeasureRoute();
9377 bool bSelectAllowed =
true;
9379 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9381 bSelectAllowed =
false;
9385 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9386 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9387 significant_drag) ||
9388 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9389 significant_drag)) {
9390 bSelectAllowed =
false;
9398 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9400 if (bSelectAllowed) {
9401 bool b_was_editing_mark = m_bMarkEditing;
9402 bool b_was_editing_route = m_bRouteEditing;
9403 FindRoutePointsAtCursor(SelectRadius,
9409 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9410 m_pRoutePointEditTarget = NULL;
9412 if (!b_was_editing_route) {
9413 if (m_pEditRouteArray) {
9414 b_startedit_route =
true;
9418 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9419 m_pTrackRolloverWin->IsActive(
false);
9421 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9422 m_pRouteRolloverWin->IsActive(
false);
9426 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9428 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9436 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9437 pre_rect.Union(route_rect);
9440 RefreshRect(pre_rect,
true);
9443 b_startedit_route =
false;
9447 if (m_pRoutePointEditTarget) {
9448 if (b_was_editing_mark ||
9449 b_was_editing_route) {
9450 if (m_lastRoutePointEditTarget) {
9454 .EnableDragHandle(
false);
9455 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9456 SELTYPE_DRAGHANDLE);
9460 if (m_pRoutePointEditTarget) {
9463 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9464 wxPoint2DDouble dragHandlePoint =
9466 .GetDragHandlePoint(
this);
9468 dragHandlePoint.m_y, dragHandlePoint.m_x,
9469 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9472 if (m_lastRoutePointEditTarget) {
9476 .EnableDragHandle(
false);
9477 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9478 SELTYPE_DRAGHANDLE);
9481 wxArrayPtrVoid *lastEditRouteArray =
9483 m_lastRoutePointEditTarget);
9484 if (lastEditRouteArray) {
9485 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9487 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9492 delete lastEditRouteArray;
9503 if (m_lastRoutePointEditTarget) {
9506 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9507 RefreshRect(wp_rect,
true);
9510 if (m_pRoutePointEditTarget) {
9513 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9514 RefreshRect(wp_rect,
true);
9522 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9523 bool b_start_rollover =
false;
9527 if (pFind) b_start_rollover =
true;
9530 if (!b_start_rollover && !b_startedit_route) {
9531 SelectableItemList SelList =
pSelect->FindSelectionList(
9535 if (pr && pr->IsVisible()) {
9536 b_start_rollover =
true;
9542 if (!b_start_rollover && !b_startedit_route) {
9543 SelectableItemList SelList =
pSelect->FindSelectionList(
9547 if (tr && tr->IsVisible()) {
9548 b_start_rollover =
true;
9554 if (b_start_rollover)
9555 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9559 bool appending =
false;
9560 bool inserting =
false;
9562 if (m_bRouteEditing ) {
9564 if (m_pRoutePointEditTarget) {
9570 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9571 double nearby_radius_meters =
9572 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9573 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9574 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9575 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9577 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9581 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9583 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9587 std::find(list->begin(), list->end(), pNearbyPoint);
9588 if (pos != list->end()) {
9600 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9605 OCPNMessageBox(
this,
9606 _(
"Replace this RoutePoint by the nearby "
9608 _(
"OpenCPN RoutePoint change"),
9609 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9610 if (dlg_return == wxID_YES) {
9615 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9618 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9620 if (tail && current && (tail != current)) {
9622 connect = tail->GetIndexOf(pNearbyPoint);
9623 int index_current_route =
9624 current->GetIndexOf(m_pRoutePointEditTarget);
9625 index_last = current->GetIndexOf(current->GetLastPoint());
9626 dlg_return1 = wxID_NO;
9628 index_current_route) {
9630 if (connect != tail->GetnPoints()) {
9633 _(
"Last part of route to be appended to dragged "
9637 _(
"Full route to be appended to dragged route?");
9639 dlg_return1 = OCPNMessageBox(
9640 this, dmsg, _(
"OpenCPN Route Create"),
9641 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9642 if (dlg_return1 == wxID_YES) {
9646 }
else if (index_current_route ==
9651 _(
"First part of route to be inserted into dragged "
9653 if (connect == tail->GetnPoints())
9655 "Full route to be inserted into dragged route?");
9657 dlg_return1 = OCPNMessageBox(
9658 this, dmsg, _(
"OpenCPN Route Create"),
9659 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9660 if (dlg_return1 == wxID_YES) {
9667 if (m_pRoutePointEditTarget->IsShared()) {
9669 dlg_return = OCPNMessageBox(
9671 _(
"Do you really want to delete and replace this "
9673 "\n" + _(
"which has been created manually?"),
9674 (
"OpenCPN RoutePoint warning"),
9675 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9678 if (dlg_return == wxID_YES) {
9679 pMousePoint = pNearbyPoint;
9681 pMousePoint->SetShared(
true);
9691 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9693 if (m_pEditRouteArray) {
9694 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9696 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9701 auto pos = std::find(list->begin(), list->end(),
9702 m_pRoutePointEditTarget);
9704 pSelect->DeleteAllSelectableRoutePoints(pr);
9705 pSelect->DeleteAllSelectableRouteSegments(pr);
9708 pos = std::find(list->begin(), list->end(),
9709 m_pRoutePointEditTarget);
9712 pSelect->AddAllSelectableRouteSegments(pr);
9713 pSelect->AddAllSelectableRoutePoints(pr);
9715 pr->FinalizeForRendering();
9716 pr->UpdateSegmentDistances();
9717 if (m_bRoutePoinDragging) {
9719 NavObj_dB::GetInstance().UpdateRoute(pr);
9727 if (m_pEditRouteArray) {
9728 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9730 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9749 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9756 delete m_pRoutePointEditTarget;
9757 m_lastRoutePointEditTarget = NULL;
9758 m_pRoutePointEditTarget = NULL;
9759 undo->AfterUndoableAction(pMousePoint);
9760 undo->InvalidateUndo();
9765 else if (m_bMarkEditing) {
9766 if (m_pRoutePointEditTarget)
9767 if (m_bRoutePoinDragging) {
9769 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9773 if (m_pRoutePointEditTarget)
9774 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9776 if (!m_pRoutePointEditTarget) {
9777 delete m_pEditRouteArray;
9778 m_pEditRouteArray = NULL;
9779 m_bRouteEditing =
false;
9781 m_bRoutePoinDragging =
false;
9788 int length = tail->GetnPoints();
9789 for (
int i = connect + 1; i <= length; i++) {
9790 current->AddPointAndSegment(tail->GetPoint(i),
false);
9793 gFrame->RefreshAllCanvas();
9796 current->FinalizeForRendering();
9802 pSelect->DeleteAllSelectableRoutePoints(current);
9803 pSelect->DeleteAllSelectableRouteSegments(current);
9804 for (
int i = 1; i < connect; i++) {
9805 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9807 pSelect->AddAllSelectableRouteSegments(current);
9808 pSelect->AddAllSelectableRoutePoints(current);
9809 current->FinalizeForRendering();
9816 if (m_pEditRouteArray) {
9817 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9818 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9831 if (m_bRouteEditing) {
9834 bool appending =
false;
9835 bool inserting =
false;
9838 if (m_pRoutePointEditTarget) {
9839 m_pRoutePointEditTarget->
m_bBlink =
false;
9843 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9844 double nearby_radius_meters =
9845 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9846 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9847 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9848 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9850 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9851 bool duplicate =
false;
9853 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9855 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9859 std::find(list->begin(), list->end(), pNearbyPoint);
9860 if (pos != list->end()) {
9872 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9877 OCPNMessageBox(
this,
9878 _(
"Replace this RoutePoint by the nearby "
9880 _(
"OpenCPN RoutePoint change"),
9881 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9882 if (dlg_return == wxID_YES) {
9886 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9889 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9891 if (tail && current && (tail != current)) {
9893 connect = tail->GetIndexOf(pNearbyPoint);
9894 int index_current_route =
9895 current->GetIndexOf(m_pRoutePointEditTarget);
9896 index_last = current->GetIndexOf(current->GetLastPoint());
9897 dlg_return1 = wxID_NO;
9899 index_current_route) {
9901 if (connect != tail->GetnPoints()) {
9904 _(
"Last part of route to be appended to dragged "
9908 _(
"Full route to be appended to dragged route?");
9910 dlg_return1 = OCPNMessageBox(
9911 this, dmsg, _(
"OpenCPN Route Create"),
9912 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9913 if (dlg_return1 == wxID_YES) {
9917 }
else if (index_current_route ==
9922 _(
"First part of route to be inserted into dragged "
9924 if (connect == tail->GetnPoints())
9926 "Full route to be inserted into dragged route?");
9928 dlg_return1 = OCPNMessageBox(
9929 this, dmsg, _(
"OpenCPN Route Create"),
9930 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9931 if (dlg_return1 == wxID_YES) {
9938 if (m_pRoutePointEditTarget->IsShared()) {
9939 dlg_return = wxID_NO;
9940 dlg_return = OCPNMessageBox(
9942 _(
"Do you really want to delete and replace this "
9944 "\n" + _(
"which has been created manually?"),
9945 (
"OpenCPN RoutePoint warning"),
9946 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9949 if (dlg_return == wxID_YES) {
9950 pMousePoint = pNearbyPoint;
9952 pMousePoint->SetShared(
true);
9962 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9964 if (m_pEditRouteArray) {
9965 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9967 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9971 auto pos = std::find(list->begin(), list->end(),
9972 m_pRoutePointEditTarget);
9974 pSelect->DeleteAllSelectableRoutePoints(pr);
9975 pSelect->DeleteAllSelectableRouteSegments(pr);
9978 pos = std::find(list->begin(), list->end(),
9979 m_pRoutePointEditTarget);
9980 if (pos != list->end()) list->erase(pos);
9983 pSelect->AddAllSelectableRouteSegments(pr);
9984 pSelect->AddAllSelectableRoutePoints(pr);
9986 pr->FinalizeForRendering();
9987 pr->UpdateSegmentDistances();
9990 if (m_bRoutePoinDragging) {
9995 NavObj_dB::GetInstance().UpdateRoutePoint(
9996 m_pRoutePointEditTarget);
9998 NavObj_dB::GetInstance().UpdateRoute(pr);
10010 int length = tail->GetnPoints();
10011 for (
int i = connect + 1; i <= length; i++) {
10012 current->AddPointAndSegment(tail->GetPoint(i),
false);
10016 gFrame->RefreshAllCanvas();
10019 current->FinalizeForRendering();
10025 pSelect->DeleteAllSelectableRoutePoints(current);
10026 pSelect->DeleteAllSelectableRouteSegments(current);
10027 for (
int i = 1; i < connect; i++) {
10028 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10030 pSelect->AddAllSelectableRouteSegments(current);
10031 pSelect->AddAllSelectableRoutePoints(current);
10032 current->FinalizeForRendering();
10039 if (m_pEditRouteArray) {
10040 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10042 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10054 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10061 delete m_pRoutePointEditTarget;
10062 m_lastRoutePointEditTarget = NULL;
10063 undo->AfterUndoableAction(pMousePoint);
10064 undo->InvalidateUndo();
10069 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10072 delete m_pEditRouteArray;
10073 m_pEditRouteArray = NULL;
10077 m_bRouteEditing =
false;
10078 m_pRoutePointEditTarget = NULL;
10084 else if (m_bMarkEditing) {
10085 if (m_pRoutePointEditTarget) {
10086 if (m_bRoutePoinDragging) {
10088 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10090 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10095 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10097 RefreshRect(wp_rect,
true);
10100 m_pRoutePointEditTarget = NULL;
10101 m_bMarkEditing =
false;
10106 else if (leftIsDown) {
10107 leftIsDown =
false;
10111 if (!m_bChartDragging && !m_bMeasure_Active) {
10113 m_bChartDragging =
false;
10117 m_bRoutePoinDragging =
false;
10120 if (ret)
return true;
10123 if (event.RightDown()) {
10134 m_FinishRouteOnKillFocus =
false;
10135 CallPopupMenu(mx, my);
10136 m_FinishRouteOnKillFocus =
true;
10146 if (event.ShiftDown()) {
10150 event.GetPosition(&x, &y);
10152 x *= m_displayScale;
10153 y *= m_displayScale;
10159 int wheel_dir =
event.GetWheelRotation();
10162 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10163 wheel_dir = wheel_dir > 0 ? 1 : -1;
10165 double factor = g_mouse_zoom_sensitivity;
10166 if (wheel_dir < 0) factor = 1 / factor;
10169 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10170 if (wheel_dir == m_last_wheel_dir) {
10171 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10176 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10177 m_wheelstopwatch.Start(0);
10182 m_last_wheel_dir = wheel_dir;
10187 if (event.LeftDown()) {
10193 last_drag.x = x, last_drag.y = y;
10194 panleftIsDown =
true;
10197 if (event.LeftUp()) {
10198 if (panleftIsDown) {
10200 panleftIsDown =
false;
10203 if (!m_bChartDragging && !m_bMeasure_Active) {
10204 switch (cursor_region) {
10226 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10231 m_bChartDragging =
false;
10237 if (event.Dragging() && event.LeftIsDown()) {
10253 if (g_btouch && !m_inPinch) {
10254 struct timespec now;
10255 clock_gettime(CLOCK_MONOTONIC, &now);
10256 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10258 bool trigger_hold =
false;
10259 if (
false == m_bChartDragging) {
10260 if (m_DragTrigger < 0) {
10263 m_DragTriggerStartTime = tnow;
10264 trigger_hold =
true;
10266 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10267 m_DragTrigger = -1;
10272 if (trigger_hold)
return true;
10274 if (
false == m_bChartDragging) {
10277 last_drag.x = x - 1, last_drag.y = y - 1;
10278 m_bChartDragging =
true;
10279 m_chart_drag_total_time = 0;
10280 m_chart_drag_total_x = 0;
10281 m_chart_drag_total_y = 0;
10282 m_inertia_last_drag_x = x;
10283 m_inertia_last_drag_y = y;
10284 m_drag_vec_x.clear();
10285 m_drag_vec_y.clear();
10286 m_drag_vec_t.clear();
10287 m_last_drag_time = tnow;
10291 uint64_t delta_t = tnow - m_last_drag_time;
10292 double delta_tf = delta_t / 1e9;
10294 m_chart_drag_total_time += delta_tf;
10295 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10296 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10298 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10299 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10300 m_drag_vec_t.push_back(delta_tf);
10302 m_inertia_last_drag_x = x;
10303 m_inertia_last_drag_y = y;
10304 m_last_drag_time = tnow;
10306 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10307 m_bChartDragging =
true;
10308 StartTimedMovement();
10309 m_pan_drag.x += last_drag.x - x;
10310 m_pan_drag.y += last_drag.y - y;
10311 last_drag.x = x, last_drag.y = y;
10313 }
else if (!g_btouch) {
10314 if ((last_drag.x != x) || (last_drag.y != y)) {
10315 if (!m_routeState) {
10318 m_bChartDragging =
true;
10319 StartTimedMovement();
10320 m_pan_drag.x += last_drag.x - x;
10321 m_pan_drag.y += last_drag.y - y;
10322 last_drag.x = x, last_drag.y = y;
10329 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10331 m_ignore_next_leftup =
true;
10332 m_DoubleClickTimer->Start();
10333 singleClickEventIsValid =
false;
10341void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10342 if (MouseEventOverlayWindows(event))
return;
10346 bool nm = MouseEventProcessObjects(event);
10350void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10353 wxCursor *ptarget_cursor = pCursorArrow;
10354 if (!pPlugIn_Cursor) {
10355 ptarget_cursor = pCursorArrow;
10356 if ((!m_routeState) &&
10357 (!m_bMeasure_Active) ) {
10358 if (cursor_region == MID_RIGHT) {
10359 ptarget_cursor = pCursorRight;
10360 }
else if (cursor_region == MID_LEFT) {
10361 ptarget_cursor = pCursorLeft;
10362 }
else if (cursor_region == MID_TOP) {
10363 ptarget_cursor = pCursorDown;
10364 }
else if (cursor_region == MID_BOT) {
10365 ptarget_cursor = pCursorUp;
10367 ptarget_cursor = pCursorArrow;
10369 }
else if (m_bMeasure_Active ||
10371 ptarget_cursor = pCursorPencil;
10373 ptarget_cursor = pPlugIn_Cursor;
10376 SetCursor(*ptarget_cursor);
10379void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10380 SetCursor(*pCursorArrow);
10383void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10387 wxArrayString files;
10389 ChartBase *target_chart = GetChartAtCursor();
10390 if (target_chart) {
10391 file.Assign(target_chart->GetFullPath());
10392 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10393 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10396 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10398 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10399 unsigned int im = stackIndexArray.size();
10400 int scale = 2147483647;
10401 if (VPoint.b_quilt && im > 0) {
10402 for (
unsigned int is = 0; is < im; is++) {
10403 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10404 CHART_TYPE_MBTILES) {
10405 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10407 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10408 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10410 .Contains(lat, lon)) {
10411 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10414 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10415 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10423 std::vector<Ais8_001_22 *> area_notices;
10425 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10428 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10429 auto target_data = target.second;
10430 if (!target_data->area_notices.empty()) {
10431 for (
auto &ani : target_data->area_notices) {
10436 for (Ais8_001_22_SubAreaList::iterator sa =
10437 area_notice.sub_areas.begin();
10438 sa != area_notice.sub_areas.end(); ++sa) {
10439 switch (sa->shape) {
10440 case AIS8_001_22_SHAPE_CIRCLE: {
10441 wxPoint target_point;
10443 bbox.Expand(target_point);
10444 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10447 case AIS8_001_22_SHAPE_RECT: {
10448 wxPoint target_point;
10450 bbox.Expand(target_point);
10451 if (sa->e_dim_m > sa->n_dim_m)
10452 bbox.EnLarge(sa->e_dim_m * vp_scale);
10454 bbox.EnLarge(sa->n_dim_m * vp_scale);
10457 case AIS8_001_22_SHAPE_POLYGON:
10458 case AIS8_001_22_SHAPE_POLYLINE: {
10459 for (
int i = 0; i < 4; ++i) {
10460 double lat = sa->latitude;
10461 double lon = sa->longitude;
10462 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10464 wxPoint target_point;
10466 bbox.Expand(target_point);
10470 case AIS8_001_22_SHAPE_SECTOR: {
10471 double lat1 = sa->latitude;
10472 double lon1 = sa->longitude;
10474 wxPoint target_point;
10476 bbox.Expand(target_point);
10477 for (
int i = 0; i < 18; ++i) {
10480 sa->left_bound_deg +
10481 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10482 sa->radius_m / 1852.0, &lat, &lon);
10484 bbox.Expand(target_point);
10486 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10489 bbox.Expand(target_point);
10495 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10496 area_notices.push_back(&area_notice);
10503 if (target_chart || !area_notices.empty() || file.HasName()) {
10505 int sel_rad_pix = 5;
10506 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10511 SetCursor(wxCURSOR_WAIT);
10512 bool lightsVis = m_encShowLights;
10513 if (!lightsVis) SetShowENCLights(
true);
10516 ListOfObjRazRules *rule_list = NULL;
10517 ListOfPI_S57Obj *pi_rule_list = NULL;
10520 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10521 else if (target_plugin_chart)
10522 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10523 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10525 ListOfObjRazRules *overlay_rule_list = NULL;
10526 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10529 if (CHs57_Overlay) {
10530 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10531 zlat, zlon, SelectRadius, &GetVP());
10534 if (!lightsVis) SetShowENCLights(
false);
10537 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10538 wxString face = dFont->GetFaceName();
10542 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10543 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10547 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10555 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10556 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10559 int points = dFont->GetPointSize();
10561 int points = dFont->GetPointSize() + 1;
10565 for (
int i = -2; i < 5; i++) {
10566 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10570 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10572 if (overlay_rule_list && CHs57_Overlay) {
10573 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10574 objText <<
"<hr noshade>";
10577 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10578 an != area_notices.end(); ++an) {
10579 objText <<
"<b>AIS Area Notice:</b> ";
10580 objText << ais8_001_22_notice_names[(*an)->notice_type];
10581 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10582 (*an)->sub_areas.begin();
10583 sa != (*an)->sub_areas.end(); ++sa)
10584 if (!sa->text.empty()) objText << sa->text;
10585 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10586 objText <<
"<hr noshade>";
10590 objText << Chs57->CreateObjDescriptions(rule_list);
10591 else if (target_plugin_chart)
10592 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10595 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10598 wxString AddFiles, filenameOK;
10600 if (!target_plugin_chart) {
10603 AddFiles = wxString::Format(
10604 "<hr noshade><br><b>Additional info files attached to: </b> "
10606 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10608 file.GetFullName());
10610 file.Assign(file.GetPath(),
"");
10611 wxDir dir(file.GetFullPath());
10613 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10615 file.Assign(dir.GetNameWithSep().append(filename));
10616 wxString FormatString =
10617 "<td valign=top><font size=-2><a "
10618 "href=\"%s\">%s</a></font></td>";
10619 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10620 filenameOK = file.GetFullPath();
10622 if (3 * ((
int)filecount / 3) == filecount)
10623 FormatString.Prepend(
"<tr>");
10625 FormatString.Prepend(
10626 "<td>  </td>");
10629 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10630 file.GetFullName());
10633 cont = dir.GetNext(&filename);
10635 objText << AddFiles <<
"</table>";
10637 objText <<
"</font>";
10638 objText <<
"</body></html>";
10640 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10644 if ((!Chs57 && filecount == 1)) {
10646 wxHtmlLinkInfo hli(filenameOK);
10647 wxHtmlLinkEvent hle(1, hli);
10651 if (rule_list) rule_list->Clear();
10654 if (overlay_rule_list) overlay_rule_list->Clear();
10655 delete overlay_rule_list;
10657 if (pi_rule_list) pi_rule_list->Clear();
10658 delete pi_rule_list;
10660 SetCursor(wxCURSOR_ARROW);
10664void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10673 wxSize canvas_size = GetSize();
10680 wxPoint canvas_pos = GetPosition();
10683 bool newFit =
false;
10684 if (canvas_size.x < fitted_size.x) {
10685 fitted_size.x = canvas_size.x - 40;
10686 if (canvas_size.y < fitted_size.y)
10687 fitted_size.y -= 40;
10689 if (canvas_size.y < fitted_size.y) {
10690 fitted_size.y = canvas_size.y - 40;
10691 if (canvas_size.x < fitted_size.x)
10692 fitted_size.x -= 40;
10703 wxString title_base = _(
"Mark Properties");
10705 title_base = _(
"Waypoint Properties");
10710 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10722void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10732 if (g_bresponsive) {
10733 wxSize canvas_size = GetSize();
10734 wxPoint canvas_pos = GetPosition();
10738 if (canvas_size.x < fitted_size.x) {
10739 fitted_size.x = canvas_size.x;
10740 if (canvas_size.y < fitted_size.y)
10741 fitted_size.y -= 20;
10743 if (canvas_size.y < fitted_size.y) {
10744 fitted_size.y = canvas_size.y;
10745 if (canvas_size.x < fitted_size.x)
10746 fitted_size.x -= 20;
10755 wxPoint xxp = ClientToScreen(canvas_pos);
10766void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10778void pupHandler_PasteWaypoint() {
10781 int pasteBuffer = kml.ParsePasteBuffer();
10782 RoutePoint *pasted = kml.GetParsedRoutePoint();
10783 if (!pasted)
return;
10785 double nearby_radius_meters =
10786 g_Platform->GetSelectRadiusPix() /
10787 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10789 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10790 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10792 int answer = wxID_NO;
10796 "There is an existing waypoint at the same location as the one you are "
10797 "pasting. Would you like to merge the pasted data with it?\n\n");
10798 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10799 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10800 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10803 if (answer == wxID_YES) {
10804 nearPoint->SetName(pasted->GetName());
10806 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10807 pRouteManagerDialog->UpdateWptListCtrl();
10810 if (answer == wxID_NO) {
10813 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10816 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10819 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10820 pRouteManagerDialog->UpdateWptListCtrl();
10825 gFrame->InvalidateAllGL();
10826 gFrame->RefreshAllCanvas(
false);
10829void pupHandler_PasteRoute() {
10832 int pasteBuffer = kml.ParsePasteBuffer();
10833 Route *pasted = kml.GetParsedRoute();
10834 if (!pasted)
return;
10836 double nearby_radius_meters =
10837 g_Platform->GetSelectRadiusPix() /
10838 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10844 bool mergepoints =
false;
10845 bool createNewRoute =
true;
10846 int existingWaypointCounter = 0;
10848 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10849 curPoint = pasted->GetPoint(i);
10850 nearPoint = pWayPointMan->GetNearbyWaypoint(
10851 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10853 mergepoints =
true;
10854 existingWaypointCounter++;
10862 int answer = wxID_NO;
10866 "There are existing waypoints at the same location as some of the ones "
10867 "you are pasting. Would you like to just merge the pasted data into "
10869 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10870 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10871 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10873 if (answer == wxID_CANCEL) {
10880 if (mergepoints && answer == wxID_YES &&
10881 existingWaypointCounter == pasted->GetnPoints()) {
10884 createNewRoute =
false;
10890 Route *newRoute = 0;
10893 if (createNewRoute) {
10894 newRoute =
new Route();
10898 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10899 curPoint = pasted->GetPoint(i);
10902 newPoint = pWayPointMan->GetNearbyWaypoint(
10903 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10904 newPoint->SetName(curPoint->GetName());
10907 if (createNewRoute) newRoute->AddPoint(newPoint);
10913 newPoint->SetIconName(
"circle");
10916 newPoint->SetShared(
false);
10918 newRoute->AddPoint(newPoint);
10919 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10922 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10925 if (i > 1 && createNewRoute)
10926 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10927 curPoint->m_lat, curPoint->m_lon,
10928 prevPoint, newPoint, newRoute);
10929 prevPoint = newPoint;
10932 if (createNewRoute) {
10935 NavObj_dB::GetInstance().InsertRoute(newRoute);
10941 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10942 pRouteManagerDialog->UpdateRouteListCtrl();
10943 pRouteManagerDialog->UpdateWptListCtrl();
10945 gFrame->InvalidateAllGL();
10946 gFrame->RefreshAllCanvas(
false);
10952void pupHandler_PasteTrack() {
10955 int pasteBuffer = kml.ParsePasteBuffer();
10956 Track *pasted = kml.GetParsedTrack();
10957 if (!pasted)
return;
10965 newTrack->SetName(pasted->GetName());
10967 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10968 curPoint = pasted->GetPoint(i);
10972 wxDateTime now = wxDateTime::Now();
10975 newTrack->AddPoint(newPoint);
10978 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10979 newPoint->m_lat, newPoint->m_lon,
10980 prevPoint, newPoint, newTrack);
10982 prevPoint = newPoint;
10987 NavObj_dB::GetInstance().InsertTrack(newTrack);
10989 gFrame->InvalidateAllGL();
10990 gFrame->RefreshAllCanvas(
false);
10993bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10996 v[
"CursorPosition_x"] = x;
10997 v[
"CursorPosition_y"] = y;
11000 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11001 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11002 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11007 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11009 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11012#define SELTYPE_UNKNOWN 0x0001
11013#define SELTYPE_ROUTEPOINT 0x0002
11014#define SELTYPE_ROUTESEGMENT 0x0004
11015#define SELTYPE_TIDEPOINT 0x0008
11016#define SELTYPE_CURRENTPOINT 0x0010
11017#define SELTYPE_ROUTECREATE 0x0020
11018#define SELTYPE_AISTARGET 0x0040
11019#define SELTYPE_MARKPOINT 0x0080
11020#define SELTYPE_TRACKSEGMENT 0x0100
11021#define SELTYPE_DRAGHANDLE 0x0200
11024 if (g_bhide_context_menus)
return true;
11026 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11027 m_pIDXCandidate, m_nmea_log);
11030 wxEVT_COMMAND_MENU_SELECTED,
11031 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11037 if (m_inLongPress) {
11038 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11039 m_inLongPress =
false;
11043 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11046 wxEVT_COMMAND_MENU_SELECTED,
11047 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11049 delete m_canvasMenu;
11050 m_canvasMenu = NULL;
11060void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11063 if (m_canvasMenu) {
11064 m_canvasMenu->PopupMenuHandler(event);
11069void ChartCanvas::StartRoute() {
11071 if (g_brouteCreating)
return;
11075 g_brouteCreating =
true;
11077 m_bDrawingRoute =
false;
11078 SetCursor(*pCursorPencil);
11080 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11082 HideGlobalToolbar();
11085 androidSetRouteAnnunciator(
true);
11089wxString ChartCanvas::FinishRoute() {
11091 m_prev_pMousePoint = NULL;
11092 m_bDrawingRoute =
false;
11094 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11097 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11099 androidSetRouteAnnunciator(
false);
11102 SetCursor(*pCursorArrow);
11104 if (m_pMouseRoute) {
11105 if (m_bAppendingRoute) {
11107 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11109 if (m_pMouseRoute->GetnPoints() > 1) {
11111 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11114 m_pMouseRoute = NULL;
11117 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11124 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11125 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11126 pRouteManagerDialog->UpdateRouteListCtrl();
11129 m_bAppendingRoute =
false;
11130 m_pMouseRoute = NULL;
11132 m_pSelectedRoute = NULL;
11134 undo->InvalidateUndo();
11135 gFrame->RefreshAllCanvas(
true);
11139 ShowGlobalToolbar();
11141 g_brouteCreating =
false;
11146void ChartCanvas::HideGlobalToolbar() {
11147 if (m_canvasIndex == 0) {
11148 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11152void ChartCanvas::ShowGlobalToolbar() {
11153 if (m_canvasIndex == 0) {
11154 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11158void ChartCanvas::ShowAISTargetList() {
11159 if (NULL == g_pAISTargetList) {
11163 g_pAISTargetList->UpdateAISTargetList();
11166void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11167 if (!m_bShowOutlines)
return;
11171 int nEntry =
ChartData->GetChartTableEntries();
11173 for (
int i = 0; i < nEntry; i++) {
11177 bool b_group_draw =
false;
11178 if (m_groupIndex > 0) {
11179 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11180 int index = pt->GetGroupArray()[ig];
11181 if (m_groupIndex == index) {
11182 b_group_draw =
true;
11187 b_group_draw =
true;
11189 if (b_group_draw) RenderChartOutline(dc, i, vp);
11195 if (VPoint.b_quilt) {
11196 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11197 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11201 }
else if (m_singleChart &&
11202 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11206 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11209 if (zoom_factor > 8.0) {
11210 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11213 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11217 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11221void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11223 if (g_bopengl && m_glcc) {
11225 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11230 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11231 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11234 float plylat, plylon;
11235 float plylat1, plylon1;
11237 int pixx, pixy, pixx1, pixy1;
11240 ChartData->GetDBBoundingBox(dbIndex, box);
11244 if (box.GetLonRange() == 360)
return;
11246 double lon_bias = 0;
11248 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11250 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11252 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11253 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11255 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11256 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11259 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11262 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11263 if (0 == nAuxPlyEntries)
11267 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11268 plylon += lon_bias;
11274 for (
int i = 0; i < nPly - 1; i++) {
11275 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11276 plylon1 += lon_bias;
11282 int pixxs1 = pixx1;
11283 int pixys1 = pixy1;
11285 bool b_skip =
false;
11289 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11290 pow((
double)(pixy1 - pixy), 2)) /
11296 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11301 if (fabs(dist - distgc) > 10000. * 1852.)
11307 ClipResult res = cohen_sutherland_line_clip_i(
11309 if (res != Invisible && !b_skip)
11310 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11318 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11319 plylon1 += lon_bias;
11325 ClipResult res = cohen_sutherland_line_clip_i(
11327 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11334 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11335 for (
int j = 0; j < nAuxPlyEntries; j++) {
11337 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11342 for (
int i = 0; i < nAuxPly - 1; i++) {
11343 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11349 int pixxs1 = pixx1;
11350 int pixys1 = pixy1;
11352 bool b_skip =
false;
11356 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11357 ((pixy1 - pixy) * (pixy1 - pixy))) /
11362 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11367 if (fabs(dist - distgc) > 10000. * 1852.)
11373 ClipResult res = cohen_sutherland_line_clip_i(
11375 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11383 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11388 ClipResult res = cohen_sutherland_line_clip_i(
11390 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11395static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11396 const wxString &second) {
11397 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11399 int pointsize = dFont->GetPointSize();
11403 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11404 false, dFont->GetFaceName());
11406 dc.SetFont(*psRLI_font);
11414 int hilite_offset = 3;
11417 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11418 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11420 dc.GetTextExtent(first, &w1, &h1);
11421 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11427 w = wxMax(w1, w2) + (h1 / 2);
11432 xp = ref_point.x - w;
11434 yp += hilite_offset;
11436 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11438 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11439 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11441 dc.DrawText(first, xp, yp);
11442 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11445void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11446 if (!g_bAllowShipToActive)
return;
11452 wxPoint2DDouble pa, pb;
11459 if (rt->
m_width != wxPENSTYLE_INVALID)
11461 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11462 g_shipToActiveStyle, 5)];
11463 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11465 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11468 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11471 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11474 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11475 (
int)pb.m_y, GetVP(),
true);
11479#ifdef USE_ANDROID_GLES2
11480 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11482 if (style != wxPENSTYLE_SOLID) {
11483 if (glChartCanvas::dash_map.find(style) !=
11484 glChartCanvas::dash_map.end()) {
11485 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11489 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11492 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11493 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11499void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11501 if (m_routeState >= 2) route = m_pMouseRoute;
11502 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11503 route = m_pMeasureRoute;
11505 if (!route)
return;
11513 int np = route->GetnPoints();
11515 if (g_btouch && (np > 1)) np--;
11517 render_lat = rp.m_lat;
11518 render_lon = rp.m_lon;
11521 double rhumbBearing, rhumbDist;
11523 &rhumbBearing, &rhumbDist);
11524 double brg = rhumbBearing;
11525 double dist = rhumbDist;
11529 double gcBearing, gcBearing2, gcDist;
11530 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11533 double gcDistm = gcDist / 1852.0;
11536 rhumbBearing = 90.;
11538 wxPoint destPoint, lastPoint;
11541 int milesDiff = rhumbDist - gcDistm;
11542 if (milesDiff > 1) {
11553 for (
int i = 1; i <= milesDiff; i++) {
11554 double p = (double)i * (1.0 / (
double)milesDiff);
11556 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11557 &pLon, &pLat, &gcBearing2);
11559 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11561 lastPoint = destPoint;
11564 if (r_rband.x && r_rband.y) {
11565 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11567 if (m_bMeasure_DistCircle) {
11568 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11569 powf((
float)(r_rband.y - lastPoint.y), 2));
11572 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11573 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11579 wxString routeInfo;
11582 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11588 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11590 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11591 (
int)varBrg, 0x00B0);
11598 routeInfo <<
"\nReverse: ";
11600 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11601 (
int)(brg + 180.) % 360, 0x00B0);
11603 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11604 (
int)(varBrg + 180.) % 360, 0x00B0);
11609 s0.Append(_(
"Route") +
": ");
11611 s0.Append(_(
"Layer Route: "));
11614 if (!g_btouch) disp_length += dist;
11617 RouteLegInfo(dc, r_rband, routeInfo, s0);
11619 m_brepaint_piano =
true;
11622void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11623 if (!m_bShowVisibleSectors)
return;
11625 if (g_bDeferredInitDone) {
11627 double rhumbBearing, rhumbDist;
11628 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11629 &rhumbBearing, &rhumbDist);
11631 if (rhumbDist > 0.05)
11633 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11634 m_sectorlegsVisible);
11635 m_sector_glat =
gLat;
11636 m_sector_glon =
gLon;
11638 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11642void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11650void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11651 if (!ps52plib)
return;
11653 if (VPoint.b_quilt) {
11654 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11656 if (m_pQuilt->IsQuiltVector()) {
11657 if (ps52plib->GetStateHash() != m_s52StateHash) {
11659 m_s52StateHash = ps52plib->GetStateHash();
11663 if (ps52plib->GetStateHash() != m_s52StateHash) {
11665 m_s52StateHash = ps52plib->GetStateHash();
11670 bool bSendPlibState =
true;
11671 if (VPoint.b_quilt) {
11672 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11675 if (bSendPlibState) {
11677 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11678 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11679 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11680 v[
"OpenCPN Version Date"] = VERSION_DATE;
11681 v[
"OpenCPN Version Full"] = VERSION_FULL;
11684 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11685 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11686 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11687 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11688 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11689 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11690 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11694 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11695 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11699 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11700 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11701 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11702 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11703 ps52plib->m_bShowS57ImportantTextOnly;
11704 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11705 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11706 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11707 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11708 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11711 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11712 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11713 v[
"OpenCPN Scale Factor Exp"] =
11714 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11721 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11722 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11723 g_lastS52PLIBPluginMessage = out;
11730 wxPaintDC dc(
this);
11740 if (!m_b_paint_enable) {
11748 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11750 if (m_glcc && g_bopengl) {
11751 if (!s_in_update) {
11761 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11763 wxRegion ru = GetUpdateRegion();
11765 int rx, ry, rwidth, rheight;
11766 ru.GetBox(rx, ry, rwidth, rheight);
11768#ifdef ocpnUSE_DIBSECTION
11771 wxMemoryDC temp_dc;
11779 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11780 height += m_Piano->GetHeight();
11782 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11786 int thumbx, thumby, thumbsx, thumbsy;
11787 pthumbwin->GetPosition(&thumbx, &thumby);
11788 pthumbwin->GetSize(&thumbsx, &thumbsy);
11789 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11792 rgn_chart.Subtract(rgn_thumbwin);
11793 ru.Subtract(rgn_thumbwin);
11799 wxRegion rgn_blit = ru;
11800 if (g_bShowChartBar) {
11801 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11802 GetClientSize().x, m_Piano->GetHeight());
11805 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11806 if (style->chartStatusWindowTransparent)
11807 m_brepaint_piano =
true;
11809 ru.Subtract(chart_bar_rect);
11813 if (m_Compass && m_Compass->IsShown()) {
11814 wxRect compassRect = m_Compass->
GetRect();
11815 if (ru.Contains(compassRect) != wxOutRegion) {
11816 ru.Subtract(compassRect);
11820 if (m_notification_button) {
11821 wxRect noteRect = m_notification_button->
GetRect();
11822 if (ru.Contains(noteRect) != wxOutRegion) {
11823 ru.Subtract(noteRect);
11828 bool b_newview =
true;
11833 m_cache_vp.IsValid()) {
11839 bool b_rcache_ok =
false;
11840 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11841 b_rcache_ok = !b_newview;
11844 if (VPoint.b_MercatorProjectionOverride)
11845 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11859 if (b_rcache_ok) chart_get_region.Clear();
11862 if (VPoint.b_quilt)
11864 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11866 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11871 AbstractPlatform::ShowBusySpinner();
11875 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11876 (m_working_bm.GetHeight() != svp.
pix_height))
11880 if (fabs(VPoint.
rotation) < 0.01) {
11881 bool b_save =
true;
11886 m_cache_vp.Invalidate();
11900 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11905 int dy = c_new.y - c_old.y;
11906 int dx = c_new.x - c_old.x;
11911 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11915 temp_dc.SelectObject(m_working_bm);
11917 wxMemoryDC cache_dc;
11918 cache_dc.SelectObject(m_cached_chart_bm);
11922 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11925 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11931 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11934 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11942 update_region.Union(
11945 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11950 update_region.Union(
11953 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11957 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11959 cache_dc.SelectObject(wxNullBitmap);
11963 temp_dc.SelectObject(m_cached_chart_bm);
11966 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11970 temp_dc.SelectObject(m_working_bm);
11971 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11976 temp_dc.SelectObject(m_cached_chart_bm);
11981 temp_dc.SelectObject(m_working_bm);
11982 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11995 wxMemoryDC scratch_dc_0;
11996 scratch_dc_0.SelectObject(m_cached_chart_bm);
11999 scratch_dc_0.SelectObject(wxNullBitmap);
12008 temp_dc.SelectObject(m_working_bm);
12011 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12012 chart_get_all_region);
12015 AbstractPlatform::HideBusySpinner();
12021 if (!m_singleChart) {
12022 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12027 if (!chart_get_region.IsEmpty()) {
12028 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12032 if (temp_dc.IsOk()) {
12037 if (!VPoint.b_quilt) {
12040 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12041 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12048 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12049 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12052 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12054 temp_dc.DestroyClippingRegion();
12059 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12061 if (!backgroundRegion.IsEmpty()) {
12067 wxColour water = pWorldBackgroundChart->water;
12068 if (water.IsOk()) {
12069 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12070 temp_dc.SetBrush(wxBrush(water));
12072 while (upd.HaveRects()) {
12073 wxRect rect = upd.GetRect();
12074 temp_dc.DrawRectangle(rect);
12079 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12080 temp_dc.SetDeviceClippingRegion(*clip_region);
12081 delete clip_region;
12085 SetVPRotation(VPoint.
skew);
12094 wxMemoryDC *pChartDC = &temp_dc;
12095 wxMemoryDC rotd_dc;
12097 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12099 if (!b_rcache_ok) {
12101 wxMemoryDC tbase_dc;
12103 tbase_dc.SelectObject(bm_base);
12105 tbase_dc.SelectObject(wxNullBitmap);
12107 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12110 wxImage base_image;
12111 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12119 bool b_rot_ok =
false;
12120 if (base_image.IsOk()) {
12123 m_b_rot_hidef =
false;
12127 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12128 m_b_rot_hidef, &m_roffset);
12133 rot_vp.IsValid() && (ri.IsOk())) {
12140 m_prot_bm =
new wxBitmap(ri);
12143 m_roffset.x += VPoint.rv_rect.x;
12144 m_roffset.y += VPoint.rv_rect.y;
12147 if (m_prot_bm && m_prot_bm->IsOk()) {
12148 rotd_dc.SelectObject(*m_prot_bm);
12149 pChartDC = &rotd_dc;
12151 pChartDC = &temp_dc;
12152 m_roffset = wxPoint(0, 0);
12155 pChartDC = &temp_dc;
12156 m_roffset = wxPoint(0, 0);
12159 wxPoint offset = m_roffset;
12162 m_cache_vp = VPoint;
12165 wxMemoryDC mscratch_dc;
12166 mscratch_dc.SelectObject(*pscratch_bm);
12168 mscratch_dc.ResetBoundingBox();
12169 mscratch_dc.DestroyClippingRegion();
12170 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12173 wxRegionIterator upd(rgn_blit);
12175 wxRect rect = upd.GetRect();
12177 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12178 rect.x - offset.x, rect.y - offset.y);
12184 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12185 if (
this == wxWindow::FindFocus()) {
12188 wxColour colour = GetGlobalColor(
"BLUE4");
12189 mscratch_dc.SetPen(wxPen(colour));
12190 mscratch_dc.SetBrush(wxBrush(colour));
12192 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12193 mscratch_dc.DrawRectangle(activeRect);
12198 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12199 unsigned int im = stackIndexArray.size();
12200 if (VPoint.b_quilt && im > 0) {
12201 std::vector<int> tiles_to_show;
12202 for (
unsigned int is = 0; is < im; is++) {
12204 ChartData->GetChartTableEntry(stackIndexArray[is]);
12205 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12208 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12209 tiles_to_show.push_back(stackIndexArray[is]);
12213 if (tiles_to_show.size())
12214 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12220 ocpnDC scratch_dc(mscratch_dc);
12221 RenderAlertMessage(mscratch_dc, GetVP());
12227#ifdef ocpnUSE_DIBSECTION
12232 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12233 q_dc.SelectObject(qbm);
12236 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12239 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12240 q_dc.SetBrush(qbr);
12241 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12244 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12247 q_dc.SelectObject(wxNullBitmap);
12256 if( VPoint.b_quilt ) {
12257 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12258 ChartBase *chart = m_pQuilt->GetRefChart();
12259 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12264 ChPI->ClearPLIBTextList();
12267 ps52plib->ClearTextList();
12271 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12273 wxColor maskBackground = wxColour(1,0,0);
12274 t_dc.SelectObject( qbm );
12275 t_dc.SetBackground(wxBrush(maskBackground));
12279 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12282 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12283 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12286 wxRegionIterator upd_final( ru );
12287 while( upd_final ) {
12288 wxRect rect = upd_final.GetRect();
12289 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12293 t_dc.SelectObject( wxNullBitmap );
12299 if (VPoint.b_quilt) {
12300 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12301 ChartBase *chart = m_pQuilt->GetRefChart();
12302 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12306 ChPI->ClearPLIBTextList();
12308 if (ps52plib) ps52plib->ClearTextList();
12313 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12315 if (g_bShowChartBar && m_Piano) {
12316 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12317 GetVP().pix_width, m_Piano->GetHeight());
12320 if (!style->chartStatusWindowTransparent)
12321 chart_all_text_region.Subtract(chart_bar_rect);
12324 if (m_Compass && m_Compass->IsShown()) {
12325 wxRect compassRect = m_Compass->
GetRect();
12326 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12327 chart_all_text_region.Subtract(compassRect);
12331 mscratch_dc.DestroyClippingRegion();
12333 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12334 chart_all_text_region);
12340 ocpnDC scratch_dc(mscratch_dc);
12341 DrawOverlayObjects(scratch_dc, ru);
12344 wxRegionIterator upd_final(rgn_blit);
12345 while (upd_final) {
12346 wxRect rect = upd_final.GetRect();
12347 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12354 temp_dc.SelectObject(wxNullBitmap);
12356 mscratch_dc.SelectObject(wxNullBitmap);
12358 dc.DestroyClippingRegion();
12363void ChartCanvas::PaintCleanup() {
12365 if (m_inPinch)
return;
12376 m_bTCupdate =
false;
12380 WarpPointer(warp_x, warp_y);
12387 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12388 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12392wxColour GetErrorGraphicColor(
double val)
12411 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12412 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12413 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12414 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12415 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12416 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12417 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12418 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12419 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12420 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12421 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12422 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12423 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12424 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12425 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12426 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12427 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12428 else if( val >= 48) c.Set(
"#410000");
12433void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12436 gr_image.InitAlpha();
12438 double maxval = -10000;
12439 double minval = 10000;
12456 maxval = wxMax(maxval, (glat - rlat));
12457 minval = wxMin(minval, (glat - rlat));
12474 double f = ((glat - rlat)-minval)/(maxval - minval);
12476 double dy = (f * 40);
12478 wxColour c = GetErrorGraphicColor(dy);
12479 unsigned char r = c.Red();
12480 unsigned char g = c.Green();
12481 unsigned char b = c.Blue();
12483 gr_image.SetRGB(j, i, r,g,b);
12484 if((glat - rlat )!= 0)
12485 gr_image.SetAlpha(j, i, 128);
12487 gr_image.SetAlpha(j, i, 255);
12494 wxBitmap *pbm =
new wxBitmap(gr_image);
12495 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12496 pbm->SetMask(gr_mask);
12498 pmdc->DrawBitmap(*pbm, 0,0);
12506void ChartCanvas::CancelMouseRoute() {
12508 m_pMouseRoute = NULL;
12509 m_bDrawingRoute =
false;
12512int ChartCanvas::GetNextContextMenuId() {
12513 return CanvasMenuHandler::GetNextContextMenuId();
12516bool ChartCanvas::SetCursor(
const wxCursor &c) {
12518 if (g_bopengl && m_glcc)
12519 return m_glcc->SetCursor(c);
12522 return wxWindow::SetCursor(c);
12525void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12526 if (g_bquiting)
return;
12536 if (!m_RolloverPopupTimer.IsRunning() &&
12537 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12538 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12539 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12540 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12543 if (m_glcc && g_bopengl) {
12546 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12548 m_glcc->Refresh(eraseBackground,
12565 if (m_pCIWin && m_pCIWin->IsShown()) {
12567 m_pCIWin->Refresh(
false);
12575 wxWindow::Refresh(eraseBackground, rect);
12578void ChartCanvas::Update() {
12579 if (m_glcc && g_bopengl) {
12584 wxWindow::Update();
12588 if (!pemboss)
return;
12589 int x = pemboss->x, y = pemboss->y;
12590 const double factor = 200;
12592 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12593 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12594 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12597 wxMemoryDC snip_dc;
12598 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12599 snip_dc.SelectObject(snip_bmp);
12601 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12602 snip_dc.SelectObject(wxNullBitmap);
12604 wxImage snip_img = snip_bmp.ConvertToImage();
12607 unsigned char *pdata = snip_img.GetData();
12609 for (
int y = 0; y < pemboss->height; y++) {
12610 int map_index = (y * pemboss->width);
12611 for (
int x = 0; x < pemboss->width; x++) {
12612 double val = (pemboss->pmap[map_index] * factor) / 256.;
12614 int nred = (int)((*pdata) + val);
12615 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12616 *pdata++ = (
unsigned char)nred;
12618 int ngreen = (int)((*pdata) + val);
12619 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12620 *pdata++ = (
unsigned char)ngreen;
12622 int nblue = (int)((*pdata) + val);
12623 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12624 *pdata++ = (
unsigned char)nblue;
12632 wxBitmap emb_bmp(snip_img);
12635 wxMemoryDC result_dc;
12636 result_dc.SelectObject(emb_bmp);
12639 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12641 result_dc.SelectObject(wxNullBitmap);
12647 if (GetQuiltMode()) {
12649 int refIndex = GetQuiltRefChartdbIndex();
12650 if (refIndex >= 0) {
12652 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12653 if (current_type == CHART_TYPE_MBTILES) {
12654 ChartBase *pChart = m_pQuilt->GetRefChart();
12657 zoom_factor = ptc->GetZoomFactor();
12662 if (zoom_factor <= 3.9)
return NULL;
12664 if (m_singleChart) {
12665 if (zoom_factor <= 3.9)
return NULL;
12670 if (m_pEM_OverZoom) {
12671 m_pEM_OverZoom->x = 4;
12672 m_pEM_OverZoom->y = 0;
12674 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12675 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12678 return m_pEM_OverZoom;
12681void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12694 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12695 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12699 AISDrawAreaNotices(dc, GetVP(),
this);
12701 wxDC *pdc = dc.GetDC();
12703 pdc->DestroyClippingRegion();
12704 wxDCClipper(*pdc, ru);
12707 if (m_bShowNavobjects) {
12708 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12709 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12710 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12711 DrawAnchorWatchPoints(dc);
12713 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12714 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12717 AISDraw(dc, GetVP(),
this);
12721 RenderVisibleSectorLights(dc);
12723 RenderAllChartOutlines(dc, GetVP());
12724 RenderRouteLegs(dc);
12725 RenderShipToActive(dc,
false);
12727 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12729 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12733 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12734 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12737 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12742 RebuildTideSelectList(GetVP().GetBBox());
12743 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12746 if (m_bShowCurrent) {
12747 RebuildCurrentSelectList(GetVP().GetBBox());
12748 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12751 if (!g_PrintingInProgress) {
12752 if (IsPrimaryCanvas()) {
12756 if (IsPrimaryCanvas()) {
12760 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12762 if (m_pTrackRolloverWin) {
12763 m_pTrackRolloverWin->Draw(dc);
12764 m_brepaint_piano =
true;
12767 if (m_pRouteRolloverWin) {
12768 m_pRouteRolloverWin->Draw(dc);
12769 m_brepaint_piano =
true;
12772 if (m_pAISRolloverWin) {
12773 m_pAISRolloverWin->Draw(dc);
12774 m_brepaint_piano =
true;
12776 if (m_brepaint_piano && g_bShowChartBar) {
12777 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12780 if (m_Compass) m_Compass->Paint(dc);
12782 if (!g_CanvasHideNotificationIcon) {
12783 if (IsPrimaryCanvas()) {
12784 auto ¬eman = NotificationManager::GetInstance();
12785 if (noteman.GetNotificationCount()) {
12786 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12787 if (m_notification_button->UpdateStatus()) Refresh();
12788 m_notification_button->Show(
true);
12789 m_notification_button->Paint(dc);
12791 m_notification_button->Show(
false);
12797 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12803 if (!m_bShowDepthUnits)
return NULL;
12805 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12807 if (GetQuiltMode()) {
12808 wxString s = m_pQuilt->GetQuiltDepthUnit();
12811 depth_unit_type = DEPTH_UNIT_FEET;
12812 else if (s.StartsWith(
"FATHOMS"))
12813 depth_unit_type = DEPTH_UNIT_FATHOMS;
12814 else if (s.StartsWith(
"METERS"))
12815 depth_unit_type = DEPTH_UNIT_METERS;
12816 else if (s.StartsWith(
"METRES"))
12817 depth_unit_type = DEPTH_UNIT_METERS;
12818 else if (s.StartsWith(
"METRIC"))
12819 depth_unit_type = DEPTH_UNIT_METERS;
12820 else if (s.StartsWith(
"METER"))
12821 depth_unit_type = DEPTH_UNIT_METERS;
12824 if (m_singleChart) {
12825 depth_unit_type = m_singleChart->GetDepthUnitType();
12826 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12827 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12832 switch (depth_unit_type) {
12833 case DEPTH_UNIT_FEET:
12836 case DEPTH_UNIT_METERS:
12837 ped = m_pEM_Meters;
12839 case DEPTH_UNIT_FATHOMS:
12840 ped = m_pEM_Fathoms;
12846 ped->x = (GetVP().
pix_width - ped->width);
12848 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12849 wxRect r = m_Compass->
GetRect();
12850 ped->y = r.y + r.height;
12857void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12860 if (style->embossFont == wxEmptyString) {
12861 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12863 font.SetPointSize(60);
12864 font.SetWeight(wxFONTWEIGHT_BOLD);
12866 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12867 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12869 int emboss_width = 500;
12870 int emboss_height = 200;
12874 delete m_pEM_Meters;
12875 delete m_pEM_Fathoms;
12879 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12881 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12883 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12886#define OVERZOOM_TEXT _("OverZoom")
12888void ChartCanvas::SetOverzoomFont() {
12893 if (style->embossFont == wxEmptyString) {
12894 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12896 font.SetPointSize(40);
12897 font.SetWeight(wxFONTWEIGHT_BOLD);
12899 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12900 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12902 wxClientDC dc(
this);
12904 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12906 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12907 font.SetPointSize(font.GetPointSize() - 1);
12909 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12911 m_overzoomFont = font;
12912 m_overzoomTextWidth = w;
12913 m_overzoomTextHeight = h;
12916void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12917 delete m_pEM_OverZoom;
12919 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12921 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12922 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12925emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12926 int height,
const wxString &str,
12931 wxBitmap bmp(width, height, -1);
12934 wxMemoryDC temp_dc;
12935 temp_dc.SelectObject(bmp);
12938 temp_dc.SetBackground(*wxWHITE_BRUSH);
12939 temp_dc.SetTextBackground(*wxWHITE);
12940 temp_dc.SetTextForeground(*wxBLACK);
12944 temp_dc.SetFont(font);
12947 temp_dc.GetTextExtent(str, &str_w, &str_h);
12949 temp_dc.DrawText(str, 1, 1);
12952 temp_dc.SelectObject(wxNullBitmap);
12955 wxImage img = bmp.ConvertToImage();
12957 int image_width = str_w * 105 / 100;
12958 int image_height = str_h * 105 / 100;
12959 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12960 wxMin(image_height, img.GetHeight()));
12961 wxImage imgs = img.GetSubImage(r);
12965 case GLOBAL_COLOR_SCHEME_DAY:
12969 case GLOBAL_COLOR_SCHEME_DUSK:
12972 case GLOBAL_COLOR_SCHEME_NIGHT:
12979 const int w = imgs.GetWidth();
12980 const int h = imgs.GetHeight();
12981 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12986 for (
int y = 1; y < h - 1; y++) {
12987 for (
int x = 1; x < w - 1; x++) {
12989 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12990 val = (int)(val * val_factor);
12991 index = (y * w) + x;
13004void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13005 Track *active_track = NULL;
13008 active_track = pTrackDraw;
13012 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13015 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13018void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13019 Track *active_track = NULL;
13022 active_track = pTrackDraw;
13026 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13029void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13030 Route *active_route = NULL;
13032 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13033 active_route = pRouteDraw;
13038 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13043 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13046void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13047 Route *active_route = NULL;
13050 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13051 active_route = pRouteDraw;
13055 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13058void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13059 if (!pWayPointMan)
return;
13061 auto node = pWayPointMan->GetWaypointList()->begin();
13063 while (node != pWayPointMan->GetWaypointList()->end()) {
13072 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13076 if (pWP->GetShowWaypointRangeRings() &&
13077 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13078 double factor = 1.00;
13079 if (pWP->GetWaypointRangeRingsStepUnits() ==
13081 factor = 1 / 1.852;
13083 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13084 pWP->GetWaypointRangeRingsStep() / 60.;
13088 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13089 pWP->m_lat + radius, pWP->m_lon + radius);
13090 if (!BltBBox.IntersectOut(radar_box)) {
13101void ChartCanvas::DrawBlinkObjects() {
13103 wxRect update_rect;
13105 if (!pWayPointMan)
return;
13107 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13114 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13117void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13122 wxPoint lAnchorPoint1, lAnchorPoint2;
13136 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13137 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13139 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13140 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13141 dc.SetBrush(*ppBrush);
13145 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13150 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13155 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13160 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13165double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13168 wxPoint lAnchorPoint;
13171 double tlat1, tlon1;
13173 if (pAnchorWatchPoint) {
13174 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13175 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13176 dabs = fabs(d1 / 1852.);
13177 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13182 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13183 pow((
double)(lAnchorPoint.y - r1.y), 2));
13186 if (d1 < 0) lpp = -lpp;
13194void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13197 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13199 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13205 if ((type ==
't') || (type ==
'T')) {
13206 if (BBox.Contains(lat, lon)) {
13208 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13214void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13217 wxDateTime this_now = gTimeSource;
13218 bool cur_time = !gTimeSource.IsValid();
13219 if (cur_time) this_now = wxDateTime::Now();
13220 time_t t_this_now = this_now.GetTicks();
13222 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13224 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13225 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13226 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13227 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13229 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13230 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13231 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13232 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13233 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13234 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13236 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13237 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13238 int font_size = wxMax(10, dFont->GetPointSize());
13241 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13242 false, dFont->GetFaceName());
13244 dc.SetPen(*pblack_pen);
13245 dc.SetBrush(*pgreen_brush);
13249 case GLOBAL_COLOR_SCHEME_DAY:
13252 case GLOBAL_COLOR_SCHEME_DUSK:
13255 case GLOBAL_COLOR_SCHEME_NIGHT:
13256 bm = m_bmTideNight;
13263 int bmw = bm.GetWidth();
13264 int bmh = bm.GetHeight();
13266 float scale_factor = 1.0;
13270 float icon_pixelRefDim = 45;
13275 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13277 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13279 scale_factor *= pix_factor;
13286 scale_factor *= user_scale_factor;
13287 scale_factor *= GetContentScaleFactor();
13290 double marge = 0.05;
13291 std::vector<LLBBox> drawn_boxes;
13292 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13296 if ((type ==
't') || (type ==
'T'))
13301 if (BBox.ContainsMarge(lat, lon, marge)) {
13303 if (GetVP().chart_scale < 500000) {
13304 bool bdrawn =
false;
13305 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13306 if (drawn_boxes[i].Contains(lat, lon)) {
13311 if (bdrawn)
continue;
13314 this_box.Set(lat, lon, lat, lon);
13315 this_box.EnLarge(.005);
13316 drawn_boxes.push_back(this_box);
13322 if (GetVP().chart_scale > 500000) {
13323 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13327 dc.SetFont(*plabelFont);
13339 if (
ptcmgr->GetTideFlowSens(
13340 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13344 ptcmgr->GetHightOrLowTide(
13345 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13346 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13358 if (tctime > t_this_now)
13359 ptcmgr->GetHightOrLowTide(
13360 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13361 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13365 ptcmgr->GetHightOrLowTide(
13366 t_this_now, FORWARD_TEN_MINUTES_STEP,
13367 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13381 int width = (int)(12 * scale_factor + 0.5);
13382 int height = (int)(45 * scale_factor + 0.5);
13383 int linew = wxMax(1, (
int)(scale_factor));
13384 int xDraw = r.x - (width / 2);
13385 int yDraw = r.y - (height / 2);
13388 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13389 int hs = (httime > lttime) ? -4 : 4;
13390 hs *= (int)(scale_factor + 0.5);
13391 if (ts > 0.995 || ts < 0.005) hs = 0;
13392 int ht_y = (int)(height * ts);
13395 pblack_pen->SetWidth(linew);
13396 dc.SetPen(*pblack_pen);
13397 dc.SetBrush(*pyelo_brush);
13398 dc.DrawRectangle(xDraw, yDraw, width, height);
13402 dc.SetPen(*pblue_pen);
13403 dc.SetBrush(*pblue_brush);
13404 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13405 (width - (4 * linew)), height - ht_y);
13411 arrow[0].x = xDraw + 2 * linew;
13412 arrow[1].x = xDraw + width / 2;
13413 arrow[2].x = xDraw + width - 2 * linew;
13414 pyelo_pen->SetWidth(linew);
13415 pblue_pen->SetWidth(linew);
13416 if (ts > 0.35 || ts < 0.15)
13418 hl = (int)(height * 0.25) + yDraw;
13420 arrow[1].y = hl + hs;
13423 dc.SetPen(*pyelo_pen);
13425 dc.SetPen(*pblue_pen);
13426 dc.DrawLines(3, arrow);
13428 if (ts > 0.60 || ts < 0.40)
13430 hl = (int)(height * 0.5) + yDraw;
13432 arrow[1].y = hl + hs;
13435 dc.SetPen(*pyelo_pen);
13437 dc.SetPen(*pblue_pen);
13438 dc.DrawLines(3, arrow);
13440 if (ts < 0.65 || ts > 0.85)
13442 hl = (int)(height * 0.75) + yDraw;
13444 arrow[1].y = hl + hs;
13447 dc.SetPen(*pyelo_pen);
13449 dc.SetPen(*pblue_pen);
13450 dc.DrawLines(3, arrow);
13454 s.Printf(
"%3.1f", nowlev);
13456 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13458 dc.GetTextExtent(s, &wx1, NULL);
13460 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13475void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13478 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13480 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13486 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13487 if ((BBox.Contains(lat, lon))) {
13489 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13495void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13498 float tcvalue, dir;
13502 double lon_last = 0.;
13503 double lat_last = 0.;
13505 double marge = 0.2;
13506 bool cur_time = !gTimeSource.IsValid();
13508 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13509 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13511 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13513 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13514 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13515 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13516 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13517 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13518 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13519 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13520 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13522 double skew_angle = GetVPRotation();
13524 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13525 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13526 int font_size = wxMax(10, dFont->GetPointSize());
13529 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13530 false, dFont->GetFaceName());
13532 float scale_factor = 1.0;
13538 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13540 float nominal_icon_size_pixels = 15;
13541 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13543 scale_factor *= pix_factor;
13550 scale_factor *= user_scale_factor;
13552 scale_factor *= GetContentScaleFactor();
13555 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13561 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13562 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13567 int dd = (int)(5.0 * scale_factor + 0.5);
13578 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13579 dc.SetPen(*pblack_pen);
13580 dc.SetBrush(*porange_brush);
13581 dc.DrawPolygon(4, d);
13584 dc.SetBrush(*pblack_brush);
13585 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13589 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13603 double a1 = fabs(tcvalue) * 10.;
13605 a1 = wxMax(1.0, a1);
13606 double a2 = log10(a1);
13608 float cscale = scale_factor * a2 * 0.3;
13610 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13611 dc.SetPen(*porange_pen);
13612 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13616 if (bDrawCurrentValues) {
13617 dc.SetFont(*pTCFont);
13618 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13619 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13645 if (!pvIDX)
return;
13650 if (pCwin && pCwin->IsShown()) {
13658 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13673 pCwin =
new TCWin(
this, x, y, pvIDX);
13691#define NUM_CURRENT_ARROW_POINTS 9
13692static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13693 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13694 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13695 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13697void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13699 if (
scale > 1e-2) {
13700 float sin_rot = sin(rot_angle * PI / 180.);
13701 float cos_rot = cos(rot_angle * PI / 180.);
13705 float xt = CurrentArrowArray[0].x;
13706 float yt = CurrentArrowArray[0].y;
13708 float xp = (xt * cos_rot) - (yt * sin_rot);
13709 float yp = (xt * sin_rot) + (yt * cos_rot);
13710 int x1 = (int)(xp *
scale);
13711 int y1 = (int)(yp *
scale);
13714 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13715 xt = CurrentArrowArray[ip].x;
13716 yt = CurrentArrowArray[ip].y;
13718 float xp = (xt * cos_rot) - (yt * sin_rot);
13719 float yp = (xt * sin_rot) + (yt * cos_rot);
13720 int x2 = (int)(xp *
scale);
13721 int y2 = (int)(yp *
scale);
13723 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13731wxString ChartCanvas::FindValidUploadPort() {
13734 if (!g_uploadConnection.IsEmpty() &&
13735 g_uploadConnection.StartsWith(
"Serial")) {
13736 port = g_uploadConnection;
13742 for (
auto *cp : TheConnectionParams()) {
13743 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13744 port <<
"Serial:" << cp->Port;
13750void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13753 if (NULL == g_pais_query_dialog_active) {
13754 int pos_x = g_ais_query_dialog_x;
13755 int pos_y = g_ais_query_dialog_y;
13757 if (g_pais_query_dialog_active) {
13758 g_pais_query_dialog_active->Destroy();
13764 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13765 wxPoint(pos_x, pos_y));
13767 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13768 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13769 g_pais_query_dialog_active->SetMMSI(mmsi);
13770 g_pais_query_dialog_active->UpdateText();
13771 wxSize sz = g_pais_query_dialog_active->GetSize();
13773 bool b_reset_pos =
false;
13778 RECT frame_title_rect;
13779 frame_title_rect.left = pos_x;
13780 frame_title_rect.top = pos_y;
13781 frame_title_rect.right = pos_x + sz.x;
13782 frame_title_rect.bottom = pos_y + 30;
13784 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13785 b_reset_pos =
true;
13790 wxRect window_title_rect;
13791 window_title_rect.x = pos_x;
13792 window_title_rect.y = pos_y;
13793 window_title_rect.width = sz.x;
13794 window_title_rect.height = 30;
13796 wxRect ClientRect = wxGetClientDisplayRect();
13797 ClientRect.Deflate(
13799 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13803 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13806 g_pais_query_dialog_active->SetMMSI(mmsi);
13807 g_pais_query_dialog_active->UpdateText();
13810 g_pais_query_dialog_active->Show();
13813void ChartCanvas::ToggleCanvasQuiltMode() {
13814 bool cur_mode = GetQuiltMode();
13816 if (!GetQuiltMode())
13817 SetQuiltMode(
true);
13818 else if (GetQuiltMode()) {
13819 SetQuiltMode(
false);
13820 g_sticky_chart = GetQuiltReferenceChartIndex();
13823 if (cur_mode != GetQuiltMode()) {
13824 SetupCanvasQuiltMode();
13833 if (ps52plib) ps52plib->GenerateStateHash();
13835 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13836 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13839void ChartCanvas::DoCanvasStackDelta(
int direction) {
13840 if (!GetQuiltMode()) {
13841 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13842 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13843 if ((current_stack_index + direction) < 0)
return;
13845 if (m_bpersistent_quilt ) {
13847 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13849 if (IsChartQuiltableRef(new_dbIndex)) {
13850 ToggleCanvasQuiltMode();
13851 SelectQuiltRefdbChart(new_dbIndex);
13852 m_bpersistent_quilt =
false;
13855 SelectChartFromStack(current_stack_index + direction);
13858 std::vector<int> piano_chart_index_array =
13859 GetQuiltExtendedStackdbIndexArray();
13860 int refdb = GetQuiltRefChartdbIndex();
13863 int current_index = -1;
13864 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13865 if (refdb == piano_chart_index_array[i]) {
13870 if (current_index == -1)
return;
13873 int target_family = ctet.GetChartFamily();
13875 int new_index = -1;
13876 int check_index = current_index + direction;
13877 bool found =
false;
13878 int check_dbIndex = -1;
13879 int new_dbIndex = -1;
13883 (
unsigned int)check_index < piano_chart_index_array.size() &&
13884 (check_index >= 0)) {
13885 check_dbIndex = piano_chart_index_array[check_index];
13887 if (target_family == cte.GetChartFamily()) {
13889 new_index = check_index;
13890 new_dbIndex = check_dbIndex;
13894 check_index += direction;
13897 if (!found)
return;
13899 if (!IsChartQuiltableRef(new_dbIndex)) {
13900 ToggleCanvasQuiltMode();
13901 SelectdbChart(new_dbIndex);
13902 m_bpersistent_quilt =
true;
13904 SelectQuiltRefChart(new_index);
13908 gFrame->UpdateGlobalMenuItems();
13910 SetQuiltChartHiLiteIndex(-1);
13921void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13924 switch (event.GetId()) {
13936 DoCanvasStackDelta(1);
13941 DoCanvasStackDelta(-1);
13951 ShowCurrents(!GetbShowCurrent());
13958 ShowTides(!GetbShowTide());
13965 if (0 == m_routeState) {
13972 androidSetRouteAnnunciator(m_routeState == 1);
13978 SetAISCanvasDisplayStyle(-1);
13990void ChartCanvas::SetShowAIS(
bool show) {
13992 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13993 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13996void ChartCanvas::SetAttenAIS(
bool show) {
13997 m_bShowAISScaled = show;
13998 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13999 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14002void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14005 bool bShowAIS_Array[3] = {
true,
true,
false};
14006 bool bShowScaled_Array[3] = {
false,
true,
true};
14007 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14008 _(
"Attenuate less critical AIS targets"),
14009 _(
"Hide AIS Targets")};
14010 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14012 int AIS_Toolbar_Switch = 0;
14013 if (StyleIndx == -1) {
14015 for (
int i = 1; i < ArraySize; i++) {
14016 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14017 (bShowScaled_Array[i] == m_bShowAISScaled))
14018 AIS_Toolbar_Switch = i;
14020 AIS_Toolbar_Switch++;
14021 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14022 AIS_Toolbar_Switch++;
14025 AIS_Toolbar_Switch = StyleIndx;
14028 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14030 int AIS_Toolbar_Switch_Next =
14031 AIS_Toolbar_Switch + 1;
14032 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14033 AIS_Toolbar_Switch_Next++;
14034 if (AIS_Toolbar_Switch_Next >= ArraySize)
14035 AIS_Toolbar_Switch_Next = 0;
14038 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14039 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14042void ChartCanvas::TouchAISToolActive() {}
14044void ChartCanvas::UpdateAISTBTool() {}
14052void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14054 bool b_update =
false;
14055 int cc1_edge_comp = 2;
14056 wxRect rect = m_Compass->
GetRect();
14057 wxSize parent_size = GetSize();
14059 parent_size *= m_displayScale;
14063 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14064 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14065 wxRect compass_rect(compass_pt, rect.GetSize());
14067 m_Compass->Move(compass_pt);
14069 if (m_Compass && m_Compass->IsShown())
14070 m_Compass->UpdateStatus(b_force_new | b_update);
14072 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14073 scaler = wxMax(scaler, 1.0);
14074 wxPoint note_point = wxPoint(
14075 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14076 if (m_notification_button) {
14077 m_notification_button->Move(note_point);
14078 m_notification_button->UpdateStatus();
14081 if (b_force_new | b_update) Refresh();
14084void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14085 ChartTypeEnum New_Type,
14086 ChartFamilyEnum New_Family) {
14087 if (!GetpCurrentStack())
return;
14090 if (index < GetpCurrentStack()->nEntry) {
14093 pTentative_Chart =
ChartData->OpenStackChartConditional(
14094 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14096 if (pTentative_Chart) {
14097 if (m_singleChart) m_singleChart->Deactivate();
14099 m_singleChart = pTentative_Chart;
14100 m_singleChart->Activate();
14102 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14103 GetpCurrentStack(), m_singleChart->GetFullPath());
14116 double best_scale_ppm = GetBestVPScale(m_singleChart);
14117 double rotation = GetVPRotation();
14118 double oldskew = GetVPSkew();
14119 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14121 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14122 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14123 if (fabs(newskew) > 0.0001) rotation = newskew;
14126 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14128 UpdateGPSCompassStatusBox(
true);
14132 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14133 if (idx < 0)
return;
14135 std::vector<int> piano_active_chart_index_array;
14136 piano_active_chart_index_array.push_back(
14137 GetpCurrentStack()->GetCurrentEntrydbIndex());
14138 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14141void ChartCanvas::SelectdbChart(
int dbindex) {
14142 if (!GetpCurrentStack())
return;
14145 if (dbindex >= 0) {
14148 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14150 if (pTentative_Chart) {
14151 if (m_singleChart) m_singleChart->Deactivate();
14153 m_singleChart = pTentative_Chart;
14154 m_singleChart->Activate();
14156 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14157 GetpCurrentStack(), m_singleChart->GetFullPath());
14170 double best_scale_ppm = GetBestVPScale(m_singleChart);
14174 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14184void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14187 if (!GetQuiltMode()) {
14188 if (GetpCurrentStack()) {
14189 int stack_index = -1;
14190 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14191 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14192 if (check_dbIndex < 0)
continue;
14194 ChartData->GetChartTableEntry(check_dbIndex);
14195 if (type == cte.GetChartType()) {
14198 }
else if (family == cte.GetChartFamily()) {
14204 if (stack_index >= 0) {
14205 SelectChartFromStack(stack_index);
14209 int sel_dbIndex = -1;
14210 std::vector<int> piano_chart_index_array =
14211 GetQuiltExtendedStackdbIndexArray();
14212 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14213 int check_dbIndex = piano_chart_index_array[i];
14215 if (type == cte.GetChartType()) {
14216 if (IsChartQuiltableRef(check_dbIndex)) {
14217 sel_dbIndex = check_dbIndex;
14220 }
else if (family == cte.GetChartFamily()) {
14221 if (IsChartQuiltableRef(check_dbIndex)) {
14222 sel_dbIndex = check_dbIndex;
14228 if (sel_dbIndex >= 0) {
14229 SelectQuiltRefdbChart(sel_dbIndex,
false);
14231 AdjustQuiltRefChart();
14238 SetQuiltChartHiLiteIndex(-1);
14243bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14244 return std::find(m_tile_yesshow_index_array.begin(),
14245 m_tile_yesshow_index_array.end(),
14246 index) != m_tile_yesshow_index_array.end();
14249bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14250 return std::find(m_tile_noshow_index_array.begin(),
14251 m_tile_noshow_index_array.end(),
14252 index) != m_tile_noshow_index_array.end();
14255void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14256 if (std::find(m_tile_noshow_index_array.begin(),
14257 m_tile_noshow_index_array.end(),
14258 index) == m_tile_noshow_index_array.end()) {
14259 m_tile_noshow_index_array.push_back(index);
14269void ChartCanvas::HandlePianoClick(
14270 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14273 if (!m_pCurrentStack)
return;
14289 double distance = 25000;
14290 int closest_index = -1;
14291 for (
int chart_index : selected_dbIndex_array) {
14293 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14294 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14297 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14298 if (test_distance < distance) {
14299 distance = test_distance;
14300 closest_index = chart_index;
14304 int selected_dbIndex = selected_dbIndex_array[0];
14305 if (closest_index >= 0) selected_dbIndex = closest_index;
14307 if (!GetQuiltMode()) {
14308 if (m_bpersistent_quilt ) {
14309 if (IsChartQuiltableRef(selected_dbIndex)) {
14310 ToggleCanvasQuiltMode();
14311 SelectQuiltRefdbChart(selected_dbIndex);
14312 m_bpersistent_quilt =
false;
14314 SelectChartFromStack(selected_index);
14317 SelectChartFromStack(selected_index);
14318 g_sticky_chart = selected_dbIndex;
14322 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14326 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14327 bool bfound =
false;
14328 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14329 if (m_tile_noshow_index_array[i] ==
14330 selected_dbIndex) {
14331 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14338 m_tile_noshow_index_array.push_back(selected_dbIndex);
14342 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14343 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14347 if (IsChartQuiltableRef(selected_dbIndex)) {
14353 bool set_scale =
false;
14354 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14355 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14361 SelectQuiltRefdbChart(selected_dbIndex,
true);
14363 SelectQuiltRefdbChart(selected_dbIndex,
false);
14368 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14370 double proposed_scale_onscreen =
14373 if (g_bPreserveScaleOnX) {
14374 proposed_scale_onscreen =
14375 wxMin(proposed_scale_onscreen,
14377 GetCanvasWidth()));
14379 proposed_scale_onscreen =
14380 wxMin(proposed_scale_onscreen,
14382 GetCanvasWidth()));
14384 proposed_scale_onscreen =
14385 wxMax(proposed_scale_onscreen,
14394 ToggleCanvasQuiltMode();
14395 SelectdbChart(selected_dbIndex);
14396 m_bpersistent_quilt =
true;
14401 SetQuiltChartHiLiteIndex(-1);
14402 gFrame->UpdateGlobalMenuItems();
14404 HideChartInfoWindow();
14409void ChartCanvas::HandlePianoRClick(
14410 int x,
int y,
int selected_index,
14411 const std::vector<int> &selected_dbIndex_array) {
14414 if (!GetpCurrentStack())
return;
14416 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14417 UpdateCanvasControlBar();
14419 SetQuiltChartHiLiteIndex(-1);
14422void ChartCanvas::HandlePianoRollover(
14423 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14424 int n_charts,
int scale) {
14427 if (!GetpCurrentStack())
return;
14432 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14434 if (!GetQuiltMode()) {
14435 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14438 std::vector<int> piano_chart_index_array;
14439 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14440 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14441 if ((GetpCurrentStack()->nEntry > 1) ||
14442 (piano_chart_index_array.size() >= 1)) {
14443 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14445 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14447 }
else if (GetpCurrentStack()->nEntry == 1) {
14449 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14450 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14451 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14453 }
else if ((-1 == selected_index) &&
14454 (0 == selected_dbIndex_array.size())) {
14455 ShowChartInfoWindow(key_location.x, -1);
14459 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14461 if ((GetpCurrentStack()->nEntry > 1) ||
14462 (piano_chart_index_array.size() >= 1)) {
14464 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14465 selected_dbIndex_array);
14466 else if (n_charts == 1)
14467 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14469 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14476void ChartCanvas::ClearPianoRollover() {
14477 ClearQuiltChartHiLiteIndexArray();
14478 ShowChartInfoWindow(0, -1);
14479 std::vector<int> vec;
14480 ShowCompositeInfoWindow(0, 0, 0, vec);
14484void ChartCanvas::UpdateCanvasControlBar() {
14485 if (m_pianoFrozen)
return;
14487 if (!GetpCurrentStack())
return;
14489 if (!g_bShowChartBar)
return;
14492 int sel_family = -1;
14494 std::vector<int> piano_chart_index_array;
14495 std::vector<int> empty_piano_chart_index_array;
14497 wxString old_hash = m_Piano->GetStoredHash();
14499 if (GetQuiltMode()) {
14500 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14501 GetQuiltFullScreendbIndexArray());
14503 std::vector<int> piano_active_chart_index_array =
14504 GetQuiltCandidatedbIndexArray();
14505 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14507 std::vector<int> piano_eclipsed_chart_index_array =
14508 GetQuiltEclipsedStackdbIndexArray();
14509 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14511 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14512 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14514 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14515 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14517 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14518 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14521 if (m_singleChart) {
14522 sel_type = m_singleChart->GetChartType();
14523 sel_family = m_singleChart->GetChartFamily();
14528 std::vector<int> piano_skew_chart_index_array;
14529 std::vector<int> piano_tmerc_chart_index_array;
14530 std::vector<int> piano_poly_chart_index_array;
14532 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14534 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14535 double skew_norm = ctei.GetChartSkew();
14536 if (skew_norm > 180.) skew_norm -= 360.;
14538 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14539 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14542 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14543 if (fabs(skew_norm) > 1.)
14544 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14546 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14547 }
else if (fabs(skew_norm) > 1.)
14548 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14550 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14551 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14552 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14554 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14555 if (new_hash != old_hash) {
14556 m_Piano->FormatKeys();
14557 HideChartInfoWindow();
14558 m_Piano->ResetRollover();
14559 SetQuiltChartHiLiteIndex(-1);
14560 m_brepaint_piano =
true;
14566 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14568 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14569 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14570 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14571 if (e == CHART_FAMILY_RASTER) mask |= 1;
14572 if (e == CHART_FAMILY_VECTOR) {
14573 if (t == CHART_TYPE_CM93COMP)
14580 wxString s_indicated;
14581 if (sel_type == CHART_TYPE_CM93COMP)
14582 s_indicated =
"cm93";
14584 if (sel_family == CHART_FAMILY_RASTER)
14585 s_indicated =
"raster";
14586 else if (sel_family == CHART_FAMILY_VECTOR)
14587 s_indicated =
"vector";
14590 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14593void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14595void ChartCanvas::PianoPopupMenu(
14596 int x,
int y,
int selected_index,
14597 const std::vector<int> &selected_dbIndex_array) {
14598 if (!GetpCurrentStack())
return;
14601 if (!GetQuiltMode())
return;
14603 m_piano_ctx_menu =
new wxMenu();
14605 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14615 menu_selected_dbIndex = selected_dbIndex_array[0];
14616 menu_selected_index = selected_index;
14619 bool b_is_in_noshow =
false;
14620 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14621 if (m_quilt_noshow_index_array[i] ==
14622 menu_selected_dbIndex)
14624 b_is_in_noshow =
true;
14629 if (b_is_in_noshow) {
14630 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14631 _(
"Show This Chart"));
14632 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14633 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14634 }
else if (GetpCurrentStack()->nEntry > 1) {
14635 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14636 _(
"Hide This Chart"));
14637 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14638 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14642 wxPoint pos = wxPoint(x, y - 30);
14645 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14646 PopupMenu(m_piano_ctx_menu, pos);
14648 delete m_piano_ctx_menu;
14649 m_piano_ctx_menu = NULL;
14651 HideChartInfoWindow();
14652 m_Piano->ResetRollover();
14654 SetQuiltChartHiLiteIndex(-1);
14655 ClearQuiltChartHiLiteIndexArray();
14660void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14661 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14662 if (m_quilt_noshow_index_array[i] ==
14663 menu_selected_dbIndex)
14665 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14671void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14672 if (!GetpCurrentStack())
return;
14675 RemoveChartFromQuilt(menu_selected_dbIndex);
14679 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14680 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14682 int i = menu_selected_index + 1;
14683 bool b_success =
false;
14684 while (i < GetpCurrentStack()->nEntry - 1) {
14685 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14686 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14687 SelectQuiltRefChart(i);
14697 i = menu_selected_index - 1;
14699 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14700 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14701 SelectQuiltRefChart(i);
14711void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14713 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14714 if (m_quilt_noshow_index_array[i] ==
14717 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14722 m_quilt_noshow_index_array.push_back(dbIndex);
14725bool ChartCanvas::UpdateS52State() {
14726 bool retval =
false;
14729 ps52plib->SetShowS57Text(m_encShowText);
14730 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14731 ps52plib->m_bShowSoundg = m_encShowDepth;
14732 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14733 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14736 if (!m_encShowLights)
14737 ps52plib->AddObjNoshow(
"LIGHTS");
14739 ps52plib->RemoveObjNoshow(
"LIGHTS");
14740 ps52plib->SetLightsOff(!m_encShowLights);
14741 ps52plib->m_bExtendLightSectors =
true;
14744 ps52plib->SetAnchorOn(m_encShowAnchor);
14745 ps52plib->SetQualityOfData(m_encShowDataQual);
14751void ChartCanvas::SetShowENCDataQual(
bool show) {
14752 m_encShowDataQual = show;
14753 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14754 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14756 m_s52StateHash = 0;
14759void ChartCanvas::SetShowENCText(
bool show) {
14760 m_encShowText = show;
14761 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14762 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14764 m_s52StateHash = 0;
14767void ChartCanvas::SetENCDisplayCategory(
int category) {
14768 m_encDisplayCategory = category;
14769 m_s52StateHash = 0;
14772void ChartCanvas::SetShowENCDepth(
bool show) {
14773 m_encShowDepth = show;
14774 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14775 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14777 m_s52StateHash = 0;
14780void ChartCanvas::SetShowENCLightDesc(
bool show) {
14781 m_encShowLightDesc = show;
14782 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14783 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14785 m_s52StateHash = 0;
14788void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14789 m_encShowBuoyLabels = show;
14790 m_s52StateHash = 0;
14793void ChartCanvas::SetShowENCLights(
bool show) {
14794 m_encShowLights = show;
14795 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14796 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14798 m_s52StateHash = 0;
14801void ChartCanvas::SetShowENCAnchor(
bool show) {
14802 m_encShowAnchor = show;
14803 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14804 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14806 m_s52StateHash = 0;
14809wxRect ChartCanvas::GetMUIBarRect() {
14812 rv = m_muiBar->GetRect();
14818void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14819 if (!GetAlertString().IsEmpty()) {
14820 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14821 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14823 dc.SetFont(*pfont);
14824 dc.SetPen(*wxTRANSPARENT_PEN);
14826 dc.SetBrush(wxColour(243, 229, 47));
14828 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14832 wxRect sbr = GetScaleBarRect();
14833 int xp = sbr.x + sbr.width + 10;
14834 int yp = (sbr.y + sbr.height) - h;
14836 int wdraw = w + 10;
14837 dc.DrawRectangle(xp, yp, wdraw, h);
14838 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14839 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14849#define BRIGHT_XCALIB
14850#define __OPCPN_USEICC__
14853#ifdef __OPCPN_USEICC__
14854int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14855 double co_green,
double co_blue);
14857wxString temp_file_name;
14861class ocpnCurtain:
public wxDialog
14863 DECLARE_CLASS( ocpnCurtain )
14864 DECLARE_EVENT_TABLE()
14867 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14869 bool ProcessEvent(wxEvent& event);
14873IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14875BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14878ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14880 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14883ocpnCurtain::~ocpnCurtain()
14887bool ocpnCurtain::ProcessEvent(wxEvent& event)
14889 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14890 return GetParent()->GetEventHandler()->ProcessEvent(event);
14895#include <windows.h>
14898typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14899typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14900SetDeviceGammaRamp_ptr_type
14901 g_pSetDeviceGammaRamp;
14902GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14904WORD *g_pSavedGammaMap;
14908int InitScreenBrightness() {
14911 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14915 if (NULL == hGDI32DLL) {
14916 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14918 if (NULL != hGDI32DLL) {
14920 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14921 hGDI32DLL,
"SetDeviceGammaRamp");
14922 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14923 hGDI32DLL,
"GetDeviceGammaRamp");
14926 if ((NULL == g_pSetDeviceGammaRamp) ||
14927 (NULL == g_pGetDeviceGammaRamp)) {
14928 FreeLibrary(hGDI32DLL);
14937 if (!g_pSavedGammaMap) {
14938 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14941 bbr = g_pGetDeviceGammaRamp(
14942 hDC, g_pSavedGammaMap);
14943 ReleaseDC(NULL, hDC);
14948 wxRegKey *pRegKey =
new wxRegKey(
14949 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14950 "NT\\CurrentVersion\\ICM");
14951 if (!pRegKey->Exists()) pRegKey->Create();
14952 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14954 g_brightness_init =
true;
14960 if (NULL == g_pcurtain) {
14961 if (gFrame->CanSetTransparent()) {
14963 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14964 wxPoint(0, 0), ::wxGetDisplaySize(),
14965 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14966 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14973 g_pcurtain->Hide();
14975 HWND hWnd = GetHwndOf(g_pcurtain);
14976 SetWindowLong(hWnd, GWL_EXSTYLE,
14977 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14978 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14979 g_pcurtain->SetTransparent(0);
14981 g_pcurtain->Maximize();
14982 g_pcurtain->Show();
14985 g_pcurtain->Enable();
14986 g_pcurtain->Disable();
14993 g_brightness_init =
true;
14999 wxString cmd(
"xcalib -version");
15001 wxArrayString output;
15002 long r = wxExecute(cmd, output);
15005 " External application \"xcalib\" not found. Screen brightness "
15008 g_brightness_init =
true;
15013int RestoreScreenBrightness() {
15016 if (g_pSavedGammaMap) {
15017 HDC hDC = GetDC(NULL);
15018 g_pSetDeviceGammaRamp(hDC,
15020 ReleaseDC(NULL, hDC);
15022 free(g_pSavedGammaMap);
15023 g_pSavedGammaMap = NULL;
15027 g_pcurtain->Close();
15028 g_pcurtain->Destroy();
15032 g_brightness_init =
false;
15037#ifdef BRIGHT_XCALIB
15038 if (g_brightness_init) {
15040 cmd =
"xcalib -clear";
15041 wxExecute(cmd, wxEXEC_ASYNC);
15042 g_brightness_init =
false;
15052int SetScreenBrightness(
int brightness) {
15059 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15061 g_pcurtain->Close();
15062 g_pcurtain->Destroy();
15066 InitScreenBrightness();
15068 if (NULL == hGDI32DLL) {
15070 wchar_t wdll_name[80];
15071 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15072 LPCWSTR cstr = wdll_name;
15074 hGDI32DLL = LoadLibrary(cstr);
15076 if (NULL != hGDI32DLL) {
15078 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15079 hGDI32DLL,
"SetDeviceGammaRamp");
15080 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15081 hGDI32DLL,
"GetDeviceGammaRamp");
15084 if ((NULL == g_pSetDeviceGammaRamp) ||
15085 (NULL == g_pGetDeviceGammaRamp)) {
15086 FreeLibrary(hGDI32DLL);
15093 HDC hDC = GetDC(NULL);
15104 int increment = brightness * 256 / 100;
15107 WORD GammaTable[3][256];
15110 for (
int i = 0; i < 256; i++) {
15111 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15112 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15113 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15115 table_val += increment;
15117 if (table_val > 65535) table_val = 65535;
15120 g_pSetDeviceGammaRamp(hDC, GammaTable);
15121 ReleaseDC(NULL, hDC);
15128 if (g_pSavedGammaMap) {
15129 HDC hDC = GetDC(NULL);
15130 g_pSetDeviceGammaRamp(hDC,
15132 ReleaseDC(NULL, hDC);
15135 if (brightness < 100) {
15136 if (NULL == g_pcurtain) InitScreenBrightness();
15139 int sbrite = wxMax(1, brightness);
15140 sbrite = wxMin(100, sbrite);
15142 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15146 g_pcurtain->Close();
15147 g_pcurtain->Destroy();
15157#ifdef BRIGHT_XCALIB
15159 if (!g_brightness_init) {
15160 last_brightness = 100;
15161 g_brightness_init =
true;
15162 temp_file_name = wxFileName::CreateTempFileName(
"");
15163 InitScreenBrightness();
15166#ifdef __OPCPN_USEICC__
15169 if (!CreateSimpleICCProfileFile(
15170 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15171 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15172 wxString cmd(
"xcalib ");
15173 cmd += temp_file_name;
15175 wxExecute(cmd, wxEXEC_ASYNC);
15184 if (brightness > last_brightness) {
15186 cmd =
"xcalib -clear";
15187 wxExecute(cmd, wxEXEC_ASYNC);
15189 ::wxMilliSleep(10);
15191 int brite_adj = wxMax(1, brightness);
15192 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15193 wxExecute(cmd, wxEXEC_ASYNC);
15195 int brite_adj = wxMax(1, brightness);
15196 int factor = (brite_adj * 100) / last_brightness;
15197 factor = wxMax(1, factor);
15199 cmd.Printf(
"xcalib -co %2d -a", factor);
15200 wxExecute(cmd, wxEXEC_ASYNC);
15205 last_brightness = brightness;
15212#ifdef __OPCPN_USEICC__
15214#define MLUT_TAG 0x6d4c5554L
15215#define VCGT_TAG 0x76636774L
15217int GetIntEndian(
unsigned char *s) {
15222 p = (
unsigned char *)&ret;
15225 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15227 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15232unsigned short GetShortEndian(
unsigned char *s) {
15233 unsigned short ret;
15237 p = (
unsigned char *)&ret;
15240 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15242 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15248int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15249 double co_green,
double co_blue) {
15253 fp = fopen(file_name,
"wb");
15254 if (!fp)
return -1;
15260 for (
int i = 0; i < 128; i++) header[i] = 0;
15262 fwrite(header, 128, 1, fp);
15266 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15267 fwrite(&numTags, 1, 4, fp);
15269 int tagName0 = VCGT_TAG;
15270 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15271 fwrite(&tagName, 1, 4, fp);
15273 int tagOffset0 = 128 + 4 *
sizeof(int);
15274 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15275 fwrite(&tagOffset, 1, 4, fp);
15278 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15279 fwrite(&tagSize, 1, 4, fp);
15281 fwrite(&tagName, 1, 4, fp);
15283 fwrite(&tagName, 1, 4, fp);
15288 int gammatype0 = 0;
15289 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15290 fwrite(&gammatype, 1, 4, fp);
15292 int numChannels0 = 3;
15293 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15294 fwrite(&numChannels, 1, 2, fp);
15296 int numEntries0 = 256;
15297 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15298 fwrite(&numEntries, 1, 2, fp);
15300 int entrySize0 = 1;
15301 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15302 fwrite(&entrySize, 1, 2, fp);
15304 unsigned char ramp[256];
15307 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15308 fwrite(ramp, 256, 1, fp);
15311 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15312 fwrite(ramp, 256, 1, fp);
15315 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15316 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.