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();
2781 if (event.ShiftDown()) {
2783 auto current_family = m_pQuilt->GetRefFamily();
2784 auto target_family = CHART_FAMILY_UNKNOWN;
2785 if (current_family == CHART_FAMILY_RASTER)
2786 target_family = CHART_FAMILY_VECTOR;
2788 target_family = CHART_FAMILY_RASTER;
2790 std::shared_ptr<HostApi> host_api;
2792 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2795 api_121->SelectChartFamily(m_canvasIndex,
2803 SetShowENCText(!GetShowENCText());
2809 if (!m_bMeasure_Active) {
2810 if (event.ShiftDown())
2811 m_bMeasure_DistCircle =
true;
2813 m_bMeasure_DistCircle =
false;
2815 StartMeasureRoute();
2817 CancelMeasureRoute();
2819 SetCursor(*pCursorArrow);
2829 parent_frame->ToggleColorScheme();
2831 TriggerDeferredFocus();
2835 int mod = m_modkeys & wxMOD_SHIFT;
2836 if (mod != m_brightmod) {
2838 m_bbrightdir = !m_bbrightdir;
2841 if (!m_bbrightdir) {
2842 g_nbrightness -= 10;
2843 if (g_nbrightness <= MIN_BRIGHT) {
2844 g_nbrightness = MIN_BRIGHT;
2845 m_bbrightdir =
true;
2848 g_nbrightness += 10;
2849 if (g_nbrightness >= MAX_BRIGHT) {
2850 g_nbrightness = MAX_BRIGHT;
2851 m_bbrightdir =
false;
2855 SetScreenBrightness(g_nbrightness);
2856 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2865 parent_frame->DoStackDown(
this);
2869 parent_frame->DoStackUp(
this);
2874 ToggleCanvasQuiltMode();
2880 parent_frame->ToggleFullScreen();
2885 if (m_modkeys == wxMOD_ALT) {
2888 ToggleChartOutlines();
2894 parent_frame->ActivateMOB();
2898 case WXK_NUMPAD_ADD:
2903 case WXK_NUMPAD_SUBTRACT:
2904 case WXK_PAGEDOWN: {
2905 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2910 if (m_bMeasure_Active) {
2911 if (m_nMeasureState > 2) {
2912 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2914 m_pMeasureRoute->GetnPoints();
2916 gFrame->RefreshAllCanvas();
2918 CancelMeasureRoute();
2919 StartMeasureRoute();
2927 if (event.GetKeyCode() < 128)
2929 int key_char =
event.GetKeyCode();
2933 if (!g_b_assume_azerty) {
2935 if (g_benable_rotate) {
2967 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2974 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2975 m_modkeys & wxMOD_RAW_CONTROL) {
2976 parent_frame->ToggleFullScreen();
2981 if (event.ControlDown()) key_char -= 64;
2983 if (key_char >=
'0' && key_char <=
'9')
2984 SetGroupIndex(key_char -
'0');
2989 SetShowENCAnchor(!GetShowENCAnchor());
2995 parent_frame->ToggleColorScheme();
3000 event.GetPosition(&x, &y);
3001 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3002 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3005 if (VPoint.b_quilt) {
3007 if (m_pQuilt->GetChartAtPix(
3012 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3014 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3019 if (m_singleChart) {
3020 ChartType = m_singleChart->GetChartType();
3021 ChartFam = m_singleChart->GetChartFamily();
3025 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3026 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3028 this, -1, ChartType, ChartFam,
3029 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3030 wxDefaultSize, wxSIMPLE_BORDER,
"");
3043 m_nmea_log->Raise();
3047 SetShowENCLights(!GetShowENCLights());
3053 if (event.ShiftDown())
3054 m_bMeasure_DistCircle =
true;
3056 m_bMeasure_DistCircle =
false;
3058 StartMeasureRoute();
3062 if (g_bInlandEcdis && ps52plib) {
3063 SetENCDisplayCategory((_DisCat)STANDARD);
3068 ToggleChartOutlines();
3072 ToggleCanvasQuiltMode();
3076 parent_frame->ToggleTestPause();
3079 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3080 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3081 g_iNavAidRadarRingsNumberVisible = 1;
3082 else if (!g_bNavAidRadarRingsShown &&
3083 g_iNavAidRadarRingsNumberVisible == 1)
3084 g_iNavAidRadarRingsNumberVisible = 0;
3087 SetShowENCDepth(!m_encShowDepth);
3092 SetShowENCText(!GetShowENCText());
3097 SetShowENCDataQual(!GetShowENCDataQual());
3102 m_bShowNavobjects = !m_bShowNavobjects;
3117 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3122 if (event.ControlDown()) gFrame->DropMarker(
false);
3129 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3130 if ((indexActive + 1) <= r->GetnPoints()) {
3141 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3147 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3153 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3160 parent_frame->DoSettings();
3164 parent_frame->Close();
3180 if (undo->AnythingToRedo()) {
3181 undo->RedoNextAction();
3188 if (event.ShiftDown()) {
3189 if (undo->AnythingToRedo()) {
3190 undo->RedoNextAction();
3195 if (undo->AnythingToUndo()) {
3196 undo->UndoLastAction();
3205 if (m_bMeasure_Active) {
3206 CancelMeasureRoute();
3208 SetCursor(*pCursorArrow);
3211 gFrame->RefreshAllCanvas();
3225 switch (gamma_state) {
3245 SetScreenBrightness(g_nbrightness);
3250 if (event.ControlDown()) {
3251 m_bShowCompassWin = !m_bShowCompassWin;
3252 SetShowGPSCompassWindow(m_bShowCompassWin);
3269void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3270 if (SendKeyEventToPlugins(event))
3274 switch (event.GetKeyCode()) {
3276 parent_frame->SwitchKBFocus(
this);
3282 if (!m_pany) m_panspeed = 0;
3288 if (!m_panx) m_panspeed = 0;
3291 case WXK_NUMPAD_ADD:
3292 case WXK_NUMPAD_SUBTRACT:
3301 m_modkeys &= ~wxMOD_ALT;
3302#ifdef OCPN_ALT_MENUBAR
3307 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3308 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3309 parent_frame->ApplyGlobalSettings(
false);
3311 m_bMayToggleMenuBar =
true;
3317 m_modkeys &= ~wxMOD_CONTROL;
3321 if (event.GetKeyCode() < 128)
3323 int key_char =
event.GetKeyCode();
3327 if (!g_b_assume_azerty) {
3342 m_rotation_speed = 0;
3360void ChartCanvas::ToggleChartOutlines() {
3361 m_bShowOutlines = !m_bShowOutlines;
3367 if (g_bopengl) InvalidateGL();
3371void ChartCanvas::ToggleLookahead() {
3372 m_bLookAhead = !m_bLookAhead;
3377void ChartCanvas::SetUpMode(
int mode) {
3380 if (mode != NORTH_UP_MODE) {
3383 if (!std::isnan(
gCog)) stuff =
gCog;
3386 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3389 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3391 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3392 SetVPRotation(GetVPSkew());
3397 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3398 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3400 UpdateGPSCompassStatusBox(
true);
3401 gFrame->DoChartUpdate();
3404bool ChartCanvas::DoCanvasCOGSet() {
3405 if (GetUpMode() == NORTH_UP_MODE)
return false;
3407 if (g_btenhertz) cog_use =
gCog;
3409 double rotation = 0;
3410 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3411 rotation = -
gHdt * PI / 180.;
3412 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3413 rotation = -cog_use * PI / 180.;
3415 SetVPRotation(rotation);
3419double easeOutCubic(
double t) {
3421 return 1.0 - pow(1.0 - t, 3.0);
3424void ChartCanvas::StartChartDragInertia() {
3425 m_bChartDragging =
false;
3428 m_chart_drag_inertia_time = 750;
3429 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3434 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3438 size_t length = m_drag_vec_t.size();
3439 for (
size_t i = 0; i < n_vel; i++) {
3440 xacc += m_drag_vec_x.at(length - 1 - i);
3441 yacc += m_drag_vec_y.at(length - 1 - i);
3442 tacc += m_drag_vec_t.at(length - 1 - i);
3445 if (tacc == 0)
return;
3447 double drag_velocity_x = xacc / tacc;
3448 double drag_velocity_y = yacc / tacc;
3454 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3456 m_chart_drag_velocity_x = drag_velocity_x;
3457 m_chart_drag_velocity_y = drag_velocity_y;
3459 m_chart_drag_inertia_active =
true;
3461 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3464void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3465 if (!m_chart_drag_inertia_active)
return;
3467 wxLongLong now = wxGetLocalTimeMillis();
3468 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3469 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3470 if (t > 1.0) t = 1.0;
3471 double e = 1.0 - easeOutCubic(t);
3474 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3476 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3478 m_last_elapsed = elapsed;
3482 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3483 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3484 double inertia_lat, inertia_lon;
3488 if (!IsOwnshipOnScreen()) {
3490 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3491 UpdateFollowButtonState();
3502 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3503 m_chart_drag_inertia_timer.Stop();
3506 m_target_lat = GetVP().
clat;
3507 m_target_lon = GetVP().
clon;
3508 m_pan_drag.x = m_pan_drag.y = 0;
3509 m_panx = m_pany = 0;
3510 m_chart_drag_inertia_active =
false;
3514 int target_redraw_interval = 40;
3515 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3519void ChartCanvas::StopMovement() {
3520 m_panx = m_pany = 0;
3523 m_rotation_speed = 0;
3526#if !defined(__WXGTK__) && !defined(__WXQT__)
3537bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3539 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3541 if (!pMovementTimer->IsRunning()) {
3542 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3545 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3550 m_last_movement_time = wxDateTime::UNow();
3554void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3557 m_target_lat = target_lat;
3558 m_target_lon = target_lon;
3561 m_start_lat = GetVP().
clat;
3562 m_start_lon = GetVP().
clon;
3564 m_VPMovementTimer.Start(1,
true);
3565 m_timed_move_vp_active =
true;
3567 m_timedVP_step = nstep;
3570void ChartCanvas::DoTimedMovementVP() {
3571 if (!m_timed_move_vp_active)
return;
3572 if (m_stvpc++ > m_timedVP_step * 2) {
3579 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3594 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3595 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3597 m_run_lat = new_lat;
3598 m_run_lon = new_lon;
3603void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3605void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3607void ChartCanvas::StartTimedMovementTarget() {}
3609void ChartCanvas::DoTimedMovementTarget() {}
3611void ChartCanvas::StopMovementTarget() {}
3614void ChartCanvas::DoTimedMovement() {
3615 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3619 wxDateTime now = wxDateTime::UNow();
3621 if (m_last_movement_time.IsValid())
3622 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3624 m_last_movement_time = now;
3634 if (dt == 0) dt = 1;
3637 if (m_mustmove < 0) m_mustmove = 0;
3640 if (m_pan_drag.x || m_pan_drag.y) {
3642 m_pan_drag.x = m_pan_drag.y = 0;
3645 if (m_panx || m_pany) {
3646 const double slowpan = .1, maxpan = 2;
3647 if (m_modkeys == wxMOD_ALT)
3648 m_panspeed = slowpan;
3650 m_panspeed += (double)dt / 500;
3651 m_panspeed = wxMin(maxpan, m_panspeed);
3653 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3656 if (m_zoom_factor != 1) {
3657 double alpha = 400, beta = 1.5;
3658 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3660 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3662 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3667 if (zoom_factor > 1) {
3668 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3672 else if (zoom_factor < 1) {
3673 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3678 if (fabs(zoom_factor - 1) > 1e-4) {
3679 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3684 if (m_wheelzoom_stop_oneshot > 0) {
3685 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3686 m_wheelzoom_stop_oneshot = 0;
3691 if (zoom_factor > 1) {
3693 m_wheelzoom_stop_oneshot = 0;
3696 }
else if (zoom_factor < 1) {
3698 m_wheelzoom_stop_oneshot = 0;
3705 if (m_rotation_speed) {
3706 double speed = m_rotation_speed;
3707 if (m_modkeys == wxMOD_ALT) speed /= 10;
3708 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3712void ChartCanvas::SetColorScheme(ColorScheme cs) {
3717 case GLOBAL_COLOR_SCHEME_DAY:
3718 m_pos_image_red = &m_os_image_red_day;
3719 m_pos_image_grey = &m_os_image_grey_day;
3720 m_pos_image_yellow = &m_os_image_yellow_day;
3721 m_pos_image_user = m_pos_image_user_day;
3722 m_pos_image_user_grey = m_pos_image_user_grey_day;
3723 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3724 m_cTideBitmap = m_bmTideDay;
3725 m_cCurrentBitmap = m_bmCurrentDay;
3728 case GLOBAL_COLOR_SCHEME_DUSK:
3729 m_pos_image_red = &m_os_image_red_dusk;
3730 m_pos_image_grey = &m_os_image_grey_dusk;
3731 m_pos_image_yellow = &m_os_image_yellow_dusk;
3732 m_pos_image_user = m_pos_image_user_dusk;
3733 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3734 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3735 m_cTideBitmap = m_bmTideDusk;
3736 m_cCurrentBitmap = m_bmCurrentDusk;
3738 case GLOBAL_COLOR_SCHEME_NIGHT:
3739 m_pos_image_red = &m_os_image_red_night;
3740 m_pos_image_grey = &m_os_image_grey_night;
3741 m_pos_image_yellow = &m_os_image_yellow_night;
3742 m_pos_image_user = m_pos_image_user_night;
3743 m_pos_image_user_grey = m_pos_image_user_grey_night;
3744 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3745 m_cTideBitmap = m_bmTideNight;
3746 m_cCurrentBitmap = m_bmCurrentNight;
3749 m_pos_image_red = &m_os_image_red_day;
3750 m_pos_image_grey = &m_os_image_grey_day;
3751 m_pos_image_yellow = &m_os_image_yellow_day;
3752 m_pos_image_user = m_pos_image_user_day;
3753 m_pos_image_user_grey = m_pos_image_user_grey_day;
3754 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3755 m_cTideBitmap = m_bmTideDay;
3756 m_cCurrentBitmap = m_bmCurrentDay;
3760 CreateDepthUnitEmbossMaps(cs);
3761 CreateOZEmbossMapData(cs);
3764 m_fog_color = wxColor(
3768 case GLOBAL_COLOR_SCHEME_DUSK:
3771 case GLOBAL_COLOR_SCHEME_NIGHT:
3777 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3778 m_fog_color.Blue() * dim);
3782 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3783 SetBackgroundColour( wxColour(0,0,0) );
3785 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3788 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3790 SetBackgroundColour( wxNullColour );
3797 m_Piano->SetColorScheme(cs);
3799 m_Compass->SetColorScheme(cs);
3801 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3803 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3805 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3806 if (m_notification_button) {
3807 m_notification_button->SetColorScheme(cs);
3811 if (g_bopengl && m_glcc) {
3812 m_glcc->SetColorScheme(cs);
3818 m_brepaint_piano =
true;
3825wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3826 wxImage img = Bitmap.ConvertToImage();
3827 int sx = img.GetWidth();
3828 int sy = img.GetHeight();
3830 wxImage new_img(img);
3832 for (
int i = 0; i < sx; i++) {
3833 for (
int j = 0; j < sy; j++) {
3834 if (!img.IsTransparent(i, j)) {
3835 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3836 (
unsigned char)(img.GetGreen(i, j) * factor),
3837 (
unsigned char)(img.GetBlue(i, j) * factor));
3842 wxBitmap ret = wxBitmap(new_img);
3847void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3850 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3852 if (!m_pBrightPopup) {
3855 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3859 m_pBrightPopup->SetSize(x, y);
3860 m_pBrightPopup->Move(120, 120);
3863 int bmpsx = m_pBrightPopup->GetSize().x;
3864 int bmpsy = m_pBrightPopup->GetSize().y;
3866 wxBitmap bmp(bmpsx, bmpsx);
3867 wxMemoryDC mdc(bmp);
3869 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3870 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3871 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3872 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3875 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3877 mdc.SetFont(*pfont);
3880 if (brightness == max)
3882 else if (brightness == min)
3885 val.Printf(
"%3d", brightness);
3887 mdc.DrawText(val, 0, 0);
3889 mdc.SelectObject(wxNullBitmap);
3891 m_pBrightPopup->SetBitmap(bmp);
3892 m_pBrightPopup->Show();
3893 m_pBrightPopup->Refresh();
3896void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3897 m_b_rot_hidef =
true;
3901void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3904 bool b_need_refresh =
false;
3906 wxSize win_size = GetSize() * m_displayScale;
3910 bool showAISRollover =
false;
3912 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3916 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3917 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3920 showAISRollover =
true;
3922 if (NULL == m_pAISRolloverWin) {
3924 m_pAISRolloverWin->IsActive(
false);
3925 b_need_refresh =
true;
3926 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3927 m_AISRollover_MMSI != FoundAIS_MMSI) {
3933 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3934 m_pAISRolloverWin->IsActive(
false);
3935 m_AISRollover_MMSI = 0;
3940 m_AISRollover_MMSI = FoundAIS_MMSI;
3942 if (!m_pAISRolloverWin->IsActive()) {
3943 wxString s = ptarget->GetRolloverString();
3944 m_pAISRolloverWin->SetString(s);
3946 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3947 AIS_ROLLOVER, win_size);
3948 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3949 m_pAISRolloverWin->IsActive(
true);
3950 b_need_refresh =
true;
3954 m_AISRollover_MMSI = 0;
3955 showAISRollover =
false;
3960 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3961 m_pAISRolloverWin->IsActive(
false);
3962 m_AISRollover_MMSI = 0;
3963 b_need_refresh =
true;
3968 bool showRouteRollover =
false;
3970 if (NULL == m_pRolloverRouteSeg) {
3974 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3975 SelectableItemList SelList =
pSelect->FindSelectionList(
3977 auto node = SelList.begin();
3978 while (node != SelList.end()) {
3983 if (pr && pr->IsVisible()) {
3984 m_pRolloverRouteSeg = pFindSel;
3985 showRouteRollover =
true;
3987 if (NULL == m_pRouteRolloverWin) {
3989 m_pRouteRolloverWin->IsActive(
false);
3992 if (!m_pRouteRolloverWin->IsActive()) {
4000 DistanceBearingMercator(
4001 segShow_point_b->m_lat, segShow_point_b->m_lon,
4002 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4004 if (!pr->m_bIsInLayer)
4005 s.Append(_(
"Route") +
": ");
4007 s.Append(_(
"Layer Route: "));
4009 if (pr->m_RouteNameString.IsEmpty())
4010 s.Append(_(
"(unnamed)"));
4012 s.Append(pr->m_RouteNameString);
4017 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4018 << segShow_point_b->GetName() <<
"\n";
4021 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4022 (
int)floor(brg + 0.5), 0x00B0);
4025 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4027 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4028 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4030 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4031 (
int)floor(varBrg + 0.5), 0x00B0);
4039 double shiptoEndLeg = 0.;
4040 bool validActive =
false;
4041 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4044 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4045 auto node = pr->pRoutePointList->begin();
4047 float dist_to_endleg = 0;
4050 for (++node; node != pr->pRoutePointList->end(); ++node) {
4057 if (prp->IsSame(segShow_point_a))
break;
4065 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4068 ->GetCurrentRngToActivePoint();
4077 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4082 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4083 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4085 << wxString(ttg_sec > SECONDS_PER_DAY
4086 ? ttg_span.Format(_(
"%Dd %H:%M"))
4087 : ttg_span.Format(_(
"%H:%M")));
4088 wxDateTime dtnow, eta;
4089 eta = dtnow.SetToCurrent().Add(ttg_span);
4090 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4091 << eta.Format(
" %d %H:%M");
4095 m_pRouteRolloverWin->SetString(s);
4097 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4098 LEG_ROLLOVER, win_size);
4099 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4100 m_pRouteRolloverWin->IsActive(
true);
4101 b_need_refresh =
true;
4102 showRouteRollover =
true;
4111 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4113 m_pRolloverRouteSeg))
4114 showRouteRollover =
false;
4115 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4116 showRouteRollover =
false;
4118 showRouteRollover =
true;
4122 if (m_routeState) showRouteRollover =
false;
4125 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4126 showRouteRollover =
false;
4128 if (m_pRouteRolloverWin &&
4129 !showRouteRollover) {
4130 m_pRouteRolloverWin->IsActive(
false);
4131 m_pRolloverRouteSeg = NULL;
4132 m_pRouteRolloverWin->Destroy();
4133 m_pRouteRolloverWin = NULL;
4134 b_need_refresh =
true;
4135 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4136 m_pRouteRolloverWin->IsActive(
true);
4137 b_need_refresh =
true;
4142 bool showTrackRollover =
false;
4144 if (NULL == m_pRolloverTrackSeg) {
4148 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4149 SelectableItemList SelList =
pSelect->FindSelectionList(
4152 auto node = SelList.begin();
4153 while (node != SelList.end()) {
4158 if (pt && pt->IsVisible()) {
4159 m_pRolloverTrackSeg = pFindSel;
4160 showTrackRollover =
true;
4162 if (NULL == m_pTrackRolloverWin) {
4164 m_pTrackRolloverWin->IsActive(
false);
4167 if (!m_pTrackRolloverWin->IsActive()) {
4175 DistanceBearingMercator(
4176 segShow_point_b->m_lat, segShow_point_b->m_lon,
4177 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4179 if (!pt->m_bIsInLayer)
4180 s.Append(_(
"Track") +
": ");
4182 s.Append(_(
"Layer Track: "));
4184 if (pt->GetName().IsEmpty())
4185 s.Append(_(
"(unnamed)"));
4187 s.Append(pt->GetName());
4188 double tlenght = pt->Length();
4190 if (pt->GetLastPoint()->GetTimeString() &&
4191 pt->GetPoint(0)->GetTimeString()) {
4192 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4193 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4194 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4195 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4196 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4197 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4198 << getUsrSpeedUnit();
4199 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4200 : ttime.Format(
" %H:%M"));
4204 if (g_bShowTrackPointTime &&
4205 strlen(segShow_point_b->GetTimeString())) {
4206 wxString stamp = segShow_point_b->GetTimeString();
4207 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4208 if (timestamp.IsValid()) {
4212 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4214 s <<
"\n" << _(
"Segment Created: ") << stamp;
4219 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4224 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4226 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4227 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4229 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4235 if (segShow_point_a->GetTimeString() &&
4236 segShow_point_b->GetTimeString()) {
4237 wxDateTime apoint = segShow_point_a->GetCreateTime();
4238 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4239 if (apoint.IsValid() && bpoint.IsValid()) {
4240 double segmentSpeed = toUsrSpeed(
4241 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4242 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4243 << getUsrSpeedUnit();
4247 m_pTrackRolloverWin->SetString(s);
4249 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4250 LEG_ROLLOVER, win_size);
4251 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4252 m_pTrackRolloverWin->IsActive(
true);
4253 b_need_refresh =
true;
4254 showTrackRollover =
true;
4263 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4265 m_pRolloverTrackSeg))
4266 showTrackRollover =
false;
4267 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4268 showTrackRollover =
false;
4270 showTrackRollover =
true;
4274 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4275 showTrackRollover =
false;
4278 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4279 showTrackRollover =
false;
4285 if (m_pTrackRolloverWin &&
4286 !showTrackRollover) {
4287 m_pTrackRolloverWin->IsActive(
false);
4288 m_pRolloverTrackSeg = NULL;
4289 m_pTrackRolloverWin->Destroy();
4290 m_pTrackRolloverWin = NULL;
4291 b_need_refresh =
true;
4292 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4293 m_pTrackRolloverWin->IsActive(
true);
4294 b_need_refresh =
true;
4297 if (b_need_refresh) Refresh();
4300void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4301 if ((GetShowENCLights() || m_bsectors_shown) &&
4302 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4303 extendedSectorLegs)) {
4304 if (!m_bsectors_shown) {
4306 m_bsectors_shown =
true;
4309 if (m_bsectors_shown) {
4311 m_bsectors_shown =
false;
4319#if defined(__WXGTK__) || defined(__WXQT__)
4324 double cursor_lat, cursor_lon;
4327 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4328 while (cursor_lon < -180.) cursor_lon += 360.;
4330 while (cursor_lon > 180.) cursor_lon -= 360.;
4332 SetCursorStatus(cursor_lat, cursor_lon);
4338void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4339 if (!parent_frame->m_pStatusBar)
return;
4343 s1 += toSDMM(1, cursor_lat);
4345 s1 += toSDMM(2, cursor_lon);
4347 if (STAT_FIELD_CURSOR_LL >= 0)
4348 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4350 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4355 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4356 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4357 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4359 wxString s = st + sm;
4372 if (g_bShowLiveETA) {
4375 float boatSpeedDefault = g_defaultBoatSpeed;
4380 if (!std::isnan(
gSog)) {
4382 if (boatSpeed < 0.5) {
4385 realTimeETA = dist / boatSpeed * 60;
4394 s << minutesToHoursDays(realTimeETA);
4399 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4400 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4402 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4407 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4415wxString minutesToHoursDays(
float timeInMinutes) {
4418 if (timeInMinutes == 0) {
4423 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4424 s << wxString::Format(
"%d", (
int)timeInMinutes);
4429 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4432 hours = (int)timeInMinutes / 60;
4433 min = (int)timeInMinutes % 60;
4436 s << wxString::Format(
"%d", hours);
4439 s << wxString::Format(
"%d", hours);
4441 s << wxString::Format(
"%d", min);
4448 else if (timeInMinutes > 24 * 60) {
4451 days = (int)(timeInMinutes / 60) / 24;
4452 hours = (int)(timeInMinutes / 60) % 24;
4455 s << wxString::Format(
"%d", days);
4458 s << wxString::Format(
"%d", days);
4460 s << wxString::Format(
"%d", hours);
4472void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4480 wxPoint2DDouble *r) {
4485 double rlon, wxPoint2DDouble *r) {
4496 if (!g_bopengl && m_singleChart &&
4497 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4498 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4499 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4500 (m_singleChart->GetChartProjectionType() !=
4501 PROJECTION_TRANSVERSE_MERCATOR) &&
4502 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4503 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4504 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4518 Cur_BSB_Ch->SetVPRasterParms(vp);
4519 double rpixxd, rpixyd;
4520 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4546 if (std::isnan(p.m_x)) {
4547 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4551 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4552 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4554 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4573 if (!g_bopengl && m_singleChart &&
4574 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4575 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4576 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4577 (m_singleChart->GetChartProjectionType() !=
4578 PROJECTION_TRANSVERSE_MERCATOR) &&
4579 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4580 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4581 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4592 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4595 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4600 else if (slon > 180.)
4611 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4617 DoZoomCanvas(factor,
false);
4618 extendedSectorLegs.clear();
4623 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4626 if (StartTimedMovement(stoptimer)) {
4628 m_zoom_factor = factor;
4633 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4635 DoZoomCanvas(factor, can_zoom_to_cursor);
4638 extendedSectorLegs.clear();
4641void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4644 if (!m_pCurrentStack)
return;
4650 if (m_bzooming)
return;
4659 double proposed_scale_onscreen =
4662 bool b_do_zoom =
false;
4671 if (!VPoint.b_quilt) {
4674 if (!m_disable_adjust_on_zoom) {
4675 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4676 if (new_db_index >= 0)
4677 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4681 int current_ref_stack_index = -1;
4682 if (m_pCurrentStack->nEntry) {
4684 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4685 m_pQuilt->SetReferenceChart(trial_index);
4686 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4687 if (new_db_index >= 0)
4688 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4692 if (m_pCurrentStack)
4693 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4704 double min_allowed_scale =
4707 if (proposed_scale_onscreen < min_allowed_scale) {
4712 proposed_scale_onscreen = min_allowed_scale;
4716 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4719 }
else if (factor < 1) {
4724 bool b_smallest =
false;
4726 if (!VPoint.b_quilt) {
4731 LLBBox viewbox = VPoint.GetBBox();
4733 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4734 double max_allowed_scale;
4748 if (proposed_scale_onscreen > max_allowed_scale) {
4750 proposed_scale_onscreen = max_allowed_scale;
4755 if (!m_disable_adjust_on_zoom) {
4757 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4758 if (new_db_index >= 0)
4759 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4761 if (m_pCurrentStack)
4762 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4765 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4767 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4768 proposed_scale_onscreen =
4769 wxMin(proposed_scale_onscreen,
4775 m_absolute_min_scale_ppm)
4776 proposed_scale_onscreen =
4785 bool b_allow_ztc =
true;
4786 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4787 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4789 double brg, distance;
4790 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4793 meters_to_shift = distance * 1852;
4801 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4804 if (m_bFollow) DoCanvasUpdate();
4811void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4813 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4817void ChartCanvas::RotateCanvas(
double dir) {
4821 if (StartTimedMovement()) {
4823 m_rotation_speed = dir * 60;
4826 double speed = dir * 10;
4827 if (m_modkeys == wxMOD_ALT) speed /= 20;
4828 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4832void ChartCanvas::DoRotateCanvas(
double rotation) {
4833 while (rotation < 0) rotation += 2 * PI;
4834 while (rotation > 2 * PI) rotation -= 2 * PI;
4836 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4838 SetVPRotation(rotation);
4839 parent_frame->UpdateRotationState(VPoint.
rotation);
4842void ChartCanvas::DoTiltCanvas(
double tilt) {
4843 while (tilt < 0) tilt = 0;
4844 while (tilt > .95) tilt = .95;
4846 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4852void ChartCanvas::TogglebFollow() {
4859void ChartCanvas::ClearbFollow() {
4862 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4864 UpdateFollowButtonState();
4868 parent_frame->SetChartUpdatePeriod();
4871void ChartCanvas::SetbFollow() {
4874 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4875 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4883 p.m_x += m_OSoffsetx;
4884 p.m_y -= m_OSoffsety;
4893 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4894 UpdateFollowButtonState();
4896 if (!g_bSmoothRecenter) {
4900 parent_frame->SetChartUpdatePeriod();
4903void ChartCanvas::UpdateFollowButtonState() {
4906 m_muiBar->SetFollowButtonState(0);
4909 m_muiBar->SetFollowButtonState(2);
4911 m_muiBar->SetFollowButtonState(1);
4917 androidSetFollowTool(0);
4920 androidSetFollowTool(2);
4922 androidSetFollowTool(1);
4929 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4930 if (pic->m_enabled && pic->m_init_state) {
4931 switch (pic->m_api_version) {
4934 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4945void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4946 if (g_bSmoothRecenter && !m_routeState) {
4947 if (StartSmoothJump(lat, lon, scale_ppm))
4951 double gcDist, gcBearingEnd;
4952 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4954 gcBearingEnd += 180;
4955 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4958 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4959 double new_lat = lat + (lat_offset / (1852 * 60));
4960 double new_lon = lon + (lon_offset / (1852 * 60));
4963 StartSmoothJump(lat, lon, scale_ppm);
4968 if (lon > 180.0) lon -= 360.0;
4974 if (!GetQuiltMode()) {
4976 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4977 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4981 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4982 AdjustQuiltRefChart();
4989 UpdateFollowButtonState();
4997bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5002 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5003 double distance_pixels = gcDist *
GetVPScale();
5004 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5010 m_startLat = m_vLat;
5011 m_startLon = m_vLon;
5016 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5017 m_endScale = scale_ppm;
5020 m_animationDuration = 600;
5021 m_animationStart = wxGetLocalTimeMillis();
5028 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5029 m_animationActive =
true;
5034void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5036 wxLongLong now = wxGetLocalTimeMillis();
5037 double elapsed = (now - m_animationStart).ToDouble();
5038 double t = elapsed / m_animationDuration.ToDouble();
5039 if (t > 1.0) t = 1.0;
5042 double e = easeOutCubic(t);
5045 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5046 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5047 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5052 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5058 m_animationActive =
false;
5059 UpdateFollowButtonState();
5068 extendedSectorLegs.clear();
5077 if (iters++ > 5)
return false;
5078 if (!std::isnan(dlat))
break;
5081 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5087 else if (dlat < -90)
5090 if (dlon > 360.) dlon -= 360.;
5091 if (dlon < -360.) dlon += 360.;
5106 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5110 if (VPoint.b_quilt) {
5111 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5112 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5116 double tweak_scale_ppm =
5122 if (new_ref_dbIndex == -1) {
5123#pragma GCC diagnostic push
5124#pragma GCC diagnostic ignored "-Warray-bounds"
5131 int trial_index = -1;
5132 if (m_pCurrentStack->nEntry) {
5134 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5137 if (trial_index < 0) {
5138 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5139 if (full_screen_array.size())
5140 trial_index = full_screen_array[full_screen_array.size() - 1];
5143 if (trial_index >= 0) {
5144 m_pQuilt->SetReferenceChart(trial_index);
5149#pragma GCC diagnostic pop
5156 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5158 double offset_angle = atan2(offy, offx);
5159 double offset_distance = sqrt((offy * offy) + (offx * offx));
5160 double chart_angle = GetVPRotation();
5161 double target_angle = chart_angle - offset_angle;
5162 double d_east_mod = offset_distance * cos(target_angle);
5163 double d_north_mod = offset_distance * sin(target_angle);
5168 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5169 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5171 UpdateFollowButtonState();
5177 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5182bool ChartCanvas::IsOwnshipOnScreen() {
5185 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5186 ((r.y > 0) && r.y < GetCanvasHeight()))
5192void ChartCanvas::ReloadVP(
bool b_adjust) {
5193 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5195 LoadVP(VPoint, b_adjust);
5198void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5200 if (g_bopengl && m_glcc) {
5201 m_glcc->Invalidate();
5202 if (m_glcc->GetSize() != GetSize()) {
5203 m_glcc->SetSize(GetSize());
5208 m_cache_vp.Invalidate();
5209 m_bm_cache_vp.Invalidate();
5212 VPoint.Invalidate();
5214 if (m_pQuilt) m_pQuilt->Invalidate();
5223 vp.m_projection_type, b_adjust);
5226void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5227 m_pQuilt->SetReferenceChart(dbIndex);
5228 VPoint.Invalidate();
5229 m_pQuilt->Invalidate();
5232double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5234 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5241int ChartCanvas::AdjustQuiltRefChart() {
5246 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5248 double min_ref_scale =
5249 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5250 double max_ref_scale =
5251 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5254 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5255 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5256 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5258 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5261 int target_stack_index = wxNOT_FOUND;
5263 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5264 if (index == m_pQuilt->GetRefChartdbIndex()) {
5265 target_stack_index = il;
5270 if (wxNOT_FOUND == target_stack_index)
5271 target_stack_index = 0;
5273 int ref_family = pc->GetChartFamily();
5274 int extended_array_count =
5275 m_pQuilt->GetExtendedStackIndexArray().size();
5276 while ((!brender_ok) &&
5277 ((
int)target_stack_index < (extended_array_count - 1))) {
5278 target_stack_index++;
5280 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5282 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5283 IsChartQuiltableRef(test_db_index)) {
5286 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5288 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5295 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5296 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5297 IsChartQuiltableRef(new_db_index)) {
5298 m_pQuilt->SetReferenceChart(new_db_index);
5301 ret = m_pQuilt->GetRefChartdbIndex();
5303 ret = m_pQuilt->GetRefChartdbIndex();
5306 ret = m_pQuilt->GetRefChartdbIndex();
5315void ChartCanvas::UpdateCanvasOnGroupChange() {
5316 delete m_pCurrentStack;
5328bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5329 double latNE,
double lonNE) {
5331 double latc = (latSW + latNE) / 2.0;
5332 double lonc = (lonSW + lonNE) / 2.0;
5335 double ne_easting, ne_northing;
5336 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5338 double sw_easting, sw_northing;
5339 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5341 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5348 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5351bool ChartCanvas::SetVPProjection(
int projection) {
5357 double prev_true_scale_ppm = m_true_scale_ppm;
5362 m_absolute_min_scale_ppm));
5370bool ChartCanvas::SetVPRotation(
double angle) {
5372 VPoint.
skew, angle);
5375 double skew,
double rotation,
int projection,
5376 bool b_adjust,
bool b_refresh) {
5381 if (VPoint.IsValid()) {
5382 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5383 (fabs(VPoint.
skew - skew) < 1e-9) &&
5384 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5385 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5386 (VPoint.m_projection_type == projection ||
5387 projection == PROJECTION_UNKNOWN))
5390 if (VPoint.m_projection_type != projection)
5391 VPoint.InvalidateTransformCache();
5401 if (projection != PROJECTION_UNKNOWN)
5402 VPoint.SetProjectionType(projection);
5403 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5404 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5407 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5408 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5409 if (VPoint.
clat > 89.5)
5411 else if (VPoint.
clat < -89.5)
5412 VPoint.
clat = -89.5;
5417 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5418 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5430 bool bwasValid = VPoint.IsValid();
5435 m_cache_vp.Invalidate();
5440 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5444 int mouseX = mouse_x;
5445 int mouseY = mouse_y;
5446 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5452 SendCursorLatLonToAllPlugIns(lat, lon);
5455 if (!VPoint.b_quilt && m_singleChart) {
5460 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5464 if ((!m_cache_vp.IsValid()) ||
5469 wxPoint cp_last, cp_this;
5473 if (cp_last != cp_this) {
5479 if (m_pCurrentStack) {
5481 int current_db_index;
5483 m_pCurrentStack->GetCurrentEntrydbIndex();
5485 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5487 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5490 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5494 if (VPoint.b_quilt) {
5498 m_pQuilt->InvalidateAllQuiltPatchs();
5502 if (!m_pCurrentStack)
return false;
5504 int current_db_index;
5506 m_pCurrentStack->GetCurrentEntrydbIndex();
5508 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5509 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5512 int current_ref_stack_index = -1;
5513 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5514 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5515 current_ref_stack_index = i;
5518 if (g_bFullScreenQuilt) {
5519 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5523 bool b_needNewRef =
false;
5526 if ((-1 == current_ref_stack_index) &&
5527 (m_pQuilt->GetRefChartdbIndex() >= 0))
5528 b_needNewRef =
true;
5535 bool renderable =
true;
5537 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5538 if (referenceChart) {
5539 double chartMaxScale = referenceChart->GetNormalScaleMax(
5541 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5543 if (!renderable) b_needNewRef =
true;
5546 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5548 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5549 int target_scale = cte_ref.GetScale();
5550 int target_type = cte_ref.GetChartType();
5551 int candidate_stack_index;
5558 candidate_stack_index = 0;
5559 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5561 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5562 int candidate_scale = cte_candidate.GetScale();
5563 int candidate_type = cte_candidate.GetChartType();
5565 if ((candidate_scale >= target_scale) &&
5566 (candidate_type == target_type)) {
5567 bool renderable =
true;
5569 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5570 if (tentative_referenceChart) {
5571 double chartMaxScale =
5572 tentative_referenceChart->GetNormalScaleMax(
5574 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5577 if (renderable)
break;
5580 candidate_stack_index++;
5585 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5586 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5587 while (candidate_stack_index >= 0) {
5588 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5592 int candidate_scale = cte_candidate.GetScale();
5593 int candidate_type = cte_candidate.GetChartType();
5595 if ((candidate_scale <= target_scale) &&
5596 (candidate_type == target_type))
5599 candidate_stack_index--;
5604 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5605 (candidate_stack_index < 0))
5606 candidate_stack_index = 0;
5608 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5610 m_pQuilt->SetReferenceChart(new_ref_index);
5616 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5621 bool renderable =
true;
5623 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5624 if (referenceChart) {
5625 double chartMaxScale = referenceChart->GetNormalScaleMax(
5627 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5628 proj =
ChartData->GetDBChartProj(ref_db_index);
5630 proj = PROJECTION_MERCATOR;
5632 VPoint.b_MercatorProjectionOverride =
5633 (m_pQuilt->GetnCharts() == 0 || !renderable);
5635 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5637 VPoint.SetProjectionType(proj);
5642 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5647 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5667 m_pQuilt->Invalidate();
5684 if (b_refresh) Refresh(
false);
5691 }
else if (!g_bopengl) {
5692 OcpnProjType projection = PROJECTION_UNKNOWN;
5695 projection = m_singleChart->GetChartProjectionType();
5696 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5697 VPoint.SetProjectionType(projection);
5701 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5702 m_cache_vp.Invalidate();
5706 UpdateCanvasControlBar();
5710 if (VPoint.GetBBox().GetValid()) {
5713 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5722 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5725 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5732 wxPoint2DDouble r, r1;
5734 double delta_check =
5738 double check_point = wxMin(89., VPoint.
clat);
5740 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5743 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5744 VPoint.
clon, 0, &rhumbDist);
5749 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5750 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5752 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5756 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5762 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5764 if (m_true_scale_ppm)
5765 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5770 double round_factor = 1000.;
5774 round_factor = 100.;
5776 round_factor = 1000.;
5779 double retina_coef = 1;
5783 retina_coef = GetContentScaleFactor();
5794 double true_scale_display =
5795 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5800 if (m_displayed_scale_factor > 10.0)
5801 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5802 m_displayed_scale_factor);
5803 else if (m_displayed_scale_factor > 1.0)
5804 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5805 m_displayed_scale_factor);
5806 else if (m_displayed_scale_factor > 0.1) {
5807 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5808 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5809 }
else if (m_displayed_scale_factor > 0.01) {
5810 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5811 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5814 "%s %4.0f (---)", _(
"Scale"),
5815 true_scale_display);
5818 m_scaleValue = true_scale_display;
5820 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5822 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5823 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5825 bool b_noshow =
false;
5829 wxClientDC dc(parent_frame->GetStatusBar());
5831 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5832 dc.SetFont(*templateFont);
5833 dc.GetTextExtent(text, &w, &h);
5838 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5839 if (w && w > rect.width) {
5840 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5844 dc.GetTextExtent(text, &w, &h);
5846 if (w && w > rect.width) {
5852 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5857 m_vLat = VPoint.
clat;
5858 m_vLon = VPoint.
clon;
5872static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5876static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5877 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5879wxColour ChartCanvas::PredColor() {
5882 if (SHIP_NORMAL == m_ownship_state)
5883 return GetGlobalColor(
"URED");
5885 else if (SHIP_LOWACCURACY == m_ownship_state)
5886 return GetGlobalColor(
"YELO1");
5888 return GetGlobalColor(
"NODTA");
5891wxColour ChartCanvas::ShipColor() {
5895 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5897 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5899 return GetGlobalColor(
"URED");
5902void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5903 wxPoint2DDouble lShipMidPoint) {
5904 dc.SetPen(wxPen(PredColor(), 2));
5906 if (SHIP_NORMAL == m_ownship_state)
5907 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5909 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5911 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5912 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5914 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5916 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5917 lShipMidPoint.m_y + 12);
5920void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5921 wxPoint GPSOffsetPixels,
5922 wxPoint2DDouble lGPSPoint) {
5927 float ref_dim = m_display_size_mm / 24;
5928 ref_dim = wxMin(ref_dim, 12);
5929 ref_dim = wxMax(ref_dim, 6);
5932 cPred.Set(g_cog_predictor_color);
5933 if (cPred == wxNullColour) cPred = PredColor();
5940 double nominal_line_width_pix = wxMax(
5942 floor(m_pix_per_mm / 2));
5946 if (nominal_line_width_pix > g_cog_predictor_width)
5947 g_cog_predictor_width = nominal_line_width_pix;
5950 wxPoint lPredPoint, lHeadPoint;
5952 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5953 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5955 double pred_lat, pred_lon;
5956 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5957 &pred_lat, &pred_lon);
5968 float ndelta_pix = 10.;
5969 double hdg_pred_lat, hdg_pred_lon;
5970 bool b_render_hdt =
false;
5971 if (!std::isnan(
gHdt)) {
5973 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5976 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5977 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5978 if (dist > ndelta_pix ) {
5979 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5980 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5985 wxPoint lShipMidPoint;
5986 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5987 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5988 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5989 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5991 if (lpp >= img_height / 2) {
5992 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
5993 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
5994 !std::isnan(
gSog)) {
5996 float dash_length = ref_dim;
5997 wxDash dash_long[2];
5999 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6000 g_cog_predictor_width);
6001 dash_long[1] = dash_long[0] / 2.0;
6005 if (dash_length > 250.) {
6006 dash_long[0] = 250. / g_cog_predictor_width;
6007 dash_long[1] = dash_long[0] / 2;
6010 wxPen ppPen2(cPred, g_cog_predictor_width,
6011 (wxPenStyle)g_cog_predictor_style);
6012 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6013 ppPen2.SetDashes(2, dash_long);
6016 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6017 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6019 if (g_cog_predictor_width > 1) {
6020 float line_width = g_cog_predictor_width / 3.;
6022 wxDash dash_long3[2];
6023 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6024 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6026 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6027 (wxPenStyle)g_cog_predictor_style);
6028 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6029 ppPen3.SetDashes(2, dash_long3);
6031 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6032 lGPSPoint.m_y + GPSOffsetPixels.y,
6033 lPredPoint.x + GPSOffsetPixels.x,
6034 lPredPoint.y + GPSOffsetPixels.y);
6037 if (g_cog_predictor_endmarker) {
6039 double png_pred_icon_scale_factor = .4;
6040 if (g_ShipScaleFactorExp > 1.0)
6041 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6042 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6046 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6047 (
float)(lPredPoint.x - lShipMidPoint.x));
6048 cog_rad += (float)PI;
6050 for (
int i = 0; i < 4; i++) {
6052 double pxa = (double)(s_png_pred_icon[j]);
6053 double pya = (double)(s_png_pred_icon[j + 1]);
6055 pya *= png_pred_icon_scale_factor;
6056 pxa *= png_pred_icon_scale_factor;
6058 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6059 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6061 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6062 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6066 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6069 dc.SetBrush(wxBrush(cPred));
6071 dc.StrokePolygon(4, icon);
6078 float hdt_dash_length = ref_dim * 0.4;
6080 cPred.Set(g_ownship_HDTpredictor_color);
6081 if (cPred == wxNullColour) cPred = PredColor();
6083 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6084 : g_cog_predictor_width * 0.8);
6085 wxDash dash_short[2];
6087 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6090 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6093 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6094 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6095 ppPen2.SetDashes(2, dash_short);
6099 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6100 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6102 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6104 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6106 if (g_ownship_HDTpredictor_endmarker) {
6107 double nominal_circle_size_pixels = wxMax(
6108 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6111 if (g_ShipScaleFactorExp > 1.0)
6112 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6114 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6115 lHeadPoint.y + GPSOffsetPixels.y,
6116 nominal_circle_size_pixels / 2);
6121 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6122 double factor = 1.00;
6123 if (g_pNavAidRadarRingsStepUnits == 1)
6125 else if (g_pNavAidRadarRingsStepUnits == 2) {
6126 if (std::isnan(
gSog))
6131 factor *= g_fNavAidRadarRingsStep;
6135 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6138 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6139 pow((
double)(lGPSPoint.m_y - r.y), 2));
6140 int pix_radius = (int)lpp;
6142 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6144 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6147 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6149 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6150 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6154void ChartCanvas::ComputeShipScaleFactor(
6155 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6156 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6157 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6158 float screenResolution = m_pix_per_mm;
6161 double ship_bow_lat, ship_bow_lon;
6162 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6163 &ship_bow_lat, &ship_bow_lon);
6164 wxPoint lShipBowPoint;
6165 wxPoint2DDouble b_point =
6169 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6170 powf((
float)(b_point.m_y - a_point.m_y), 2));
6173 float shipLength_mm = shipLength_px / screenResolution;
6176 float ownship_min_mm = g_n_ownship_min_mm;
6177 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6180 float hdt_ant = icon_hdt + 180.;
6181 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6182 float dx = g_n_gps_antenna_offset_x / 1852.;
6183 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6191 if (shipLength_mm < ownship_min_mm) {
6192 dy /= shipLength_mm / ownship_min_mm;
6193 dx /= shipLength_mm / ownship_min_mm;
6196 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6198 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6199 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6205 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6206 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6208 float scale_factor = shipLength_px / ownShipLength;
6211 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6214 scale_factor = wxMax(scale_factor, scale_factor_min);
6216 scale_factor_y = scale_factor;
6217 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6218 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6221void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6222 if (!GetVP().IsValid())
return;
6224 wxPoint GPSOffsetPixels(0, 0);
6225 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6228 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6229 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6233 lShipMidPoint = lGPSPoint;
6237 float icon_hdt = pCog;
6238 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6241 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6245 double osd_head_lat, osd_head_lon;
6246 wxPoint osd_head_point;
6248 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6253 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6254 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6255 icon_rad += (float)PI;
6257 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6261 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6265 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6266 if (GetVP().chart_scale >
6269 ShipDrawLargeScale(dc, lShipMidPoint);
6275 if (m_pos_image_user)
6276 pos_image = m_pos_image_user->Copy();
6277 else if (SHIP_NORMAL == m_ownship_state)
6278 pos_image = m_pos_image_red->Copy();
6279 if (SHIP_LOWACCURACY == m_ownship_state)
6280 pos_image = m_pos_image_yellow->Copy();
6281 else if (SHIP_NORMAL != m_ownship_state)
6282 pos_image = m_pos_image_grey->Copy();
6285 if (m_pos_image_user) {
6286 pos_image = m_pos_image_user->Copy();
6288 if (SHIP_LOWACCURACY == m_ownship_state)
6289 pos_image = m_pos_image_user_yellow->Copy();
6290 else if (SHIP_NORMAL != m_ownship_state)
6291 pos_image = m_pos_image_user_grey->Copy();
6294 img_height = pos_image.GetHeight();
6296 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6297 g_OwnShipIconType > 0)
6299 int ownShipWidth = 22;
6300 int ownShipLength = 84;
6301 if (g_OwnShipIconType == 1) {
6302 ownShipWidth = pos_image.GetWidth();
6303 ownShipLength = pos_image.GetHeight();
6306 float scale_factor_x, scale_factor_y;
6307 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6308 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6309 scale_factor_x, scale_factor_y);
6311 if (g_OwnShipIconType == 1) {
6312 pos_image.Rescale(ownShipWidth * scale_factor_x,
6313 ownShipLength * scale_factor_y,
6314 wxIMAGE_QUALITY_HIGH);
6315 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6317 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6320 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6321 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6322 if (rot_image.GetAlpha(ip, jp) > 64)
6323 rot_image.SetAlpha(ip, jp, 255);
6325 wxBitmap os_bm(rot_image);
6327 int w = os_bm.GetWidth();
6328 int h = os_bm.GetHeight();
6331 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6332 lShipMidPoint.m_y - h / 2,
true);
6335 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6336 lShipMidPoint.m_y - h / 2);
6337 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6338 lShipMidPoint.m_y - h / 2 + h);
6341 else if (g_OwnShipIconType == 2) {
6342 wxPoint ownship_icon[10];
6344 for (
int i = 0; i < 10; i++) {
6346 float pxa = (float)(s_ownship_icon[j]);
6347 float pya = (float)(s_ownship_icon[j + 1]);
6348 pya *= scale_factor_y;
6349 pxa *= scale_factor_x;
6351 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6352 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6354 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6355 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6358 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6360 dc.SetBrush(wxBrush(ShipColor()));
6362 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6365 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6367 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6371 img_height = ownShipLength * scale_factor_y;
6375 if (m_pos_image_user) circle_rad = 1;
6377 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6378 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6379 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6382 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6384 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6387 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6388 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6389 if (rot_image.GetAlpha(ip, jp) > 64)
6390 rot_image.SetAlpha(ip, jp, 255);
6392 wxBitmap os_bm(rot_image);
6394 if (g_ShipScaleFactorExp > 1) {
6395 wxImage scaled_image = os_bm.ConvertToImage();
6396 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6398 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6399 scaled_image.GetHeight() * factor,
6400 wxIMAGE_QUALITY_HIGH));
6402 int w = os_bm.GetWidth();
6403 int h = os_bm.GetHeight();
6406 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6407 lShipMidPoint.m_y - h / 2,
true);
6411 if (m_pos_image_user) circle_rad = 1;
6413 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6414 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6415 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6418 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6419 lShipMidPoint.m_y - h / 2);
6420 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6421 lShipMidPoint.m_y - h / 2 + h);
6426 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6439void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6440 float &MinorSpacing) {
6445 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6446 {.000001f, 45.0f, 15.0f},
6447 {.0002f, 30.0f, 10.0f},
6448 {.0003f, 10.0f, 2.0f},
6449 {.0008f, 5.0f, 1.0f},
6450 {.001f, 2.0f, 30.0f / 60.0f},
6451 {.003f, 1.0f, 20.0f / 60.0f},
6452 {.006f, 0.5f, 10.0f / 60.0f},
6453 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6454 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6455 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6456 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6457 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6458 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6459 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6460 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6463 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6464 if (view_scale_ppm < lltab[tabi][0])
break;
6465 MajorSpacing = lltab[tabi][1];
6466 MinorSpacing = lltab[tabi][2];
6480wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6481 int deg = (int)fabs(latlon);
6482 float min = fabs((fabs(latlon) - deg) * 60.0);
6492 }
else if (latlon < 0.0) {
6504 if (spacing >= 1.0) {
6505 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6506 }
else if (spacing >= (1.0 / 60.0)) {
6507 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6509 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6526void ChartCanvas::GridDraw(
ocpnDC &dc) {
6527 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6529 double nlat, elon, slat, wlon;
6532 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6534 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6536 if (!m_pgridFont) SetupGridFont();
6537 dc.SetFont(*m_pgridFont);
6538 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6541 h = m_canvas_height;
6552 dlon = dlon + 360.0;
6555 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6558 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6561 while (lat < nlat) {
6564 CalcGridText(lat, gridlatMajor,
true);
6566 dc.
DrawLine(0, r.y, w, r.y,
false);
6567 dc.DrawText(st, 0, r.y);
6568 lat = lat + gridlatMajor;
6570 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6574 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6577 while (lat < nlat) {
6580 dc.
DrawLine(0, r.y, 10, r.y,
false);
6581 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6582 lat = lat + gridlatMinor;
6586 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6589 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6592 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6594 wxString st = CalcGridText(lon, gridlonMajor,
false);
6596 dc.
DrawLine(r.x, 0, r.x, h,
false);
6597 dc.DrawText(st, r.x, 0);
6598 lon = lon + gridlonMajor;
6603 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6607 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6609 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6612 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6613 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6614 lon = lon + gridlonMinor;
6621void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6623 double blat, blon, tlat, tlon;
6626 int x_origin = m_bDisplayGrid ? 60 : 20;
6627 int y_origin = m_canvas_height - 50;
6633 if (GetVP().chart_scale > 80000)
6637 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6638 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6643 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6644 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6648 double rotation = -VPoint.
rotation;
6650 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6652 int l1 = (y_origin - r.y) / count;
6654 for (
int i = 0; i < count; i++) {
6661 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6664 double blat, blon, tlat, tlon;
6671 int y_origin = m_canvas_height - chartbar_height - 5;
6675 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6682 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6687 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6688 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6692 float places = floor(logdist), rem = logdist - places;
6693 dist = pow(10, places);
6700 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6701 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6702 double rotation = -VPoint.
rotation;
6708 int l1 = r.x - x_origin;
6710 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6715 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6716 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6717 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6719 if (!m_pgridFont) SetupGridFont();
6720 dc.SetFont(*m_pgridFont);
6721 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6723 dc.GetTextExtent(s, &w, &h);
6729 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6733void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6738 double ra_max = 40.;
6740 wxPen pen_save = dc.GetPen();
6742 wxDateTime now = wxDateTime::Now();
6748 x0 = x1 = x + radius;
6753 while (angle < 360.) {
6754 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6757 if (angle > 360.) angle = 360.;
6759 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6767 x1 = (int)(x + cos(angle * PI / 180.) * r);
6768 y1 = (int)(y + sin(angle * PI / 180.) * r);
6778 dc.
DrawLine(x + radius, y, x1, y1);
6780 dc.SetPen(pen_save);
6783static bool bAnchorSoundPlaying =
false;
6785static void onAnchorSoundFinished(
void *ptr) {
6786 o_sound::g_anchorwatch_sound->UnLoad();
6787 bAnchorSoundPlaying =
false;
6790void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6791 using namespace o_sound;
6793 bool play_sound =
false;
6795 if (AnchorAlertOn1) {
6796 wxPoint TargetPoint;
6799 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6800 TargetPoint.y, 100);
6804 AnchorAlertOn1 =
false;
6807 if (AnchorAlertOn2) {
6808 wxPoint TargetPoint;
6811 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6812 TargetPoint.y, 100);
6816 AnchorAlertOn2 =
false;
6819 if (!bAnchorSoundPlaying) {
6820 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6821 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6822 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6823 if (g_anchorwatch_sound->IsOk()) {
6824 bAnchorSoundPlaying =
true;
6825 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6826 g_anchorwatch_sound->Play();
6832void ChartCanvas::UpdateShips() {
6835 wxClientDC dc(
this);
6836 if (!dc.IsOk())
return;
6838 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6839 if (!test_bitmap.IsOk())
return;
6841 wxMemoryDC temp_dc(test_bitmap);
6843 temp_dc.ResetBoundingBox();
6844 temp_dc.DestroyClippingRegion();
6845 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6856 ocpndc.CalcBoundingBox(px.x, px.y);
6861 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6862 temp_dc.MaxY() - temp_dc.MinY());
6864 wxRect own_ship_update_rect = ship_draw_rect;
6866 if (!own_ship_update_rect.IsEmpty()) {
6869 own_ship_update_rect.Union(ship_draw_last_rect);
6870 own_ship_update_rect.Inflate(2);
6873 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6875 ship_draw_last_rect = ship_draw_rect;
6877 temp_dc.SelectObject(wxNullBitmap);
6880void ChartCanvas::UpdateAlerts() {
6885 wxClientDC dc(
this);
6889 dc.GetSize(&sx, &sy);
6892 wxBitmap test_bitmap(sx, sy, -1);
6896 temp_dc.SelectObject(test_bitmap);
6898 temp_dc.ResetBoundingBox();
6899 temp_dc.DestroyClippingRegion();
6900 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6907 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6908 temp_dc.MaxX() - temp_dc.MinX(),
6909 temp_dc.MaxY() - temp_dc.MinY());
6911 if (!alert_rect.IsEmpty())
6912 alert_rect.Inflate(2);
6914 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6917 wxRect alert_update_rect = alert_draw_rect;
6918 alert_update_rect.Union(alert_rect);
6921 RefreshRect(alert_update_rect,
false);
6925 alert_draw_rect = alert_rect;
6927 temp_dc.SelectObject(wxNullBitmap);
6930void ChartCanvas::UpdateAIS() {
6936 wxClientDC dc(
this);
6940 dc.GetSize(&sx, &sy);
6948 if (
g_pAIS->GetTargetList().size() > 10) {
6949 ais_rect = wxRect(0, 0, sx, sy);
6952 wxBitmap test_bitmap(sx, sy, -1);
6956 temp_dc.SelectObject(test_bitmap);
6958 temp_dc.ResetBoundingBox();
6959 temp_dc.DestroyClippingRegion();
6960 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6964 AISDraw(ocpndc, GetVP(),
this);
6965 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6969 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6970 temp_dc.MaxY() - temp_dc.MinY());
6972 if (!ais_rect.IsEmpty())
6973 ais_rect.Inflate(2);
6975 temp_dc.SelectObject(wxNullBitmap);
6978 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6981 wxRect ais_update_rect = ais_draw_rect;
6982 ais_update_rect.Union(ais_rect);
6985 RefreshRect(ais_update_rect,
false);
6989 ais_draw_rect = ais_rect;
6992void ChartCanvas::ToggleCPAWarn() {
6993 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6999 g_bTCPA_Max =
false;
7003 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
7004 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7006 if (!g_AisFirstTimeUse) {
7007 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7008 _(
"CPA") +
" " + mess, 4, 4);
7013void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7015void ChartCanvas::OnSize(wxSizeEvent &event) {
7016 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7018 GetClientSize(&m_canvas_width, &m_canvas_height);
7022 m_displayScale = GetContentScaleFactor();
7026 m_canvas_width *= m_displayScale;
7027 m_canvas_height *= m_displayScale;
7040 m_absolute_min_scale_ppm =
7042 (1.2 * WGS84_semimajor_axis_meters * PI);
7045 gFrame->ProcessCanvasResize();
7055 SetMUIBarPosition();
7056 UpdateFollowButtonState();
7057 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7061 xr_margin = m_canvas_width * 95 / 100;
7062 xl_margin = m_canvas_width * 5 / 100;
7063 yt_margin = m_canvas_height * 5 / 100;
7064 yb_margin = m_canvas_height * 95 / 100;
7067 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7072 m_brepaint_piano =
true;
7075 m_dc_route.SelectObject(wxNullBitmap);
7078 m_dc_route.SelectObject(*proute_bm);
7092 m_glcc->OnSize(event);
7101void ChartCanvas::ProcessNewGUIScale() {
7109void ChartCanvas::CreateMUIBar() {
7110 if (g_useMUI && !m_muiBar) {
7111 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7112 m_muiBar->SetColorScheme(m_cs);
7113 m_muiBarHOSize = m_muiBar->m_size;
7121 SetMUIBarPosition();
7122 UpdateFollowButtonState();
7123 m_muiBar->UpdateDynamicValues();
7124 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7128void ChartCanvas::SetMUIBarPosition() {
7132 int pianoWidth = GetClientSize().x * 0.6f;
7137 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7138 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7140 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7141 m_muiBar->SetColorScheme(m_cs);
7145 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7146 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7148 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7149 m_muiBar->SetColorScheme(m_cs);
7153 m_muiBar->SetBestPosition();
7157void ChartCanvas::DestroyMuiBar() {
7164void ChartCanvas::ShowCompositeInfoWindow(
7165 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7167 if (NULL == m_pCIWin) {
7172 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7175 s = _(
"Composite of ");
7178 s1.Printf(
"%d ", n_charts);
7186 s1.Printf(_(
"Chart scale"));
7189 s2.Printf(
"1:%d\n",
scale);
7193 s1 = _(
"Zoom in for more information");
7197 int char_width = s1.Length();
7198 int char_height = 3;
7200 if (g_bChartBarEx) {
7203 for (
int i : index_vector) {
7205 wxString path = cte.GetFullSystemPath();
7209 char_width = wxMax(char_width, path.Length());
7210 if (j++ >= 9)
break;
7213 s +=
" .\n .\n .\n";
7222 m_pCIWin->SetString(s);
7224 m_pCIWin->FitToChars(char_width, char_height);
7227 p.x = x / GetContentScaleFactor();
7228 if ((p.x + m_pCIWin->GetWinSize().x) >
7229 (m_canvas_width / GetContentScaleFactor()))
7230 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7231 m_pCIWin->GetWinSize().x) /
7234 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7235 4 - m_pCIWin->GetWinSize().y;
7237 m_pCIWin->dbIndex = 0;
7238 m_pCIWin->chart_scale = 0;
7239 m_pCIWin->SetPosition(p);
7240 m_pCIWin->SetBitmap();
7241 m_pCIWin->Refresh();
7245 HideChartInfoWindow();
7249void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7251 if (NULL == m_pCIWin) {
7256 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7265 dbIndex, FULL_INIT);
7267 int char_width, char_height;
7268 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7269 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7271 m_pCIWin->SetString(s);
7272 m_pCIWin->FitToChars(char_width, char_height);
7275 p.x = x / GetContentScaleFactor();
7276 if ((p.x + m_pCIWin->GetWinSize().x) >
7277 (m_canvas_width / GetContentScaleFactor()))
7278 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7279 m_pCIWin->GetWinSize().x) /
7282 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7283 4 - m_pCIWin->GetWinSize().y;
7285 m_pCIWin->dbIndex = dbIndex;
7286 m_pCIWin->SetPosition(p);
7287 m_pCIWin->SetBitmap();
7288 m_pCIWin->Refresh();
7292 HideChartInfoWindow();
7296void ChartCanvas::HideChartInfoWindow() {
7299 m_pCIWin->Destroy();
7303 androidForceFullRepaint();
7308void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7309 wxMouseEvent ev(wxEVT_MOTION);
7312 ev.m_leftDown = mouse_leftisdown;
7314 wxEvtHandler *evthp = GetEventHandler();
7316 ::wxPostEvent(evthp, ev);
7319void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7320 if ((m_panx_target_final - m_panx_target_now) ||
7321 (m_pany_target_final - m_pany_target_now)) {
7322 DoTimedMovementTarget();
7327void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7329bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7331 if (m_disable_edge_pan)
return false;
7334 int pan_margin = m_canvas_width * margin / 100;
7335 int pan_timer_set = 200;
7336 double pan_delta = GetVP().
pix_width * delta / 100;
7340 if (x > m_canvas_width - pan_margin) {
7345 else if (x < pan_margin) {
7350 if (y < pan_margin) {
7355 else if (y > m_canvas_height - pan_margin) {
7364 wxMouseState state = ::wxGetMouseState();
7365#if wxCHECK_VERSION(3, 0, 0)
7366 if (!state.LeftIsDown())
7368 if (!state.LeftDown())
7373 if ((bft) && !pPanTimer->IsRunning()) {
7375 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7381 if ((!bft) && pPanTimer->IsRunning()) {
7391void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7392 bool setBeingEdited) {
7393 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7394 m_pRoutePointEditTarget = NULL;
7395 m_pFoundPoint = NULL;
7398 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7399 SelectableItemList SelList =
pSelect->FindSelectionList(
7409 bool brp_viz =
false;
7410 if (m_pEditRouteArray) {
7411 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7412 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7413 if (pr->IsVisible()) {
7419 brp_viz = frp->IsVisible();
7423 if (m_pEditRouteArray)
7425 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7426 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7429 m_bRouteEditing = setBeingEdited;
7432 frp->m_bRPIsBeingEdited = setBeingEdited;
7433 m_bMarkEditing = setBeingEdited;
7436 m_pRoutePointEditTarget = frp;
7437 m_pFoundPoint = pFind;
7442std::shared_ptr<HostApi121::PiPointContext>
7443ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7457 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7458 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7459 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7460 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7461 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7465 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7468 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7473 int FoundAIS_MMSI = 0;
7475 FoundAIS_MMSI = pFindAIS->GetUserData();
7478 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7479 seltype |= SELTYPE_AISTARGET;
7485 Route *SelectedRoute = NULL;
7491 Route *pSelectedActiveRoute = NULL;
7492 Route *pSelectedVizRoute = NULL;
7495 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7496 SelectableItemList SelList =
7497 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7505 bool brp_viz =
false;
7507 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7509 if (pr->IsVisible()) {
7514 if (!brp_viz && prp->IsShared())
7516 brp_viz = prp->IsVisible();
7519 brp_viz = prp->IsVisible();
7521 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7527 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7530 pSelectedActiveRoute = pr;
7531 pFoundActiveRoutePoint = prp;
7536 if (NULL == pSelectedVizRoute) {
7537 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7539 if (pr->IsVisible()) {
7540 pSelectedVizRoute = pr;
7541 pFoundVizRoutePoint = prp;
7547 delete proute_array;
7552 if (pFoundActiveRoutePoint) {
7553 FoundRoutePoint = pFoundActiveRoutePoint;
7554 SelectedRoute = pSelectedActiveRoute;
7555 }
else if (pFoundVizRoutePoint) {
7556 FoundRoutePoint = pFoundVizRoutePoint;
7557 SelectedRoute = pSelectedVizRoute;
7560 FoundRoutePoint = pFirstVizPoint;
7562 if (SelectedRoute) {
7563 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7564 }
else if (FoundRoutePoint) {
7565 seltype |= SELTYPE_MARKPOINT;
7570 if (m_pFoundRoutePoint) {
7574 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7575 RefreshRect(wp_rect,
true);
7584 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7585 SelectableItemList SelList =
7586 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7588 if (NULL == SelectedRoute)
7593 if (pr->IsVisible()) {
7600 if (SelectedRoute) {
7601 if (NULL == FoundRoutePoint)
7602 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7605 seltype |= SELTYPE_ROUTESEGMENT;
7609 if (pFindTrackSeg) {
7610 m_pSelectedTrack = NULL;
7611 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7612 SelectableItemList SelList =
7613 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7618 if (pt->IsVisible()) {
7619 m_pSelectedTrack = pt;
7623 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7626 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7629 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7630 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7631 rstruct->object_ident =
"";
7633 if (seltype == SELTYPE_AISTARGET) {
7634 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7636 val.Printf(
"%d", FoundAIS_MMSI);
7637 rstruct->object_ident = val.ToStdString();
7638 }
else if (seltype & SELTYPE_MARKPOINT) {
7639 if (FoundRoutePoint) {
7640 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7641 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7643 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7644 if (SelectedRoute) {
7645 rstruct->object_type =
7646 HostApi121::PiContextObjectType::kObjectRoutesegment;
7647 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7649 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7650 if (m_pSelectedTrack) {
7651 rstruct->object_type =
7652 HostApi121::PiContextObjectType::kObjectTracksegment;
7653 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7660void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7661 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7662 singleClickEventIsValid =
false;
7663 m_DoubleClickTimer->Stop();
7668bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7669 if (!m_bChartDragging && !m_bDrawingRoute) {
7674 if (m_Compass && m_Compass->IsShown()) {
7676 bool isInCompass = logicalRect.Contains(event.GetPosition());
7677 if (isInCompass || m_mouseWasInCompass) {
7678 if (m_Compass->MouseEvent(event)) {
7679 cursor_region = CENTER;
7680 if (!g_btouch) SetCanvasCursor(event);
7681 m_mouseWasInCompass = isInCompass;
7685 m_mouseWasInCompass = isInCompass;
7688 if (m_notification_button && m_notification_button->IsShown()) {
7690 bool isinButton = logicalRect.Contains(event.GetPosition());
7692 SetCursor(*pCursorArrow);
7693 if (event.LeftDown()) HandleNotificationMouseClick();
7698 if (MouseEventToolbar(event))
return true;
7700 if (MouseEventChartBar(event))
return true;
7702 if (MouseEventMUIBar(event))
return true;
7704 if (MouseEventIENCBar(event))
return true;
7709void ChartCanvas::HandleNotificationMouseClick() {
7710 if (!m_NotificationsList) {
7714 m_NotificationsList->RecalculateSize();
7715 m_NotificationsList->Hide();
7718 if (m_NotificationsList->IsShown()) {
7719 m_NotificationsList->Hide();
7721 m_NotificationsList->RecalculateSize();
7722 m_NotificationsList->ReloadNotificationList();
7723 m_NotificationsList->Show();
7726bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7727 if (!g_bShowChartBar)
return false;
7729 if (!m_Piano->MouseEvent(event))
return false;
7731 cursor_region = CENTER;
7732 if (!g_btouch) SetCanvasCursor(event);
7736bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7737 if (!IsPrimaryCanvas())
return false;
7746 cursor_region = CENTER;
7747 if (!g_btouch) SetCanvasCursor(event);
7751bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7752 if (!IsPrimaryCanvas())
return false;
7765bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7767 if (!m_muiBar->MouseEvent(event))
return false;
7770 cursor_region = CENTER;
7771 if (!g_btouch) SetCanvasCursor(event);
7783 event.GetPosition(&x, &y);
7785 x *= m_displayScale;
7786 y *= m_displayScale;
7788 m_MouseDragging =
event.Dragging();
7794 if (event.Dragging()) {
7795 if ((x == mouse_x) && (y == mouse_y))
return true;
7801 mouse_leftisdown =
event.LeftDown();
7805 cursor_region = CENTER;
7809 if (m_Compass && m_Compass->IsShown() &&
7810 m_Compass->
GetRect().Contains(event.GetPosition())) {
7811 cursor_region = CENTER;
7812 }
else if (x > xr_margin) {
7813 cursor_region = MID_RIGHT;
7814 }
else if (x < xl_margin) {
7815 cursor_region = MID_LEFT;
7816 }
else if (y > yb_margin - chartbar_height &&
7817 y < m_canvas_height - chartbar_height) {
7818 cursor_region = MID_TOP;
7819 }
else if (y < yt_margin) {
7820 cursor_region = MID_BOT;
7822 cursor_region = CENTER;
7825 if (!g_btouch) SetCanvasCursor(event);
7829 leftIsDown =
event.LeftDown();
7832 if (event.LeftDown()) {
7833 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7836 g_bTempShowMenuBar =
false;
7837 parent_frame->ApplyGlobalSettings(
false);
7845 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7846 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7850 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7851 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7854 event.SetEventObject(
this);
7855 if (SendMouseEventToPlugins(event))
7862 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7863 StartChartDragInertia();
7866 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7867 !singleClickEventIsValid) {
7869 if (m_DoubleClickTimer->IsRunning()) {
7870 m_DoubleClickTimer->Stop();
7875 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7876 singleClickEvent = event;
7877 singleClickEventIsValid =
true;
7886 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7887 if (g_click_stop > 0) {
7895 if (GetUpMode() == COURSE_UP_MODE) {
7896 m_b_rot_hidef =
false;
7897 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7899 pRotDefTimer->Stop();
7902 bool bRoll = !g_btouch;
7907 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7908 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7909 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7910 m_RolloverPopupTimer.Start(
7914 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7918 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7927#if !defined(__WXGTK__) && !defined(__WXQT__)
7935 if ((x >= 0) && (y >= 0))
7940 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7941 wxPoint p = ClientToScreen(wxPoint(x, y));
7947 if (m_routeState >= 2) {
7950 m_bDrawingRoute =
true;
7952 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7957 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7960 m_bDrawingRoute =
true;
7962 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7975#if defined(__WXMAC__) || defined(__ANDROID__)
7979 wxClientDC cdc(GetParent());
7991 if (m_pSelectedRoute) {
7993 m_pSelectedRoute->DeSelectRoute();
7995 if (g_bopengl && m_glcc) {
8000 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8003 if (m_pFoundRoutePoint) {
8011 if (g_btouch && m_pRoutePointEditTarget) {
8014 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8018 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8019 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8020 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8021 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8022 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8026 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8029 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8035 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8038 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8039 seltype |= SELTYPE_AISTARGET;
8044 m_pFoundRoutePoint = NULL;
8049 Route *pSelectedActiveRoute = NULL;
8050 Route *pSelectedVizRoute = NULL;
8053 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8054 SelectableItemList SelList =
8055 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8063 bool brp_viz =
false;
8065 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8067 if (pr->IsVisible()) {
8072 if (!brp_viz && prp->IsShared())
8074 brp_viz = prp->IsVisible();
8077 brp_viz = prp->IsVisible();
8079 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8084 m_pSelectedRoute = NULL;
8086 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8089 pSelectedActiveRoute = pr;
8090 pFoundActiveRoutePoint = prp;
8095 if (NULL == pSelectedVizRoute) {
8096 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8098 if (pr->IsVisible()) {
8099 pSelectedVizRoute = pr;
8100 pFoundVizRoutePoint = prp;
8106 delete proute_array;
8111 if (pFoundActiveRoutePoint) {
8112 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8113 m_pSelectedRoute = pSelectedActiveRoute;
8114 }
else if (pFoundVizRoutePoint) {
8115 m_pFoundRoutePoint = pFoundVizRoutePoint;
8116 m_pSelectedRoute = pSelectedVizRoute;
8119 m_pFoundRoutePoint = pFirstVizPoint;
8121 if (m_pSelectedRoute) {
8122 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8123 }
else if (m_pFoundRoutePoint) {
8124 seltype |= SELTYPE_MARKPOINT;
8128 if (m_pFoundRoutePoint) {
8132 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8133 RefreshRect(wp_rect,
true);
8141 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8142 SelectableItemList SelList =
8143 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8145 if (NULL == m_pSelectedRoute)
8150 if (pr->IsVisible()) {
8151 m_pSelectedRoute = pr;
8157 if (m_pSelectedRoute) {
8158 if (NULL == m_pFoundRoutePoint)
8159 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8164 if (g_bopengl && m_glcc) {
8169 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8171 seltype |= SELTYPE_ROUTESEGMENT;
8175 if (pFindTrackSeg) {
8176 m_pSelectedTrack = NULL;
8177 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8178 SelectableItemList SelList =
8179 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8184 if (pt->IsVisible()) {
8185 m_pSelectedTrack = pt;
8189 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8195 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8196 seltype |= SELTYPE_CURRENTPOINT;
8199 else if (pFindTide) {
8200 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8201 seltype |= SELTYPE_TIDEPOINT;
8206 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8211IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8221 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8222 SelectableItemList SelList =
8223 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8226 pFind = *SelList.begin();
8227 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8229 auto node = SelList.begin();
8230 if (SelList.size() > 1) {
8231 for (++node; node != SelList.end(); ++node) {
8234 if (pIDX_candidate->
IDX_type ==
'c') {
8235 pIDX_best_candidate = pIDX_candidate;
8240 pFind = *SelList.begin();
8241 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8244 return pIDX_best_candidate;
8246void ChartCanvas::CallPopupMenu(
int x,
int y) {
8250 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8258 if (SELTYPE_CURRENTPOINT == seltype) {
8264 if (SELTYPE_TIDEPOINT == seltype) {
8270 InvokeCanvasMenu(x, y, seltype);
8273 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8277 m_pSelectedRoute = NULL;
8279 if (m_pFoundRoutePoint) {
8280 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8283 m_pFoundRoutePoint = NULL;
8289bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8297 event.GetPosition(&x, &y);
8303 SelectRadius = g_Platform->GetSelectRadiusPix() /
8304 (m_true_scale_ppm * 1852 * 60);
8311 if (event.LeftDClick() && (cursor_region == CENTER)) {
8312 m_DoubleClickTimer->Start();
8313 singleClickEventIsValid =
false;
8319 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8322 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8325 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8326 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8327 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8333 SelectableItemList rpSelList =
8334 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8335 bool b_onRPtarget =
false;
8338 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8339 b_onRPtarget =
true;
8347 std::unique_ptr<HostApi> host_api =
GetHostApi();
8348 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8350 if (m_pRoutePointEditTarget) {
8352 if ((api_121->GetContextMenuMask() &
8353 api_121->kContextMenuDisableWaypoint))
8355 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8361 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8364 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8365 m_pRoutePointEditTarget = NULL;
8366 RefreshRect(wp_rect,
true);
8370 auto node = rpSelList.begin();
8371 if (node != rpSelList.end()) {
8375 wxArrayPtrVoid *proute_array =
8380 bool brp_viz =
false;
8382 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8384 if (pr->IsVisible()) {
8389 delete proute_array;
8393 brp_viz = frp->IsVisible();
8395 brp_viz = frp->IsVisible();
8398 if ((api_121->GetContextMenuMask() &
8399 api_121->kContextMenuDisableWaypoint))
8402 ShowMarkPropertiesDialog(frp);
8411 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8413 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8416 if (pr->IsVisible()) {
8417 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8422 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8424 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8427 if (pt->IsVisible()) {
8428 ShowTrackPropertiesDialog(pt);
8437 if (m_bShowCurrent) {
8439 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8441 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8449 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8451 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8459 ShowObjectQueryWindow(x, y, zlat, zlon);
8464 if (event.LeftDown()) {
8480 bool appending =
false;
8481 bool inserting =
false;
8484 SetCursor(*pCursorPencil);
8488 m_bRouteEditing =
true;
8490 if (m_routeState == 1) {
8491 m_pMouseRoute =
new Route();
8492 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8502 double nearby_radius_meters =
8503 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8506 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8507 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8508 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8509 wxArrayPtrVoid *proute_array =
8514 bool brp_viz =
false;
8516 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8518 if (pr->IsVisible()) {
8523 delete proute_array;
8525 pNearbyPoint->IsShared())
8528 pNearbyPoint->IsVisible();
8530 brp_viz = pNearbyPoint->IsVisible();
8533 wxString msg = _(
"Use nearby waypoint?");
8535 const bool noname(pNearbyPoint->GetName() ==
"");
8538 _(
"Use nearby nameless waypoint and name it M with"
8539 " a unique number?");
8542 m_FinishRouteOnKillFocus =
false;
8544 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8545 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8546 m_FinishRouteOnKillFocus =
true;
8547 if (dlg_return == wxID_YES) {
8549 if (m_pMouseRoute) {
8550 int last_wp_num = m_pMouseRoute->GetnPoints();
8552 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8553 wxString wp_name = wxString::Format(
8554 "M%002i-%s", last_wp_num + 1, guid_short);
8555 pNearbyPoint->SetName(wp_name);
8557 pNearbyPoint->SetName(
"WPXX");
8559 pMousePoint = pNearbyPoint;
8562 if (m_routeState > 1)
8563 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8564 Undo_HasParent, NULL);
8567 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8568 bool procede =
false;
8572 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8578 m_FinishRouteOnKillFocus =
false;
8584 _(
"Insert first part of this route in the new route?");
8585 if (tail->GetIndexOf(pMousePoint) ==
8588 dmsg = _(
"Insert this route in the new route?");
8590 if (tail->GetIndexOf(pMousePoint) != 1) {
8591 dlg_return = OCPNMessageBox(
8592 this, dmsg, _(
"OpenCPN Route Create"),
8593 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8594 m_FinishRouteOnKillFocus =
true;
8596 if (dlg_return == wxID_YES) {
8603 _(
"Append last part of this route to the new route?");
8604 if (tail->GetIndexOf(pMousePoint) == 1)
8606 "Append this route to the new route?");
8611 if (tail->GetLastPoint() != pMousePoint) {
8612 dlg_return = OCPNMessageBox(
8613 this, dmsg, _(
"OpenCPN Route Create"),
8614 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8615 m_FinishRouteOnKillFocus =
true;
8617 if (dlg_return == wxID_YES) {
8628 if (!FindRouteContainingWaypoint(pMousePoint))
8629 pMousePoint->SetShared(
true);
8634 if (NULL == pMousePoint) {
8635 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8637 pMousePoint->SetNameShown(
false);
8641 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8643 if (m_routeState > 1)
8644 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8645 Undo_IsOrphanded, NULL);
8648 if (m_pMouseRoute) {
8649 if (m_routeState == 1) {
8651 m_pMouseRoute->AddPoint(pMousePoint);
8655 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8656 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8657 &rhumbBearing, &rhumbDist);
8658 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8659 rlat, &gcDist, &gcBearing, NULL);
8660 double gcDistNM = gcDist / 1852.0;
8663 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8664 pow(rhumbDist - gcDistNM - 1, 0.5);
8667 msg << _(
"For this leg the Great Circle route is ")
8669 << _(
" shorter than rhumbline.\n\n")
8670 << _(
"Would you like include the Great Circle routing points "
8673 m_FinishRouteOnKillFocus =
false;
8674 m_disable_edge_pan =
true;
8677 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8678 wxYES_NO | wxNO_DEFAULT);
8680 m_disable_edge_pan =
false;
8681 m_FinishRouteOnKillFocus =
true;
8683 if (answer == wxID_YES) {
8685 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8686 wxRealPoint gcCoord;
8688 for (
int i = 1; i <= segmentCount; i++) {
8689 double fraction = (double)i * (1.0 / (
double)segmentCount);
8690 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8691 gcDist * fraction, gcBearing,
8692 &gcCoord.x, &gcCoord.y, NULL);
8694 if (i < segmentCount) {
8695 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8697 gcPoint->SetNameShown(
false);
8699 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8701 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8704 gcPoint = pMousePoint;
8707 m_pMouseRoute->AddPoint(gcPoint);
8708 pSelect->AddSelectableRouteSegment(
8709 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8710 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8711 prevGcPoint = gcPoint;
8714 undo->CancelUndoableAction(
true);
8717 m_pMouseRoute->AddPoint(pMousePoint);
8718 pSelect->AddSelectableRouteSegment(
8719 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8720 pMousePoint, m_pMouseRoute);
8721 undo->AfterUndoableAction(m_pMouseRoute);
8725 m_pMouseRoute->AddPoint(pMousePoint);
8726 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8727 rlon, m_prev_pMousePoint,
8728 pMousePoint, m_pMouseRoute);
8729 undo->AfterUndoableAction(m_pMouseRoute);
8735 m_prev_pMousePoint = pMousePoint;
8743 int connect = tail->GetIndexOf(pMousePoint);
8748 int length = tail->GetnPoints();
8753 start = connect + 1;
8758 m_pMouseRoute->RemovePoint(
8762 for (i = start; i <= stop; i++) {
8763 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8766 m_pMouseRoute->GetnPoints();
8768 gFrame->RefreshAllCanvas();
8772 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8774 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8775 m_pMouseRoute->FinalizeForRendering();
8777 gFrame->RefreshAllCanvas();
8781 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8783 SetCursor(*pCursorPencil);
8785 if (!m_pMeasureRoute) {
8786 m_pMeasureRoute =
new Route();
8790 if (m_nMeasureState == 1) {
8797 wxEmptyString, wxEmptyString);
8799 pMousePoint->SetShowWaypointRangeRings(
false);
8801 m_pMeasureRoute->AddPoint(pMousePoint);
8805 m_prev_pMousePoint = pMousePoint;
8809 gFrame->RefreshAllCanvas();
8814 FindRoutePointsAtCursor(SelectRadius,
true);
8818 m_last_touch_down_pos =
event.GetPosition();
8820 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8828 if (ret)
return true;
8831 if (event.Dragging()) {
8834 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8836 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8838 SelectableItemList SelList =
pSelect->FindSelectionList(
8842 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8847 if (m_pRoutePointEditTarget &&
8848 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8850 SelectableItemList SelList =
pSelect->FindSelectionList(
8854 if (m_pRoutePointEditTarget == frp) {
8855 m_bIsInRadius =
true;
8860 if (!m_dragoffsetSet) {
8862 .PresetDragOffset(
this, mouse_x, mouse_y);
8863 m_dragoffsetSet =
true;
8868 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8869 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8872 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8874 DraggingAllowed =
false;
8876 if (m_pRoutePointEditTarget &&
8877 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8878 DraggingAllowed =
false;
8880 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8882 if (DraggingAllowed) {
8883 if (!undo->InUndoableAction()) {
8884 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8885 Undo_NeedsCopy, m_pFoundPoint);
8891 if (!g_bopengl && m_pEditRouteArray) {
8892 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8893 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8900 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8901 pre_rect.Union(route_rect);
8909 if (CheckEdgePan(x, y,
true, 5, 2))
8917 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8919 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8920 m_pRoutePointEditTarget,
8921 SELTYPE_DRAGHANDLE);
8922 m_pFoundPoint->m_slat =
8923 m_pRoutePointEditTarget->m_lat;
8924 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8926 m_pRoutePointEditTarget->m_lat =
8928 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8929 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8930 m_pFoundPoint->m_slat =
8932 m_pFoundPoint->m_slon = new_cursor_lon;
8948 if (m_pEditRouteArray) {
8949 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8951 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8954 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8955 post_rect.Union(route_rect);
8961 pre_rect.Union(post_rect);
8962 RefreshRect(pre_rect,
false);
8964 gFrame->RefreshCanvasOther(
this);
8965 m_bRoutePoinDragging =
true;
8970 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8971 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8974 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8976 DraggingAllowed =
false;
8978 if (m_pRoutePointEditTarget &&
8979 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8980 DraggingAllowed =
false;
8982 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8984 if (DraggingAllowed) {
8985 if (!undo->InUndoableAction()) {
8986 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8987 Undo_NeedsCopy, m_pFoundPoint);
9001 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9007 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9008 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9009 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9010 (
int)(lppmax - (pre_rect.height / 2)));
9018 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9021 m_pRoutePointEditTarget,
9022 SELTYPE_DRAGHANDLE);
9023 m_pFoundPoint->m_slat =
9024 m_pRoutePointEditTarget->m_lat;
9025 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9027 m_pRoutePointEditTarget->m_lat =
9030 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9043 if (!g_btouch) InvalidateGL();
9049 .CalculateDCRect(m_dc_route,
this, &post_rect);
9050 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9051 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9052 (
int)(lppmax - (post_rect.height / 2)));
9055 pre_rect.Union(post_rect);
9056 RefreshRect(pre_rect,
false);
9058 gFrame->RefreshCanvasOther(
this);
9059 m_bRoutePoinDragging =
true;
9061 ret = g_btouch ? m_bRoutePoinDragging :
true;
9064 if (ret)
return true;
9067 if (event.LeftUp()) {
9068 bool b_startedit_route =
false;
9069 m_dragoffsetSet =
false;
9072 m_bChartDragging =
false;
9073 m_bIsInRadius =
false;
9077 if (m_ignore_next_leftup) {
9078 m_ignore_next_leftup =
false;
9083 m_bedge_pan =
false;
9088 bool appending =
false;
9089 bool inserting =
false;
9095 if (m_pRoutePointEditTarget) {
9101 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9102 RefreshRect(wp_rect,
true);
9104 m_pRoutePointEditTarget = NULL;
9106 m_bRouteEditing =
true;
9108 if (m_routeState == 1) {
9109 m_pMouseRoute =
new Route();
9110 m_pMouseRoute->SetHiLite(50);
9114 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9121 double nearby_radius_meters =
9122 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9125 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9126 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9127 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9130 m_FinishRouteOnKillFocus =
9132 dlg_return = OCPNMessageBox(
9133 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9134 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9135 m_FinishRouteOnKillFocus =
true;
9137 dlg_return = wxID_YES;
9139 if (dlg_return == wxID_YES) {
9140 pMousePoint = pNearbyPoint;
9143 if (m_routeState > 1)
9144 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9145 Undo_HasParent, NULL);
9146 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9148 bool procede =
false;
9152 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9158 m_FinishRouteOnKillFocus =
false;
9159 if (m_routeState == 1) {
9163 _(
"Insert first part of this route in the new route?");
9164 if (tail->GetIndexOf(pMousePoint) ==
9167 dmsg = _(
"Insert this route in the new route?");
9169 if (tail->GetIndexOf(pMousePoint) != 1) {
9171 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9172 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9173 m_FinishRouteOnKillFocus =
true;
9175 if (dlg_return == wxID_YES) {
9182 _(
"Append last part of this route to the new route?");
9183 if (tail->GetIndexOf(pMousePoint) == 1)
9185 "Append this route to the new route?");
9189 if (tail->GetLastPoint() != pMousePoint) {
9191 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9192 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9193 m_FinishRouteOnKillFocus =
true;
9195 if (dlg_return == wxID_YES) {
9206 if (!FindRouteContainingWaypoint(pMousePoint))
9207 pMousePoint->SetShared(
true);
9211 if (NULL == pMousePoint) {
9212 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9214 pMousePoint->SetNameShown(
false);
9216 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9218 if (m_routeState > 1)
9219 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9220 Undo_IsOrphanded, NULL);
9223 if (m_routeState == 1) {
9225 m_pMouseRoute->AddPoint(pMousePoint);
9226 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9230 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9231 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9232 &rhumbBearing, &rhumbDist);
9233 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9234 &gcDist, &gcBearing, NULL);
9235 double gcDistNM = gcDist / 1852.0;
9238 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9239 pow(rhumbDist - gcDistNM - 1, 0.5);
9242 msg << _(
"For this leg the Great Circle route is ")
9244 << _(
" shorter than rhumbline.\n\n")
9245 << _(
"Would you like include the Great Circle routing points "
9249 m_FinishRouteOnKillFocus =
false;
9250 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9251 wxYES_NO | wxNO_DEFAULT);
9252 m_FinishRouteOnKillFocus =
true;
9254 int answer = wxID_NO;
9257 if (answer == wxID_YES) {
9259 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9260 wxRealPoint gcCoord;
9262 for (
int i = 1; i <= segmentCount; i++) {
9263 double fraction = (double)i * (1.0 / (
double)segmentCount);
9264 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9265 gcDist * fraction, gcBearing,
9266 &gcCoord.x, &gcCoord.y, NULL);
9268 if (i < segmentCount) {
9269 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9271 gcPoint->SetNameShown(
false);
9272 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9275 gcPoint = pMousePoint;
9278 m_pMouseRoute->AddPoint(gcPoint);
9279 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9281 pSelect->AddSelectableRouteSegment(
9282 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9283 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9284 prevGcPoint = gcPoint;
9287 undo->CancelUndoableAction(
true);
9290 m_pMouseRoute->AddPoint(pMousePoint);
9291 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9292 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9293 rlon, m_prev_pMousePoint,
9294 pMousePoint, m_pMouseRoute);
9295 undo->AfterUndoableAction(m_pMouseRoute);
9299 m_pMouseRoute->AddPoint(pMousePoint);
9300 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9302 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9303 rlon, m_prev_pMousePoint,
9304 pMousePoint, m_pMouseRoute);
9305 undo->AfterUndoableAction(m_pMouseRoute);
9311 m_prev_pMousePoint = pMousePoint;
9318 int connect = tail->GetIndexOf(pMousePoint);
9323 int length = tail->GetnPoints();
9328 start = connect + 1;
9333 m_pMouseRoute->RemovePoint(
9337 for (i = start; i <= stop; i++) {
9338 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9341 m_pMouseRoute->GetnPoints();
9343 gFrame->RefreshAllCanvas();
9347 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9349 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9350 m_pMouseRoute->FinalizeForRendering();
9355 }
else if (m_bMeasure_Active && m_nMeasureState)
9358 m_bedge_pan =
false;
9362 if (m_ignore_next_leftup) {
9363 m_ignore_next_leftup =
false;
9367 if (m_nMeasureState == 1) {
9368 m_pMeasureRoute =
new Route();
9374 if (m_pMeasureRoute) {
9377 wxEmptyString, wxEmptyString);
9380 m_pMeasureRoute->AddPoint(pMousePoint);
9384 m_prev_pMousePoint = pMousePoint;
9386 m_pMeasureRoute->GetnPoints();
9390 CancelMeasureRoute();
9396 bool bSelectAllowed =
true;
9398 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9400 bSelectAllowed =
false;
9404 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9405 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9406 significant_drag) ||
9407 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9408 significant_drag)) {
9409 bSelectAllowed =
false;
9417 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9419 if (bSelectAllowed) {
9420 bool b_was_editing_mark = m_bMarkEditing;
9421 bool b_was_editing_route = m_bRouteEditing;
9422 FindRoutePointsAtCursor(SelectRadius,
9428 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9429 m_pRoutePointEditTarget = NULL;
9431 if (!b_was_editing_route) {
9432 if (m_pEditRouteArray) {
9433 b_startedit_route =
true;
9437 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9438 m_pTrackRolloverWin->IsActive(
false);
9440 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9441 m_pRouteRolloverWin->IsActive(
false);
9445 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9447 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9455 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9456 pre_rect.Union(route_rect);
9459 RefreshRect(pre_rect,
true);
9462 b_startedit_route =
false;
9466 if (m_pRoutePointEditTarget) {
9467 if (b_was_editing_mark ||
9468 b_was_editing_route) {
9469 if (m_lastRoutePointEditTarget) {
9473 .EnableDragHandle(
false);
9474 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9475 SELTYPE_DRAGHANDLE);
9479 if (m_pRoutePointEditTarget) {
9482 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9483 wxPoint2DDouble dragHandlePoint =
9485 .GetDragHandlePoint(
this);
9487 dragHandlePoint.m_y, dragHandlePoint.m_x,
9488 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9491 if (m_lastRoutePointEditTarget) {
9495 .EnableDragHandle(
false);
9496 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9497 SELTYPE_DRAGHANDLE);
9500 wxArrayPtrVoid *lastEditRouteArray =
9502 m_lastRoutePointEditTarget);
9503 if (lastEditRouteArray) {
9504 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9506 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9511 delete lastEditRouteArray;
9522 if (m_lastRoutePointEditTarget) {
9525 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9526 RefreshRect(wp_rect,
true);
9529 if (m_pRoutePointEditTarget) {
9532 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9533 RefreshRect(wp_rect,
true);
9541 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9542 bool b_start_rollover =
false;
9546 if (pFind) b_start_rollover =
true;
9549 if (!b_start_rollover && !b_startedit_route) {
9550 SelectableItemList SelList =
pSelect->FindSelectionList(
9554 if (pr && pr->IsVisible()) {
9555 b_start_rollover =
true;
9561 if (!b_start_rollover && !b_startedit_route) {
9562 SelectableItemList SelList =
pSelect->FindSelectionList(
9566 if (tr && tr->IsVisible()) {
9567 b_start_rollover =
true;
9573 if (b_start_rollover)
9574 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9578 bool appending =
false;
9579 bool inserting =
false;
9581 if (m_bRouteEditing ) {
9583 if (m_pRoutePointEditTarget) {
9589 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9590 double nearby_radius_meters =
9591 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9592 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9593 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9594 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9596 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9600 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9602 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9606 std::find(list->begin(), list->end(), pNearbyPoint);
9607 if (pos != list->end()) {
9619 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9624 OCPNMessageBox(
this,
9625 _(
"Replace this RoutePoint by the nearby "
9627 _(
"OpenCPN RoutePoint change"),
9628 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9629 if (dlg_return == wxID_YES) {
9634 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9637 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9639 if (tail && current && (tail != current)) {
9641 connect = tail->GetIndexOf(pNearbyPoint);
9642 int index_current_route =
9643 current->GetIndexOf(m_pRoutePointEditTarget);
9644 index_last = current->GetIndexOf(current->GetLastPoint());
9645 dlg_return1 = wxID_NO;
9647 index_current_route) {
9649 if (connect != tail->GetnPoints()) {
9652 _(
"Last part of route to be appended to dragged "
9656 _(
"Full route to be appended to dragged route?");
9658 dlg_return1 = OCPNMessageBox(
9659 this, dmsg, _(
"OpenCPN Route Create"),
9660 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9661 if (dlg_return1 == wxID_YES) {
9665 }
else if (index_current_route ==
9670 _(
"First part of route to be inserted into dragged "
9672 if (connect == tail->GetnPoints())
9674 "Full route to be inserted into dragged route?");
9676 dlg_return1 = OCPNMessageBox(
9677 this, dmsg, _(
"OpenCPN Route Create"),
9678 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9679 if (dlg_return1 == wxID_YES) {
9686 if (m_pRoutePointEditTarget->IsShared()) {
9688 dlg_return = OCPNMessageBox(
9690 _(
"Do you really want to delete and replace this "
9692 "\n" + _(
"which has been created manually?"),
9693 (
"OpenCPN RoutePoint warning"),
9694 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9697 if (dlg_return == wxID_YES) {
9698 pMousePoint = pNearbyPoint;
9700 pMousePoint->SetShared(
true);
9710 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9712 if (m_pEditRouteArray) {
9713 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9715 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9720 auto pos = std::find(list->begin(), list->end(),
9721 m_pRoutePointEditTarget);
9723 pSelect->DeleteAllSelectableRoutePoints(pr);
9724 pSelect->DeleteAllSelectableRouteSegments(pr);
9727 pos = std::find(list->begin(), list->end(),
9728 m_pRoutePointEditTarget);
9731 pSelect->AddAllSelectableRouteSegments(pr);
9732 pSelect->AddAllSelectableRoutePoints(pr);
9734 pr->FinalizeForRendering();
9735 pr->UpdateSegmentDistances();
9736 if (m_bRoutePoinDragging) {
9738 NavObj_dB::GetInstance().UpdateRoute(pr);
9746 if (m_pEditRouteArray) {
9747 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9749 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9768 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9775 delete m_pRoutePointEditTarget;
9776 m_lastRoutePointEditTarget = NULL;
9777 m_pRoutePointEditTarget = NULL;
9778 undo->AfterUndoableAction(pMousePoint);
9779 undo->InvalidateUndo();
9784 else if (m_bMarkEditing) {
9785 if (m_pRoutePointEditTarget)
9786 if (m_bRoutePoinDragging) {
9788 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9792 if (m_pRoutePointEditTarget)
9793 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9795 if (!m_pRoutePointEditTarget) {
9796 delete m_pEditRouteArray;
9797 m_pEditRouteArray = NULL;
9798 m_bRouteEditing =
false;
9800 m_bRoutePoinDragging =
false;
9807 int length = tail->GetnPoints();
9808 for (
int i = connect + 1; i <= length; i++) {
9809 current->AddPointAndSegment(tail->GetPoint(i),
false);
9812 gFrame->RefreshAllCanvas();
9815 current->FinalizeForRendering();
9821 pSelect->DeleteAllSelectableRoutePoints(current);
9822 pSelect->DeleteAllSelectableRouteSegments(current);
9823 for (
int i = 1; i < connect; i++) {
9824 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9826 pSelect->AddAllSelectableRouteSegments(current);
9827 pSelect->AddAllSelectableRoutePoints(current);
9828 current->FinalizeForRendering();
9835 if (m_pEditRouteArray) {
9836 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9837 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9850 if (m_bRouteEditing) {
9853 bool appending =
false;
9854 bool inserting =
false;
9857 if (m_pRoutePointEditTarget) {
9858 m_pRoutePointEditTarget->
m_bBlink =
false;
9862 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9863 double nearby_radius_meters =
9864 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9865 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9866 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9867 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9869 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9870 bool duplicate =
false;
9872 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9874 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9878 std::find(list->begin(), list->end(), pNearbyPoint);
9879 if (pos != list->end()) {
9891 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9896 OCPNMessageBox(
this,
9897 _(
"Replace this RoutePoint by the nearby "
9899 _(
"OpenCPN RoutePoint change"),
9900 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9901 if (dlg_return == wxID_YES) {
9905 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9908 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9910 if (tail && current && (tail != current)) {
9912 connect = tail->GetIndexOf(pNearbyPoint);
9913 int index_current_route =
9914 current->GetIndexOf(m_pRoutePointEditTarget);
9915 index_last = current->GetIndexOf(current->GetLastPoint());
9916 dlg_return1 = wxID_NO;
9918 index_current_route) {
9920 if (connect != tail->GetnPoints()) {
9923 _(
"Last part of route to be appended to dragged "
9927 _(
"Full route to be appended to dragged route?");
9929 dlg_return1 = OCPNMessageBox(
9930 this, dmsg, _(
"OpenCPN Route Create"),
9931 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9932 if (dlg_return1 == wxID_YES) {
9936 }
else if (index_current_route ==
9941 _(
"First part of route to be inserted into dragged "
9943 if (connect == tail->GetnPoints())
9945 "Full route to be inserted into dragged route?");
9947 dlg_return1 = OCPNMessageBox(
9948 this, dmsg, _(
"OpenCPN Route Create"),
9949 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9950 if (dlg_return1 == wxID_YES) {
9957 if (m_pRoutePointEditTarget->IsShared()) {
9958 dlg_return = wxID_NO;
9959 dlg_return = OCPNMessageBox(
9961 _(
"Do you really want to delete and replace this "
9963 "\n" + _(
"which has been created manually?"),
9964 (
"OpenCPN RoutePoint warning"),
9965 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9968 if (dlg_return == wxID_YES) {
9969 pMousePoint = pNearbyPoint;
9971 pMousePoint->SetShared(
true);
9981 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9983 if (m_pEditRouteArray) {
9984 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9986 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9990 auto pos = std::find(list->begin(), list->end(),
9991 m_pRoutePointEditTarget);
9993 pSelect->DeleteAllSelectableRoutePoints(pr);
9994 pSelect->DeleteAllSelectableRouteSegments(pr);
9997 pos = std::find(list->begin(), list->end(),
9998 m_pRoutePointEditTarget);
9999 if (pos != list->end()) list->erase(pos);
10002 pSelect->AddAllSelectableRouteSegments(pr);
10003 pSelect->AddAllSelectableRoutePoints(pr);
10005 pr->FinalizeForRendering();
10006 pr->UpdateSegmentDistances();
10009 if (m_bRoutePoinDragging) {
10014 NavObj_dB::GetInstance().UpdateRoutePoint(
10015 m_pRoutePointEditTarget);
10017 NavObj_dB::GetInstance().UpdateRoute(pr);
10029 int length = tail->GetnPoints();
10030 for (
int i = connect + 1; i <= length; i++) {
10031 current->AddPointAndSegment(tail->GetPoint(i),
false);
10035 gFrame->RefreshAllCanvas();
10038 current->FinalizeForRendering();
10044 pSelect->DeleteAllSelectableRoutePoints(current);
10045 pSelect->DeleteAllSelectableRouteSegments(current);
10046 for (
int i = 1; i < connect; i++) {
10047 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10049 pSelect->AddAllSelectableRouteSegments(current);
10050 pSelect->AddAllSelectableRoutePoints(current);
10051 current->FinalizeForRendering();
10058 if (m_pEditRouteArray) {
10059 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10061 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10073 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10080 delete m_pRoutePointEditTarget;
10081 m_lastRoutePointEditTarget = NULL;
10082 undo->AfterUndoableAction(pMousePoint);
10083 undo->InvalidateUndo();
10088 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10091 delete m_pEditRouteArray;
10092 m_pEditRouteArray = NULL;
10096 m_bRouteEditing =
false;
10097 m_pRoutePointEditTarget = NULL;
10103 else if (m_bMarkEditing) {
10104 if (m_pRoutePointEditTarget) {
10105 if (m_bRoutePoinDragging) {
10107 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10109 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10114 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10116 RefreshRect(wp_rect,
true);
10119 m_pRoutePointEditTarget = NULL;
10120 m_bMarkEditing =
false;
10125 else if (leftIsDown) {
10126 leftIsDown =
false;
10130 if (!m_bChartDragging && !m_bMeasure_Active) {
10132 m_bChartDragging =
false;
10136 m_bRoutePoinDragging =
false;
10139 if (ret)
return true;
10142 if (event.RightDown()) {
10153 m_FinishRouteOnKillFocus =
false;
10154 CallPopupMenu(mx, my);
10155 m_FinishRouteOnKillFocus =
true;
10165 if (event.ShiftDown()) {
10169 event.GetPosition(&x, &y);
10171 x *= m_displayScale;
10172 y *= m_displayScale;
10178 int wheel_dir =
event.GetWheelRotation();
10181 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10182 wheel_dir = wheel_dir > 0 ? 1 : -1;
10184 double factor = g_mouse_zoom_sensitivity;
10185 if (wheel_dir < 0) factor = 1 / factor;
10188 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10189 if (wheel_dir == m_last_wheel_dir) {
10190 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10195 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10196 m_wheelstopwatch.Start(0);
10201 m_last_wheel_dir = wheel_dir;
10206 if (event.LeftDown()) {
10212 last_drag.x = x, last_drag.y = y;
10213 panleftIsDown =
true;
10216 if (event.LeftUp()) {
10217 if (panleftIsDown) {
10219 panleftIsDown =
false;
10222 if (!m_bChartDragging && !m_bMeasure_Active) {
10223 switch (cursor_region) {
10245 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10250 m_bChartDragging =
false;
10256 if (event.Dragging() && event.LeftIsDown()) {
10272 if (g_btouch && !m_inPinch) {
10273 struct timespec now;
10274 clock_gettime(CLOCK_MONOTONIC, &now);
10275 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10277 bool trigger_hold =
false;
10278 if (
false == m_bChartDragging) {
10279 if (m_DragTrigger < 0) {
10282 m_DragTriggerStartTime = tnow;
10283 trigger_hold =
true;
10285 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10286 m_DragTrigger = -1;
10291 if (trigger_hold)
return true;
10293 if (
false == m_bChartDragging) {
10296 last_drag.x = x - 1, last_drag.y = y - 1;
10297 m_bChartDragging =
true;
10298 m_chart_drag_total_time = 0;
10299 m_chart_drag_total_x = 0;
10300 m_chart_drag_total_y = 0;
10301 m_inertia_last_drag_x = x;
10302 m_inertia_last_drag_y = y;
10303 m_drag_vec_x.clear();
10304 m_drag_vec_y.clear();
10305 m_drag_vec_t.clear();
10306 m_last_drag_time = tnow;
10310 uint64_t delta_t = tnow - m_last_drag_time;
10311 double delta_tf = delta_t / 1e9;
10313 m_chart_drag_total_time += delta_tf;
10314 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10315 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10317 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10318 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10319 m_drag_vec_t.push_back(delta_tf);
10321 m_inertia_last_drag_x = x;
10322 m_inertia_last_drag_y = y;
10323 m_last_drag_time = tnow;
10325 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10326 m_bChartDragging =
true;
10327 StartTimedMovement();
10328 m_pan_drag.x += last_drag.x - x;
10329 m_pan_drag.y += last_drag.y - y;
10330 last_drag.x = x, last_drag.y = y;
10332 }
else if (!g_btouch) {
10333 if ((last_drag.x != x) || (last_drag.y != y)) {
10334 if (!m_routeState) {
10337 m_bChartDragging =
true;
10338 StartTimedMovement();
10339 m_pan_drag.x += last_drag.x - x;
10340 m_pan_drag.y += last_drag.y - y;
10341 last_drag.x = x, last_drag.y = y;
10348 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10350 m_ignore_next_leftup =
true;
10351 m_DoubleClickTimer->Start();
10352 singleClickEventIsValid =
false;
10360void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10361 if (MouseEventOverlayWindows(event))
return;
10365 bool nm = MouseEventProcessObjects(event);
10369void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10372 wxCursor *ptarget_cursor = pCursorArrow;
10373 if (!pPlugIn_Cursor) {
10374 ptarget_cursor = pCursorArrow;
10375 if ((!m_routeState) &&
10376 (!m_bMeasure_Active) ) {
10377 if (cursor_region == MID_RIGHT) {
10378 ptarget_cursor = pCursorRight;
10379 }
else if (cursor_region == MID_LEFT) {
10380 ptarget_cursor = pCursorLeft;
10381 }
else if (cursor_region == MID_TOP) {
10382 ptarget_cursor = pCursorDown;
10383 }
else if (cursor_region == MID_BOT) {
10384 ptarget_cursor = pCursorUp;
10386 ptarget_cursor = pCursorArrow;
10388 }
else if (m_bMeasure_Active ||
10390 ptarget_cursor = pCursorPencil;
10392 ptarget_cursor = pPlugIn_Cursor;
10395 SetCursor(*ptarget_cursor);
10398void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10399 SetCursor(*pCursorArrow);
10402void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10406 wxArrayString files;
10408 ChartBase *target_chart = GetChartAtCursor();
10409 if (target_chart) {
10410 file.Assign(target_chart->GetFullPath());
10411 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10412 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10415 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10417 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10418 unsigned int im = stackIndexArray.size();
10419 int scale = 2147483647;
10420 if (VPoint.b_quilt && im > 0) {
10421 for (
unsigned int is = 0; is < im; is++) {
10422 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10423 CHART_TYPE_MBTILES) {
10424 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10426 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10427 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10429 .Contains(lat, lon)) {
10430 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10433 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10434 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10442 std::vector<Ais8_001_22 *> area_notices;
10444 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10447 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10448 auto target_data = target.second;
10449 if (!target_data->area_notices.empty()) {
10450 for (
auto &ani : target_data->area_notices) {
10455 for (Ais8_001_22_SubAreaList::iterator sa =
10456 area_notice.sub_areas.begin();
10457 sa != area_notice.sub_areas.end(); ++sa) {
10458 switch (sa->shape) {
10459 case AIS8_001_22_SHAPE_CIRCLE: {
10460 wxPoint target_point;
10462 bbox.Expand(target_point);
10463 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10466 case AIS8_001_22_SHAPE_RECT: {
10467 wxPoint target_point;
10469 bbox.Expand(target_point);
10470 if (sa->e_dim_m > sa->n_dim_m)
10471 bbox.EnLarge(sa->e_dim_m * vp_scale);
10473 bbox.EnLarge(sa->n_dim_m * vp_scale);
10476 case AIS8_001_22_SHAPE_POLYGON:
10477 case AIS8_001_22_SHAPE_POLYLINE: {
10478 for (
int i = 0; i < 4; ++i) {
10479 double lat = sa->latitude;
10480 double lon = sa->longitude;
10481 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10483 wxPoint target_point;
10485 bbox.Expand(target_point);
10489 case AIS8_001_22_SHAPE_SECTOR: {
10490 double lat1 = sa->latitude;
10491 double lon1 = sa->longitude;
10493 wxPoint target_point;
10495 bbox.Expand(target_point);
10496 for (
int i = 0; i < 18; ++i) {
10499 sa->left_bound_deg +
10500 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10501 sa->radius_m / 1852.0, &lat, &lon);
10503 bbox.Expand(target_point);
10505 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10508 bbox.Expand(target_point);
10514 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10515 area_notices.push_back(&area_notice);
10522 if (target_chart || !area_notices.empty() || file.HasName()) {
10524 int sel_rad_pix = 5;
10525 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10530 SetCursor(wxCURSOR_WAIT);
10531 bool lightsVis = m_encShowLights;
10532 if (!lightsVis) SetShowENCLights(
true);
10535 ListOfObjRazRules *rule_list = NULL;
10536 ListOfPI_S57Obj *pi_rule_list = NULL;
10539 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10540 else if (target_plugin_chart)
10541 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10542 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10544 ListOfObjRazRules *overlay_rule_list = NULL;
10545 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10548 if (CHs57_Overlay) {
10549 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10550 zlat, zlon, SelectRadius, &GetVP());
10553 if (!lightsVis) SetShowENCLights(
false);
10556 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10557 wxString face = dFont->GetFaceName();
10561 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10562 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10566 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10574 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10575 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10578 int points = dFont->GetPointSize();
10580 int points = dFont->GetPointSize() + 1;
10584 for (
int i = -2; i < 5; i++) {
10585 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10589 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10591 if (overlay_rule_list && CHs57_Overlay) {
10592 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10593 objText <<
"<hr noshade>";
10596 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10597 an != area_notices.end(); ++an) {
10598 objText <<
"<b>AIS Area Notice:</b> ";
10599 objText << ais8_001_22_notice_names[(*an)->notice_type];
10600 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10601 (*an)->sub_areas.begin();
10602 sa != (*an)->sub_areas.end(); ++sa)
10603 if (!sa->text.empty()) objText << sa->text;
10604 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10605 objText <<
"<hr noshade>";
10609 objText << Chs57->CreateObjDescriptions(rule_list);
10610 else if (target_plugin_chart)
10611 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10614 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10617 wxString AddFiles, filenameOK;
10619 if (!target_plugin_chart) {
10622 AddFiles = wxString::Format(
10623 "<hr noshade><br><b>Additional info files attached to: </b> "
10625 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10627 file.GetFullName());
10629 file.Assign(file.GetPath(),
"");
10630 wxDir dir(file.GetFullPath());
10632 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10634 file.Assign(dir.GetNameWithSep().append(filename));
10635 wxString FormatString =
10636 "<td valign=top><font size=-2><a "
10637 "href=\"%s\">%s</a></font></td>";
10638 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10639 filenameOK = file.GetFullPath();
10641 if (3 * ((
int)filecount / 3) == filecount)
10642 FormatString.Prepend(
"<tr>");
10644 FormatString.Prepend(
10645 "<td>  </td>");
10648 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10649 file.GetFullName());
10652 cont = dir.GetNext(&filename);
10654 objText << AddFiles <<
"</table>";
10656 objText <<
"</font>";
10657 objText <<
"</body></html>";
10659 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10663 if ((!Chs57 && filecount == 1)) {
10665 wxHtmlLinkInfo hli(filenameOK);
10666 wxHtmlLinkEvent hle(1, hli);
10670 if (rule_list) rule_list->Clear();
10673 if (overlay_rule_list) overlay_rule_list->Clear();
10674 delete overlay_rule_list;
10676 if (pi_rule_list) pi_rule_list->Clear();
10677 delete pi_rule_list;
10679 SetCursor(wxCURSOR_ARROW);
10683void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10692 wxSize canvas_size = GetSize();
10699 wxPoint canvas_pos = GetPosition();
10702 bool newFit =
false;
10703 if (canvas_size.x < fitted_size.x) {
10704 fitted_size.x = canvas_size.x - 40;
10705 if (canvas_size.y < fitted_size.y)
10706 fitted_size.y -= 40;
10708 if (canvas_size.y < fitted_size.y) {
10709 fitted_size.y = canvas_size.y - 40;
10710 if (canvas_size.x < fitted_size.x)
10711 fitted_size.x -= 40;
10722 wxString title_base = _(
"Mark Properties");
10724 title_base = _(
"Waypoint Properties");
10729 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10741void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10751 if (g_bresponsive) {
10752 wxSize canvas_size = GetSize();
10753 wxPoint canvas_pos = GetPosition();
10757 if (canvas_size.x < fitted_size.x) {
10758 fitted_size.x = canvas_size.x;
10759 if (canvas_size.y < fitted_size.y)
10760 fitted_size.y -= 20;
10762 if (canvas_size.y < fitted_size.y) {
10763 fitted_size.y = canvas_size.y;
10764 if (canvas_size.x < fitted_size.x)
10765 fitted_size.x -= 20;
10774 wxPoint xxp = ClientToScreen(canvas_pos);
10785void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10797void pupHandler_PasteWaypoint() {
10800 int pasteBuffer = kml.ParsePasteBuffer();
10801 RoutePoint *pasted = kml.GetParsedRoutePoint();
10802 if (!pasted)
return;
10804 double nearby_radius_meters =
10805 g_Platform->GetSelectRadiusPix() /
10806 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10808 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10809 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10811 int answer = wxID_NO;
10815 "There is an existing waypoint at the same location as the one you are "
10816 "pasting. Would you like to merge the pasted data with it?\n\n");
10817 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10818 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10819 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10822 if (answer == wxID_YES) {
10823 nearPoint->SetName(pasted->GetName());
10825 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10826 pRouteManagerDialog->UpdateWptListCtrl();
10829 if (answer == wxID_NO) {
10832 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10835 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10838 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10839 pRouteManagerDialog->UpdateWptListCtrl();
10844 gFrame->InvalidateAllGL();
10845 gFrame->RefreshAllCanvas(
false);
10848void pupHandler_PasteRoute() {
10851 int pasteBuffer = kml.ParsePasteBuffer();
10852 Route *pasted = kml.GetParsedRoute();
10853 if (!pasted)
return;
10855 double nearby_radius_meters =
10856 g_Platform->GetSelectRadiusPix() /
10857 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10863 bool mergepoints =
false;
10864 bool createNewRoute =
true;
10865 int existingWaypointCounter = 0;
10867 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10868 curPoint = pasted->GetPoint(i);
10869 nearPoint = pWayPointMan->GetNearbyWaypoint(
10870 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10872 mergepoints =
true;
10873 existingWaypointCounter++;
10881 int answer = wxID_NO;
10885 "There are existing waypoints at the same location as some of the ones "
10886 "you are pasting. Would you like to just merge the pasted data into "
10888 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10889 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10890 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10892 if (answer == wxID_CANCEL) {
10899 if (mergepoints && answer == wxID_YES &&
10900 existingWaypointCounter == pasted->GetnPoints()) {
10903 createNewRoute =
false;
10909 Route *newRoute = 0;
10912 if (createNewRoute) {
10913 newRoute =
new Route();
10917 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10918 curPoint = pasted->GetPoint(i);
10921 newPoint = pWayPointMan->GetNearbyWaypoint(
10922 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10923 newPoint->SetName(curPoint->GetName());
10926 if (createNewRoute) newRoute->AddPoint(newPoint);
10932 newPoint->SetIconName(
"circle");
10935 newPoint->SetShared(
false);
10937 newRoute->AddPoint(newPoint);
10938 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10941 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10944 if (i > 1 && createNewRoute)
10945 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10946 curPoint->m_lat, curPoint->m_lon,
10947 prevPoint, newPoint, newRoute);
10948 prevPoint = newPoint;
10951 if (createNewRoute) {
10954 NavObj_dB::GetInstance().InsertRoute(newRoute);
10960 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10961 pRouteManagerDialog->UpdateRouteListCtrl();
10962 pRouteManagerDialog->UpdateWptListCtrl();
10964 gFrame->InvalidateAllGL();
10965 gFrame->RefreshAllCanvas(
false);
10971void pupHandler_PasteTrack() {
10974 int pasteBuffer = kml.ParsePasteBuffer();
10975 Track *pasted = kml.GetParsedTrack();
10976 if (!pasted)
return;
10984 newTrack->SetName(pasted->GetName());
10986 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10987 curPoint = pasted->GetPoint(i);
10991 wxDateTime now = wxDateTime::Now();
10994 newTrack->AddPoint(newPoint);
10997 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10998 newPoint->m_lat, newPoint->m_lon,
10999 prevPoint, newPoint, newTrack);
11001 prevPoint = newPoint;
11006 NavObj_dB::GetInstance().InsertTrack(newTrack);
11008 gFrame->InvalidateAllGL();
11009 gFrame->RefreshAllCanvas(
false);
11012bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11015 v[
"CursorPosition_x"] = x;
11016 v[
"CursorPosition_y"] = y;
11019 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11020 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11021 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11026 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11028 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11031#define SELTYPE_UNKNOWN 0x0001
11032#define SELTYPE_ROUTEPOINT 0x0002
11033#define SELTYPE_ROUTESEGMENT 0x0004
11034#define SELTYPE_TIDEPOINT 0x0008
11035#define SELTYPE_CURRENTPOINT 0x0010
11036#define SELTYPE_ROUTECREATE 0x0020
11037#define SELTYPE_AISTARGET 0x0040
11038#define SELTYPE_MARKPOINT 0x0080
11039#define SELTYPE_TRACKSEGMENT 0x0100
11040#define SELTYPE_DRAGHANDLE 0x0200
11043 if (g_bhide_context_menus)
return true;
11045 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11046 m_pIDXCandidate, m_nmea_log);
11049 wxEVT_COMMAND_MENU_SELECTED,
11050 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11056 if (m_inLongPress) {
11057 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11058 m_inLongPress =
false;
11062 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11065 wxEVT_COMMAND_MENU_SELECTED,
11066 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11068 delete m_canvasMenu;
11069 m_canvasMenu = NULL;
11079void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11082 if (m_canvasMenu) {
11083 m_canvasMenu->PopupMenuHandler(event);
11088void ChartCanvas::StartRoute() {
11090 if (g_brouteCreating)
return;
11094 g_brouteCreating =
true;
11096 m_bDrawingRoute =
false;
11097 SetCursor(*pCursorPencil);
11099 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11101 HideGlobalToolbar();
11104 androidSetRouteAnnunciator(
true);
11108wxString ChartCanvas::FinishRoute() {
11110 m_prev_pMousePoint = NULL;
11111 m_bDrawingRoute =
false;
11113 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11116 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11118 androidSetRouteAnnunciator(
false);
11121 SetCursor(*pCursorArrow);
11123 if (m_pMouseRoute) {
11124 if (m_bAppendingRoute) {
11126 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11128 if (m_pMouseRoute->GetnPoints() > 1) {
11130 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11133 m_pMouseRoute = NULL;
11136 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11143 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11144 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11145 pRouteManagerDialog->UpdateRouteListCtrl();
11148 m_bAppendingRoute =
false;
11149 m_pMouseRoute = NULL;
11151 m_pSelectedRoute = NULL;
11153 undo->InvalidateUndo();
11154 gFrame->RefreshAllCanvas(
true);
11158 ShowGlobalToolbar();
11160 g_brouteCreating =
false;
11165void ChartCanvas::HideGlobalToolbar() {
11166 if (m_canvasIndex == 0) {
11167 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11171void ChartCanvas::ShowGlobalToolbar() {
11172 if (m_canvasIndex == 0) {
11173 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11177void ChartCanvas::ShowAISTargetList() {
11178 if (NULL == g_pAISTargetList) {
11182 g_pAISTargetList->UpdateAISTargetList();
11185void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11186 if (!m_bShowOutlines)
return;
11190 int nEntry =
ChartData->GetChartTableEntries();
11192 for (
int i = 0; i < nEntry; i++) {
11196 bool b_group_draw =
false;
11197 if (m_groupIndex > 0) {
11198 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11199 int index = pt->GetGroupArray()[ig];
11200 if (m_groupIndex == index) {
11201 b_group_draw =
true;
11206 b_group_draw =
true;
11208 if (b_group_draw) RenderChartOutline(dc, i, vp);
11214 if (VPoint.b_quilt) {
11215 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11216 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11220 }
else if (m_singleChart &&
11221 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11225 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11228 if (zoom_factor > 8.0) {
11229 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11232 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11236 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11240void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11242 if (g_bopengl && m_glcc) {
11244 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11249 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11250 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11253 float plylat, plylon;
11254 float plylat1, plylon1;
11256 int pixx, pixy, pixx1, pixy1;
11259 ChartData->GetDBBoundingBox(dbIndex, box);
11263 if (box.GetLonRange() == 360)
return;
11265 double lon_bias = 0;
11267 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11269 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11271 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11272 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11274 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11275 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11278 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11281 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11282 if (0 == nAuxPlyEntries)
11286 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11287 plylon += lon_bias;
11293 for (
int i = 0; i < nPly - 1; i++) {
11294 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11295 plylon1 += lon_bias;
11301 int pixxs1 = pixx1;
11302 int pixys1 = pixy1;
11304 bool b_skip =
false;
11308 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11309 pow((
double)(pixy1 - pixy), 2)) /
11315 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11320 if (fabs(dist - distgc) > 10000. * 1852.)
11326 ClipResult res = cohen_sutherland_line_clip_i(
11328 if (res != Invisible && !b_skip)
11329 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11337 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11338 plylon1 += lon_bias;
11344 ClipResult res = cohen_sutherland_line_clip_i(
11346 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11353 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11354 for (
int j = 0; j < nAuxPlyEntries; j++) {
11356 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11361 for (
int i = 0; i < nAuxPly - 1; i++) {
11362 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11368 int pixxs1 = pixx1;
11369 int pixys1 = pixy1;
11371 bool b_skip =
false;
11375 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11376 ((pixy1 - pixy) * (pixy1 - pixy))) /
11381 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11386 if (fabs(dist - distgc) > 10000. * 1852.)
11392 ClipResult res = cohen_sutherland_line_clip_i(
11394 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11402 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11407 ClipResult res = cohen_sutherland_line_clip_i(
11409 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11414static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11415 const wxArrayString &legend) {
11416 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11418 int pointsize = dFont->GetPointSize();
11422 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11423 false, dFont->GetFaceName());
11425 dc.SetFont(*psRLI_font);
11432 int hilite_offset = 3;
11434 for (wxString line : legend) {
11437 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11439 dc.GetTextExtent(line, &wl, &hl);
11448 xp = ref_point.x - w;
11450 yp += hilite_offset;
11452 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11454 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11455 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11457 for (wxString line : legend) {
11458 dc.DrawText(line, xp, yp);
11463void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11464 if (!g_bAllowShipToActive)
return;
11470 wxPoint2DDouble pa, pb;
11477 if (rt->
m_width != wxPENSTYLE_INVALID)
11479 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11480 g_shipToActiveStyle, 5)];
11481 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11483 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11486 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11489 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11492 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11493 (
int)pb.m_y, GetVP(),
true);
11497#ifdef USE_ANDROID_GLES2
11498 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11500 if (style != wxPENSTYLE_SOLID) {
11501 if (glChartCanvas::dash_map.find(style) !=
11502 glChartCanvas::dash_map.end()) {
11503 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11507 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11510 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11511 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11517void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11519 if (m_routeState >= 2) route = m_pMouseRoute;
11520 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11521 route = m_pMeasureRoute;
11523 if (!route)
return;
11531 int np = route->GetnPoints();
11533 if (g_btouch && (np > 1)) np--;
11535 render_lat = rp.m_lat;
11536 render_lon = rp.m_lon;
11539 double rhumbBearing, rhumbDist;
11541 &rhumbBearing, &rhumbDist);
11542 double brg = rhumbBearing;
11543 double dist = rhumbDist;
11547 double gcBearing, gcBearing2, gcDist;
11548 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11551 double gcDistm = gcDist / 1852.0;
11554 rhumbBearing = 90.;
11556 wxPoint destPoint, lastPoint;
11559 int milesDiff = rhumbDist - gcDistm;
11560 if (milesDiff > 1) {
11571 for (
int i = 1; i <= milesDiff; i++) {
11572 double p = (double)i * (1.0 / (
double)milesDiff);
11574 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11575 &pLon, &pLat, &gcBearing2);
11577 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11579 lastPoint = destPoint;
11582 if (r_rband.x && r_rband.y) {
11583 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11585 if (m_bMeasure_DistCircle) {
11586 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11587 powf((
float)(r_rband.y - lastPoint.y), 2));
11590 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11591 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11597 wxString routeInfo;
11598 wxArrayString infoArray;
11601 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11607 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11609 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11610 (
int)varBrg, 0x00B0);
11613 infoArray.Add(routeInfo);
11619 routeInfo <<
"Reverse: ";
11621 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11622 (
int)(brg + 180.) % 360, 0x00B0);
11624 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11625 (
int)(varBrg + 180.) % 360, 0x00B0);
11626 infoArray.Add(routeInfo);
11632 s0.Append(_(
"Route") +
": ");
11634 s0.Append(_(
"Layer Route: "));
11637 if (!g_btouch) disp_length += dist;
11643 RouteLegInfo(dc, r_rband, infoArray);
11645 m_brepaint_piano =
true;
11648void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11649 if (!m_bShowVisibleSectors)
return;
11651 if (g_bDeferredInitDone) {
11653 double rhumbBearing, rhumbDist;
11654 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11655 &rhumbBearing, &rhumbDist);
11657 if (rhumbDist > 0.05)
11659 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11660 m_sectorlegsVisible);
11661 m_sector_glat =
gLat;
11662 m_sector_glon =
gLon;
11664 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11668void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11676void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11677 if (!ps52plib)
return;
11679 if (VPoint.b_quilt) {
11680 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11682 if (m_pQuilt->IsQuiltVector()) {
11683 if (ps52plib->GetStateHash() != m_s52StateHash) {
11685 m_s52StateHash = ps52plib->GetStateHash();
11689 if (ps52plib->GetStateHash() != m_s52StateHash) {
11691 m_s52StateHash = ps52plib->GetStateHash();
11696 bool bSendPlibState =
true;
11697 if (VPoint.b_quilt) {
11698 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11701 if (bSendPlibState) {
11703 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11704 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11705 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11706 v[
"OpenCPN Version Date"] = VERSION_DATE;
11707 v[
"OpenCPN Version Full"] = VERSION_FULL;
11710 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11711 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11712 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11713 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11714 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11715 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11716 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11720 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11721 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11725 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11726 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11727 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11728 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11729 ps52plib->m_bShowS57ImportantTextOnly;
11730 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11731 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11732 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11733 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11734 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11737 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11738 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11739 v[
"OpenCPN Scale Factor Exp"] =
11740 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11747 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11748 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11749 g_lastS52PLIBPluginMessage = out;
11756 wxPaintDC dc(
this);
11766 if (!m_b_paint_enable) {
11774 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11776 if (m_glcc && g_bopengl) {
11777 if (!s_in_update) {
11787 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11789 wxRegion ru = GetUpdateRegion();
11791 int rx, ry, rwidth, rheight;
11792 ru.GetBox(rx, ry, rwidth, rheight);
11794#ifdef ocpnUSE_DIBSECTION
11797 wxMemoryDC temp_dc;
11805 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11806 height += m_Piano->GetHeight();
11808 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11812 int thumbx, thumby, thumbsx, thumbsy;
11813 pthumbwin->GetPosition(&thumbx, &thumby);
11814 pthumbwin->GetSize(&thumbsx, &thumbsy);
11815 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11818 rgn_chart.Subtract(rgn_thumbwin);
11819 ru.Subtract(rgn_thumbwin);
11825 wxRegion rgn_blit = ru;
11826 if (g_bShowChartBar) {
11827 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11828 GetClientSize().x, m_Piano->GetHeight());
11831 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11832 if (style->chartStatusWindowTransparent)
11833 m_brepaint_piano =
true;
11835 ru.Subtract(chart_bar_rect);
11839 if (m_Compass && m_Compass->IsShown()) {
11840 wxRect compassRect = m_Compass->
GetRect();
11841 if (ru.Contains(compassRect) != wxOutRegion) {
11842 ru.Subtract(compassRect);
11846 if (m_notification_button) {
11847 wxRect noteRect = m_notification_button->
GetRect();
11848 if (ru.Contains(noteRect) != wxOutRegion) {
11849 ru.Subtract(noteRect);
11854 bool b_newview =
true;
11859 m_cache_vp.IsValid()) {
11865 bool b_rcache_ok =
false;
11866 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11867 b_rcache_ok = !b_newview;
11870 if (VPoint.b_MercatorProjectionOverride)
11871 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11885 if (b_rcache_ok) chart_get_region.Clear();
11888 if (VPoint.b_quilt)
11890 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11892 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11897 AbstractPlatform::ShowBusySpinner();
11901 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11902 (m_working_bm.GetHeight() != svp.
pix_height))
11906 if (fabs(VPoint.
rotation) < 0.01) {
11907 bool b_save =
true;
11912 m_cache_vp.Invalidate();
11926 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11931 int dy = c_new.y - c_old.y;
11932 int dx = c_new.x - c_old.x;
11937 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11941 temp_dc.SelectObject(m_working_bm);
11943 wxMemoryDC cache_dc;
11944 cache_dc.SelectObject(m_cached_chart_bm);
11948 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11951 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11957 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11960 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11968 update_region.Union(
11971 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11976 update_region.Union(
11979 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11983 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11985 cache_dc.SelectObject(wxNullBitmap);
11989 temp_dc.SelectObject(m_cached_chart_bm);
11992 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11996 temp_dc.SelectObject(m_working_bm);
11997 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12002 temp_dc.SelectObject(m_cached_chart_bm);
12007 temp_dc.SelectObject(m_working_bm);
12008 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12021 wxMemoryDC scratch_dc_0;
12022 scratch_dc_0.SelectObject(m_cached_chart_bm);
12025 scratch_dc_0.SelectObject(wxNullBitmap);
12034 temp_dc.SelectObject(m_working_bm);
12037 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12038 chart_get_all_region);
12041 AbstractPlatform::HideBusySpinner();
12047 if (!m_singleChart) {
12048 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12053 if (!chart_get_region.IsEmpty()) {
12054 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12058 if (temp_dc.IsOk()) {
12063 if (!VPoint.b_quilt) {
12066 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12067 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12074 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12075 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12078 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12080 temp_dc.DestroyClippingRegion();
12085 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12087 if (!backgroundRegion.IsEmpty()) {
12093 wxColour water = pWorldBackgroundChart->water;
12094 if (water.IsOk()) {
12095 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12096 temp_dc.SetBrush(wxBrush(water));
12098 while (upd.HaveRects()) {
12099 wxRect rect = upd.GetRect();
12100 temp_dc.DrawRectangle(rect);
12105 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12106 temp_dc.SetDeviceClippingRegion(*clip_region);
12107 delete clip_region;
12111 SetVPRotation(VPoint.
skew);
12120 wxMemoryDC *pChartDC = &temp_dc;
12121 wxMemoryDC rotd_dc;
12123 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12125 if (!b_rcache_ok) {
12127 wxMemoryDC tbase_dc;
12129 tbase_dc.SelectObject(bm_base);
12131 tbase_dc.SelectObject(wxNullBitmap);
12133 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12136 wxImage base_image;
12137 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12145 bool b_rot_ok =
false;
12146 if (base_image.IsOk()) {
12149 m_b_rot_hidef =
false;
12153 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12154 m_b_rot_hidef, &m_roffset);
12159 rot_vp.IsValid() && (ri.IsOk())) {
12166 m_prot_bm =
new wxBitmap(ri);
12169 m_roffset.x += VPoint.rv_rect.x;
12170 m_roffset.y += VPoint.rv_rect.y;
12173 if (m_prot_bm && m_prot_bm->IsOk()) {
12174 rotd_dc.SelectObject(*m_prot_bm);
12175 pChartDC = &rotd_dc;
12177 pChartDC = &temp_dc;
12178 m_roffset = wxPoint(0, 0);
12181 pChartDC = &temp_dc;
12182 m_roffset = wxPoint(0, 0);
12185 wxPoint offset = m_roffset;
12188 m_cache_vp = VPoint;
12191 wxMemoryDC mscratch_dc;
12192 mscratch_dc.SelectObject(*pscratch_bm);
12194 mscratch_dc.ResetBoundingBox();
12195 mscratch_dc.DestroyClippingRegion();
12196 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12199 wxRegionIterator upd(rgn_blit);
12201 wxRect rect = upd.GetRect();
12203 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12204 rect.x - offset.x, rect.y - offset.y);
12210 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12211 if (
this == wxWindow::FindFocus()) {
12214 wxColour colour = GetGlobalColor(
"BLUE4");
12215 mscratch_dc.SetPen(wxPen(colour));
12216 mscratch_dc.SetBrush(wxBrush(colour));
12218 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12219 mscratch_dc.DrawRectangle(activeRect);
12224 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12225 unsigned int im = stackIndexArray.size();
12226 if (VPoint.b_quilt && im > 0) {
12227 std::vector<int> tiles_to_show;
12228 for (
unsigned int is = 0; is < im; is++) {
12230 ChartData->GetChartTableEntry(stackIndexArray[is]);
12231 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12234 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12235 tiles_to_show.push_back(stackIndexArray[is]);
12239 if (tiles_to_show.size())
12240 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12246 ocpnDC scratch_dc(mscratch_dc);
12247 RenderAlertMessage(mscratch_dc, GetVP());
12253#ifdef ocpnUSE_DIBSECTION
12258 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12259 q_dc.SelectObject(qbm);
12262 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12265 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12266 q_dc.SetBrush(qbr);
12267 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12270 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12273 q_dc.SelectObject(wxNullBitmap);
12282 if( VPoint.b_quilt ) {
12283 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12284 ChartBase *chart = m_pQuilt->GetRefChart();
12285 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12290 ChPI->ClearPLIBTextList();
12293 ps52plib->ClearTextList();
12297 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12299 wxColor maskBackground = wxColour(1,0,0);
12300 t_dc.SelectObject( qbm );
12301 t_dc.SetBackground(wxBrush(maskBackground));
12305 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12308 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12309 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12312 wxRegionIterator upd_final( ru );
12313 while( upd_final ) {
12314 wxRect rect = upd_final.GetRect();
12315 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12319 t_dc.SelectObject( wxNullBitmap );
12325 if (VPoint.b_quilt) {
12326 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12327 ChartBase *chart = m_pQuilt->GetRefChart();
12328 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12332 ChPI->ClearPLIBTextList();
12334 if (ps52plib) ps52plib->ClearTextList();
12339 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12341 if (g_bShowChartBar && m_Piano) {
12342 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12343 GetVP().pix_width, m_Piano->GetHeight());
12346 if (!style->chartStatusWindowTransparent)
12347 chart_all_text_region.Subtract(chart_bar_rect);
12350 if (m_Compass && m_Compass->IsShown()) {
12351 wxRect compassRect = m_Compass->
GetRect();
12352 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12353 chart_all_text_region.Subtract(compassRect);
12357 mscratch_dc.DestroyClippingRegion();
12359 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12360 chart_all_text_region);
12366 ocpnDC scratch_dc(mscratch_dc);
12367 DrawOverlayObjects(scratch_dc, ru);
12370 wxRegionIterator upd_final(rgn_blit);
12371 while (upd_final) {
12372 wxRect rect = upd_final.GetRect();
12373 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12380 temp_dc.SelectObject(wxNullBitmap);
12382 mscratch_dc.SelectObject(wxNullBitmap);
12384 dc.DestroyClippingRegion();
12389void ChartCanvas::PaintCleanup() {
12391 if (m_inPinch)
return;
12402 m_bTCupdate =
false;
12406 WarpPointer(warp_x, warp_y);
12413 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12414 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12418wxColour GetErrorGraphicColor(
double val)
12437 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12438 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12439 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12440 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12441 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12442 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12443 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12444 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12445 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12446 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12447 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12448 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12449 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12450 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12451 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12452 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12453 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12454 else if( val >= 48) c.Set(
"#410000");
12459void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12462 gr_image.InitAlpha();
12464 double maxval = -10000;
12465 double minval = 10000;
12482 maxval = wxMax(maxval, (glat - rlat));
12483 minval = wxMin(minval, (glat - rlat));
12500 double f = ((glat - rlat)-minval)/(maxval - minval);
12502 double dy = (f * 40);
12504 wxColour c = GetErrorGraphicColor(dy);
12505 unsigned char r = c.Red();
12506 unsigned char g = c.Green();
12507 unsigned char b = c.Blue();
12509 gr_image.SetRGB(j, i, r,g,b);
12510 if((glat - rlat )!= 0)
12511 gr_image.SetAlpha(j, i, 128);
12513 gr_image.SetAlpha(j, i, 255);
12520 wxBitmap *pbm =
new wxBitmap(gr_image);
12521 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12522 pbm->SetMask(gr_mask);
12524 pmdc->DrawBitmap(*pbm, 0,0);
12532void ChartCanvas::CancelMouseRoute() {
12534 m_pMouseRoute = NULL;
12535 m_bDrawingRoute =
false;
12538int ChartCanvas::GetNextContextMenuId() {
12539 return CanvasMenuHandler::GetNextContextMenuId();
12542bool ChartCanvas::SetCursor(
const wxCursor &c) {
12544 if (g_bopengl && m_glcc)
12545 return m_glcc->SetCursor(c);
12548 return wxWindow::SetCursor(c);
12551void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12552 if (g_bquiting)
return;
12562 if (!m_RolloverPopupTimer.IsRunning() &&
12563 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12564 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12565 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12566 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12569 if (m_glcc && g_bopengl) {
12572 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12574 m_glcc->Refresh(eraseBackground,
12591 if (m_pCIWin && m_pCIWin->IsShown()) {
12593 m_pCIWin->Refresh(
false);
12601 wxWindow::Refresh(eraseBackground, rect);
12604void ChartCanvas::Update() {
12605 if (m_glcc && g_bopengl) {
12610 wxWindow::Update();
12614 if (!pemboss)
return;
12615 int x = pemboss->x, y = pemboss->y;
12616 const double factor = 200;
12618 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12619 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12620 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12623 wxMemoryDC snip_dc;
12624 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12625 snip_dc.SelectObject(snip_bmp);
12627 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12628 snip_dc.SelectObject(wxNullBitmap);
12630 wxImage snip_img = snip_bmp.ConvertToImage();
12633 unsigned char *pdata = snip_img.GetData();
12635 for (
int y = 0; y < pemboss->height; y++) {
12636 int map_index = (y * pemboss->width);
12637 for (
int x = 0; x < pemboss->width; x++) {
12638 double val = (pemboss->pmap[map_index] * factor) / 256.;
12640 int nred = (int)((*pdata) + val);
12641 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12642 *pdata++ = (
unsigned char)nred;
12644 int ngreen = (int)((*pdata) + val);
12645 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12646 *pdata++ = (
unsigned char)ngreen;
12648 int nblue = (int)((*pdata) + val);
12649 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12650 *pdata++ = (
unsigned char)nblue;
12658 wxBitmap emb_bmp(snip_img);
12661 wxMemoryDC result_dc;
12662 result_dc.SelectObject(emb_bmp);
12665 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12667 result_dc.SelectObject(wxNullBitmap);
12673 if (GetQuiltMode()) {
12675 int refIndex = GetQuiltRefChartdbIndex();
12676 if (refIndex >= 0) {
12678 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12679 if (current_type == CHART_TYPE_MBTILES) {
12680 ChartBase *pChart = m_pQuilt->GetRefChart();
12683 zoom_factor = ptc->GetZoomFactor();
12688 if (zoom_factor <= 3.9)
return NULL;
12690 if (m_singleChart) {
12691 if (zoom_factor <= 3.9)
return NULL;
12696 if (m_pEM_OverZoom) {
12697 m_pEM_OverZoom->x = 4;
12698 m_pEM_OverZoom->y = 0;
12700 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12701 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12704 return m_pEM_OverZoom;
12707void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12720 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12721 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12725 AISDrawAreaNotices(dc, GetVP(),
this);
12727 wxDC *pdc = dc.GetDC();
12729 pdc->DestroyClippingRegion();
12730 wxDCClipper(*pdc, ru);
12733 if (m_bShowNavobjects) {
12734 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12735 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12736 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12737 DrawAnchorWatchPoints(dc);
12739 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12740 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12743 AISDraw(dc, GetVP(),
this);
12747 RenderVisibleSectorLights(dc);
12749 RenderAllChartOutlines(dc, GetVP());
12750 RenderRouteLegs(dc);
12751 RenderShipToActive(dc,
false);
12753 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12755 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12759 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12760 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12763 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12768 RebuildTideSelectList(GetVP().GetBBox());
12769 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12772 if (m_bShowCurrent) {
12773 RebuildCurrentSelectList(GetVP().GetBBox());
12774 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12777 if (!g_PrintingInProgress) {
12778 if (IsPrimaryCanvas()) {
12782 if (IsPrimaryCanvas()) {
12786 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12788 if (m_pTrackRolloverWin) {
12789 m_pTrackRolloverWin->Draw(dc);
12790 m_brepaint_piano =
true;
12793 if (m_pRouteRolloverWin) {
12794 m_pRouteRolloverWin->Draw(dc);
12795 m_brepaint_piano =
true;
12798 if (m_pAISRolloverWin) {
12799 m_pAISRolloverWin->Draw(dc);
12800 m_brepaint_piano =
true;
12802 if (m_brepaint_piano && g_bShowChartBar) {
12803 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12806 if (m_Compass) m_Compass->Paint(dc);
12808 if (!g_CanvasHideNotificationIcon) {
12809 if (IsPrimaryCanvas()) {
12810 auto ¬eman = NotificationManager::GetInstance();
12811 if (noteman.GetNotificationCount()) {
12812 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12813 if (m_notification_button->UpdateStatus()) Refresh();
12814 m_notification_button->Show(
true);
12815 m_notification_button->Paint(dc);
12817 m_notification_button->Show(
false);
12823 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12829 if (!m_bShowDepthUnits)
return NULL;
12831 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12833 if (GetQuiltMode()) {
12834 wxString s = m_pQuilt->GetQuiltDepthUnit();
12837 depth_unit_type = DEPTH_UNIT_FEET;
12838 else if (s.StartsWith(
"FATHOMS"))
12839 depth_unit_type = DEPTH_UNIT_FATHOMS;
12840 else if (s.StartsWith(
"METERS"))
12841 depth_unit_type = DEPTH_UNIT_METERS;
12842 else if (s.StartsWith(
"METRES"))
12843 depth_unit_type = DEPTH_UNIT_METERS;
12844 else if (s.StartsWith(
"METRIC"))
12845 depth_unit_type = DEPTH_UNIT_METERS;
12846 else if (s.StartsWith(
"METER"))
12847 depth_unit_type = DEPTH_UNIT_METERS;
12850 if (m_singleChart) {
12851 depth_unit_type = m_singleChart->GetDepthUnitType();
12852 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12853 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12858 switch (depth_unit_type) {
12859 case DEPTH_UNIT_FEET:
12862 case DEPTH_UNIT_METERS:
12863 ped = m_pEM_Meters;
12865 case DEPTH_UNIT_FATHOMS:
12866 ped = m_pEM_Fathoms;
12872 ped->x = (GetVP().
pix_width - ped->width);
12874 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12875 wxRect r = m_Compass->
GetRect();
12876 ped->y = r.y + r.height;
12883void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12886 if (style->embossFont == wxEmptyString) {
12887 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12889 font.SetPointSize(60);
12890 font.SetWeight(wxFONTWEIGHT_BOLD);
12892 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12893 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12895 int emboss_width = 500;
12896 int emboss_height = 200;
12900 delete m_pEM_Meters;
12901 delete m_pEM_Fathoms;
12905 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12907 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12909 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12912#define OVERZOOM_TEXT _("OverZoom")
12914void ChartCanvas::SetOverzoomFont() {
12919 if (style->embossFont == wxEmptyString) {
12920 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12922 font.SetPointSize(40);
12923 font.SetWeight(wxFONTWEIGHT_BOLD);
12925 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12926 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12928 wxClientDC dc(
this);
12930 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12932 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12933 font.SetPointSize(font.GetPointSize() - 1);
12935 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12937 m_overzoomFont = font;
12938 m_overzoomTextWidth = w;
12939 m_overzoomTextHeight = h;
12942void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12943 delete m_pEM_OverZoom;
12945 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12947 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12948 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12951emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12952 int height,
const wxString &str,
12957 wxBitmap bmp(width, height, -1);
12960 wxMemoryDC temp_dc;
12961 temp_dc.SelectObject(bmp);
12964 temp_dc.SetBackground(*wxWHITE_BRUSH);
12965 temp_dc.SetTextBackground(*wxWHITE);
12966 temp_dc.SetTextForeground(*wxBLACK);
12970 temp_dc.SetFont(font);
12973 temp_dc.GetTextExtent(str, &str_w, &str_h);
12975 temp_dc.DrawText(str, 1, 1);
12978 temp_dc.SelectObject(wxNullBitmap);
12981 wxImage img = bmp.ConvertToImage();
12983 int image_width = str_w * 105 / 100;
12984 int image_height = str_h * 105 / 100;
12985 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12986 wxMin(image_height, img.GetHeight()));
12987 wxImage imgs = img.GetSubImage(r);
12991 case GLOBAL_COLOR_SCHEME_DAY:
12995 case GLOBAL_COLOR_SCHEME_DUSK:
12998 case GLOBAL_COLOR_SCHEME_NIGHT:
13005 const int w = imgs.GetWidth();
13006 const int h = imgs.GetHeight();
13007 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13012 for (
int y = 1; y < h - 1; y++) {
13013 for (
int x = 1; x < w - 1; x++) {
13015 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13016 val = (int)(val * val_factor);
13017 index = (y * w) + x;
13030void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13031 Track *active_track = NULL;
13034 active_track = pTrackDraw;
13038 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13041 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13044void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13045 Track *active_track = NULL;
13048 active_track = pTrackDraw;
13052 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13055void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13056 Route *active_route = NULL;
13058 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13059 active_route = pRouteDraw;
13064 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13069 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13072void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13073 Route *active_route = NULL;
13076 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13077 active_route = pRouteDraw;
13081 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13084void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13085 if (!pWayPointMan)
return;
13087 auto node = pWayPointMan->GetWaypointList()->begin();
13089 while (node != pWayPointMan->GetWaypointList()->end()) {
13098 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13102 if (pWP->GetShowWaypointRangeRings() &&
13103 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13104 double factor = 1.00;
13105 if (pWP->GetWaypointRangeRingsStepUnits() ==
13107 factor = 1 / 1.852;
13109 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13110 pWP->GetWaypointRangeRingsStep() / 60.;
13114 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13115 pWP->m_lat + radius, pWP->m_lon + radius);
13116 if (!BltBBox.IntersectOut(radar_box)) {
13127void ChartCanvas::DrawBlinkObjects() {
13129 wxRect update_rect;
13131 if (!pWayPointMan)
return;
13133 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13140 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13143void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13148 wxPoint lAnchorPoint1, lAnchorPoint2;
13162 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13163 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13165 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13166 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13167 dc.SetBrush(*ppBrush);
13171 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13176 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13181 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13186 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13191double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13194 wxPoint lAnchorPoint;
13197 double tlat1, tlon1;
13199 if (pAnchorWatchPoint) {
13200 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13201 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13202 dabs = fabs(d1 / 1852.);
13203 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13208 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13209 pow((
double)(lAnchorPoint.y - r1.y), 2));
13212 if (d1 < 0) lpp = -lpp;
13220void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13223 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13225 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13231 if ((type ==
't') || (type ==
'T')) {
13232 if (BBox.Contains(lat, lon)) {
13234 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13240void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13243 wxDateTime this_now = gTimeSource;
13244 bool cur_time = !gTimeSource.IsValid();
13245 if (cur_time) this_now = wxDateTime::Now();
13246 time_t t_this_now = this_now.GetTicks();
13248 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13250 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13251 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13252 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13253 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13255 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13256 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13257 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13258 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13259 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13260 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13262 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13263 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13264 int font_size = wxMax(10, dFont->GetPointSize());
13267 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13268 false, dFont->GetFaceName());
13270 dc.SetPen(*pblack_pen);
13271 dc.SetBrush(*pgreen_brush);
13275 case GLOBAL_COLOR_SCHEME_DAY:
13278 case GLOBAL_COLOR_SCHEME_DUSK:
13281 case GLOBAL_COLOR_SCHEME_NIGHT:
13282 bm = m_bmTideNight;
13289 int bmw = bm.GetWidth();
13290 int bmh = bm.GetHeight();
13292 float scale_factor = 1.0;
13296 float icon_pixelRefDim = 45;
13301 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13303 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13305 scale_factor *= pix_factor;
13312 scale_factor *= user_scale_factor;
13313 scale_factor *= GetContentScaleFactor();
13316 double marge = 0.05;
13317 std::vector<LLBBox> drawn_boxes;
13318 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13322 if ((type ==
't') || (type ==
'T'))
13327 if (BBox.ContainsMarge(lat, lon, marge)) {
13329 if (GetVP().chart_scale < 500000) {
13330 bool bdrawn =
false;
13331 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13332 if (drawn_boxes[i].Contains(lat, lon)) {
13337 if (bdrawn)
continue;
13340 this_box.Set(lat, lon, lat, lon);
13341 this_box.EnLarge(.005);
13342 drawn_boxes.push_back(this_box);
13348 if (GetVP().chart_scale > 500000) {
13349 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13353 dc.SetFont(*plabelFont);
13365 if (
ptcmgr->GetTideFlowSens(
13366 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13370 ptcmgr->GetHightOrLowTide(
13371 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13372 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13384 if (tctime > t_this_now)
13385 ptcmgr->GetHightOrLowTide(
13386 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13387 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13391 ptcmgr->GetHightOrLowTide(
13392 t_this_now, FORWARD_TEN_MINUTES_STEP,
13393 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13407 int width = (int)(12 * scale_factor + 0.5);
13408 int height = (int)(45 * scale_factor + 0.5);
13409 int linew = wxMax(1, (
int)(scale_factor));
13410 int xDraw = r.x - (width / 2);
13411 int yDraw = r.y - (height / 2);
13414 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13415 int hs = (httime > lttime) ? -4 : 4;
13416 hs *= (int)(scale_factor + 0.5);
13417 if (ts > 0.995 || ts < 0.005) hs = 0;
13418 int ht_y = (int)(height * ts);
13421 pblack_pen->SetWidth(linew);
13422 dc.SetPen(*pblack_pen);
13423 dc.SetBrush(*pyelo_brush);
13424 dc.DrawRectangle(xDraw, yDraw, width, height);
13428 dc.SetPen(*pblue_pen);
13429 dc.SetBrush(*pblue_brush);
13430 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13431 (width - (4 * linew)), height - ht_y);
13437 arrow[0].x = xDraw + 2 * linew;
13438 arrow[1].x = xDraw + width / 2;
13439 arrow[2].x = xDraw + width - 2 * linew;
13440 pyelo_pen->SetWidth(linew);
13441 pblue_pen->SetWidth(linew);
13442 if (ts > 0.35 || ts < 0.15)
13444 hl = (int)(height * 0.25) + yDraw;
13446 arrow[1].y = hl + hs;
13449 dc.SetPen(*pyelo_pen);
13451 dc.SetPen(*pblue_pen);
13452 dc.DrawLines(3, arrow);
13454 if (ts > 0.60 || ts < 0.40)
13456 hl = (int)(height * 0.5) + yDraw;
13458 arrow[1].y = hl + hs;
13461 dc.SetPen(*pyelo_pen);
13463 dc.SetPen(*pblue_pen);
13464 dc.DrawLines(3, arrow);
13466 if (ts < 0.65 || ts > 0.85)
13468 hl = (int)(height * 0.75) + yDraw;
13470 arrow[1].y = hl + hs;
13473 dc.SetPen(*pyelo_pen);
13475 dc.SetPen(*pblue_pen);
13476 dc.DrawLines(3, arrow);
13480 s.Printf(
"%3.1f", nowlev);
13482 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13484 dc.GetTextExtent(s, &wx1, NULL);
13486 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13501void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13504 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13506 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13512 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13513 if ((BBox.Contains(lat, lon))) {
13515 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13521void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13524 float tcvalue, dir;
13528 double lon_last = 0.;
13529 double lat_last = 0.;
13531 double marge = 0.2;
13532 bool cur_time = !gTimeSource.IsValid();
13534 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13535 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13537 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13539 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13540 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13541 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13542 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13543 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13544 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13545 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13546 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13548 double skew_angle = GetVPRotation();
13550 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13551 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13552 int font_size = wxMax(10, dFont->GetPointSize());
13555 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13556 false, dFont->GetFaceName());
13558 float scale_factor = 1.0;
13564 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13566 float nominal_icon_size_pixels = 15;
13567 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13569 scale_factor *= pix_factor;
13576 scale_factor *= user_scale_factor;
13578 scale_factor *= GetContentScaleFactor();
13581 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13587 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13588 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13593 int dd = (int)(5.0 * scale_factor + 0.5);
13604 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13605 dc.SetPen(*pblack_pen);
13606 dc.SetBrush(*porange_brush);
13607 dc.DrawPolygon(4, d);
13610 dc.SetBrush(*pblack_brush);
13611 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13615 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13629 double a1 = fabs(tcvalue) * 10.;
13631 a1 = wxMax(1.0, a1);
13632 double a2 = log10(a1);
13634 float cscale = scale_factor * a2 * 0.3;
13636 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13637 dc.SetPen(*porange_pen);
13638 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13642 if (bDrawCurrentValues) {
13643 dc.SetFont(*pTCFont);
13644 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13645 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13671 if (!pvIDX)
return;
13676 if (pCwin && pCwin->IsShown()) {
13684 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13699 pCwin =
new TCWin(
this, x, y, pvIDX);
13717#define NUM_CURRENT_ARROW_POINTS 9
13718static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13719 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13720 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13721 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13723void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13725 if (
scale > 1e-2) {
13726 float sin_rot = sin(rot_angle * PI / 180.);
13727 float cos_rot = cos(rot_angle * PI / 180.);
13731 float xt = CurrentArrowArray[0].x;
13732 float yt = CurrentArrowArray[0].y;
13734 float xp = (xt * cos_rot) - (yt * sin_rot);
13735 float yp = (xt * sin_rot) + (yt * cos_rot);
13736 int x1 = (int)(xp *
scale);
13737 int y1 = (int)(yp *
scale);
13740 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13741 xt = CurrentArrowArray[ip].x;
13742 yt = CurrentArrowArray[ip].y;
13744 float xp = (xt * cos_rot) - (yt * sin_rot);
13745 float yp = (xt * sin_rot) + (yt * cos_rot);
13746 int x2 = (int)(xp *
scale);
13747 int y2 = (int)(yp *
scale);
13749 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13757wxString ChartCanvas::FindValidUploadPort() {
13760 if (!g_uploadConnection.IsEmpty() &&
13761 g_uploadConnection.StartsWith(
"Serial")) {
13762 port = g_uploadConnection;
13768 for (
auto *cp : TheConnectionParams()) {
13769 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13770 port <<
"Serial:" << cp->Port;
13776void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13779 if (NULL == g_pais_query_dialog_active) {
13780 int pos_x = g_ais_query_dialog_x;
13781 int pos_y = g_ais_query_dialog_y;
13783 if (g_pais_query_dialog_active) {
13784 g_pais_query_dialog_active->Destroy();
13790 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13791 wxPoint(pos_x, pos_y));
13793 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13794 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13795 g_pais_query_dialog_active->SetMMSI(mmsi);
13796 g_pais_query_dialog_active->UpdateText();
13797 wxSize sz = g_pais_query_dialog_active->GetSize();
13799 bool b_reset_pos =
false;
13804 RECT frame_title_rect;
13805 frame_title_rect.left = pos_x;
13806 frame_title_rect.top = pos_y;
13807 frame_title_rect.right = pos_x + sz.x;
13808 frame_title_rect.bottom = pos_y + 30;
13810 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13811 b_reset_pos =
true;
13816 wxRect window_title_rect;
13817 window_title_rect.x = pos_x;
13818 window_title_rect.y = pos_y;
13819 window_title_rect.width = sz.x;
13820 window_title_rect.height = 30;
13822 wxRect ClientRect = wxGetClientDisplayRect();
13823 ClientRect.Deflate(
13825 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13829 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13832 g_pais_query_dialog_active->SetMMSI(mmsi);
13833 g_pais_query_dialog_active->UpdateText();
13836 g_pais_query_dialog_active->Show();
13839void ChartCanvas::ToggleCanvasQuiltMode() {
13840 bool cur_mode = GetQuiltMode();
13842 if (!GetQuiltMode())
13843 SetQuiltMode(
true);
13844 else if (GetQuiltMode()) {
13845 SetQuiltMode(
false);
13846 g_sticky_chart = GetQuiltReferenceChartIndex();
13849 if (cur_mode != GetQuiltMode()) {
13850 SetupCanvasQuiltMode();
13859 if (ps52plib) ps52plib->GenerateStateHash();
13861 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13862 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13865void ChartCanvas::DoCanvasStackDelta(
int direction) {
13866 if (!GetQuiltMode()) {
13867 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13868 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13869 if ((current_stack_index + direction) < 0)
return;
13871 if (m_bpersistent_quilt ) {
13873 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13875 if (IsChartQuiltableRef(new_dbIndex)) {
13876 ToggleCanvasQuiltMode();
13877 SelectQuiltRefdbChart(new_dbIndex);
13878 m_bpersistent_quilt =
false;
13881 SelectChartFromStack(current_stack_index + direction);
13884 std::vector<int> piano_chart_index_array =
13885 GetQuiltExtendedStackdbIndexArray();
13886 int refdb = GetQuiltRefChartdbIndex();
13889 int current_index = -1;
13890 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13891 if (refdb == piano_chart_index_array[i]) {
13896 if (current_index == -1)
return;
13899 int target_family = ctet.GetChartFamily();
13901 int new_index = -1;
13902 int check_index = current_index + direction;
13903 bool found =
false;
13904 int check_dbIndex = -1;
13905 int new_dbIndex = -1;
13909 (
unsigned int)check_index < piano_chart_index_array.size() &&
13910 (check_index >= 0)) {
13911 check_dbIndex = piano_chart_index_array[check_index];
13913 if (target_family == cte.GetChartFamily()) {
13915 new_index = check_index;
13916 new_dbIndex = check_dbIndex;
13920 check_index += direction;
13923 if (!found)
return;
13925 if (!IsChartQuiltableRef(new_dbIndex)) {
13926 ToggleCanvasQuiltMode();
13927 SelectdbChart(new_dbIndex);
13928 m_bpersistent_quilt =
true;
13930 SelectQuiltRefChart(new_index);
13934 gFrame->UpdateGlobalMenuItems();
13936 SetQuiltChartHiLiteIndex(-1);
13947void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13950 switch (event.GetId()) {
13962 DoCanvasStackDelta(1);
13967 DoCanvasStackDelta(-1);
13977 ShowCurrents(!GetbShowCurrent());
13984 ShowTides(!GetbShowTide());
13991 if (0 == m_routeState) {
13998 androidSetRouteAnnunciator(m_routeState == 1);
14004 SetAISCanvasDisplayStyle(-1);
14016void ChartCanvas::SetShowAIS(
bool show) {
14018 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14019 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14022void ChartCanvas::SetAttenAIS(
bool show) {
14023 m_bShowAISScaled = show;
14024 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14025 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14028void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14031 bool bShowAIS_Array[3] = {
true,
true,
false};
14032 bool bShowScaled_Array[3] = {
false,
true,
true};
14033 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14034 _(
"Attenuate less critical AIS targets"),
14035 _(
"Hide AIS Targets")};
14036 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14038 int AIS_Toolbar_Switch = 0;
14039 if (StyleIndx == -1) {
14041 for (
int i = 1; i < ArraySize; i++) {
14042 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14043 (bShowScaled_Array[i] == m_bShowAISScaled))
14044 AIS_Toolbar_Switch = i;
14046 AIS_Toolbar_Switch++;
14047 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14048 AIS_Toolbar_Switch++;
14051 AIS_Toolbar_Switch = StyleIndx;
14054 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14056 int AIS_Toolbar_Switch_Next =
14057 AIS_Toolbar_Switch + 1;
14058 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14059 AIS_Toolbar_Switch_Next++;
14060 if (AIS_Toolbar_Switch_Next >= ArraySize)
14061 AIS_Toolbar_Switch_Next = 0;
14064 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14065 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14068void ChartCanvas::TouchAISToolActive() {}
14070void ChartCanvas::UpdateAISTBTool() {}
14078void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14080 bool b_update =
false;
14081 int cc1_edge_comp = 2;
14082 wxRect rect = m_Compass->
GetRect();
14083 wxSize parent_size = GetSize();
14085 parent_size *= m_displayScale;
14089 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14090 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14091 wxRect compass_rect(compass_pt, rect.GetSize());
14093 m_Compass->Move(compass_pt);
14095 if (m_Compass && m_Compass->IsShown())
14096 m_Compass->UpdateStatus(b_force_new | b_update);
14098 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14099 scaler = wxMax(scaler, 1.0);
14100 wxPoint note_point = wxPoint(
14101 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14102 if (m_notification_button) {
14103 m_notification_button->Move(note_point);
14104 m_notification_button->UpdateStatus();
14107 if (b_force_new | b_update) Refresh();
14110void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14111 ChartTypeEnum New_Type,
14112 ChartFamilyEnum New_Family) {
14113 if (!GetpCurrentStack())
return;
14116 if (index < GetpCurrentStack()->nEntry) {
14119 pTentative_Chart =
ChartData->OpenStackChartConditional(
14120 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14122 if (pTentative_Chart) {
14123 if (m_singleChart) m_singleChart->Deactivate();
14125 m_singleChart = pTentative_Chart;
14126 m_singleChart->Activate();
14128 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14129 GetpCurrentStack(), m_singleChart->GetFullPath());
14142 double best_scale_ppm = GetBestVPScale(m_singleChart);
14143 double rotation = GetVPRotation();
14144 double oldskew = GetVPSkew();
14145 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14147 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14148 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14149 if (fabs(newskew) > 0.0001) rotation = newskew;
14152 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14154 UpdateGPSCompassStatusBox(
true);
14158 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14159 if (idx < 0)
return;
14161 std::vector<int> piano_active_chart_index_array;
14162 piano_active_chart_index_array.push_back(
14163 GetpCurrentStack()->GetCurrentEntrydbIndex());
14164 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14167void ChartCanvas::SelectdbChart(
int dbindex) {
14168 if (!GetpCurrentStack())
return;
14171 if (dbindex >= 0) {
14174 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14176 if (pTentative_Chart) {
14177 if (m_singleChart) m_singleChart->Deactivate();
14179 m_singleChart = pTentative_Chart;
14180 m_singleChart->Activate();
14182 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14183 GetpCurrentStack(), m_singleChart->GetFullPath());
14196 double best_scale_ppm = GetBestVPScale(m_singleChart);
14200 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14210void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14213 if (!GetQuiltMode()) {
14214 if (GetpCurrentStack()) {
14215 int stack_index = -1;
14216 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14217 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14218 if (check_dbIndex < 0)
continue;
14220 ChartData->GetChartTableEntry(check_dbIndex);
14221 if (type == cte.GetChartType()) {
14224 }
else if (family == cte.GetChartFamily()) {
14230 if (stack_index >= 0) {
14231 SelectChartFromStack(stack_index);
14235 int sel_dbIndex = -1;
14236 std::vector<int> piano_chart_index_array =
14237 GetQuiltExtendedStackdbIndexArray();
14238 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14239 int check_dbIndex = piano_chart_index_array[i];
14241 if (type == cte.GetChartType()) {
14242 if (IsChartQuiltableRef(check_dbIndex)) {
14243 sel_dbIndex = check_dbIndex;
14246 }
else if (family == cte.GetChartFamily()) {
14247 if (IsChartQuiltableRef(check_dbIndex)) {
14248 sel_dbIndex = check_dbIndex;
14254 if (sel_dbIndex >= 0) {
14255 SelectQuiltRefdbChart(sel_dbIndex,
false);
14257 AdjustQuiltRefChart();
14264 SetQuiltChartHiLiteIndex(-1);
14269bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14270 return std::find(m_tile_yesshow_index_array.begin(),
14271 m_tile_yesshow_index_array.end(),
14272 index) != m_tile_yesshow_index_array.end();
14275bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14276 return std::find(m_tile_noshow_index_array.begin(),
14277 m_tile_noshow_index_array.end(),
14278 index) != m_tile_noshow_index_array.end();
14281void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14282 if (std::find(m_tile_noshow_index_array.begin(),
14283 m_tile_noshow_index_array.end(),
14284 index) == m_tile_noshow_index_array.end()) {
14285 m_tile_noshow_index_array.push_back(index);
14295void ChartCanvas::HandlePianoClick(
14296 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14299 if (!m_pCurrentStack)
return;
14315 double distance = 25000;
14316 int closest_index = -1;
14317 for (
int chart_index : selected_dbIndex_array) {
14319 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14320 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14323 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14324 if (test_distance < distance) {
14325 distance = test_distance;
14326 closest_index = chart_index;
14330 int selected_dbIndex = selected_dbIndex_array[0];
14331 if (closest_index >= 0) selected_dbIndex = closest_index;
14333 if (!GetQuiltMode()) {
14334 if (m_bpersistent_quilt ) {
14335 if (IsChartQuiltableRef(selected_dbIndex)) {
14336 ToggleCanvasQuiltMode();
14337 SelectQuiltRefdbChart(selected_dbIndex);
14338 m_bpersistent_quilt =
false;
14340 SelectChartFromStack(selected_index);
14343 SelectChartFromStack(selected_index);
14344 g_sticky_chart = selected_dbIndex;
14348 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14352 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14353 bool bfound =
false;
14354 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14355 if (m_tile_noshow_index_array[i] ==
14356 selected_dbIndex) {
14357 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14364 m_tile_noshow_index_array.push_back(selected_dbIndex);
14368 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14369 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14373 if (IsChartQuiltableRef(selected_dbIndex)) {
14379 bool set_scale =
false;
14380 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14381 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14387 SelectQuiltRefdbChart(selected_dbIndex,
true);
14389 SelectQuiltRefdbChart(selected_dbIndex,
false);
14394 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14396 double proposed_scale_onscreen =
14399 if (g_bPreserveScaleOnX) {
14400 proposed_scale_onscreen =
14401 wxMin(proposed_scale_onscreen,
14403 GetCanvasWidth()));
14405 proposed_scale_onscreen =
14406 wxMin(proposed_scale_onscreen,
14408 GetCanvasWidth()));
14410 proposed_scale_onscreen =
14411 wxMax(proposed_scale_onscreen,
14420 ToggleCanvasQuiltMode();
14421 SelectdbChart(selected_dbIndex);
14422 m_bpersistent_quilt =
true;
14427 SetQuiltChartHiLiteIndex(-1);
14428 gFrame->UpdateGlobalMenuItems();
14430 HideChartInfoWindow();
14435void ChartCanvas::HandlePianoRClick(
14436 int x,
int y,
int selected_index,
14437 const std::vector<int> &selected_dbIndex_array) {
14440 if (!GetpCurrentStack())
return;
14442 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14443 UpdateCanvasControlBar();
14445 SetQuiltChartHiLiteIndex(-1);
14448void ChartCanvas::HandlePianoRollover(
14449 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14450 int n_charts,
int scale) {
14453 if (!GetpCurrentStack())
return;
14458 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14460 if (!GetQuiltMode()) {
14461 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14464 std::vector<int> piano_chart_index_array;
14465 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14466 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14467 if ((GetpCurrentStack()->nEntry > 1) ||
14468 (piano_chart_index_array.size() >= 1)) {
14469 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14471 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14473 }
else if (GetpCurrentStack()->nEntry == 1) {
14475 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14476 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14477 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14479 }
else if ((-1 == selected_index) &&
14480 (0 == selected_dbIndex_array.size())) {
14481 ShowChartInfoWindow(key_location.x, -1);
14485 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14487 if ((GetpCurrentStack()->nEntry > 1) ||
14488 (piano_chart_index_array.size() >= 1)) {
14490 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14491 selected_dbIndex_array);
14492 else if (n_charts == 1)
14493 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14495 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14502void ChartCanvas::ClearPianoRollover() {
14503 ClearQuiltChartHiLiteIndexArray();
14504 ShowChartInfoWindow(0, -1);
14505 std::vector<int> vec;
14506 ShowCompositeInfoWindow(0, 0, 0, vec);
14510void ChartCanvas::UpdateCanvasControlBar() {
14511 if (m_pianoFrozen)
return;
14513 if (!GetpCurrentStack())
return;
14515 if (!g_bShowChartBar)
return;
14518 int sel_family = -1;
14520 std::vector<int> piano_chart_index_array;
14521 std::vector<int> empty_piano_chart_index_array;
14523 wxString old_hash = m_Piano->GetStoredHash();
14525 if (GetQuiltMode()) {
14526 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14527 GetQuiltFullScreendbIndexArray());
14529 std::vector<int> piano_active_chart_index_array =
14530 GetQuiltCandidatedbIndexArray();
14531 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14533 std::vector<int> piano_eclipsed_chart_index_array =
14534 GetQuiltEclipsedStackdbIndexArray();
14535 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14537 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14538 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14540 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14541 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14543 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14544 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14547 if (m_singleChart) {
14548 sel_type = m_singleChart->GetChartType();
14549 sel_family = m_singleChart->GetChartFamily();
14554 std::vector<int> piano_skew_chart_index_array;
14555 std::vector<int> piano_tmerc_chart_index_array;
14556 std::vector<int> piano_poly_chart_index_array;
14558 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14560 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14561 double skew_norm = ctei.GetChartSkew();
14562 if (skew_norm > 180.) skew_norm -= 360.;
14564 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14565 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14568 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14569 if (fabs(skew_norm) > 1.)
14570 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14572 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14573 }
else if (fabs(skew_norm) > 1.)
14574 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14576 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14577 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14578 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14580 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14581 if (new_hash != old_hash) {
14582 m_Piano->FormatKeys();
14583 HideChartInfoWindow();
14584 m_Piano->ResetRollover();
14585 SetQuiltChartHiLiteIndex(-1);
14586 m_brepaint_piano =
true;
14592 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14594 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14595 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14596 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14597 if (e == CHART_FAMILY_RASTER) mask |= 1;
14598 if (e == CHART_FAMILY_VECTOR) {
14599 if (t == CHART_TYPE_CM93COMP)
14606 wxString s_indicated;
14607 if (sel_type == CHART_TYPE_CM93COMP)
14608 s_indicated =
"cm93";
14610 if (sel_family == CHART_FAMILY_RASTER)
14611 s_indicated =
"raster";
14612 else if (sel_family == CHART_FAMILY_VECTOR)
14613 s_indicated =
"vector";
14616 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14619void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14621void ChartCanvas::PianoPopupMenu(
14622 int x,
int y,
int selected_index,
14623 const std::vector<int> &selected_dbIndex_array) {
14624 if (!GetpCurrentStack())
return;
14627 if (!GetQuiltMode())
return;
14629 m_piano_ctx_menu =
new wxMenu();
14631 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14641 menu_selected_dbIndex = selected_dbIndex_array[0];
14642 menu_selected_index = selected_index;
14645 bool b_is_in_noshow =
false;
14646 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14647 if (m_quilt_noshow_index_array[i] ==
14648 menu_selected_dbIndex)
14650 b_is_in_noshow =
true;
14655 if (b_is_in_noshow) {
14656 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14657 _(
"Show This Chart"));
14658 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14659 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14660 }
else if (GetpCurrentStack()->nEntry > 1) {
14661 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14662 _(
"Hide This Chart"));
14663 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14664 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14668 wxPoint pos = wxPoint(x, y - 30);
14671 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14672 PopupMenu(m_piano_ctx_menu, pos);
14674 delete m_piano_ctx_menu;
14675 m_piano_ctx_menu = NULL;
14677 HideChartInfoWindow();
14678 m_Piano->ResetRollover();
14680 SetQuiltChartHiLiteIndex(-1);
14681 ClearQuiltChartHiLiteIndexArray();
14686void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14687 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14688 if (m_quilt_noshow_index_array[i] ==
14689 menu_selected_dbIndex)
14691 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14697void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14698 if (!GetpCurrentStack())
return;
14701 RemoveChartFromQuilt(menu_selected_dbIndex);
14705 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14706 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14708 int i = menu_selected_index + 1;
14709 bool b_success =
false;
14710 while (i < GetpCurrentStack()->nEntry - 1) {
14711 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14712 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14713 SelectQuiltRefChart(i);
14723 i = menu_selected_index - 1;
14725 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14726 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14727 SelectQuiltRefChart(i);
14737void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14739 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14740 if (m_quilt_noshow_index_array[i] ==
14743 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14748 m_quilt_noshow_index_array.push_back(dbIndex);
14751bool ChartCanvas::UpdateS52State() {
14752 bool retval =
false;
14755 ps52plib->SetShowS57Text(m_encShowText);
14756 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14757 ps52plib->m_bShowSoundg = m_encShowDepth;
14758 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14759 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14762 if (!m_encShowLights)
14763 ps52plib->AddObjNoshow(
"LIGHTS");
14765 ps52plib->RemoveObjNoshow(
"LIGHTS");
14766 ps52plib->SetLightsOff(!m_encShowLights);
14767 ps52plib->m_bExtendLightSectors =
true;
14770 ps52plib->SetAnchorOn(m_encShowAnchor);
14771 ps52plib->SetQualityOfData(m_encShowDataQual);
14777void ChartCanvas::SetShowENCDataQual(
bool show) {
14778 m_encShowDataQual = show;
14779 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14780 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14782 m_s52StateHash = 0;
14785void ChartCanvas::SetShowENCText(
bool show) {
14786 m_encShowText = show;
14787 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14788 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14790 m_s52StateHash = 0;
14793void ChartCanvas::SetENCDisplayCategory(
int category) {
14794 m_encDisplayCategory = category;
14795 m_s52StateHash = 0;
14798void ChartCanvas::SetShowENCDepth(
bool show) {
14799 m_encShowDepth = show;
14800 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14801 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14803 m_s52StateHash = 0;
14806void ChartCanvas::SetShowENCLightDesc(
bool show) {
14807 m_encShowLightDesc = show;
14808 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14809 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14811 m_s52StateHash = 0;
14814void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14815 m_encShowBuoyLabels = show;
14816 m_s52StateHash = 0;
14819void ChartCanvas::SetShowENCLights(
bool show) {
14820 m_encShowLights = show;
14821 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14822 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14824 m_s52StateHash = 0;
14827void ChartCanvas::SetShowENCAnchor(
bool show) {
14828 m_encShowAnchor = show;
14829 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14830 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14832 m_s52StateHash = 0;
14835wxRect ChartCanvas::GetMUIBarRect() {
14838 rv = m_muiBar->GetRect();
14844void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14845 if (!GetAlertString().IsEmpty()) {
14846 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14847 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14849 dc.SetFont(*pfont);
14850 dc.SetPen(*wxTRANSPARENT_PEN);
14852 dc.SetBrush(wxColour(243, 229, 47));
14854 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14858 wxRect sbr = GetScaleBarRect();
14859 int xp = sbr.x + sbr.width + 10;
14860 int yp = (sbr.y + sbr.height) - h;
14862 int wdraw = w + 10;
14863 dc.DrawRectangle(xp, yp, wdraw, h);
14864 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14865 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14875#define BRIGHT_XCALIB
14876#define __OPCPN_USEICC__
14879#ifdef __OPCPN_USEICC__
14880int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14881 double co_green,
double co_blue);
14883wxString temp_file_name;
14887class ocpnCurtain:
public wxDialog
14889 DECLARE_CLASS( ocpnCurtain )
14890 DECLARE_EVENT_TABLE()
14893 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14895 bool ProcessEvent(wxEvent& event);
14899IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14901BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14904ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14906 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14909ocpnCurtain::~ocpnCurtain()
14913bool ocpnCurtain::ProcessEvent(wxEvent& event)
14915 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14916 return GetParent()->GetEventHandler()->ProcessEvent(event);
14921#include <windows.h>
14924typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14925typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14926SetDeviceGammaRamp_ptr_type
14927 g_pSetDeviceGammaRamp;
14928GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14930WORD *g_pSavedGammaMap;
14934int InitScreenBrightness() {
14937 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14941 if (NULL == hGDI32DLL) {
14942 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14944 if (NULL != hGDI32DLL) {
14946 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14947 hGDI32DLL,
"SetDeviceGammaRamp");
14948 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14949 hGDI32DLL,
"GetDeviceGammaRamp");
14952 if ((NULL == g_pSetDeviceGammaRamp) ||
14953 (NULL == g_pGetDeviceGammaRamp)) {
14954 FreeLibrary(hGDI32DLL);
14963 if (!g_pSavedGammaMap) {
14964 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14967 bbr = g_pGetDeviceGammaRamp(
14968 hDC, g_pSavedGammaMap);
14969 ReleaseDC(NULL, hDC);
14974 wxRegKey *pRegKey =
new wxRegKey(
14975 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14976 "NT\\CurrentVersion\\ICM");
14977 if (!pRegKey->Exists()) pRegKey->Create();
14978 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14980 g_brightness_init =
true;
14986 if (NULL == g_pcurtain) {
14987 if (gFrame->CanSetTransparent()) {
14989 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14990 wxPoint(0, 0), ::wxGetDisplaySize(),
14991 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14992 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14999 g_pcurtain->Hide();
15001 HWND hWnd = GetHwndOf(g_pcurtain);
15002 SetWindowLong(hWnd, GWL_EXSTYLE,
15003 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15004 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15005 g_pcurtain->SetTransparent(0);
15007 g_pcurtain->Maximize();
15008 g_pcurtain->Show();
15011 g_pcurtain->Enable();
15012 g_pcurtain->Disable();
15019 g_brightness_init =
true;
15025 wxString cmd(
"xcalib -version");
15027 wxArrayString output;
15028 long r = wxExecute(cmd, output);
15031 " External application \"xcalib\" not found. Screen brightness "
15034 g_brightness_init =
true;
15039int RestoreScreenBrightness() {
15042 if (g_pSavedGammaMap) {
15043 HDC hDC = GetDC(NULL);
15044 g_pSetDeviceGammaRamp(hDC,
15046 ReleaseDC(NULL, hDC);
15048 free(g_pSavedGammaMap);
15049 g_pSavedGammaMap = NULL;
15053 g_pcurtain->Close();
15054 g_pcurtain->Destroy();
15058 g_brightness_init =
false;
15063#ifdef BRIGHT_XCALIB
15064 if (g_brightness_init) {
15066 cmd =
"xcalib -clear";
15067 wxExecute(cmd, wxEXEC_ASYNC);
15068 g_brightness_init =
false;
15078int SetScreenBrightness(
int brightness) {
15085 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15087 g_pcurtain->Close();
15088 g_pcurtain->Destroy();
15092 InitScreenBrightness();
15094 if (NULL == hGDI32DLL) {
15096 wchar_t wdll_name[80];
15097 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15098 LPCWSTR cstr = wdll_name;
15100 hGDI32DLL = LoadLibrary(cstr);
15102 if (NULL != hGDI32DLL) {
15104 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15105 hGDI32DLL,
"SetDeviceGammaRamp");
15106 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15107 hGDI32DLL,
"GetDeviceGammaRamp");
15110 if ((NULL == g_pSetDeviceGammaRamp) ||
15111 (NULL == g_pGetDeviceGammaRamp)) {
15112 FreeLibrary(hGDI32DLL);
15119 HDC hDC = GetDC(NULL);
15130 int increment = brightness * 256 / 100;
15133 WORD GammaTable[3][256];
15136 for (
int i = 0; i < 256; i++) {
15137 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15138 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15139 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15141 table_val += increment;
15143 if (table_val > 65535) table_val = 65535;
15146 g_pSetDeviceGammaRamp(hDC, GammaTable);
15147 ReleaseDC(NULL, hDC);
15154 if (g_pSavedGammaMap) {
15155 HDC hDC = GetDC(NULL);
15156 g_pSetDeviceGammaRamp(hDC,
15158 ReleaseDC(NULL, hDC);
15161 if (brightness < 100) {
15162 if (NULL == g_pcurtain) InitScreenBrightness();
15165 int sbrite = wxMax(1, brightness);
15166 sbrite = wxMin(100, sbrite);
15168 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15172 g_pcurtain->Close();
15173 g_pcurtain->Destroy();
15183#ifdef BRIGHT_XCALIB
15185 if (!g_brightness_init) {
15186 last_brightness = 100;
15187 g_brightness_init =
true;
15188 temp_file_name = wxFileName::CreateTempFileName(
"");
15189 InitScreenBrightness();
15192#ifdef __OPCPN_USEICC__
15195 if (!CreateSimpleICCProfileFile(
15196 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15197 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15198 wxString cmd(
"xcalib ");
15199 cmd += temp_file_name;
15201 wxExecute(cmd, wxEXEC_ASYNC);
15210 if (brightness > last_brightness) {
15212 cmd =
"xcalib -clear";
15213 wxExecute(cmd, wxEXEC_ASYNC);
15215 ::wxMilliSleep(10);
15217 int brite_adj = wxMax(1, brightness);
15218 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15219 wxExecute(cmd, wxEXEC_ASYNC);
15221 int brite_adj = wxMax(1, brightness);
15222 int factor = (brite_adj * 100) / last_brightness;
15223 factor = wxMax(1, factor);
15225 cmd.Printf(
"xcalib -co %2d -a", factor);
15226 wxExecute(cmd, wxEXEC_ASYNC);
15231 last_brightness = brightness;
15238#ifdef __OPCPN_USEICC__
15240#define MLUT_TAG 0x6d4c5554L
15241#define VCGT_TAG 0x76636774L
15243int GetIntEndian(
unsigned char *s) {
15248 p = (
unsigned char *)&ret;
15251 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15253 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15258unsigned short GetShortEndian(
unsigned char *s) {
15259 unsigned short ret;
15263 p = (
unsigned char *)&ret;
15266 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15268 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15274int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15275 double co_green,
double co_blue) {
15279 fp = fopen(file_name,
"wb");
15280 if (!fp)
return -1;
15286 for (
int i = 0; i < 128; i++) header[i] = 0;
15288 fwrite(header, 128, 1, fp);
15292 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15293 fwrite(&numTags, 1, 4, fp);
15295 int tagName0 = VCGT_TAG;
15296 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15297 fwrite(&tagName, 1, 4, fp);
15299 int tagOffset0 = 128 + 4 *
sizeof(int);
15300 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15301 fwrite(&tagOffset, 1, 4, fp);
15304 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15305 fwrite(&tagSize, 1, 4, fp);
15307 fwrite(&tagName, 1, 4, fp);
15309 fwrite(&tagName, 1, 4, fp);
15314 int gammatype0 = 0;
15315 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15316 fwrite(&gammatype, 1, 4, fp);
15318 int numChannels0 = 3;
15319 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15320 fwrite(&numChannels, 1, 2, fp);
15322 int numEntries0 = 256;
15323 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15324 fwrite(&numEntries, 1, 2, fp);
15326 int entrySize0 = 1;
15327 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15328 fwrite(&entrySize, 1, 2, fp);
15330 unsigned char ramp[256];
15333 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15334 fwrite(ramp, 256, 1, fp);
15337 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15338 fwrite(ramp, 256, 1, fp);
15341 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15342 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.
ChartFamilyEnumPI
Enumeration of chart families (broad categories).
#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.