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;
758 delete m_notification_button;
761void ChartCanvas::SetupGridFont() {
762 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
764 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
766 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
767 FALSE, wxString(
"Arial"));
770void ChartCanvas::RebuildCursors() {
776 delete pCursorPencil;
780 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
784 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
785 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
786 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
787 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
788 wxImage ICursorPencil =
789 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
790 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
792#if !defined(__WXMSW__) && !defined(__WXQT__)
793 ICursorLeft.ConvertAlphaToMask(128);
794 ICursorRight.ConvertAlphaToMask(128);
795 ICursorUp.ConvertAlphaToMask(128);
796 ICursorDown.ConvertAlphaToMask(128);
797 ICursorPencil.ConvertAlphaToMask(10);
798 ICursorCross.ConvertAlphaToMask(10);
801 if (ICursorLeft.Ok()) {
802 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
803 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
804 pCursorLeft =
new wxCursor(ICursorLeft);
806 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
808 if (ICursorRight.Ok()) {
809 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
810 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
811 pCursorRight =
new wxCursor(ICursorRight);
813 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
815 if (ICursorUp.Ok()) {
816 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
817 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
818 pCursorUp =
new wxCursor(ICursorUp);
820 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
822 if (ICursorDown.Ok()) {
823 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
824 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
825 pCursorDown =
new wxCursor(ICursorDown);
827 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
829 if (ICursorPencil.Ok()) {
830 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
831 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
832 pCursorPencil =
new wxCursor(ICursorPencil);
834 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
836 if (ICursorCross.Ok()) {
837 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
838 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
839 pCursorCross =
new wxCursor(ICursorCross);
841 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
843 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
844 pPlugIn_Cursor = NULL;
847void ChartCanvas::CanvasApplyLocale() {
848 CreateDepthUnitEmbossMaps(m_cs);
849 CreateOZEmbossMapData(m_cs);
852void ChartCanvas::SetupGlCanvas() {
855 if (!g_bdisable_opengl) {
857 wxLogMessage(
"Creating glChartCanvas");
862 if (IsPrimaryCanvas()) {
869 wxGLContext *pctx =
new wxGLContext(m_glcc);
870 m_glcc->SetContext(pctx);
874 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
876 m_glcc->SetContext(g_pGLcontext);
886 if (!g_bdisable_opengl) {
889 wxLogMessage(
"Creating glChartCanvas");
893 if (IsPrimaryCanvas()) {
894 qDebug() <<
"Creating Primary glChartCanvas";
902 wxGLContext *pctx =
new wxGLContext(m_glcc);
903 m_glcc->SetContext(pctx);
905 m_glcc->m_pParentCanvas =
this;
908 qDebug() <<
"Creating Secondary glChartCanvas";
914 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
917 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
918 m_glcc->SetContext(pwxctx);
919 m_glcc->m_pParentCanvas =
this;
927void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
928 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
943 if (m_routeState && m_FinishRouteOnKillFocus)
944 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
946 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
950void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
951 m_routeFinishTimer.Stop();
955 gFrame->UpdateGlobalMenuItems(
this);
957 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
960void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
961 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
964#ifdef HAVE_WX_GESTURE_EVENTS
965void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
972 m_popupWanted =
true;
974 m_inLongPress = !g_bhide_context_menus;
977 m_menuPos =
event.GetPosition();
978 wxMouseEvent ev(wxEVT_LEFT_UP);
979 ev.m_x = m_menuPos.x;
980 ev.m_y = m_menuPos.y;
981 wxPostEvent(
this, ev);
985 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
986 ev_right_click.m_x = m_menuPos.x;
987 ev_right_click.m_y = m_menuPos.y;
988 MouseEvent(ev_right_click);
993void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
997void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
999void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1001void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1003 long dt = m_sw_left_up.Time() - m_sw_up_time;
1004 m_sw_up_time = m_sw_left_up.Time();
1015 wxPoint pos =
event.GetPosition();
1019 if (!m_popupWanted) {
1020 wxMouseEvent ev(wxEVT_LEFT_UP);
1027 m_popupWanted =
false;
1029 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1036void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1041 long dt = m_sw_left_down.Time() - m_sw_down_time;
1042 m_sw_down_time = m_sw_left_down.Time();
1066 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1068 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1069 m_lastTapPos.y - max_double_click_distance,
1070 max_double_click_distance * 2, max_double_click_distance * 2);
1073 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1079 m_lastTapPos =
event.GetPosition();
1080 m_tap_timer.StartOnce(
1084 if (m_tap_count == 2) {
1088 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1101void ChartCanvas::OnMotion(wxMouseEvent &event) {
1106 event.m_leftDown = m_leftdown;
1110void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1112 if (event.IsGestureEnd())
return;
1114 double factor =
event.GetZoomFactor();
1116 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1121 double wanted_factor = m_oldVPSScale / current_vps * factor;
1126 if (event.IsGestureStart()) {
1127 m_zoomStartPoint =
event.GetPosition();
1129 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1131 m_zoomStartPoint =
event.GetPosition();
1135void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1137void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1138 DoRotateCanvas(0.0);
1142void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1147void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1148 m_FinishRouteOnKillFocus =
false;
1149 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1150 m_FinishRouteOnKillFocus =
true;
1153void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1158 m_restore_dbindex = pcc->DBindex;
1160 if (pcc->GroupID < 0) pcc->GroupID = 0;
1165 m_groupIndex = pcc->GroupID;
1167 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1181 m_encDisplayCategory = pcc->nENCDisplayCategory;
1182 m_encShowDepth = pcc->bShowENCDepths;
1183 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1184 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1185 m_encShowLights = pcc->bShowENCLights;
1186 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1187 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1188 m_encShowDataQual = pcc->bShowENCDataQuality;
1192 m_upMode = NORTH_UP_MODE;
1194 m_upMode = COURSE_UP_MODE;
1196 m_upMode = HEAD_UP_MODE;
1200 m_singleChart = NULL;
1203void ChartCanvas::ApplyGlobalSettings() {
1206 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1207 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1209 if (m_notification_button) m_notification_button->UpdateStatus();
1212void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1213 bool groupOK = CheckGroup(m_groupIndex);
1216 SetGroupIndex(m_groupIndex,
true);
1220void ChartCanvas::SetShowGPS(
bool bshow) {
1221 if (m_bShowGPS != bshow) {
1224 m_Compass->SetScaleFactor(g_compass_scalefactor);
1225 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1230void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1231 m_bShowCompassWin = bshow;
1233 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1234 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1238int ChartCanvas::GetPianoHeight() {
1240 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1245void ChartCanvas::ConfigureChartBar() {
1248 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1249 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1251 if (GetQuiltMode()) {
1252 m_Piano->SetRoundedRectangles(
true);
1254 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1255 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1256 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1259void ChartCanvas::ShowTides(
bool bShow) {
1260 gFrame->LoadHarmonics();
1263 SetbShowTide(bShow);
1265 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1267 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1268 SetbShowTide(
false);
1269 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1272 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1273 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1284void ChartCanvas::ShowCurrents(
bool bShow) {
1285 gFrame->LoadHarmonics();
1288 SetbShowCurrent(bShow);
1289 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1291 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1292 SetbShowCurrent(
false);
1293 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1296 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1297 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1314void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1316void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1319 int new_index = index;
1322 bool bgroup_override =
false;
1323 int old_group_index = new_index;
1325 if (!CheckGroup(new_index)) {
1327 bgroup_override =
true;
1330 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1334 int current_chart_native_scale = GetCanvasChartNativeScale();
1337 m_groupIndex = new_index;
1343 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1347 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1351 g_sticky_chart = -1;
1355 UpdateCanvasOnGroupChange();
1358 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1360 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1363 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1364 double best_scale = GetBestStartScale(dbi_hint, vp);
1368 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1372 canvasChartsRefresh(dbi_hint);
1374 UpdateCanvasControlBar();
1376 if (!autoSwitch && bgroup_override) {
1378 wxString msg(_(
"Group \""));
1381 msg += pGroup->m_group_name;
1383 msg += _(
"\" is empty.");
1385 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1392 if (bgroup_override) {
1393 wxString msg(_(
"Group \""));
1396 msg += pGroup->m_group_name;
1398 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1400 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1404bool ChartCanvas::CheckGroup(
int igroup) {
1407 if (igroup == 0)
return true;
1414 if (pGroup->m_element_array.empty())
1418 for (
const auto &elem : pGroup->m_element_array) {
1419 for (
unsigned int ic = 0;
1420 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1422 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1424 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1429 for (
const auto &elem : pGroup->m_element_array) {
1430 const wxString &element_root = elem.m_element_name;
1431 wxString test_string =
"GSHH";
1432 if (element_root.Upper().Contains(test_string))
return true;
1438void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1441 AbstractPlatform::ShowBusySpinner();
1445 SetQuiltRefChart(-1);
1447 m_singleChart = NULL;
1453 if (!m_pCurrentStack) {
1455 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1458 if (-1 != dbi_hint) {
1459 if (GetQuiltMode()) {
1460 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1461 SetQuiltRefChart(dbi_hint);
1465 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1467 if (pTentative_Chart) {
1470 if (m_singleChart) m_singleChart->Deactivate();
1472 m_singleChart = pTentative_Chart;
1473 m_singleChart->Activate();
1475 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1476 GetpCurrentStack(), m_singleChart->GetFullPath());
1484 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1485 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1486 SetQuiltRefChart(selected_index);
1490 SetupCanvasQuiltMode();
1491 if (!GetQuiltMode() && m_singleChart == 0) {
1493 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1494 m_singleChart = pDummyChart;
1500 UpdateCanvasControlBar();
1501 UpdateGPSCompassStatusBox(
true);
1503 SetCursor(wxCURSOR_ARROW);
1505 AbstractPlatform::HideBusySpinner();
1508bool ChartCanvas::DoCanvasUpdate() {
1510 double vpLat, vpLon;
1511 bool blong_jump =
false;
1512 meters_to_shift = 0;
1515 bool bNewChart =
false;
1516 bool bNewView =
false;
1517 bool bCanvasChartAutoOpen =
true;
1519 bool bNewPiano =
false;
1520 bool bOpenSpecified;
1526 if (bDBUpdateInProgress)
return false;
1530 if (m_chart_drag_inertia_active)
return false;
1556 double dx = m_OSoffsetx;
1557 double dy = m_OSoffsety;
1561 if (GetUpMode() == NORTH_UP_MODE) {
1562 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1564 double offset_angle = atan2(d_north, d_east);
1565 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1566 double chart_angle = GetVPRotation();
1567 double target_angle = chart_angle + offset_angle;
1568 double d_east_mod = offset_distance * cos(target_angle);
1569 double d_north_mod = offset_distance * sin(target_angle);
1570 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1574 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1575 double cog_to_use =
gCog;
1577 (fabs(
gCog - gCog_gt) > 20)) {
1578 cog_to_use = gCog_gt;
1581 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1583 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1585 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1586 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1588 double pixel_delta_tent =
1589 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1591 double pixel_delta = 0;
1596 if (!std::isnan(
gSog)) {
1600 pixel_delta = pixel_delta_tent;
1603 meters_to_shift = 0;
1605 if (!std::isnan(
gCog)) {
1606 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1607 dir_to_shift = cog_to_use;
1608 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1614 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1628 if (GetQuiltMode()) {
1629 int current_db_index = -1;
1630 if (m_pCurrentStack)
1633 ->GetCurrentEntrydbIndex();
1641 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1643 if (m_pCurrentStack->nEntry) {
1644 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1646 SelectQuiltRefdbChart(new_dbIndex,
true);
1647 m_bautofind =
false;
1651 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1652 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1657 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1663 double proposed_scale_onscreen =
1666 int initial_db_index = m_restore_dbindex;
1667 if (initial_db_index < 0) {
1668 if (m_pCurrentStack->nEntry) {
1670 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1675 if (m_pCurrentStack->nEntry) {
1676 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1681 if (!IsChartQuiltableRef(initial_db_index)) {
1685 int stack_index = 0;
1687 if (stack_index >= 0) {
1688 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1689 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1690 if (IsChartQuiltableRef(test_db_index) &&
1692 ChartData->GetDBChartType(initial_db_index))) {
1693 initial_db_index = test_db_index;
1703 SetQuiltRefChart(initial_db_index);
1704 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1712 0, GetVPRotation());
1717 bool super_jump =
false;
1719 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1720 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1721 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1724 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1726 if (blong_jump) nstep = 20;
1727 StartTimedMovementVP(vpLat, vpLon, nstep);
1738 pLast_Ch = m_singleChart;
1739 ChartTypeEnum new_open_type;
1740 ChartFamilyEnum new_open_family;
1742 new_open_type = pLast_Ch->GetChartType();
1743 new_open_family = pLast_Ch->GetChartFamily();
1745 new_open_type = CHART_TYPE_KAP;
1746 new_open_family = CHART_FAMILY_RASTER;
1749 bOpenSpecified = m_bFirstAuto;
1752 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1755 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1757 if (NULL == pDummyChart) {
1763 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1765 m_singleChart = pDummyChart;
1770 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1772 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1775 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1776 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1783 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1789 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1794 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1797 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1802 if (NULL != m_singleChart)
1803 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1804 m_singleChart->GetFullPath());
1807 m_pCurrentStack->CurrentStackEntry = tEntry;
1817 if (bCanvasChartAutoOpen) {
1818 bool search_direction =
1820 int start_index = 0;
1824 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1825 (LastStack.nEntry == 0)) {
1826 search_direction =
true;
1827 start_index = m_pCurrentStack->nEntry - 1;
1831 if (bOpenSpecified) {
1832 search_direction =
false;
1834 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1837 new_open_type = CHART_TYPE_DONTCARE;
1840 pProposed =
ChartData->OpenStackChartConditional(
1841 m_pCurrentStack, start_index, search_direction, new_open_type,
1845 if (NULL == pProposed)
1846 pProposed =
ChartData->OpenStackChartConditional(
1847 m_pCurrentStack, start_index, search_direction,
1848 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1850 if (NULL == pProposed)
1851 pProposed =
ChartData->OpenStackChartConditional(
1852 m_pCurrentStack, start_index, search_direction,
1853 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1864 if (NULL == pProposed) {
1865 if (NULL == pDummyChart) {
1871 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1873 pProposed = pDummyChart;
1877 if (m_singleChart) m_singleChart->Deactivate();
1878 m_singleChart = pProposed;
1880 if (m_singleChart) {
1881 m_singleChart->Activate();
1882 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1883 m_pCurrentStack, m_singleChart->GetFullPath());
1888 if (NULL != m_singleChart) {
1894 if (!GetVP().IsValid())
1895 set_scale = 1. / 20000.;
1897 double proposed_scale_onscreen;
1900 double new_scale_ppm =
1901 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1909 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1910 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1911 double equivalent_vp_scale =
1913 double new_scale_ppm =
1914 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1919 proposed_scale_onscreen =
1920 wxMin(proposed_scale_onscreen,
1923 proposed_scale_onscreen =
1924 wxMax(proposed_scale_onscreen,
1933 m_singleChart->GetChartSkew() * PI / 180.,
1940 if ((m_bFollow) && m_singleChart)
1942 m_singleChart->GetChartSkew() * PI / 180.,
1951 m_bFirstAuto =
false;
1955 if (bNewChart && !bNewView) Refresh(
false);
1960 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1963 return bNewChart | bNewView;
1966void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1967 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1969 SetQuiltRefChart(db_index);
1974 double best_scale_ppm = GetBestVPScale(pc);
1978 SetQuiltRefChart(-1);
1980 SetQuiltRefChart(-1);
1983void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1984 std::vector<int> piano_chart_index_array =
1985 GetQuiltExtendedStackdbIndexArray();
1986 int current_db_index = piano_chart_index_array[selected_index];
1988 SelectQuiltRefdbChart(current_db_index);
1991double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1995 if ((g_bPreserveScaleOnX) ||
1996 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2002 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2003 double equivalent_vp_scale =
2005 double new_scale_ppm =
2006 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2013 double max_underzoom_multiplier = 2.0;
2014 if (GetVP().b_quilt) {
2015 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2016 pchart->GetChartType(),
2017 pchart->GetChartFamily());
2018 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2021 proposed_scale_onscreen = wxMin(
2022 proposed_scale_onscreen,
2024 max_underzoom_multiplier);
2027 proposed_scale_onscreen =
2028 wxMax(proposed_scale_onscreen,
2036void ChartCanvas::SetupCanvasQuiltMode() {
2041 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2045 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2046 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2047 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2048 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2050 m_Piano->SetRoundedRectangles(
true);
2053 int target_new_dbindex = -1;
2054 if (m_pCurrentStack) {
2055 target_new_dbindex =
2056 GetQuiltReferenceChartIndex();
2058 if (-1 != target_new_dbindex) {
2059 if (!IsChartQuiltableRef(target_new_dbindex)) {
2060 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2061 int type =
ChartData->GetDBChartType(target_new_dbindex);
2064 int stack_index = m_pCurrentStack->CurrentStackEntry;
2066 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2067 (stack_index >= 0)) {
2068 int proj_tent =
ChartData->GetDBChartProj(
2069 m_pCurrentStack->GetDBIndex(stack_index));
2070 int type_tent =
ChartData->GetDBChartType(
2071 m_pCurrentStack->GetDBIndex(stack_index));
2073 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2074 if ((proj == proj_tent) && (type_tent == type)) {
2075 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2085 if (IsChartQuiltableRef(target_new_dbindex))
2086 SelectQuiltRefdbChart(target_new_dbindex,
2089 SelectQuiltRefdbChart(-1,
false);
2091 m_singleChart = NULL;
2094 AdjustQuiltRefChart();
2102 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2106 std::vector<int> empty_array;
2107 m_Piano->SetActiveKeyArray(empty_array);
2108 m_Piano->SetNoshowIndexArray(empty_array);
2109 m_Piano->SetEclipsedIndexArray(empty_array);
2112 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2113 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2114 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2115 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2117 m_Piano->SetRoundedRectangles(
false);
2123 if (!GetQuiltMode()) {
2128 if (m_bFollow ==
true) {
2136 if (!m_singleChart) {
2139 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2147 int cur_max_scale = (int)1e8;
2149 ChartBase *pChart = GetFirstQuiltChart();
2153 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2155 if (pChart->GetNativeScale() < cur_max_scale) {
2156 Candidate_Chart = pChart;
2157 cur_max_scale = pChart->GetNativeScale();
2160 pChart = GetNextQuiltChart();
2163 m_singleChart = Candidate_Chart;
2167 if (NULL == m_singleChart) {
2168 m_singleChart =
ChartData->OpenStackChartConditional(
2169 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2170 CHART_FAMILY_DONTCARE);
2176 InvalidateAllQuiltPatchs();
2178 if (m_singleChart) {
2179 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2180 std::vector<int> one_array;
2181 one_array.push_back(dbi);
2182 m_Piano->SetActiveKeyArray(one_array);
2185 if (m_singleChart) {
2186 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2190 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2194bool ChartCanvas::IsTempMenuBarEnabled() {
2197 wxGetOsVersion(&major);
2205double ChartCanvas::GetCanvasRangeMeters() {
2207 GetSize(&width, &height);
2208 int minDimension = wxMin(width, height);
2211 range *= cos(GetVP().clat * PI / 180.);
2215void ChartCanvas::SetCanvasRangeMeters(
double range) {
2217 GetSize(&width, &height);
2218 int minDimension = wxMin(width, height);
2220 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2224bool ChartCanvas::SetUserOwnship() {
2228 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2229 double factor_dusk = 0.5;
2230 double factor_night = 0.25;
2232 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2233 m_pos_image_user_day =
new wxImage;
2234 *m_pos_image_user_day = pbmp->ConvertToImage();
2235 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2237 int gimg_width = m_pos_image_user_day->GetWidth();
2238 int gimg_height = m_pos_image_user_day->GetHeight();
2241 m_pos_image_user_dusk =
new wxImage;
2242 m_pos_image_user_night =
new wxImage;
2244 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2245 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2247 for (
int iy = 0; iy < gimg_height; iy++) {
2248 for (
int ix = 0; ix < gimg_width; ix++) {
2249 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2250 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2251 m_pos_image_user_day->GetGreen(ix, iy),
2252 m_pos_image_user_day->GetBlue(ix, iy));
2253 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2254 hsv.value = hsv.value * factor_dusk;
2255 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2256 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2259 hsv = wxImage::RGBtoHSV(rgb);
2260 hsv.value = hsv.value * factor_night;
2261 nrgb = wxImage::HSVtoRGB(hsv);
2262 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2269 m_pos_image_user_grey_day =
new wxImage;
2270 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2272 m_pos_image_user_grey_dusk =
new wxImage;
2273 m_pos_image_user_grey_night =
new wxImage;
2275 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2276 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2278 for (
int iy = 0; iy < gimg_height; iy++) {
2279 for (
int ix = 0; ix < gimg_width; ix++) {
2280 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2281 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2282 m_pos_image_user_grey_day->GetGreen(ix, iy),
2283 m_pos_image_user_grey_day->GetBlue(ix, iy));
2284 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2285 hsv.value = hsv.value * factor_dusk;
2286 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2287 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2290 hsv = wxImage::RGBtoHSV(rgb);
2291 hsv.value = hsv.value * factor_night;
2292 nrgb = wxImage::HSVtoRGB(hsv);
2293 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2300 m_pos_image_user_yellow_day =
new wxImage;
2301 m_pos_image_user_yellow_dusk =
new wxImage;
2302 m_pos_image_user_yellow_night =
new wxImage;
2304 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2305 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2306 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2308 for (
int iy = 0; iy < gimg_height; iy++) {
2309 for (
int ix = 0; ix < gimg_width; ix++) {
2310 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2311 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2312 m_pos_image_user_grey_day->GetGreen(ix, iy),
2313 m_pos_image_user_grey_day->GetBlue(ix, iy));
2317 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2318 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2319 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2321 hsv = wxImage::RGBtoHSV(rgb);
2322 hsv.value = hsv.value * factor_dusk;
2323 nrgb = wxImage::HSVtoRGB(hsv);
2324 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2326 hsv = wxImage::RGBtoHSV(rgb);
2327 hsv.value = hsv.value * factor_night;
2328 nrgb = wxImage::HSVtoRGB(hsv);
2329 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2341 m_display_size_mm = size;
2348 double horizontal = sd.x;
2352 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2353 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2357 ps52plib->SetPPMM(m_pix_per_mm);
2362 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2364 m_display_size_mm, sd.x, sd.y);
2370 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2373 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2376void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2378 wxString msg(event.m_string.c_str(), wxConvUTF8);
2380 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2381 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2384 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2386 compress_msg_array.RemoveAt(event.thread);
2387 compress_msg_array.Insert( msg, event.thread);
2390 compress_msg_array.Add(msg);
2393 wxString combined_msg;
2394 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2395 combined_msg += compress_msg_array[i];
2396 combined_msg +=
"\n";
2400 pprog->Update(pprog_count, combined_msg, &skip );
2401 pprog->SetSize(pprog_size);
2406void ChartCanvas::InvalidateGL() {
2407 if (!m_glcc)
return;
2409 if (g_bopengl) m_glcc->Invalidate();
2411 if (m_Compass) m_Compass->UpdateStatus(
true);
2414int ChartCanvas::GetCanvasChartNativeScale() {
2416 if (!VPoint.b_quilt) {
2417 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2419 ret = (int)m_pQuilt->GetRefNativeScale();
2424ChartBase *ChartCanvas::GetChartAtCursor() {
2426 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2427 target_chart = m_singleChart;
2428 else if (VPoint.b_quilt)
2429 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2431 target_chart = NULL;
2432 return target_chart;
2435ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2439 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2441 target_chart = NULL;
2442 return target_chart;
2445int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2446 int new_dbIndex = -1;
2447 if (!VPoint.b_quilt) {
2448 if (m_pCurrentStack) {
2449 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2450 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2452 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2462 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2464 for (
unsigned int is = 0; is < im; is++) {
2466 m_pQuilt->GetExtendedStackIndexArray()[is]);
2469 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2479void ChartCanvas::EnablePaint(
bool b_enable) {
2480 m_b_paint_enable = b_enable;
2482 if (m_glcc) m_glcc->EnablePaint(b_enable);
2486bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2488void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2490std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2491 return m_pQuilt->GetQuiltIndexArray();
2495void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2496 VPoint.b_quilt = b_quilt;
2497 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2500bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2502int ChartCanvas::GetQuiltReferenceChartIndex() {
2503 return m_pQuilt->GetRefChartdbIndex();
2506void ChartCanvas::InvalidateAllQuiltPatchs() {
2507 m_pQuilt->InvalidateAllQuiltPatchs();
2510ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2511 return m_pQuilt->GetLargestScaleChart();
2514ChartBase *ChartCanvas::GetFirstQuiltChart() {
2515 return m_pQuilt->GetFirstChart();
2518ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2520int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2522void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2523 m_pQuilt->SetHiliteIndex(dbIndex);
2526void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2527 m_pQuilt->SetHiliteIndexArray(hilite_array);
2530void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2531 m_pQuilt->ClearHiliteIndexArray();
2534std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2536 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2539int ChartCanvas::GetQuiltRefChartdbIndex() {
2540 return m_pQuilt->GetRefChartdbIndex();
2543std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2544 return m_pQuilt->GetExtendedStackIndexArray();
2547std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2548 return m_pQuilt->GetFullscreenIndexArray();
2551std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2552 return m_pQuilt->GetEclipsedStackIndexArray();
2555void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2557double ChartCanvas::GetQuiltMaxErrorFactor() {
2558 return m_pQuilt->GetMaxErrorFactor();
2561bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2562 return m_pQuilt->IsChartQuiltableRef(db_index);
2566 double chartMaxScale =
2568 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2571void ChartCanvas::StartMeasureRoute() {
2572 if (!m_routeState) {
2573 if (m_bMeasure_Active) {
2575 m_pMeasureRoute = NULL;
2578 m_bMeasure_Active =
true;
2579 m_nMeasureState = 1;
2580 m_bDrawingRoute =
false;
2582 SetCursor(*pCursorPencil);
2587void ChartCanvas::CancelMeasureRoute() {
2588 m_bMeasure_Active =
false;
2589 m_nMeasureState = 0;
2590 m_bDrawingRoute =
false;
2593 m_pMeasureRoute = NULL;
2595 SetCursor(*pCursorArrow);
2598ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2600void ChartCanvas::SetVP(
ViewPort &vp) {
2611void ChartCanvas::TriggerDeferredFocus() {
2614 m_deferredFocusTimer.Start(20,
true);
2616#if defined(__WXGTK__) || defined(__WXOSX__)
2627void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2632void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2633 if (SendKeyEventToPlugins(event))
2637 int key_char =
event.GetKeyCode();
2640 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2646 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2651 if (g_benable_rotate) {
2672void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2673 if (SendKeyEventToPlugins(event))
2677 bool b_handled =
false;
2679 m_modkeys =
event.GetModifiers();
2681 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2683#ifdef OCPN_ALT_MENUBAR
2689 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2691 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2692 if (!g_bTempShowMenuBar) {
2693 g_bTempShowMenuBar =
true;
2694 parent_frame->ApplyGlobalSettings(
false);
2696 m_bMayToggleMenuBar =
false;
2702 if (event.GetKeyCode() != WXK_ALT) {
2703 m_bMayToggleMenuBar =
false;
2710 switch (event.GetKeyCode()) {
2717 event.GetPosition(&x, &y);
2718 m_FinishRouteOnKillFocus =
false;
2719 CallPopupMenu(x, y);
2720 m_FinishRouteOnKillFocus =
true;
2724 m_modkeys |= wxMOD_ALT;
2728 m_modkeys |= wxMOD_CONTROL;
2733 case WXK_RAW_CONTROL:
2734 m_modkeys |= wxMOD_RAW_CONTROL;
2739 if (m_modkeys == wxMOD_CONTROL)
2740 parent_frame->DoStackDown(
this);
2742 StartTimedMovement();
2752 StartTimedMovement();
2760 if (m_modkeys == wxMOD_CONTROL)
2761 parent_frame->DoStackUp(
this);
2763 StartTimedMovement();
2773 StartTimedMovement();
2782 if (event.ShiftDown()) {
2784 auto current_family = m_pQuilt->GetRefFamily();
2785 auto target_family = CHART_FAMILY_UNKNOWN;
2786 if (current_family == CHART_FAMILY_RASTER)
2787 target_family = CHART_FAMILY_VECTOR;
2789 target_family = CHART_FAMILY_RASTER;
2791 std::shared_ptr<HostApi> host_api;
2793 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2796 api_121->SelectChartFamily(m_canvasIndex,
2804 SetShowENCText(!GetShowENCText());
2810 if (!m_bMeasure_Active) {
2811 if (event.ShiftDown())
2812 m_bMeasure_DistCircle =
true;
2814 m_bMeasure_DistCircle =
false;
2816 StartMeasureRoute();
2818 CancelMeasureRoute();
2820 SetCursor(*pCursorArrow);
2830 parent_frame->ToggleColorScheme();
2832 TriggerDeferredFocus();
2836 int mod = m_modkeys & wxMOD_SHIFT;
2837 if (mod != m_brightmod) {
2839 m_bbrightdir = !m_bbrightdir;
2842 if (!m_bbrightdir) {
2843 g_nbrightness -= 10;
2844 if (g_nbrightness <= MIN_BRIGHT) {
2845 g_nbrightness = MIN_BRIGHT;
2846 m_bbrightdir =
true;
2849 g_nbrightness += 10;
2850 if (g_nbrightness >= MAX_BRIGHT) {
2851 g_nbrightness = MAX_BRIGHT;
2852 m_bbrightdir =
false;
2856 SetScreenBrightness(g_nbrightness);
2857 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2866 parent_frame->DoStackDown(
this);
2870 parent_frame->DoStackUp(
this);
2875 ToggleCanvasQuiltMode();
2881 parent_frame->ToggleFullScreen();
2886 if (m_modkeys == wxMOD_ALT) {
2889 ToggleChartOutlines();
2895 parent_frame->ActivateMOB();
2899 case WXK_NUMPAD_ADD:
2904 case WXK_NUMPAD_SUBTRACT:
2905 case WXK_PAGEDOWN: {
2906 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2911 if (m_bMeasure_Active) {
2912 if (m_nMeasureState > 2) {
2913 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2915 m_pMeasureRoute->GetnPoints();
2917 gFrame->RefreshAllCanvas();
2919 CancelMeasureRoute();
2920 StartMeasureRoute();
2928 if (event.GetKeyCode() < 128)
2930 int key_char =
event.GetKeyCode();
2934 if (!g_b_assume_azerty) {
2936 if (g_benable_rotate) {
2968 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2975 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2976 m_modkeys & wxMOD_RAW_CONTROL) {
2977 parent_frame->ToggleFullScreen();
2982 if (event.ControlDown()) key_char -= 64;
2984 if (key_char >=
'0' && key_char <=
'9')
2985 SetGroupIndex(key_char -
'0');
2990 SetShowENCAnchor(!GetShowENCAnchor());
2996 parent_frame->ToggleColorScheme();
3001 event.GetPosition(&x, &y);
3002 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3003 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3006 if (VPoint.b_quilt) {
3008 if (m_pQuilt->GetChartAtPix(
3013 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3015 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3020 if (m_singleChart) {
3021 ChartType = m_singleChart->GetChartType();
3022 ChartFam = m_singleChart->GetChartFamily();
3026 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3027 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3029 this, -1, ChartType, ChartFam,
3030 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3031 wxDefaultSize, wxSIMPLE_BORDER,
"");
3044 m_nmea_log->Raise();
3048 SetShowENCLights(!GetShowENCLights());
3054 if (event.ShiftDown())
3055 m_bMeasure_DistCircle =
true;
3057 m_bMeasure_DistCircle =
false;
3059 StartMeasureRoute();
3063 if (g_bInlandEcdis && ps52plib) {
3064 SetENCDisplayCategory((_DisCat)STANDARD);
3069 ToggleChartOutlines();
3073 ToggleCanvasQuiltMode();
3077 parent_frame->ToggleTestPause();
3080 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3081 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3082 g_iNavAidRadarRingsNumberVisible = 1;
3083 else if (!g_bNavAidRadarRingsShown &&
3084 g_iNavAidRadarRingsNumberVisible == 1)
3085 g_iNavAidRadarRingsNumberVisible = 0;
3088 SetShowENCDepth(!m_encShowDepth);
3093 SetShowENCText(!GetShowENCText());
3098 SetShowENCDataQual(!GetShowENCDataQual());
3103 m_bShowNavobjects = !m_bShowNavobjects;
3118 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3123 if (event.ControlDown()) gFrame->DropMarker(
false);
3130 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3131 if ((indexActive + 1) <= r->GetnPoints()) {
3142 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3148 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3154 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3161 parent_frame->DoSettings();
3165 parent_frame->Close();
3181 if (undo->AnythingToRedo()) {
3182 undo->RedoNextAction();
3189 if (event.ShiftDown()) {
3190 if (undo->AnythingToRedo()) {
3191 undo->RedoNextAction();
3196 if (undo->AnythingToUndo()) {
3197 undo->UndoLastAction();
3206 if (m_bMeasure_Active) {
3207 CancelMeasureRoute();
3209 SetCursor(*pCursorArrow);
3212 gFrame->RefreshAllCanvas();
3226 switch (gamma_state) {
3246 SetScreenBrightness(g_nbrightness);
3251 if (event.ControlDown()) {
3252 m_bShowCompassWin = !m_bShowCompassWin;
3253 SetShowGPSCompassWindow(m_bShowCompassWin);
3270void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3271 if (SendKeyEventToPlugins(event))
3275 switch (event.GetKeyCode()) {
3277 parent_frame->SwitchKBFocus(
this);
3283 if (!m_pany) m_panspeed = 0;
3289 if (!m_panx) m_panspeed = 0;
3292 case WXK_NUMPAD_ADD:
3293 case WXK_NUMPAD_SUBTRACT:
3302 m_modkeys &= ~wxMOD_ALT;
3303#ifdef OCPN_ALT_MENUBAR
3308 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3309 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3310 parent_frame->ApplyGlobalSettings(
false);
3312 m_bMayToggleMenuBar =
true;
3318 m_modkeys &= ~wxMOD_CONTROL;
3322 if (event.GetKeyCode() < 128)
3324 int key_char =
event.GetKeyCode();
3328 if (!g_b_assume_azerty) {
3343 m_rotation_speed = 0;
3361void ChartCanvas::ToggleChartOutlines() {
3362 m_bShowOutlines = !m_bShowOutlines;
3368 if (g_bopengl) InvalidateGL();
3372void ChartCanvas::ToggleLookahead() {
3373 m_bLookAhead = !m_bLookAhead;
3378void ChartCanvas::SetUpMode(
int mode) {
3381 if (mode != NORTH_UP_MODE) {
3384 if (!std::isnan(
gCog)) stuff =
gCog;
3387 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3390 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3392 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3393 SetVPRotation(GetVPSkew());
3398 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3399 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3401 UpdateGPSCompassStatusBox(
true);
3402 gFrame->DoChartUpdate();
3405bool ChartCanvas::DoCanvasCOGSet() {
3406 if (GetUpMode() == NORTH_UP_MODE)
return false;
3408 if (g_btenhertz) cog_use =
gCog;
3410 double rotation = 0;
3411 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3412 rotation = -
gHdt * PI / 180.;
3413 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3414 rotation = -cog_use * PI / 180.;
3416 SetVPRotation(rotation);
3420double easeOutCubic(
double t) {
3422 return 1.0 - pow(1.0 - t, 3.0);
3425void ChartCanvas::StartChartDragInertia() {
3426 m_bChartDragging =
false;
3429 m_chart_drag_inertia_time = 750;
3430 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3435 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3439 size_t length = m_drag_vec_t.size();
3440 for (
size_t i = 0; i < n_vel; i++) {
3441 xacc += m_drag_vec_x.at(length - 1 - i);
3442 yacc += m_drag_vec_y.at(length - 1 - i);
3443 tacc += m_drag_vec_t.at(length - 1 - i);
3446 if (tacc == 0)
return;
3448 double drag_velocity_x = xacc / tacc;
3449 double drag_velocity_y = yacc / tacc;
3455 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3457 m_chart_drag_velocity_x = drag_velocity_x;
3458 m_chart_drag_velocity_y = drag_velocity_y;
3460 m_chart_drag_inertia_active =
true;
3462 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3465void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3466 if (!m_chart_drag_inertia_active)
return;
3468 wxLongLong now = wxGetLocalTimeMillis();
3469 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3470 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3471 if (t > 1.0) t = 1.0;
3472 double e = 1.0 - easeOutCubic(t);
3475 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3477 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3479 m_last_elapsed = elapsed;
3483 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3484 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3485 double inertia_lat, inertia_lon;
3489 if (!IsOwnshipOnScreen()) {
3491 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3492 UpdateFollowButtonState();
3503 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3504 m_chart_drag_inertia_timer.Stop();
3507 m_target_lat = GetVP().
clat;
3508 m_target_lon = GetVP().
clon;
3509 m_pan_drag.x = m_pan_drag.y = 0;
3510 m_panx = m_pany = 0;
3511 m_chart_drag_inertia_active =
false;
3515 int target_redraw_interval = 40;
3516 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3520void ChartCanvas::StopMovement() {
3521 m_panx = m_pany = 0;
3524 m_rotation_speed = 0;
3527#if !defined(__WXGTK__) && !defined(__WXQT__)
3538bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3540 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3542 if (!pMovementTimer->IsRunning()) {
3543 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3546 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3551 m_last_movement_time = wxDateTime::UNow();
3555void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3558 m_target_lat = target_lat;
3559 m_target_lon = target_lon;
3562 m_start_lat = GetVP().
clat;
3563 m_start_lon = GetVP().
clon;
3565 m_VPMovementTimer.Start(1,
true);
3566 m_timed_move_vp_active =
true;
3568 m_timedVP_step = nstep;
3571void ChartCanvas::DoTimedMovementVP() {
3572 if (!m_timed_move_vp_active)
return;
3573 if (m_stvpc++ > m_timedVP_step * 2) {
3580 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3595 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3596 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3598 m_run_lat = new_lat;
3599 m_run_lon = new_lon;
3604void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3606void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3608void ChartCanvas::StartTimedMovementTarget() {}
3610void ChartCanvas::DoTimedMovementTarget() {}
3612void ChartCanvas::StopMovementTarget() {}
3615void ChartCanvas::DoTimedMovement() {
3616 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3620 wxDateTime now = wxDateTime::UNow();
3622 if (m_last_movement_time.IsValid())
3623 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3625 m_last_movement_time = now;
3635 if (dt == 0) dt = 1;
3638 if (m_mustmove < 0) m_mustmove = 0;
3641 if (m_pan_drag.x || m_pan_drag.y) {
3643 m_pan_drag.x = m_pan_drag.y = 0;
3646 if (m_panx || m_pany) {
3647 const double slowpan = .1, maxpan = 2;
3648 if (m_modkeys == wxMOD_ALT)
3649 m_panspeed = slowpan;
3651 m_panspeed += (double)dt / 500;
3652 m_panspeed = wxMin(maxpan, m_panspeed);
3654 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3657 if (m_zoom_factor != 1) {
3658 double alpha = 400, beta = 1.5;
3659 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3661 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3663 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3668 if (zoom_factor > 1) {
3669 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3673 else if (zoom_factor < 1) {
3674 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3679 if (fabs(zoom_factor - 1) > 1e-4) {
3680 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3685 if (m_wheelzoom_stop_oneshot > 0) {
3686 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3687 m_wheelzoom_stop_oneshot = 0;
3692 if (zoom_factor > 1) {
3694 m_wheelzoom_stop_oneshot = 0;
3697 }
else if (zoom_factor < 1) {
3699 m_wheelzoom_stop_oneshot = 0;
3706 if (m_rotation_speed) {
3707 double speed = m_rotation_speed;
3708 if (m_modkeys == wxMOD_ALT) speed /= 10;
3709 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3713void ChartCanvas::SetColorScheme(ColorScheme cs) {
3718 case GLOBAL_COLOR_SCHEME_DAY:
3719 m_pos_image_red = &m_os_image_red_day;
3720 m_pos_image_grey = &m_os_image_grey_day;
3721 m_pos_image_yellow = &m_os_image_yellow_day;
3722 m_pos_image_user = m_pos_image_user_day;
3723 m_pos_image_user_grey = m_pos_image_user_grey_day;
3724 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3725 m_cTideBitmap = m_bmTideDay;
3726 m_cCurrentBitmap = m_bmCurrentDay;
3729 case GLOBAL_COLOR_SCHEME_DUSK:
3730 m_pos_image_red = &m_os_image_red_dusk;
3731 m_pos_image_grey = &m_os_image_grey_dusk;
3732 m_pos_image_yellow = &m_os_image_yellow_dusk;
3733 m_pos_image_user = m_pos_image_user_dusk;
3734 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3735 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3736 m_cTideBitmap = m_bmTideDusk;
3737 m_cCurrentBitmap = m_bmCurrentDusk;
3739 case GLOBAL_COLOR_SCHEME_NIGHT:
3740 m_pos_image_red = &m_os_image_red_night;
3741 m_pos_image_grey = &m_os_image_grey_night;
3742 m_pos_image_yellow = &m_os_image_yellow_night;
3743 m_pos_image_user = m_pos_image_user_night;
3744 m_pos_image_user_grey = m_pos_image_user_grey_night;
3745 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3746 m_cTideBitmap = m_bmTideNight;
3747 m_cCurrentBitmap = m_bmCurrentNight;
3750 m_pos_image_red = &m_os_image_red_day;
3751 m_pos_image_grey = &m_os_image_grey_day;
3752 m_pos_image_yellow = &m_os_image_yellow_day;
3753 m_pos_image_user = m_pos_image_user_day;
3754 m_pos_image_user_grey = m_pos_image_user_grey_day;
3755 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3756 m_cTideBitmap = m_bmTideDay;
3757 m_cCurrentBitmap = m_bmCurrentDay;
3761 CreateDepthUnitEmbossMaps(cs);
3762 CreateOZEmbossMapData(cs);
3765 m_fog_color = wxColor(
3769 case GLOBAL_COLOR_SCHEME_DUSK:
3772 case GLOBAL_COLOR_SCHEME_NIGHT:
3778 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3779 m_fog_color.Blue() * dim);
3783 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3784 SetBackgroundColour( wxColour(0,0,0) );
3786 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3789 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3791 SetBackgroundColour( wxNullColour );
3798 m_Piano->SetColorScheme(cs);
3800 m_Compass->SetColorScheme(cs);
3802 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3804 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3806 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3807 if (m_notification_button) {
3808 m_notification_button->SetColorScheme(cs);
3812 if (g_bopengl && m_glcc) {
3813 m_glcc->SetColorScheme(cs);
3819 m_brepaint_piano =
true;
3826wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3827 wxImage img = Bitmap.ConvertToImage();
3828 int sx = img.GetWidth();
3829 int sy = img.GetHeight();
3831 wxImage new_img(img);
3833 for (
int i = 0; i < sx; i++) {
3834 for (
int j = 0; j < sy; j++) {
3835 if (!img.IsTransparent(i, j)) {
3836 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3837 (
unsigned char)(img.GetGreen(i, j) * factor),
3838 (
unsigned char)(img.GetBlue(i, j) * factor));
3843 wxBitmap ret = wxBitmap(new_img);
3848void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3851 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3853 if (!m_pBrightPopup) {
3856 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3860 m_pBrightPopup->SetSize(x, y);
3861 m_pBrightPopup->Move(120, 120);
3864 int bmpsx = m_pBrightPopup->GetSize().x;
3865 int bmpsy = m_pBrightPopup->GetSize().y;
3867 wxBitmap bmp(bmpsx, bmpsx);
3868 wxMemoryDC mdc(bmp);
3870 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3871 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3872 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3873 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3876 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3878 mdc.SetFont(*pfont);
3881 if (brightness == max)
3883 else if (brightness == min)
3886 val.Printf(
"%3d", brightness);
3888 mdc.DrawText(val, 0, 0);
3890 mdc.SelectObject(wxNullBitmap);
3892 m_pBrightPopup->SetBitmap(bmp);
3893 m_pBrightPopup->Show();
3894 m_pBrightPopup->Refresh();
3897void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3898 m_b_rot_hidef =
true;
3902void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3905 bool b_need_refresh =
false;
3907 wxSize win_size = GetSize() * m_displayScale;
3911 bool showAISRollover =
false;
3913 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3917 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3918 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3921 showAISRollover =
true;
3923 if (NULL == m_pAISRolloverWin) {
3925 m_pAISRolloverWin->IsActive(
false);
3926 b_need_refresh =
true;
3927 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3928 m_AISRollover_MMSI != FoundAIS_MMSI) {
3934 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3935 m_pAISRolloverWin->IsActive(
false);
3936 m_AISRollover_MMSI = 0;
3941 m_AISRollover_MMSI = FoundAIS_MMSI;
3943 if (!m_pAISRolloverWin->IsActive()) {
3944 wxString s = ptarget->GetRolloverString();
3945 m_pAISRolloverWin->SetString(s);
3947 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3948 AIS_ROLLOVER, win_size);
3949 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3950 m_pAISRolloverWin->IsActive(
true);
3951 b_need_refresh =
true;
3955 m_AISRollover_MMSI = 0;
3956 showAISRollover =
false;
3961 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3962 m_pAISRolloverWin->IsActive(
false);
3963 m_AISRollover_MMSI = 0;
3964 b_need_refresh =
true;
3969 bool showRouteRollover =
false;
3971 if (NULL == m_pRolloverRouteSeg) {
3975 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3976 SelectableItemList SelList =
pSelect->FindSelectionList(
3978 auto node = SelList.begin();
3979 while (node != SelList.end()) {
3984 if (pr && pr->IsVisible()) {
3985 m_pRolloverRouteSeg = pFindSel;
3986 showRouteRollover =
true;
3988 if (NULL == m_pRouteRolloverWin) {
3990 m_pRouteRolloverWin->IsActive(
false);
3993 if (!m_pRouteRolloverWin->IsActive()) {
4001 DistanceBearingMercator(
4002 segShow_point_b->m_lat, segShow_point_b->m_lon,
4003 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4005 if (!pr->m_bIsInLayer)
4006 s.Append(_(
"Route") +
": ");
4008 s.Append(_(
"Layer Route: "));
4010 if (pr->m_RouteNameString.IsEmpty())
4011 s.Append(_(
"(unnamed)"));
4013 s.Append(pr->m_RouteNameString);
4018 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4019 << segShow_point_b->GetName() <<
"\n";
4022 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4023 (
int)floor(brg + 0.5), 0x00B0);
4026 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4028 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4029 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4031 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4032 (
int)floor(varBrg + 0.5), 0x00B0);
4040 double shiptoEndLeg = 0.;
4041 bool validActive =
false;
4042 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4045 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4046 auto node = pr->pRoutePointList->begin();
4048 float dist_to_endleg = 0;
4051 for (++node; node != pr->pRoutePointList->end(); ++node) {
4058 if (prp->IsSame(segShow_point_a))
break;
4066 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4069 ->GetCurrentRngToActivePoint();
4078 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4083 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4084 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4086 << wxString(ttg_sec > SECONDS_PER_DAY
4087 ? ttg_span.Format(_(
"%Dd %H:%M"))
4088 : ttg_span.Format(_(
"%H:%M")));
4089 wxDateTime dtnow, eta;
4090 eta = dtnow.SetToCurrent().Add(ttg_span);
4091 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4092 << eta.Format(
" %d %H:%M");
4096 m_pRouteRolloverWin->SetString(s);
4098 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4099 LEG_ROLLOVER, win_size);
4100 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4101 m_pRouteRolloverWin->IsActive(
true);
4102 b_need_refresh =
true;
4103 showRouteRollover =
true;
4112 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4114 m_pRolloverRouteSeg))
4115 showRouteRollover =
false;
4116 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4117 showRouteRollover =
false;
4119 showRouteRollover =
true;
4123 if (m_routeState) showRouteRollover =
false;
4126 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4127 showRouteRollover =
false;
4129 if (m_pRouteRolloverWin &&
4130 !showRouteRollover) {
4131 m_pRouteRolloverWin->IsActive(
false);
4132 m_pRolloverRouteSeg = NULL;
4133 m_pRouteRolloverWin->Destroy();
4134 m_pRouteRolloverWin = NULL;
4135 b_need_refresh =
true;
4136 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4137 m_pRouteRolloverWin->IsActive(
true);
4138 b_need_refresh =
true;
4143 bool showTrackRollover =
false;
4145 if (NULL == m_pRolloverTrackSeg) {
4149 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4150 SelectableItemList SelList =
pSelect->FindSelectionList(
4153 auto node = SelList.begin();
4154 while (node != SelList.end()) {
4159 if (pt && pt->IsVisible()) {
4160 m_pRolloverTrackSeg = pFindSel;
4161 showTrackRollover =
true;
4163 if (NULL == m_pTrackRolloverWin) {
4165 m_pTrackRolloverWin->IsActive(
false);
4168 if (!m_pTrackRolloverWin->IsActive()) {
4176 DistanceBearingMercator(
4177 segShow_point_b->m_lat, segShow_point_b->m_lon,
4178 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4180 if (!pt->m_bIsInLayer)
4181 s.Append(_(
"Track") +
": ");
4183 s.Append(_(
"Layer Track: "));
4185 if (pt->GetName().IsEmpty())
4186 s.Append(_(
"(unnamed)"));
4188 s.Append(pt->GetName());
4189 double tlenght = pt->Length();
4191 if (pt->GetLastPoint()->GetTimeString() &&
4192 pt->GetPoint(0)->GetTimeString()) {
4193 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4194 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4195 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4196 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4197 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4198 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4199 << getUsrSpeedUnit();
4200 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4201 : ttime.Format(
" %H:%M"));
4205 if (g_bShowTrackPointTime &&
4206 strlen(segShow_point_b->GetTimeString())) {
4207 wxString stamp = segShow_point_b->GetTimeString();
4208 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4209 if (timestamp.IsValid()) {
4213 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4215 s <<
"\n" << _(
"Segment Created: ") << stamp;
4220 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4225 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4227 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4228 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4230 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4236 if (segShow_point_a->GetTimeString() &&
4237 segShow_point_b->GetTimeString()) {
4238 wxDateTime apoint = segShow_point_a->GetCreateTime();
4239 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4240 if (apoint.IsValid() && bpoint.IsValid()) {
4241 double segmentSpeed = toUsrSpeed(
4242 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4243 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4244 << getUsrSpeedUnit();
4248 m_pTrackRolloverWin->SetString(s);
4250 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4251 LEG_ROLLOVER, win_size);
4252 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4253 m_pTrackRolloverWin->IsActive(
true);
4254 b_need_refresh =
true;
4255 showTrackRollover =
true;
4264 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4266 m_pRolloverTrackSeg))
4267 showTrackRollover =
false;
4268 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4269 showTrackRollover =
false;
4271 showTrackRollover =
true;
4275 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4276 showTrackRollover =
false;
4279 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4280 showTrackRollover =
false;
4286 if (m_pTrackRolloverWin &&
4287 !showTrackRollover) {
4288 m_pTrackRolloverWin->IsActive(
false);
4289 m_pRolloverTrackSeg = NULL;
4290 m_pTrackRolloverWin->Destroy();
4291 m_pTrackRolloverWin = NULL;
4292 b_need_refresh =
true;
4293 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4294 m_pTrackRolloverWin->IsActive(
true);
4295 b_need_refresh =
true;
4298 if (b_need_refresh) Refresh();
4301void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4302 if ((GetShowENCLights() || m_bsectors_shown) &&
4303 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4304 extendedSectorLegs)) {
4305 if (!m_bsectors_shown) {
4307 m_bsectors_shown =
true;
4310 if (m_bsectors_shown) {
4312 m_bsectors_shown =
false;
4320#if defined(__WXGTK__) || defined(__WXQT__)
4325 double cursor_lat, cursor_lon;
4328 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4329 while (cursor_lon < -180.) cursor_lon += 360.;
4331 while (cursor_lon > 180.) cursor_lon -= 360.;
4333 SetCursorStatus(cursor_lat, cursor_lon);
4339void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4340 if (!parent_frame->m_pStatusBar)
return;
4344 s1 += toSDMM(1, cursor_lat);
4346 s1 += toSDMM(2, cursor_lon);
4348 if (STAT_FIELD_CURSOR_LL >= 0)
4349 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4351 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4356 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4357 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4358 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4360 wxString s = st + sm;
4373 if (g_bShowLiveETA) {
4376 float boatSpeedDefault = g_defaultBoatSpeed;
4381 if (!std::isnan(
gSog)) {
4383 if (boatSpeed < 0.5) {
4386 realTimeETA = dist / boatSpeed * 60;
4395 s << minutesToHoursDays(realTimeETA);
4400 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4401 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4403 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4408 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4416wxString minutesToHoursDays(
float timeInMinutes) {
4419 if (timeInMinutes == 0) {
4424 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4425 s << wxString::Format(
"%d", (
int)timeInMinutes);
4430 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4433 hours = (int)timeInMinutes / 60;
4434 min = (int)timeInMinutes % 60;
4437 s << wxString::Format(
"%d", hours);
4440 s << wxString::Format(
"%d", hours);
4442 s << wxString::Format(
"%d", min);
4449 else if (timeInMinutes > 24 * 60) {
4452 days = (int)(timeInMinutes / 60) / 24;
4453 hours = (int)(timeInMinutes / 60) % 24;
4456 s << wxString::Format(
"%d", days);
4459 s << wxString::Format(
"%d", days);
4461 s << wxString::Format(
"%d", hours);
4473void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4481 wxPoint2DDouble *r) {
4486 double rlon, wxPoint2DDouble *r) {
4497 if (!g_bopengl && m_singleChart &&
4498 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4499 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4500 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4501 (m_singleChart->GetChartProjectionType() !=
4502 PROJECTION_TRANSVERSE_MERCATOR) &&
4503 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4504 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4505 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4519 Cur_BSB_Ch->SetVPRasterParms(vp);
4520 double rpixxd, rpixyd;
4521 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4547 if (std::isnan(p.m_x)) {
4548 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4552 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4553 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4555 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4574 if (!g_bopengl && m_singleChart &&
4575 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4576 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4577 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4578 (m_singleChart->GetChartProjectionType() !=
4579 PROJECTION_TRANSVERSE_MERCATOR) &&
4580 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4581 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4582 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4593 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4596 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4601 else if (slon > 180.)
4612 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4618 DoZoomCanvas(factor,
false);
4619 extendedSectorLegs.clear();
4624 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4627 if (StartTimedMovement(stoptimer)) {
4629 m_zoom_factor = factor;
4634 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4636 DoZoomCanvas(factor, can_zoom_to_cursor);
4639 extendedSectorLegs.clear();
4642void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4645 if (!m_pCurrentStack)
return;
4651 if (m_bzooming)
return;
4660 double proposed_scale_onscreen =
4663 bool b_do_zoom =
false;
4672 if (!VPoint.b_quilt) {
4675 if (!m_disable_adjust_on_zoom) {
4676 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4677 if (new_db_index >= 0)
4678 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4682 int current_ref_stack_index = -1;
4683 if (m_pCurrentStack->nEntry) {
4685 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4686 m_pQuilt->SetReferenceChart(trial_index);
4687 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4688 if (new_db_index >= 0)
4689 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4693 if (m_pCurrentStack)
4694 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4705 double min_allowed_scale =
4708 if (proposed_scale_onscreen < min_allowed_scale) {
4713 proposed_scale_onscreen = min_allowed_scale;
4717 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4720 }
else if (factor < 1) {
4725 bool b_smallest =
false;
4727 if (!VPoint.b_quilt) {
4732 LLBBox viewbox = VPoint.GetBBox();
4734 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4735 double max_allowed_scale;
4749 if (proposed_scale_onscreen > max_allowed_scale) {
4751 proposed_scale_onscreen = max_allowed_scale;
4756 if (!m_disable_adjust_on_zoom) {
4758 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4759 if (new_db_index >= 0)
4760 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4762 if (m_pCurrentStack)
4763 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4766 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4768 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4769 proposed_scale_onscreen =
4770 wxMin(proposed_scale_onscreen,
4776 m_absolute_min_scale_ppm)
4777 proposed_scale_onscreen =
4786 bool b_allow_ztc =
true;
4787 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4788 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4790 double brg, distance;
4791 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4794 meters_to_shift = distance * 1852;
4802 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4805 if (m_bFollow) DoCanvasUpdate();
4812void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4814 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4818void ChartCanvas::RotateCanvas(
double dir) {
4822 if (StartTimedMovement()) {
4824 m_rotation_speed = dir * 60;
4827 double speed = dir * 10;
4828 if (m_modkeys == wxMOD_ALT) speed /= 20;
4829 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4833void ChartCanvas::DoRotateCanvas(
double rotation) {
4834 while (rotation < 0) rotation += 2 * PI;
4835 while (rotation > 2 * PI) rotation -= 2 * PI;
4837 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4839 SetVPRotation(rotation);
4840 parent_frame->UpdateRotationState(VPoint.
rotation);
4843void ChartCanvas::DoTiltCanvas(
double tilt) {
4844 while (tilt < 0) tilt = 0;
4845 while (tilt > .95) tilt = .95;
4847 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4853void ChartCanvas::TogglebFollow() {
4860void ChartCanvas::ClearbFollow() {
4863 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4865 UpdateFollowButtonState();
4869 parent_frame->SetChartUpdatePeriod();
4872void ChartCanvas::SetbFollow() {
4875 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4876 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4884 p.m_x += m_OSoffsetx;
4885 p.m_y -= m_OSoffsety;
4894 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4895 UpdateFollowButtonState();
4897 if (!g_bSmoothRecenter) {
4901 parent_frame->SetChartUpdatePeriod();
4904void ChartCanvas::UpdateFollowButtonState() {
4907 m_muiBar->SetFollowButtonState(0);
4910 m_muiBar->SetFollowButtonState(2);
4912 m_muiBar->SetFollowButtonState(1);
4918 androidSetFollowTool(0);
4921 androidSetFollowTool(2);
4923 androidSetFollowTool(1);
4930 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4931 if (pic->m_enabled && pic->m_init_state) {
4932 switch (pic->m_api_version) {
4935 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4946void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4947 if (g_bSmoothRecenter && !m_routeState) {
4948 if (StartSmoothJump(lat, lon, scale_ppm))
4952 double gcDist, gcBearingEnd;
4953 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4955 gcBearingEnd += 180;
4956 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4959 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4960 double new_lat = lat + (lat_offset / (1852 * 60));
4961 double new_lon = lon + (lon_offset / (1852 * 60));
4964 StartSmoothJump(lat, lon, scale_ppm);
4969 if (lon > 180.0) lon -= 360.0;
4975 if (!GetQuiltMode()) {
4977 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4978 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4982 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4983 AdjustQuiltRefChart();
4990 UpdateFollowButtonState();
4998bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5003 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5004 double distance_pixels = gcDist *
GetVPScale();
5005 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5011 m_startLat = m_vLat;
5012 m_startLon = m_vLon;
5017 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5018 m_endScale = scale_ppm;
5021 m_animationDuration = 600;
5022 m_animationStart = wxGetLocalTimeMillis();
5029 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5030 m_animationActive =
true;
5035void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5037 wxLongLong now = wxGetLocalTimeMillis();
5038 double elapsed = (now - m_animationStart).ToDouble();
5039 double t = elapsed / m_animationDuration.ToDouble();
5040 if (t > 1.0) t = 1.0;
5043 double e = easeOutCubic(t);
5046 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5047 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5048 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5053 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5059 m_animationActive =
false;
5060 UpdateFollowButtonState();
5069 extendedSectorLegs.clear();
5078 if (iters++ > 5)
return false;
5079 if (!std::isnan(dlat))
break;
5082 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5088 else if (dlat < -90)
5091 if (dlon > 360.) dlon -= 360.;
5092 if (dlon < -360.) dlon += 360.;
5107 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5111 if (VPoint.b_quilt) {
5112 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5113 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5117 double tweak_scale_ppm =
5123 if (new_ref_dbIndex == -1) {
5124#pragma GCC diagnostic push
5125#pragma GCC diagnostic ignored "-Warray-bounds"
5132 int trial_index = -1;
5133 if (m_pCurrentStack->nEntry) {
5135 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5138 if (trial_index < 0) {
5139 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5140 if (full_screen_array.size())
5141 trial_index = full_screen_array[full_screen_array.size() - 1];
5144 if (trial_index >= 0) {
5145 m_pQuilt->SetReferenceChart(trial_index);
5150#pragma GCC diagnostic pop
5157 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5159 double offset_angle = atan2(offy, offx);
5160 double offset_distance = sqrt((offy * offy) + (offx * offx));
5161 double chart_angle = GetVPRotation();
5162 double target_angle = chart_angle - offset_angle;
5163 double d_east_mod = offset_distance * cos(target_angle);
5164 double d_north_mod = offset_distance * sin(target_angle);
5169 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5170 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5172 UpdateFollowButtonState();
5178 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5183bool ChartCanvas::IsOwnshipOnScreen() {
5186 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5187 ((r.y > 0) && r.y < GetCanvasHeight()))
5193void ChartCanvas::ReloadVP(
bool b_adjust) {
5194 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5196 LoadVP(VPoint, b_adjust);
5199void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5201 if (g_bopengl && m_glcc) {
5202 m_glcc->Invalidate();
5203 if (m_glcc->GetSize() != GetSize()) {
5204 m_glcc->SetSize(GetSize());
5209 m_cache_vp.Invalidate();
5210 m_bm_cache_vp.Invalidate();
5213 VPoint.Invalidate();
5215 if (m_pQuilt) m_pQuilt->Invalidate();
5224 vp.m_projection_type, b_adjust);
5227void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5228 m_pQuilt->SetReferenceChart(dbIndex);
5229 VPoint.Invalidate();
5230 m_pQuilt->Invalidate();
5233double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5235 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5242int ChartCanvas::AdjustQuiltRefChart() {
5247 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5249 double min_ref_scale =
5250 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5251 double max_ref_scale =
5252 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5255 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5256 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5257 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5259 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5262 int target_stack_index = wxNOT_FOUND;
5264 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5265 if (index == m_pQuilt->GetRefChartdbIndex()) {
5266 target_stack_index = il;
5271 if (wxNOT_FOUND == target_stack_index)
5272 target_stack_index = 0;
5274 int ref_family = pc->GetChartFamily();
5275 int extended_array_count =
5276 m_pQuilt->GetExtendedStackIndexArray().size();
5277 while ((!brender_ok) &&
5278 ((
int)target_stack_index < (extended_array_count - 1))) {
5279 target_stack_index++;
5281 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5283 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5284 IsChartQuiltableRef(test_db_index)) {
5287 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5289 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5296 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5297 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5298 IsChartQuiltableRef(new_db_index)) {
5299 m_pQuilt->SetReferenceChart(new_db_index);
5302 ret = m_pQuilt->GetRefChartdbIndex();
5304 ret = m_pQuilt->GetRefChartdbIndex();
5307 ret = m_pQuilt->GetRefChartdbIndex();
5316void ChartCanvas::UpdateCanvasOnGroupChange() {
5317 delete m_pCurrentStack;
5329bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5330 double latNE,
double lonNE) {
5332 double latc = (latSW + latNE) / 2.0;
5333 double lonc = (lonSW + lonNE) / 2.0;
5336 double ne_easting, ne_northing;
5337 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5339 double sw_easting, sw_northing;
5340 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5342 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5349 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5352bool ChartCanvas::SetVPProjection(
int projection) {
5358 double prev_true_scale_ppm = m_true_scale_ppm;
5363 m_absolute_min_scale_ppm));
5371bool ChartCanvas::SetVPRotation(
double angle) {
5373 VPoint.
skew, angle);
5376 double skew,
double rotation,
int projection,
5377 bool b_adjust,
bool b_refresh) {
5382 if (VPoint.IsValid()) {
5383 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5384 (fabs(VPoint.
skew - skew) < 1e-9) &&
5385 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5386 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5387 (VPoint.m_projection_type == projection ||
5388 projection == PROJECTION_UNKNOWN))
5391 if (VPoint.m_projection_type != projection)
5392 VPoint.InvalidateTransformCache();
5402 if (projection != PROJECTION_UNKNOWN)
5403 VPoint.SetProjectionType(projection);
5404 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5405 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5408 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5409 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5410 if (VPoint.
clat > 89.5)
5412 else if (VPoint.
clat < -89.5)
5413 VPoint.
clat = -89.5;
5418 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5419 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5431 bool bwasValid = VPoint.IsValid();
5436 m_cache_vp.Invalidate();
5441 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5445 int mouseX = mouse_x;
5446 int mouseY = mouse_y;
5447 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5453 SendCursorLatLonToAllPlugIns(lat, lon);
5456 if (!VPoint.b_quilt && m_singleChart) {
5461 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5465 if ((!m_cache_vp.IsValid()) ||
5470 wxPoint cp_last, cp_this;
5474 if (cp_last != cp_this) {
5480 if (m_pCurrentStack) {
5482 int current_db_index;
5484 m_pCurrentStack->GetCurrentEntrydbIndex();
5486 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5488 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5491 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5495 if (VPoint.b_quilt) {
5499 m_pQuilt->InvalidateAllQuiltPatchs();
5503 if (!m_pCurrentStack)
return false;
5505 int current_db_index;
5507 m_pCurrentStack->GetCurrentEntrydbIndex();
5509 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5510 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5513 int current_ref_stack_index = -1;
5514 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5515 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5516 current_ref_stack_index = i;
5519 if (g_bFullScreenQuilt) {
5520 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5524 bool b_needNewRef =
false;
5527 if ((-1 == current_ref_stack_index) &&
5528 (m_pQuilt->GetRefChartdbIndex() >= 0))
5529 b_needNewRef =
true;
5536 bool renderable =
true;
5538 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5539 if (referenceChart) {
5540 double chartMaxScale = referenceChart->GetNormalScaleMax(
5542 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5544 if (!renderable) b_needNewRef =
true;
5547 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5549 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5550 int target_scale = cte_ref.GetScale();
5551 int target_type = cte_ref.GetChartType();
5552 int candidate_stack_index;
5559 candidate_stack_index = 0;
5560 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5562 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5563 int candidate_scale = cte_candidate.GetScale();
5564 int candidate_type = cte_candidate.GetChartType();
5566 if ((candidate_scale >= target_scale) &&
5567 (candidate_type == target_type)) {
5568 bool renderable =
true;
5570 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5571 if (tentative_referenceChart) {
5572 double chartMaxScale =
5573 tentative_referenceChart->GetNormalScaleMax(
5575 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5578 if (renderable)
break;
5581 candidate_stack_index++;
5586 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5587 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5588 while (candidate_stack_index >= 0) {
5589 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5593 int candidate_scale = cte_candidate.GetScale();
5594 int candidate_type = cte_candidate.GetChartType();
5596 if ((candidate_scale <= target_scale) &&
5597 (candidate_type == target_type))
5600 candidate_stack_index--;
5605 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5606 (candidate_stack_index < 0))
5607 candidate_stack_index = 0;
5609 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5611 m_pQuilt->SetReferenceChart(new_ref_index);
5617 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5622 bool renderable =
true;
5624 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5625 if (referenceChart) {
5626 double chartMaxScale = referenceChart->GetNormalScaleMax(
5628 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5629 proj =
ChartData->GetDBChartProj(ref_db_index);
5631 proj = PROJECTION_MERCATOR;
5633 VPoint.b_MercatorProjectionOverride =
5634 (m_pQuilt->GetnCharts() == 0 || !renderable);
5636 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5638 VPoint.SetProjectionType(proj);
5643 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5648 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5668 m_pQuilt->Invalidate();
5685 if (b_refresh) Refresh(
false);
5692 }
else if (!g_bopengl) {
5693 OcpnProjType projection = PROJECTION_UNKNOWN;
5696 projection = m_singleChart->GetChartProjectionType();
5697 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5698 VPoint.SetProjectionType(projection);
5702 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5703 m_cache_vp.Invalidate();
5707 UpdateCanvasControlBar();
5711 if (VPoint.GetBBox().GetValid()) {
5714 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5723 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5726 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5733 wxPoint2DDouble r, r1;
5735 double delta_check =
5739 double check_point = wxMin(89., VPoint.
clat);
5741 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5744 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5745 VPoint.
clon, 0, &rhumbDist);
5750 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5751 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5753 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5757 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5763 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5765 if (m_true_scale_ppm)
5766 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5771 double round_factor = 1000.;
5775 round_factor = 100.;
5777 round_factor = 1000.;
5780 double retina_coef = 1;
5784 retina_coef = GetContentScaleFactor();
5795 double true_scale_display =
5796 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5801 if (m_displayed_scale_factor > 10.0)
5802 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5803 m_displayed_scale_factor);
5804 else if (m_displayed_scale_factor > 1.0)
5805 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5806 m_displayed_scale_factor);
5807 else if (m_displayed_scale_factor > 0.1) {
5808 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5809 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5810 }
else if (m_displayed_scale_factor > 0.01) {
5811 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5812 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5815 "%s %4.0f (---)", _(
"Scale"),
5816 true_scale_display);
5819 m_scaleValue = true_scale_display;
5821 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5823 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5824 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5826 bool b_noshow =
false;
5830 wxClientDC dc(parent_frame->GetStatusBar());
5832 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5833 dc.SetFont(*templateFont);
5834 dc.GetTextExtent(text, &w, &h);
5839 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5840 if (w && w > rect.width) {
5841 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5845 dc.GetTextExtent(text, &w, &h);
5847 if (w && w > rect.width) {
5853 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5858 m_vLat = VPoint.
clat;
5859 m_vLon = VPoint.
clon;
5873static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5877static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5878 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5880wxColour ChartCanvas::PredColor() {
5883 if (SHIP_NORMAL == m_ownship_state)
5884 return GetGlobalColor(
"URED");
5886 else if (SHIP_LOWACCURACY == m_ownship_state)
5887 return GetGlobalColor(
"YELO1");
5889 return GetGlobalColor(
"NODTA");
5892wxColour ChartCanvas::ShipColor() {
5896 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5898 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5900 return GetGlobalColor(
"URED");
5903void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5904 wxPoint2DDouble lShipMidPoint) {
5905 dc.SetPen(wxPen(PredColor(), 2));
5907 if (SHIP_NORMAL == m_ownship_state)
5908 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5910 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5912 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5913 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5915 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5917 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5918 lShipMidPoint.m_y + 12);
5921void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5922 wxPoint GPSOffsetPixels,
5923 wxPoint2DDouble lGPSPoint) {
5928 float ref_dim = m_display_size_mm / 24;
5929 ref_dim = wxMin(ref_dim, 12);
5930 ref_dim = wxMax(ref_dim, 6);
5933 cPred.Set(g_cog_predictor_color);
5934 if (cPred == wxNullColour) cPred = PredColor();
5941 double nominal_line_width_pix = wxMax(
5943 floor(m_pix_per_mm / 2));
5947 if (nominal_line_width_pix > g_cog_predictor_width)
5948 g_cog_predictor_width = nominal_line_width_pix;
5951 wxPoint lPredPoint, lHeadPoint;
5953 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5954 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5956 double pred_lat, pred_lon;
5957 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5958 &pred_lat, &pred_lon);
5969 float ndelta_pix = 10.;
5970 double hdg_pred_lat, hdg_pred_lon;
5971 bool b_render_hdt =
false;
5972 if (!std::isnan(
gHdt)) {
5974 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5977 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5978 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5979 if (dist > ndelta_pix ) {
5980 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5981 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5986 wxPoint lShipMidPoint;
5987 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5988 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5989 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5990 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5992 if (lpp >= img_height / 2) {
5993 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
5994 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
5995 !std::isnan(
gSog)) {
5997 float dash_length = ref_dim;
5998 wxDash dash_long[2];
6000 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6001 g_cog_predictor_width);
6002 dash_long[1] = dash_long[0] / 2.0;
6006 if (dash_length > 250.) {
6007 dash_long[0] = 250. / g_cog_predictor_width;
6008 dash_long[1] = dash_long[0] / 2;
6011 wxPen ppPen2(cPred, g_cog_predictor_width,
6012 (wxPenStyle)g_cog_predictor_style);
6013 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6014 ppPen2.SetDashes(2, dash_long);
6017 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6018 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6020 if (g_cog_predictor_width > 1) {
6021 float line_width = g_cog_predictor_width / 3.;
6023 wxDash dash_long3[2];
6024 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6025 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6027 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6028 (wxPenStyle)g_cog_predictor_style);
6029 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6030 ppPen3.SetDashes(2, dash_long3);
6032 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6033 lGPSPoint.m_y + GPSOffsetPixels.y,
6034 lPredPoint.x + GPSOffsetPixels.x,
6035 lPredPoint.y + GPSOffsetPixels.y);
6038 if (g_cog_predictor_endmarker) {
6040 double png_pred_icon_scale_factor = .4;
6041 if (g_ShipScaleFactorExp > 1.0)
6042 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6043 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6047 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6048 (
float)(lPredPoint.x - lShipMidPoint.x));
6049 cog_rad += (float)PI;
6051 for (
int i = 0; i < 4; i++) {
6053 double pxa = (double)(s_png_pred_icon[j]);
6054 double pya = (double)(s_png_pred_icon[j + 1]);
6056 pya *= png_pred_icon_scale_factor;
6057 pxa *= png_pred_icon_scale_factor;
6059 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6060 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6062 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6063 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6067 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6070 dc.SetBrush(wxBrush(cPred));
6072 dc.StrokePolygon(4, icon);
6079 float hdt_dash_length = ref_dim * 0.4;
6081 cPred.Set(g_ownship_HDTpredictor_color);
6082 if (cPred == wxNullColour) cPred = PredColor();
6084 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6085 : g_cog_predictor_width * 0.8);
6086 wxDash dash_short[2];
6088 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6091 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6094 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6095 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6096 ppPen2.SetDashes(2, dash_short);
6100 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6101 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6103 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6105 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6107 if (g_ownship_HDTpredictor_endmarker) {
6108 double nominal_circle_size_pixels = wxMax(
6109 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6112 if (g_ShipScaleFactorExp > 1.0)
6113 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6115 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6116 lHeadPoint.y + GPSOffsetPixels.y,
6117 nominal_circle_size_pixels / 2);
6122 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6123 double factor = 1.00;
6124 if (g_pNavAidRadarRingsStepUnits == 1)
6126 else if (g_pNavAidRadarRingsStepUnits == 2) {
6127 if (std::isnan(
gSog))
6132 factor *= g_fNavAidRadarRingsStep;
6136 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6139 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6140 pow((
double)(lGPSPoint.m_y - r.y), 2));
6141 int pix_radius = (int)lpp;
6143 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6145 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6148 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6150 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6151 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6155void ChartCanvas::ComputeShipScaleFactor(
6156 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6157 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6158 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6159 float screenResolution = m_pix_per_mm;
6162 double ship_bow_lat, ship_bow_lon;
6163 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6164 &ship_bow_lat, &ship_bow_lon);
6165 wxPoint lShipBowPoint;
6166 wxPoint2DDouble b_point =
6170 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6171 powf((
float)(b_point.m_y - a_point.m_y), 2));
6174 float shipLength_mm = shipLength_px / screenResolution;
6177 float ownship_min_mm = g_n_ownship_min_mm;
6178 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6181 float hdt_ant = icon_hdt + 180.;
6182 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6183 float dx = g_n_gps_antenna_offset_x / 1852.;
6184 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6192 if (shipLength_mm < ownship_min_mm) {
6193 dy /= shipLength_mm / ownship_min_mm;
6194 dx /= shipLength_mm / ownship_min_mm;
6197 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6199 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6200 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6206 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6207 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6209 float scale_factor = shipLength_px / ownShipLength;
6212 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6215 scale_factor = wxMax(scale_factor, scale_factor_min);
6217 scale_factor_y = scale_factor;
6218 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6219 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6222void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6223 if (!GetVP().IsValid())
return;
6225 wxPoint GPSOffsetPixels(0, 0);
6226 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6229 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6230 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6234 lShipMidPoint = lGPSPoint;
6238 float icon_hdt = pCog;
6239 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6242 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6246 double osd_head_lat, osd_head_lon;
6247 wxPoint osd_head_point;
6249 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6254 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6255 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6256 icon_rad += (float)PI;
6258 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6262 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6266 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6267 if (GetVP().chart_scale >
6270 ShipDrawLargeScale(dc, lShipMidPoint);
6276 if (m_pos_image_user)
6277 pos_image = m_pos_image_user->Copy();
6278 else if (SHIP_NORMAL == m_ownship_state)
6279 pos_image = m_pos_image_red->Copy();
6280 if (SHIP_LOWACCURACY == m_ownship_state)
6281 pos_image = m_pos_image_yellow->Copy();
6282 else if (SHIP_NORMAL != m_ownship_state)
6283 pos_image = m_pos_image_grey->Copy();
6286 if (m_pos_image_user) {
6287 pos_image = m_pos_image_user->Copy();
6289 if (SHIP_LOWACCURACY == m_ownship_state)
6290 pos_image = m_pos_image_user_yellow->Copy();
6291 else if (SHIP_NORMAL != m_ownship_state)
6292 pos_image = m_pos_image_user_grey->Copy();
6295 img_height = pos_image.GetHeight();
6297 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6298 g_OwnShipIconType > 0)
6300 int ownShipWidth = 22;
6301 int ownShipLength = 84;
6302 if (g_OwnShipIconType == 1) {
6303 ownShipWidth = pos_image.GetWidth();
6304 ownShipLength = pos_image.GetHeight();
6307 float scale_factor_x, scale_factor_y;
6308 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6309 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6310 scale_factor_x, scale_factor_y);
6312 if (g_OwnShipIconType == 1) {
6313 pos_image.Rescale(ownShipWidth * scale_factor_x,
6314 ownShipLength * scale_factor_y,
6315 wxIMAGE_QUALITY_HIGH);
6316 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6318 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6321 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6322 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6323 if (rot_image.GetAlpha(ip, jp) > 64)
6324 rot_image.SetAlpha(ip, jp, 255);
6326 wxBitmap os_bm(rot_image);
6328 int w = os_bm.GetWidth();
6329 int h = os_bm.GetHeight();
6332 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6333 lShipMidPoint.m_y - h / 2,
true);
6336 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6337 lShipMidPoint.m_y - h / 2);
6338 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6339 lShipMidPoint.m_y - h / 2 + h);
6342 else if (g_OwnShipIconType == 2) {
6343 wxPoint ownship_icon[10];
6345 for (
int i = 0; i < 10; i++) {
6347 float pxa = (float)(s_ownship_icon[j]);
6348 float pya = (float)(s_ownship_icon[j + 1]);
6349 pya *= scale_factor_y;
6350 pxa *= scale_factor_x;
6352 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6353 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6355 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6356 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6359 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6361 dc.SetBrush(wxBrush(ShipColor()));
6363 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6366 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6368 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6372 img_height = ownShipLength * scale_factor_y;
6376 if (m_pos_image_user) circle_rad = 1;
6378 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6379 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6380 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6383 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6385 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6388 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6389 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6390 if (rot_image.GetAlpha(ip, jp) > 64)
6391 rot_image.SetAlpha(ip, jp, 255);
6393 wxBitmap os_bm(rot_image);
6395 if (g_ShipScaleFactorExp > 1) {
6396 wxImage scaled_image = os_bm.ConvertToImage();
6397 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6399 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6400 scaled_image.GetHeight() * factor,
6401 wxIMAGE_QUALITY_HIGH));
6403 int w = os_bm.GetWidth();
6404 int h = os_bm.GetHeight();
6407 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6408 lShipMidPoint.m_y - h / 2,
true);
6412 if (m_pos_image_user) circle_rad = 1;
6414 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6415 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6416 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6419 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6420 lShipMidPoint.m_y - h / 2);
6421 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6422 lShipMidPoint.m_y - h / 2 + h);
6427 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6440void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6441 float &MinorSpacing) {
6446 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6447 {.000001f, 45.0f, 15.0f},
6448 {.0002f, 30.0f, 10.0f},
6449 {.0003f, 10.0f, 2.0f},
6450 {.0008f, 5.0f, 1.0f},
6451 {.001f, 2.0f, 30.0f / 60.0f},
6452 {.003f, 1.0f, 20.0f / 60.0f},
6453 {.006f, 0.5f, 10.0f / 60.0f},
6454 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6455 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6456 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6457 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6458 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6459 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6460 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6461 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6464 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6465 if (view_scale_ppm < lltab[tabi][0])
break;
6466 MajorSpacing = lltab[tabi][1];
6467 MinorSpacing = lltab[tabi][2];
6481wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6482 int deg = (int)fabs(latlon);
6483 float min = fabs((fabs(latlon) - deg) * 60.0);
6493 }
else if (latlon < 0.0) {
6505 if (spacing >= 1.0) {
6506 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6507 }
else if (spacing >= (1.0 / 60.0)) {
6508 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6510 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6527void ChartCanvas::GridDraw(
ocpnDC &dc) {
6528 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6530 double nlat, elon, slat, wlon;
6533 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6535 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6537 if (!m_pgridFont) SetupGridFont();
6538 dc.SetFont(*m_pgridFont);
6539 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6542 h = m_canvas_height;
6553 dlon = dlon + 360.0;
6556 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6559 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6562 while (lat < nlat) {
6565 CalcGridText(lat, gridlatMajor,
true);
6567 dc.
DrawLine(0, r.y, w, r.y,
false);
6568 dc.DrawText(st, 0, r.y);
6569 lat = lat + gridlatMajor;
6571 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6575 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6578 while (lat < nlat) {
6581 dc.
DrawLine(0, r.y, 10, r.y,
false);
6582 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6583 lat = lat + gridlatMinor;
6587 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6590 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6593 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6595 wxString st = CalcGridText(lon, gridlonMajor,
false);
6597 dc.
DrawLine(r.x, 0, r.x, h,
false);
6598 dc.DrawText(st, r.x, 0);
6599 lon = lon + gridlonMajor;
6604 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6608 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6610 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6613 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6614 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6615 lon = lon + gridlonMinor;
6622void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6624 double blat, blon, tlat, tlon;
6627 int x_origin = m_bDisplayGrid ? 60 : 20;
6628 int y_origin = m_canvas_height - 50;
6634 if (GetVP().chart_scale > 80000)
6638 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6639 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6644 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6645 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6649 double rotation = -VPoint.
rotation;
6651 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6653 int l1 = (y_origin - r.y) / count;
6655 for (
int i = 0; i < count; i++) {
6662 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6665 double blat, blon, tlat, tlon;
6672 int y_origin = m_canvas_height - chartbar_height - 5;
6676 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6683 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6688 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6689 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6693 float places = floor(logdist), rem = logdist - places;
6694 dist = pow(10, places);
6701 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6702 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6703 double rotation = -VPoint.
rotation;
6709 int l1 = r.x - x_origin;
6711 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6716 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6717 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6718 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6720 if (!m_pgridFont) SetupGridFont();
6721 dc.SetFont(*m_pgridFont);
6722 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6724 dc.GetTextExtent(s, &w, &h);
6730 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6734void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6739 double ra_max = 40.;
6741 wxPen pen_save = dc.GetPen();
6743 wxDateTime now = wxDateTime::Now();
6749 x0 = x1 = x + radius;
6754 while (angle < 360.) {
6755 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6758 if (angle > 360.) angle = 360.;
6760 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6768 x1 = (int)(x + cos(angle * PI / 180.) * r);
6769 y1 = (int)(y + sin(angle * PI / 180.) * r);
6779 dc.
DrawLine(x + radius, y, x1, y1);
6781 dc.SetPen(pen_save);
6784static bool bAnchorSoundPlaying =
false;
6786static void onAnchorSoundFinished(
void *ptr) {
6787 o_sound::g_anchorwatch_sound->UnLoad();
6788 bAnchorSoundPlaying =
false;
6791void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6792 using namespace o_sound;
6794 bool play_sound =
false;
6796 if (AnchorAlertOn1) {
6797 wxPoint TargetPoint;
6800 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6801 TargetPoint.y, 100);
6805 AnchorAlertOn1 =
false;
6808 if (AnchorAlertOn2) {
6809 wxPoint TargetPoint;
6812 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6813 TargetPoint.y, 100);
6817 AnchorAlertOn2 =
false;
6820 if (!bAnchorSoundPlaying) {
6821 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6822 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6823 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6824 if (g_anchorwatch_sound->IsOk()) {
6825 bAnchorSoundPlaying =
true;
6826 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6827 g_anchorwatch_sound->Play();
6833void ChartCanvas::UpdateShips() {
6836 wxClientDC dc(
this);
6837 if (!dc.IsOk())
return;
6839 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6840 if (!test_bitmap.IsOk())
return;
6842 wxMemoryDC temp_dc(test_bitmap);
6844 temp_dc.ResetBoundingBox();
6845 temp_dc.DestroyClippingRegion();
6846 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6857 ocpndc.CalcBoundingBox(px.x, px.y);
6862 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6863 temp_dc.MaxY() - temp_dc.MinY());
6865 wxRect own_ship_update_rect = ship_draw_rect;
6867 if (!own_ship_update_rect.IsEmpty()) {
6870 own_ship_update_rect.Union(ship_draw_last_rect);
6871 own_ship_update_rect.Inflate(2);
6874 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6876 ship_draw_last_rect = ship_draw_rect;
6878 temp_dc.SelectObject(wxNullBitmap);
6881void ChartCanvas::UpdateAlerts() {
6886 wxClientDC dc(
this);
6890 dc.GetSize(&sx, &sy);
6893 wxBitmap test_bitmap(sx, sy, -1);
6897 temp_dc.SelectObject(test_bitmap);
6899 temp_dc.ResetBoundingBox();
6900 temp_dc.DestroyClippingRegion();
6901 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6908 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6909 temp_dc.MaxX() - temp_dc.MinX(),
6910 temp_dc.MaxY() - temp_dc.MinY());
6912 if (!alert_rect.IsEmpty())
6913 alert_rect.Inflate(2);
6915 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6918 wxRect alert_update_rect = alert_draw_rect;
6919 alert_update_rect.Union(alert_rect);
6922 RefreshRect(alert_update_rect,
false);
6926 alert_draw_rect = alert_rect;
6928 temp_dc.SelectObject(wxNullBitmap);
6931void ChartCanvas::UpdateAIS() {
6937 wxClientDC dc(
this);
6941 dc.GetSize(&sx, &sy);
6949 if (
g_pAIS->GetTargetList().size() > 10) {
6950 ais_rect = wxRect(0, 0, sx, sy);
6953 wxBitmap test_bitmap(sx, sy, -1);
6957 temp_dc.SelectObject(test_bitmap);
6959 temp_dc.ResetBoundingBox();
6960 temp_dc.DestroyClippingRegion();
6961 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6965 AISDraw(ocpndc, GetVP(),
this);
6966 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6970 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6971 temp_dc.MaxY() - temp_dc.MinY());
6973 if (!ais_rect.IsEmpty())
6974 ais_rect.Inflate(2);
6976 temp_dc.SelectObject(wxNullBitmap);
6979 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6982 wxRect ais_update_rect = ais_draw_rect;
6983 ais_update_rect.Union(ais_rect);
6986 RefreshRect(ais_update_rect,
false);
6990 ais_draw_rect = ais_rect;
6993void ChartCanvas::ToggleCPAWarn() {
6994 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7000 g_bTCPA_Max =
false;
7004 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
7005 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7007 if (!g_AisFirstTimeUse) {
7008 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7009 _(
"CPA") +
" " + mess, 4, 4);
7014void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7016void ChartCanvas::OnSize(wxSizeEvent &event) {
7017 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7019 GetClientSize(&m_canvas_width, &m_canvas_height);
7023 m_displayScale = GetContentScaleFactor();
7027 m_canvas_width *= m_displayScale;
7028 m_canvas_height *= m_displayScale;
7041 m_absolute_min_scale_ppm =
7043 (1.2 * WGS84_semimajor_axis_meters * PI);
7046 gFrame->ProcessCanvasResize();
7056 SetMUIBarPosition();
7057 UpdateFollowButtonState();
7058 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7062 xr_margin = m_canvas_width * 95 / 100;
7063 xl_margin = m_canvas_width * 5 / 100;
7064 yt_margin = m_canvas_height * 5 / 100;
7065 yb_margin = m_canvas_height * 95 / 100;
7068 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7073 m_brepaint_piano =
true;
7076 m_dc_route.SelectObject(wxNullBitmap);
7079 m_dc_route.SelectObject(*proute_bm);
7093 m_glcc->OnSize(event);
7102void ChartCanvas::ProcessNewGUIScale() {
7110void ChartCanvas::CreateMUIBar() {
7111 if (g_useMUI && !m_muiBar) {
7112 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7113 m_muiBar->SetColorScheme(m_cs);
7114 m_muiBarHOSize = m_muiBar->m_size;
7122 SetMUIBarPosition();
7123 UpdateFollowButtonState();
7124 m_muiBar->UpdateDynamicValues();
7125 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7129void ChartCanvas::SetMUIBarPosition() {
7133 int pianoWidth = GetClientSize().x * 0.6f;
7138 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7139 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7141 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7142 m_muiBar->SetColorScheme(m_cs);
7146 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7147 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7149 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7150 m_muiBar->SetColorScheme(m_cs);
7154 m_muiBar->SetBestPosition();
7158void ChartCanvas::DestroyMuiBar() {
7165void ChartCanvas::ShowCompositeInfoWindow(
7166 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7168 if (NULL == m_pCIWin) {
7173 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7176 s = _(
"Composite of ");
7179 s1.Printf(
"%d ", n_charts);
7187 s1.Printf(_(
"Chart scale"));
7190 s2.Printf(
"1:%d\n",
scale);
7194 s1 = _(
"Zoom in for more information");
7198 int char_width = s1.Length();
7199 int char_height = 3;
7201 if (g_bChartBarEx) {
7204 for (
int i : index_vector) {
7206 wxString path = cte.GetFullSystemPath();
7210 char_width = wxMax(char_width, path.Length());
7211 if (j++ >= 9)
break;
7214 s +=
" .\n .\n .\n";
7223 m_pCIWin->SetString(s);
7225 m_pCIWin->FitToChars(char_width, char_height);
7228 p.x = x / GetContentScaleFactor();
7229 if ((p.x + m_pCIWin->GetWinSize().x) >
7230 (m_canvas_width / GetContentScaleFactor()))
7231 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7232 m_pCIWin->GetWinSize().x) /
7235 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7236 4 - m_pCIWin->GetWinSize().y;
7238 m_pCIWin->dbIndex = 0;
7239 m_pCIWin->chart_scale = 0;
7240 m_pCIWin->SetPosition(p);
7241 m_pCIWin->SetBitmap();
7242 m_pCIWin->Refresh();
7246 HideChartInfoWindow();
7250void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7252 if (NULL == m_pCIWin) {
7257 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7266 dbIndex, FULL_INIT);
7268 int char_width, char_height;
7269 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7270 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7272 m_pCIWin->SetString(s);
7273 m_pCIWin->FitToChars(char_width, char_height);
7276 p.x = x / GetContentScaleFactor();
7277 if ((p.x + m_pCIWin->GetWinSize().x) >
7278 (m_canvas_width / GetContentScaleFactor()))
7279 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7280 m_pCIWin->GetWinSize().x) /
7283 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7284 4 - m_pCIWin->GetWinSize().y;
7286 m_pCIWin->dbIndex = dbIndex;
7287 m_pCIWin->SetPosition(p);
7288 m_pCIWin->SetBitmap();
7289 m_pCIWin->Refresh();
7293 HideChartInfoWindow();
7297void ChartCanvas::HideChartInfoWindow() {
7300 m_pCIWin->Destroy();
7304 androidForceFullRepaint();
7309void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7310 wxMouseEvent ev(wxEVT_MOTION);
7313 ev.m_leftDown = mouse_leftisdown;
7315 wxEvtHandler *evthp = GetEventHandler();
7317 ::wxPostEvent(evthp, ev);
7320void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7321 if ((m_panx_target_final - m_panx_target_now) ||
7322 (m_pany_target_final - m_pany_target_now)) {
7323 DoTimedMovementTarget();
7328void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7330bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7332 if (m_disable_edge_pan)
return false;
7335 int pan_margin = m_canvas_width * margin / 100;
7336 int pan_timer_set = 200;
7337 double pan_delta = GetVP().
pix_width * delta / 100;
7341 if (x > m_canvas_width - pan_margin) {
7346 else if (x < pan_margin) {
7351 if (y < pan_margin) {
7356 else if (y > m_canvas_height - pan_margin) {
7365 wxMouseState state = ::wxGetMouseState();
7366#if wxCHECK_VERSION(3, 0, 0)
7367 if (!state.LeftIsDown())
7369 if (!state.LeftDown())
7374 if ((bft) && !pPanTimer->IsRunning()) {
7376 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7382 if ((!bft) && pPanTimer->IsRunning()) {
7392void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7393 bool setBeingEdited) {
7394 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7395 m_pRoutePointEditTarget = NULL;
7396 m_pFoundPoint = NULL;
7399 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7400 SelectableItemList SelList =
pSelect->FindSelectionList(
7410 bool brp_viz =
false;
7411 if (m_pEditRouteArray) {
7412 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7413 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7414 if (pr->IsVisible()) {
7420 brp_viz = frp->IsVisible();
7424 if (m_pEditRouteArray)
7426 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7427 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7430 m_bRouteEditing = setBeingEdited;
7433 frp->m_bRPIsBeingEdited = setBeingEdited;
7434 m_bMarkEditing = setBeingEdited;
7437 m_pRoutePointEditTarget = frp;
7438 m_pFoundPoint = pFind;
7443std::shared_ptr<HostApi121::PiPointContext>
7444ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7458 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7459 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7460 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7461 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7462 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7466 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7469 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7474 int FoundAIS_MMSI = 0;
7476 FoundAIS_MMSI = pFindAIS->GetUserData();
7479 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7480 seltype |= SELTYPE_AISTARGET;
7486 Route *SelectedRoute = NULL;
7492 Route *pSelectedActiveRoute = NULL;
7493 Route *pSelectedVizRoute = NULL;
7496 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7497 SelectableItemList SelList =
7498 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7506 bool brp_viz =
false;
7508 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7510 if (pr->IsVisible()) {
7515 if (!brp_viz && prp->IsShared())
7517 brp_viz = prp->IsVisible();
7520 brp_viz = prp->IsVisible();
7522 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7528 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7531 pSelectedActiveRoute = pr;
7532 pFoundActiveRoutePoint = prp;
7537 if (NULL == pSelectedVizRoute) {
7538 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7540 if (pr->IsVisible()) {
7541 pSelectedVizRoute = pr;
7542 pFoundVizRoutePoint = prp;
7548 delete proute_array;
7553 if (pFoundActiveRoutePoint) {
7554 FoundRoutePoint = pFoundActiveRoutePoint;
7555 SelectedRoute = pSelectedActiveRoute;
7556 }
else if (pFoundVizRoutePoint) {
7557 FoundRoutePoint = pFoundVizRoutePoint;
7558 SelectedRoute = pSelectedVizRoute;
7561 FoundRoutePoint = pFirstVizPoint;
7563 if (SelectedRoute) {
7564 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7565 }
else if (FoundRoutePoint) {
7566 seltype |= SELTYPE_MARKPOINT;
7571 if (m_pFoundRoutePoint) {
7575 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7576 RefreshRect(wp_rect,
true);
7585 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7586 SelectableItemList SelList =
7587 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7589 if (NULL == SelectedRoute)
7594 if (pr->IsVisible()) {
7601 if (SelectedRoute) {
7602 if (NULL == FoundRoutePoint)
7603 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7606 seltype |= SELTYPE_ROUTESEGMENT;
7610 if (pFindTrackSeg) {
7611 m_pSelectedTrack = NULL;
7612 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7613 SelectableItemList SelList =
7614 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7619 if (pt->IsVisible()) {
7620 m_pSelectedTrack = pt;
7624 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7627 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7630 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7631 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7632 rstruct->object_ident =
"";
7634 if (seltype == SELTYPE_AISTARGET) {
7635 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7637 val.Printf(
"%d", FoundAIS_MMSI);
7638 rstruct->object_ident = val.ToStdString();
7639 }
else if (seltype & SELTYPE_MARKPOINT) {
7640 if (FoundRoutePoint) {
7641 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7642 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7644 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7645 if (SelectedRoute) {
7646 rstruct->object_type =
7647 HostApi121::PiContextObjectType::kObjectRoutesegment;
7648 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7650 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7651 if (m_pSelectedTrack) {
7652 rstruct->object_type =
7653 HostApi121::PiContextObjectType::kObjectTracksegment;
7654 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7661void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7662 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7663 singleClickEventIsValid =
false;
7664 m_DoubleClickTimer->Stop();
7669bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7670 if (!m_bChartDragging && !m_bDrawingRoute) {
7675 if (m_Compass && m_Compass->IsShown()) {
7677 bool isInCompass = logicalRect.Contains(event.GetPosition());
7678 if (isInCompass || m_mouseWasInCompass) {
7679 if (m_Compass->MouseEvent(event)) {
7680 cursor_region = CENTER;
7681 if (!g_btouch) SetCanvasCursor(event);
7682 m_mouseWasInCompass = isInCompass;
7686 m_mouseWasInCompass = isInCompass;
7689 if (m_notification_button && m_notification_button->IsShown()) {
7691 bool isinButton = logicalRect.Contains(event.GetPosition());
7693 SetCursor(*pCursorArrow);
7694 if (event.LeftDown()) HandleNotificationMouseClick();
7699 if (MouseEventToolbar(event))
return true;
7701 if (MouseEventChartBar(event))
return true;
7703 if (MouseEventMUIBar(event))
return true;
7705 if (MouseEventIENCBar(event))
return true;
7710void ChartCanvas::HandleNotificationMouseClick() {
7711 if (!m_NotificationsList) {
7715 m_NotificationsList->RecalculateSize();
7716 m_NotificationsList->Hide();
7719 if (m_NotificationsList->IsShown()) {
7720 m_NotificationsList->Hide();
7722 m_NotificationsList->RecalculateSize();
7723 m_NotificationsList->ReloadNotificationList();
7724 m_NotificationsList->Show();
7727bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7728 if (!g_bShowChartBar)
return false;
7730 if (!m_Piano->MouseEvent(event))
return false;
7732 cursor_region = CENTER;
7733 if (!g_btouch) SetCanvasCursor(event);
7737bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7738 if (!IsPrimaryCanvas())
return false;
7747 cursor_region = CENTER;
7748 if (!g_btouch) SetCanvasCursor(event);
7752bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7753 if (!IsPrimaryCanvas())
return false;
7766bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7768 if (!m_muiBar->MouseEvent(event))
return false;
7771 cursor_region = CENTER;
7772 if (!g_btouch) SetCanvasCursor(event);
7784 event.GetPosition(&x, &y);
7786 x *= m_displayScale;
7787 y *= m_displayScale;
7789 m_MouseDragging =
event.Dragging();
7795 if (event.Dragging()) {
7796 if ((x == mouse_x) && (y == mouse_y))
return true;
7802 mouse_leftisdown =
event.LeftDown();
7806 cursor_region = CENTER;
7810 if (m_Compass && m_Compass->IsShown() &&
7811 m_Compass->
GetRect().Contains(event.GetPosition())) {
7812 cursor_region = CENTER;
7813 }
else if (x > xr_margin) {
7814 cursor_region = MID_RIGHT;
7815 }
else if (x < xl_margin) {
7816 cursor_region = MID_LEFT;
7817 }
else if (y > yb_margin - chartbar_height &&
7818 y < m_canvas_height - chartbar_height) {
7819 cursor_region = MID_TOP;
7820 }
else if (y < yt_margin) {
7821 cursor_region = MID_BOT;
7823 cursor_region = CENTER;
7826 if (!g_btouch) SetCanvasCursor(event);
7830 leftIsDown =
event.LeftDown();
7833 if (event.LeftDown()) {
7834 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7837 g_bTempShowMenuBar =
false;
7838 parent_frame->ApplyGlobalSettings(
false);
7846 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7847 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7851 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7852 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7855 event.SetEventObject(
this);
7856 if (SendMouseEventToPlugins(event))
7863 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7864 StartChartDragInertia();
7867 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7868 !singleClickEventIsValid) {
7870 if (m_DoubleClickTimer->IsRunning()) {
7871 m_DoubleClickTimer->Stop();
7876 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7877 singleClickEvent = event;
7878 singleClickEventIsValid =
true;
7887 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7888 if (g_click_stop > 0) {
7896 if (GetUpMode() == COURSE_UP_MODE) {
7897 m_b_rot_hidef =
false;
7898 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7900 pRotDefTimer->Stop();
7903 bool bRoll = !g_btouch;
7908 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7909 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7910 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7911 m_RolloverPopupTimer.Start(
7915 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7919 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7928#if !defined(__WXGTK__) && !defined(__WXQT__)
7936 if ((x >= 0) && (y >= 0))
7941 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7942 wxPoint p = ClientToScreen(wxPoint(x, y));
7948 if (m_routeState >= 2) {
7951 m_bDrawingRoute =
true;
7953 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7958 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7961 m_bDrawingRoute =
true;
7963 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7976#if defined(__WXMAC__) || defined(__ANDROID__)
7980 wxClientDC cdc(GetParent());
7992 if (m_pSelectedRoute) {
7994 m_pSelectedRoute->DeSelectRoute();
7996 if (g_bopengl && m_glcc) {
8001 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8004 if (m_pFoundRoutePoint) {
8012 if (g_btouch && m_pRoutePointEditTarget) {
8015 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8019 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8020 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8021 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8022 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8023 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8027 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8030 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8036 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8039 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8040 seltype |= SELTYPE_AISTARGET;
8045 m_pFoundRoutePoint = NULL;
8050 Route *pSelectedActiveRoute = NULL;
8051 Route *pSelectedVizRoute = NULL;
8054 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8055 SelectableItemList SelList =
8056 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8064 bool brp_viz =
false;
8066 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8068 if (pr->IsVisible()) {
8073 if (!brp_viz && prp->IsShared())
8075 brp_viz = prp->IsVisible();
8078 brp_viz = prp->IsVisible();
8080 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8085 m_pSelectedRoute = NULL;
8087 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8090 pSelectedActiveRoute = pr;
8091 pFoundActiveRoutePoint = prp;
8096 if (NULL == pSelectedVizRoute) {
8097 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8099 if (pr->IsVisible()) {
8100 pSelectedVizRoute = pr;
8101 pFoundVizRoutePoint = prp;
8107 delete proute_array;
8112 if (pFoundActiveRoutePoint) {
8113 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8114 m_pSelectedRoute = pSelectedActiveRoute;
8115 }
else if (pFoundVizRoutePoint) {
8116 m_pFoundRoutePoint = pFoundVizRoutePoint;
8117 m_pSelectedRoute = pSelectedVizRoute;
8120 m_pFoundRoutePoint = pFirstVizPoint;
8122 if (m_pSelectedRoute) {
8123 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8124 }
else if (m_pFoundRoutePoint) {
8125 seltype |= SELTYPE_MARKPOINT;
8129 if (m_pFoundRoutePoint) {
8133 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8134 RefreshRect(wp_rect,
true);
8142 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8143 SelectableItemList SelList =
8144 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8146 if (NULL == m_pSelectedRoute)
8151 if (pr->IsVisible()) {
8152 m_pSelectedRoute = pr;
8158 if (m_pSelectedRoute) {
8159 if (NULL == m_pFoundRoutePoint)
8160 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8165 if (g_bopengl && m_glcc) {
8170 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8172 seltype |= SELTYPE_ROUTESEGMENT;
8176 if (pFindTrackSeg) {
8177 m_pSelectedTrack = NULL;
8178 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8179 SelectableItemList SelList =
8180 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8185 if (pt->IsVisible()) {
8186 m_pSelectedTrack = pt;
8190 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8196 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8197 seltype |= SELTYPE_CURRENTPOINT;
8200 else if (pFindTide) {
8201 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8202 seltype |= SELTYPE_TIDEPOINT;
8207 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8212IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8222 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8223 SelectableItemList SelList =
8224 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8227 pFind = *SelList.begin();
8228 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8230 auto node = SelList.begin();
8231 if (SelList.size() > 1) {
8232 for (++node; node != SelList.end(); ++node) {
8235 if (pIDX_candidate->
IDX_type ==
'c') {
8236 pIDX_best_candidate = pIDX_candidate;
8241 pFind = *SelList.begin();
8242 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8245 return pIDX_best_candidate;
8247void ChartCanvas::CallPopupMenu(
int x,
int y) {
8251 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8259 if (SELTYPE_CURRENTPOINT == seltype) {
8265 if (SELTYPE_TIDEPOINT == seltype) {
8271 InvokeCanvasMenu(x, y, seltype);
8274 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8278 m_pSelectedRoute = NULL;
8280 if (m_pFoundRoutePoint) {
8281 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8284 m_pFoundRoutePoint = NULL;
8290bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8298 event.GetPosition(&x, &y);
8304 SelectRadius = g_Platform->GetSelectRadiusPix() /
8305 (m_true_scale_ppm * 1852 * 60);
8312 if (event.LeftDClick() && (cursor_region == CENTER)) {
8313 m_DoubleClickTimer->Start();
8314 singleClickEventIsValid =
false;
8320 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8323 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8326 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8327 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8328 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8334 SelectableItemList rpSelList =
8335 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8336 bool b_onRPtarget =
false;
8339 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8340 b_onRPtarget =
true;
8348 std::unique_ptr<HostApi> host_api =
GetHostApi();
8349 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8351 if (m_pRoutePointEditTarget) {
8353 if ((api_121->GetContextMenuMask() &
8354 api_121->kContextMenuDisableWaypoint))
8356 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8362 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8365 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8366 m_pRoutePointEditTarget = NULL;
8367 RefreshRect(wp_rect,
true);
8371 auto node = rpSelList.begin();
8372 if (node != rpSelList.end()) {
8376 wxArrayPtrVoid *proute_array =
8381 bool brp_viz =
false;
8383 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8385 if (pr->IsVisible()) {
8390 delete proute_array;
8394 brp_viz = frp->IsVisible();
8396 brp_viz = frp->IsVisible();
8399 if ((api_121->GetContextMenuMask() &
8400 api_121->kContextMenuDisableWaypoint))
8403 ShowMarkPropertiesDialog(frp);
8412 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8414 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8417 if (pr->IsVisible()) {
8418 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8423 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8425 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8428 if (pt->IsVisible()) {
8429 ShowTrackPropertiesDialog(pt);
8438 if (m_bShowCurrent) {
8440 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8442 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8450 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8452 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8460 ShowObjectQueryWindow(x, y, zlat, zlon);
8465 if (event.LeftDown()) {
8481 bool appending =
false;
8482 bool inserting =
false;
8485 SetCursor(*pCursorPencil);
8489 m_bRouteEditing =
true;
8491 if (m_routeState == 1) {
8492 m_pMouseRoute =
new Route();
8493 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8503 double nearby_radius_meters =
8504 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8507 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8508 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8509 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8510 wxArrayPtrVoid *proute_array =
8515 bool brp_viz =
false;
8517 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8519 if (pr->IsVisible()) {
8524 delete proute_array;
8526 pNearbyPoint->IsShared())
8529 pNearbyPoint->IsVisible();
8531 brp_viz = pNearbyPoint->IsVisible();
8534 wxString msg = _(
"Use nearby waypoint?");
8536 const bool noname(pNearbyPoint->GetName() ==
"");
8539 _(
"Use nearby nameless waypoint and name it M with"
8540 " a unique number?");
8543 m_FinishRouteOnKillFocus =
false;
8545 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8546 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8547 m_FinishRouteOnKillFocus =
true;
8548 if (dlg_return == wxID_YES) {
8550 if (m_pMouseRoute) {
8551 int last_wp_num = m_pMouseRoute->GetnPoints();
8553 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8554 wxString wp_name = wxString::Format(
8555 "M%002i-%s", last_wp_num + 1, guid_short);
8556 pNearbyPoint->SetName(wp_name);
8558 pNearbyPoint->SetName(
"WPXX");
8560 pMousePoint = pNearbyPoint;
8563 if (m_routeState > 1)
8564 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8565 Undo_HasParent, NULL);
8568 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8569 bool procede =
false;
8573 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8579 m_FinishRouteOnKillFocus =
false;
8585 _(
"Insert first part of this route in the new route?");
8586 if (tail->GetIndexOf(pMousePoint) ==
8589 dmsg = _(
"Insert this route in the new route?");
8591 if (tail->GetIndexOf(pMousePoint) != 1) {
8592 dlg_return = OCPNMessageBox(
8593 this, dmsg, _(
"OpenCPN Route Create"),
8594 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8595 m_FinishRouteOnKillFocus =
true;
8597 if (dlg_return == wxID_YES) {
8604 _(
"Append last part of this route to the new route?");
8605 if (tail->GetIndexOf(pMousePoint) == 1)
8607 "Append this route to the new route?");
8612 if (tail->GetLastPoint() != pMousePoint) {
8613 dlg_return = OCPNMessageBox(
8614 this, dmsg, _(
"OpenCPN Route Create"),
8615 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8616 m_FinishRouteOnKillFocus =
true;
8618 if (dlg_return == wxID_YES) {
8629 if (!FindRouteContainingWaypoint(pMousePoint))
8630 pMousePoint->SetShared(
true);
8635 if (NULL == pMousePoint) {
8636 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8638 pMousePoint->SetNameShown(
false);
8642 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8644 if (m_routeState > 1)
8645 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8646 Undo_IsOrphanded, NULL);
8649 if (m_pMouseRoute) {
8650 if (m_routeState == 1) {
8652 m_pMouseRoute->AddPoint(pMousePoint);
8656 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8657 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8658 &rhumbBearing, &rhumbDist);
8659 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8660 rlat, &gcDist, &gcBearing, NULL);
8661 double gcDistNM = gcDist / 1852.0;
8664 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8665 pow(rhumbDist - gcDistNM - 1, 0.5);
8668 msg << _(
"For this leg the Great Circle route is ")
8670 << _(
" shorter than rhumbline.\n\n")
8671 << _(
"Would you like include the Great Circle routing points "
8674 m_FinishRouteOnKillFocus =
false;
8675 m_disable_edge_pan =
true;
8678 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8679 wxYES_NO | wxNO_DEFAULT);
8681 m_disable_edge_pan =
false;
8682 m_FinishRouteOnKillFocus =
true;
8684 if (answer == wxID_YES) {
8686 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8687 wxRealPoint gcCoord;
8689 for (
int i = 1; i <= segmentCount; i++) {
8690 double fraction = (double)i * (1.0 / (
double)segmentCount);
8691 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8692 gcDist * fraction, gcBearing,
8693 &gcCoord.x, &gcCoord.y, NULL);
8695 if (i < segmentCount) {
8696 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8698 gcPoint->SetNameShown(
false);
8700 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8702 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8705 gcPoint = pMousePoint;
8708 m_pMouseRoute->AddPoint(gcPoint);
8709 pSelect->AddSelectableRouteSegment(
8710 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8711 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8712 prevGcPoint = gcPoint;
8715 undo->CancelUndoableAction(
true);
8718 m_pMouseRoute->AddPoint(pMousePoint);
8719 pSelect->AddSelectableRouteSegment(
8720 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8721 pMousePoint, m_pMouseRoute);
8722 undo->AfterUndoableAction(m_pMouseRoute);
8726 m_pMouseRoute->AddPoint(pMousePoint);
8727 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8728 rlon, m_prev_pMousePoint,
8729 pMousePoint, m_pMouseRoute);
8730 undo->AfterUndoableAction(m_pMouseRoute);
8736 m_prev_pMousePoint = pMousePoint;
8744 int connect = tail->GetIndexOf(pMousePoint);
8749 int length = tail->GetnPoints();
8754 start = connect + 1;
8759 m_pMouseRoute->RemovePoint(
8763 for (i = start; i <= stop; i++) {
8764 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8767 m_pMouseRoute->GetnPoints();
8769 gFrame->RefreshAllCanvas();
8773 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8775 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8776 m_pMouseRoute->FinalizeForRendering();
8778 gFrame->RefreshAllCanvas();
8782 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8784 SetCursor(*pCursorPencil);
8786 if (!m_pMeasureRoute) {
8787 m_pMeasureRoute =
new Route();
8791 if (m_nMeasureState == 1) {
8798 wxEmptyString, wxEmptyString);
8800 pMousePoint->SetShowWaypointRangeRings(
false);
8802 m_pMeasureRoute->AddPoint(pMousePoint);
8806 m_prev_pMousePoint = pMousePoint;
8810 gFrame->RefreshAllCanvas();
8815 FindRoutePointsAtCursor(SelectRadius,
true);
8819 m_last_touch_down_pos =
event.GetPosition();
8821 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8829 if (ret)
return true;
8832 if (event.Dragging()) {
8835 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8837 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8839 SelectableItemList SelList =
pSelect->FindSelectionList(
8843 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8848 if (m_pRoutePointEditTarget &&
8849 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8851 SelectableItemList SelList =
pSelect->FindSelectionList(
8855 if (m_pRoutePointEditTarget == frp) {
8856 m_bIsInRadius =
true;
8861 if (!m_dragoffsetSet) {
8863 .PresetDragOffset(
this, mouse_x, mouse_y);
8864 m_dragoffsetSet =
true;
8869 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8870 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8873 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8875 DraggingAllowed =
false;
8877 if (m_pRoutePointEditTarget &&
8878 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8879 DraggingAllowed =
false;
8881 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8883 if (DraggingAllowed) {
8884 if (!undo->InUndoableAction()) {
8885 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8886 Undo_NeedsCopy, m_pFoundPoint);
8892 if (!g_bopengl && m_pEditRouteArray) {
8893 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8894 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8901 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8902 pre_rect.Union(route_rect);
8910 if (CheckEdgePan(x, y,
true, 5, 2))
8918 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8920 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8921 m_pRoutePointEditTarget,
8922 SELTYPE_DRAGHANDLE);
8923 m_pFoundPoint->m_slat =
8924 m_pRoutePointEditTarget->m_lat;
8925 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8927 m_pRoutePointEditTarget->m_lat =
8929 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8930 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8931 m_pFoundPoint->m_slat =
8933 m_pFoundPoint->m_slon = new_cursor_lon;
8949 if (m_pEditRouteArray) {
8950 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8952 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8955 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8956 post_rect.Union(route_rect);
8962 pre_rect.Union(post_rect);
8963 RefreshRect(pre_rect,
false);
8965 gFrame->RefreshCanvasOther(
this);
8966 m_bRoutePoinDragging =
true;
8971 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8972 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8975 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8977 DraggingAllowed =
false;
8979 if (m_pRoutePointEditTarget &&
8980 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8981 DraggingAllowed =
false;
8983 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8985 if (DraggingAllowed) {
8986 if (!undo->InUndoableAction()) {
8987 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8988 Undo_NeedsCopy, m_pFoundPoint);
9002 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9008 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9009 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9010 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9011 (
int)(lppmax - (pre_rect.height / 2)));
9019 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9022 m_pRoutePointEditTarget,
9023 SELTYPE_DRAGHANDLE);
9024 m_pFoundPoint->m_slat =
9025 m_pRoutePointEditTarget->m_lat;
9026 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9028 m_pRoutePointEditTarget->m_lat =
9031 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9044 if (!g_btouch) InvalidateGL();
9050 .CalculateDCRect(m_dc_route,
this, &post_rect);
9051 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9052 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9053 (
int)(lppmax - (post_rect.height / 2)));
9056 pre_rect.Union(post_rect);
9057 RefreshRect(pre_rect,
false);
9059 gFrame->RefreshCanvasOther(
this);
9060 m_bRoutePoinDragging =
true;
9062 ret = g_btouch ? m_bRoutePoinDragging :
true;
9065 if (ret)
return true;
9068 if (event.LeftUp()) {
9069 bool b_startedit_route =
false;
9070 m_dragoffsetSet =
false;
9073 m_bChartDragging =
false;
9074 m_bIsInRadius =
false;
9078 if (m_ignore_next_leftup) {
9079 m_ignore_next_leftup =
false;
9084 m_bedge_pan =
false;
9089 bool appending =
false;
9090 bool inserting =
false;
9096 if (m_pRoutePointEditTarget) {
9102 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9103 RefreshRect(wp_rect,
true);
9105 m_pRoutePointEditTarget = NULL;
9107 m_bRouteEditing =
true;
9109 if (m_routeState == 1) {
9110 m_pMouseRoute =
new Route();
9111 m_pMouseRoute->SetHiLite(50);
9115 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9122 double nearby_radius_meters =
9123 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9126 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9127 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9128 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9131 m_FinishRouteOnKillFocus =
9133 dlg_return = OCPNMessageBox(
9134 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9135 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9136 m_FinishRouteOnKillFocus =
true;
9138 dlg_return = wxID_YES;
9140 if (dlg_return == wxID_YES) {
9141 pMousePoint = pNearbyPoint;
9144 if (m_routeState > 1)
9145 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9146 Undo_HasParent, NULL);
9147 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9149 bool procede =
false;
9153 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9159 m_FinishRouteOnKillFocus =
false;
9160 if (m_routeState == 1) {
9164 _(
"Insert first part of this route in the new route?");
9165 if (tail->GetIndexOf(pMousePoint) ==
9168 dmsg = _(
"Insert this route in the new route?");
9170 if (tail->GetIndexOf(pMousePoint) != 1) {
9172 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9173 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9174 m_FinishRouteOnKillFocus =
true;
9176 if (dlg_return == wxID_YES) {
9183 _(
"Append last part of this route to the new route?");
9184 if (tail->GetIndexOf(pMousePoint) == 1)
9186 "Append this route to the new route?");
9190 if (tail->GetLastPoint() != pMousePoint) {
9192 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9193 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9194 m_FinishRouteOnKillFocus =
true;
9196 if (dlg_return == wxID_YES) {
9207 if (!FindRouteContainingWaypoint(pMousePoint))
9208 pMousePoint->SetShared(
true);
9212 if (NULL == pMousePoint) {
9213 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9215 pMousePoint->SetNameShown(
false);
9217 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9219 if (m_routeState > 1)
9220 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9221 Undo_IsOrphanded, NULL);
9224 if (m_routeState == 1) {
9226 m_pMouseRoute->AddPoint(pMousePoint);
9227 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9231 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9232 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9233 &rhumbBearing, &rhumbDist);
9234 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9235 &gcDist, &gcBearing, NULL);
9236 double gcDistNM = gcDist / 1852.0;
9239 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9240 pow(rhumbDist - gcDistNM - 1, 0.5);
9243 msg << _(
"For this leg the Great Circle route is ")
9245 << _(
" shorter than rhumbline.\n\n")
9246 << _(
"Would you like include the Great Circle routing points "
9250 m_FinishRouteOnKillFocus =
false;
9251 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9252 wxYES_NO | wxNO_DEFAULT);
9253 m_FinishRouteOnKillFocus =
true;
9255 int answer = wxID_NO;
9258 if (answer == wxID_YES) {
9260 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9261 wxRealPoint gcCoord;
9263 for (
int i = 1; i <= segmentCount; i++) {
9264 double fraction = (double)i * (1.0 / (
double)segmentCount);
9265 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9266 gcDist * fraction, gcBearing,
9267 &gcCoord.x, &gcCoord.y, NULL);
9269 if (i < segmentCount) {
9270 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9272 gcPoint->SetNameShown(
false);
9273 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9276 gcPoint = pMousePoint;
9279 m_pMouseRoute->AddPoint(gcPoint);
9280 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9282 pSelect->AddSelectableRouteSegment(
9283 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9284 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9285 prevGcPoint = gcPoint;
9288 undo->CancelUndoableAction(
true);
9291 m_pMouseRoute->AddPoint(pMousePoint);
9292 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9293 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9294 rlon, m_prev_pMousePoint,
9295 pMousePoint, m_pMouseRoute);
9296 undo->AfterUndoableAction(m_pMouseRoute);
9300 m_pMouseRoute->AddPoint(pMousePoint);
9301 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9303 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9304 rlon, m_prev_pMousePoint,
9305 pMousePoint, m_pMouseRoute);
9306 undo->AfterUndoableAction(m_pMouseRoute);
9312 m_prev_pMousePoint = pMousePoint;
9319 int connect = tail->GetIndexOf(pMousePoint);
9324 int length = tail->GetnPoints();
9329 start = connect + 1;
9334 m_pMouseRoute->RemovePoint(
9338 for (i = start; i <= stop; i++) {
9339 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9342 m_pMouseRoute->GetnPoints();
9344 gFrame->RefreshAllCanvas();
9348 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9350 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9351 m_pMouseRoute->FinalizeForRendering();
9356 }
else if (m_bMeasure_Active && m_nMeasureState)
9359 m_bedge_pan =
false;
9363 if (m_ignore_next_leftup) {
9364 m_ignore_next_leftup =
false;
9368 if (m_nMeasureState == 1) {
9369 m_pMeasureRoute =
new Route();
9375 if (m_pMeasureRoute) {
9378 wxEmptyString, wxEmptyString);
9381 m_pMeasureRoute->AddPoint(pMousePoint);
9385 m_prev_pMousePoint = pMousePoint;
9387 m_pMeasureRoute->GetnPoints();
9391 CancelMeasureRoute();
9397 bool bSelectAllowed =
true;
9399 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9401 bSelectAllowed =
false;
9405 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9406 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9407 significant_drag) ||
9408 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9409 significant_drag)) {
9410 bSelectAllowed =
false;
9418 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9420 if (bSelectAllowed) {
9421 bool b_was_editing_mark = m_bMarkEditing;
9422 bool b_was_editing_route = m_bRouteEditing;
9423 FindRoutePointsAtCursor(SelectRadius,
9429 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9430 m_pRoutePointEditTarget = NULL;
9432 if (!b_was_editing_route) {
9433 if (m_pEditRouteArray) {
9434 b_startedit_route =
true;
9438 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9439 m_pTrackRolloverWin->IsActive(
false);
9441 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9442 m_pRouteRolloverWin->IsActive(
false);
9446 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9448 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9456 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9457 pre_rect.Union(route_rect);
9460 RefreshRect(pre_rect,
true);
9463 b_startedit_route =
false;
9467 if (m_pRoutePointEditTarget) {
9468 if (b_was_editing_mark ||
9469 b_was_editing_route) {
9470 if (m_lastRoutePointEditTarget) {
9474 .EnableDragHandle(
false);
9475 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9476 SELTYPE_DRAGHANDLE);
9480 if (m_pRoutePointEditTarget) {
9483 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9484 wxPoint2DDouble dragHandlePoint =
9486 .GetDragHandlePoint(
this);
9488 dragHandlePoint.m_y, dragHandlePoint.m_x,
9489 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9492 if (m_lastRoutePointEditTarget) {
9496 .EnableDragHandle(
false);
9497 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9498 SELTYPE_DRAGHANDLE);
9501 wxArrayPtrVoid *lastEditRouteArray =
9503 m_lastRoutePointEditTarget);
9504 if (lastEditRouteArray) {
9505 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9507 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9512 delete lastEditRouteArray;
9523 if (m_lastRoutePointEditTarget) {
9526 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9527 RefreshRect(wp_rect,
true);
9530 if (m_pRoutePointEditTarget) {
9533 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9534 RefreshRect(wp_rect,
true);
9542 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9543 bool b_start_rollover =
false;
9547 if (pFind) b_start_rollover =
true;
9550 if (!b_start_rollover && !b_startedit_route) {
9551 SelectableItemList SelList =
pSelect->FindSelectionList(
9555 if (pr && pr->IsVisible()) {
9556 b_start_rollover =
true;
9562 if (!b_start_rollover && !b_startedit_route) {
9563 SelectableItemList SelList =
pSelect->FindSelectionList(
9567 if (tr && tr->IsVisible()) {
9568 b_start_rollover =
true;
9574 if (b_start_rollover)
9575 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9579 bool appending =
false;
9580 bool inserting =
false;
9582 if (m_bRouteEditing ) {
9584 if (m_pRoutePointEditTarget) {
9590 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9591 double nearby_radius_meters =
9592 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9593 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9594 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9595 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9597 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9601 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9603 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9607 std::find(list->begin(), list->end(), pNearbyPoint);
9608 if (pos != list->end()) {
9620 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9625 OCPNMessageBox(
this,
9626 _(
"Replace this RoutePoint by the nearby "
9628 _(
"OpenCPN RoutePoint change"),
9629 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9630 if (dlg_return == wxID_YES) {
9635 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9638 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9640 if (tail && current && (tail != current)) {
9642 connect = tail->GetIndexOf(pNearbyPoint);
9643 int index_current_route =
9644 current->GetIndexOf(m_pRoutePointEditTarget);
9645 index_last = current->GetIndexOf(current->GetLastPoint());
9646 dlg_return1 = wxID_NO;
9648 index_current_route) {
9650 if (connect != tail->GetnPoints()) {
9653 _(
"Last part of route to be appended to dragged "
9657 _(
"Full route to be appended to dragged route?");
9659 dlg_return1 = OCPNMessageBox(
9660 this, dmsg, _(
"OpenCPN Route Create"),
9661 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9662 if (dlg_return1 == wxID_YES) {
9666 }
else if (index_current_route ==
9671 _(
"First part of route to be inserted into dragged "
9673 if (connect == tail->GetnPoints())
9675 "Full route to be inserted into dragged route?");
9677 dlg_return1 = OCPNMessageBox(
9678 this, dmsg, _(
"OpenCPN Route Create"),
9679 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9680 if (dlg_return1 == wxID_YES) {
9687 if (m_pRoutePointEditTarget->IsShared()) {
9689 dlg_return = OCPNMessageBox(
9691 _(
"Do you really want to delete and replace this "
9693 "\n" + _(
"which has been created manually?"),
9694 (
"OpenCPN RoutePoint warning"),
9695 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9698 if (dlg_return == wxID_YES) {
9699 pMousePoint = pNearbyPoint;
9701 pMousePoint->SetShared(
true);
9711 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9713 if (m_pEditRouteArray) {
9714 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9716 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9721 auto pos = std::find(list->begin(), list->end(),
9722 m_pRoutePointEditTarget);
9724 pSelect->DeleteAllSelectableRoutePoints(pr);
9725 pSelect->DeleteAllSelectableRouteSegments(pr);
9728 pos = std::find(list->begin(), list->end(),
9729 m_pRoutePointEditTarget);
9732 pSelect->AddAllSelectableRouteSegments(pr);
9733 pSelect->AddAllSelectableRoutePoints(pr);
9735 pr->FinalizeForRendering();
9736 pr->UpdateSegmentDistances();
9737 if (m_bRoutePoinDragging) {
9739 NavObj_dB::GetInstance().UpdateRoute(pr);
9747 if (m_pEditRouteArray) {
9748 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9750 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9769 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9776 delete m_pRoutePointEditTarget;
9777 m_lastRoutePointEditTarget = NULL;
9778 m_pRoutePointEditTarget = NULL;
9779 undo->AfterUndoableAction(pMousePoint);
9780 undo->InvalidateUndo();
9785 else if (m_bMarkEditing) {
9786 if (m_pRoutePointEditTarget)
9787 if (m_bRoutePoinDragging) {
9789 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9793 if (m_pRoutePointEditTarget)
9794 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9796 if (!m_pRoutePointEditTarget) {
9797 delete m_pEditRouteArray;
9798 m_pEditRouteArray = NULL;
9799 m_bRouteEditing =
false;
9801 m_bRoutePoinDragging =
false;
9808 int length = tail->GetnPoints();
9809 for (
int i = connect + 1; i <= length; i++) {
9810 current->AddPointAndSegment(tail->GetPoint(i),
false);
9813 gFrame->RefreshAllCanvas();
9816 current->FinalizeForRendering();
9822 pSelect->DeleteAllSelectableRoutePoints(current);
9823 pSelect->DeleteAllSelectableRouteSegments(current);
9824 for (
int i = 1; i < connect; i++) {
9825 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9827 pSelect->AddAllSelectableRouteSegments(current);
9828 pSelect->AddAllSelectableRoutePoints(current);
9829 current->FinalizeForRendering();
9836 if (m_pEditRouteArray) {
9837 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9838 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9851 if (m_bRouteEditing) {
9854 bool appending =
false;
9855 bool inserting =
false;
9858 if (m_pRoutePointEditTarget) {
9859 m_pRoutePointEditTarget->
m_bBlink =
false;
9863 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9864 double nearby_radius_meters =
9865 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9866 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9867 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9868 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9870 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9871 bool duplicate =
false;
9873 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9875 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9879 std::find(list->begin(), list->end(), pNearbyPoint);
9880 if (pos != list->end()) {
9892 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9897 OCPNMessageBox(
this,
9898 _(
"Replace this RoutePoint by the nearby "
9900 _(
"OpenCPN RoutePoint change"),
9901 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9902 if (dlg_return == wxID_YES) {
9906 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9909 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9911 if (tail && current && (tail != current)) {
9913 connect = tail->GetIndexOf(pNearbyPoint);
9914 int index_current_route =
9915 current->GetIndexOf(m_pRoutePointEditTarget);
9916 index_last = current->GetIndexOf(current->GetLastPoint());
9917 dlg_return1 = wxID_NO;
9919 index_current_route) {
9921 if (connect != tail->GetnPoints()) {
9924 _(
"Last part of route to be appended to dragged "
9928 _(
"Full route to be appended to dragged route?");
9930 dlg_return1 = OCPNMessageBox(
9931 this, dmsg, _(
"OpenCPN Route Create"),
9932 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9933 if (dlg_return1 == wxID_YES) {
9937 }
else if (index_current_route ==
9942 _(
"First part of route to be inserted into dragged "
9944 if (connect == tail->GetnPoints())
9946 "Full route to be inserted into dragged route?");
9948 dlg_return1 = OCPNMessageBox(
9949 this, dmsg, _(
"OpenCPN Route Create"),
9950 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9951 if (dlg_return1 == wxID_YES) {
9958 if (m_pRoutePointEditTarget->IsShared()) {
9959 dlg_return = wxID_NO;
9960 dlg_return = OCPNMessageBox(
9962 _(
"Do you really want to delete and replace this "
9964 "\n" + _(
"which has been created manually?"),
9965 (
"OpenCPN RoutePoint warning"),
9966 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9969 if (dlg_return == wxID_YES) {
9970 pMousePoint = pNearbyPoint;
9972 pMousePoint->SetShared(
true);
9982 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9984 if (m_pEditRouteArray) {
9985 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9987 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9991 auto pos = std::find(list->begin(), list->end(),
9992 m_pRoutePointEditTarget);
9994 pSelect->DeleteAllSelectableRoutePoints(pr);
9995 pSelect->DeleteAllSelectableRouteSegments(pr);
9998 pos = std::find(list->begin(), list->end(),
9999 m_pRoutePointEditTarget);
10000 if (pos != list->end()) list->erase(pos);
10003 pSelect->AddAllSelectableRouteSegments(pr);
10004 pSelect->AddAllSelectableRoutePoints(pr);
10006 pr->FinalizeForRendering();
10007 pr->UpdateSegmentDistances();
10010 if (m_bRoutePoinDragging) {
10015 NavObj_dB::GetInstance().UpdateRoutePoint(
10016 m_pRoutePointEditTarget);
10018 NavObj_dB::GetInstance().UpdateRoute(pr);
10030 int length = tail->GetnPoints();
10031 for (
int i = connect + 1; i <= length; i++) {
10032 current->AddPointAndSegment(tail->GetPoint(i),
false);
10036 gFrame->RefreshAllCanvas();
10039 current->FinalizeForRendering();
10045 pSelect->DeleteAllSelectableRoutePoints(current);
10046 pSelect->DeleteAllSelectableRouteSegments(current);
10047 for (
int i = 1; i < connect; i++) {
10048 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10050 pSelect->AddAllSelectableRouteSegments(current);
10051 pSelect->AddAllSelectableRoutePoints(current);
10052 current->FinalizeForRendering();
10059 if (m_pEditRouteArray) {
10060 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10062 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10074 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10081 delete m_pRoutePointEditTarget;
10082 m_lastRoutePointEditTarget = NULL;
10083 undo->AfterUndoableAction(pMousePoint);
10084 undo->InvalidateUndo();
10089 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10092 delete m_pEditRouteArray;
10093 m_pEditRouteArray = NULL;
10097 m_bRouteEditing =
false;
10098 m_pRoutePointEditTarget = NULL;
10104 else if (m_bMarkEditing) {
10105 if (m_pRoutePointEditTarget) {
10106 if (m_bRoutePoinDragging) {
10108 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10110 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10115 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10117 RefreshRect(wp_rect,
true);
10120 m_pRoutePointEditTarget = NULL;
10121 m_bMarkEditing =
false;
10126 else if (leftIsDown) {
10127 leftIsDown =
false;
10131 if (!m_bChartDragging && !m_bMeasure_Active) {
10133 m_bChartDragging =
false;
10137 m_bRoutePoinDragging =
false;
10140 if (ret)
return true;
10143 if (event.RightDown()) {
10154 m_FinishRouteOnKillFocus =
false;
10155 CallPopupMenu(mx, my);
10156 m_FinishRouteOnKillFocus =
true;
10166 if (event.ShiftDown()) {
10170 event.GetPosition(&x, &y);
10172 x *= m_displayScale;
10173 y *= m_displayScale;
10179 int wheel_dir =
event.GetWheelRotation();
10182 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10183 wheel_dir = wheel_dir > 0 ? 1 : -1;
10185 double factor = g_mouse_zoom_sensitivity;
10186 if (wheel_dir < 0) factor = 1 / factor;
10189 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10190 if (wheel_dir == m_last_wheel_dir) {
10191 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10196 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10197 m_wheelstopwatch.Start(0);
10202 m_last_wheel_dir = wheel_dir;
10207 if (event.LeftDown()) {
10213 last_drag.x = x, last_drag.y = y;
10214 panleftIsDown =
true;
10217 if (event.LeftUp()) {
10218 if (panleftIsDown) {
10220 panleftIsDown =
false;
10223 if (!m_bChartDragging && !m_bMeasure_Active) {
10224 switch (cursor_region) {
10246 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10251 m_bChartDragging =
false;
10257 if (event.Dragging() && event.LeftIsDown()) {
10273 if (g_btouch && !m_inPinch) {
10274 struct timespec now;
10275 clock_gettime(CLOCK_MONOTONIC, &now);
10276 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10278 bool trigger_hold =
false;
10279 if (
false == m_bChartDragging) {
10280 if (m_DragTrigger < 0) {
10283 m_DragTriggerStartTime = tnow;
10284 trigger_hold =
true;
10286 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10287 m_DragTrigger = -1;
10292 if (trigger_hold)
return true;
10294 if (
false == m_bChartDragging) {
10297 last_drag.x = x - 1, last_drag.y = y - 1;
10298 m_bChartDragging =
true;
10299 m_chart_drag_total_time = 0;
10300 m_chart_drag_total_x = 0;
10301 m_chart_drag_total_y = 0;
10302 m_inertia_last_drag_x = x;
10303 m_inertia_last_drag_y = y;
10304 m_drag_vec_x.clear();
10305 m_drag_vec_y.clear();
10306 m_drag_vec_t.clear();
10307 m_last_drag_time = tnow;
10311 uint64_t delta_t = tnow - m_last_drag_time;
10312 double delta_tf = delta_t / 1e9;
10314 m_chart_drag_total_time += delta_tf;
10315 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10316 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10318 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10319 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10320 m_drag_vec_t.push_back(delta_tf);
10322 m_inertia_last_drag_x = x;
10323 m_inertia_last_drag_y = y;
10324 m_last_drag_time = tnow;
10326 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10327 m_bChartDragging =
true;
10328 StartTimedMovement();
10329 m_pan_drag.x += last_drag.x - x;
10330 m_pan_drag.y += last_drag.y - y;
10331 last_drag.x = x, last_drag.y = y;
10333 }
else if (!g_btouch) {
10334 if ((last_drag.x != x) || (last_drag.y != y)) {
10335 if (!m_routeState) {
10338 m_bChartDragging =
true;
10339 StartTimedMovement();
10340 m_pan_drag.x += last_drag.x - x;
10341 m_pan_drag.y += last_drag.y - y;
10342 last_drag.x = x, last_drag.y = y;
10349 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10351 m_ignore_next_leftup =
true;
10352 m_DoubleClickTimer->Start();
10353 singleClickEventIsValid =
false;
10361void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10362 if (MouseEventOverlayWindows(event))
return;
10366 bool nm = MouseEventProcessObjects(event);
10370void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10373 wxCursor *ptarget_cursor = pCursorArrow;
10374 if (!pPlugIn_Cursor) {
10375 ptarget_cursor = pCursorArrow;
10376 if ((!m_routeState) &&
10377 (!m_bMeasure_Active) ) {
10378 if (cursor_region == MID_RIGHT) {
10379 ptarget_cursor = pCursorRight;
10380 }
else if (cursor_region == MID_LEFT) {
10381 ptarget_cursor = pCursorLeft;
10382 }
else if (cursor_region == MID_TOP) {
10383 ptarget_cursor = pCursorDown;
10384 }
else if (cursor_region == MID_BOT) {
10385 ptarget_cursor = pCursorUp;
10387 ptarget_cursor = pCursorArrow;
10389 }
else if (m_bMeasure_Active ||
10391 ptarget_cursor = pCursorPencil;
10393 ptarget_cursor = pPlugIn_Cursor;
10396 SetCursor(*ptarget_cursor);
10399void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10400 SetCursor(*pCursorArrow);
10403void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10407 wxArrayString files;
10409 ChartBase *target_chart = GetChartAtCursor();
10410 if (target_chart) {
10411 file.Assign(target_chart->GetFullPath());
10412 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10413 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10416 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10418 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10419 unsigned int im = stackIndexArray.size();
10420 int scale = 2147483647;
10421 if (VPoint.b_quilt && im > 0) {
10422 for (
unsigned int is = 0; is < im; is++) {
10423 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10424 CHART_TYPE_MBTILES) {
10425 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10427 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10428 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10430 .Contains(lat, lon)) {
10431 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10434 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10435 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10443 std::vector<Ais8_001_22 *> area_notices;
10445 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10448 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10449 auto target_data = target.second;
10450 if (!target_data->area_notices.empty()) {
10451 for (
auto &ani : target_data->area_notices) {
10456 for (Ais8_001_22_SubAreaList::iterator sa =
10457 area_notice.sub_areas.begin();
10458 sa != area_notice.sub_areas.end(); ++sa) {
10459 switch (sa->shape) {
10460 case AIS8_001_22_SHAPE_CIRCLE: {
10461 wxPoint target_point;
10463 bbox.Expand(target_point);
10464 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10467 case AIS8_001_22_SHAPE_RECT: {
10468 wxPoint target_point;
10470 bbox.Expand(target_point);
10471 if (sa->e_dim_m > sa->n_dim_m)
10472 bbox.EnLarge(sa->e_dim_m * vp_scale);
10474 bbox.EnLarge(sa->n_dim_m * vp_scale);
10477 case AIS8_001_22_SHAPE_POLYGON:
10478 case AIS8_001_22_SHAPE_POLYLINE: {
10479 for (
int i = 0; i < 4; ++i) {
10480 double lat = sa->latitude;
10481 double lon = sa->longitude;
10482 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10484 wxPoint target_point;
10486 bbox.Expand(target_point);
10490 case AIS8_001_22_SHAPE_SECTOR: {
10491 double lat1 = sa->latitude;
10492 double lon1 = sa->longitude;
10494 wxPoint target_point;
10496 bbox.Expand(target_point);
10497 for (
int i = 0; i < 18; ++i) {
10500 sa->left_bound_deg +
10501 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10502 sa->radius_m / 1852.0, &lat, &lon);
10504 bbox.Expand(target_point);
10506 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10509 bbox.Expand(target_point);
10515 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10516 area_notices.push_back(&area_notice);
10523 if (target_chart || !area_notices.empty() || file.HasName()) {
10525 int sel_rad_pix = 5;
10526 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10531 SetCursor(wxCURSOR_WAIT);
10532 bool lightsVis = m_encShowLights;
10533 if (!lightsVis) SetShowENCLights(
true);
10536 ListOfObjRazRules *rule_list = NULL;
10537 ListOfPI_S57Obj *pi_rule_list = NULL;
10540 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10541 else if (target_plugin_chart)
10542 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10543 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10545 ListOfObjRazRules *overlay_rule_list = NULL;
10546 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10549 if (CHs57_Overlay) {
10550 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10551 zlat, zlon, SelectRadius, &GetVP());
10554 if (!lightsVis) SetShowENCLights(
false);
10557 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10558 wxString face = dFont->GetFaceName();
10562 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10563 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10567 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10575 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10576 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10579 int points = dFont->GetPointSize();
10581 int points = dFont->GetPointSize() + 1;
10585 for (
int i = -2; i < 5; i++) {
10586 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10590 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10592 if (overlay_rule_list && CHs57_Overlay) {
10593 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10594 objText <<
"<hr noshade>";
10597 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10598 an != area_notices.end(); ++an) {
10599 objText <<
"<b>AIS Area Notice:</b> ";
10600 objText << ais8_001_22_notice_names[(*an)->notice_type];
10601 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10602 (*an)->sub_areas.begin();
10603 sa != (*an)->sub_areas.end(); ++sa)
10604 if (!sa->text.empty()) objText << sa->text;
10605 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10606 objText <<
"<hr noshade>";
10610 objText << Chs57->CreateObjDescriptions(rule_list);
10611 else if (target_plugin_chart)
10612 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10615 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10618 wxString AddFiles, filenameOK;
10620 if (!target_plugin_chart) {
10623 AddFiles = wxString::Format(
10624 "<hr noshade><br><b>Additional info files attached to: </b> "
10626 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10628 file.GetFullName());
10630 file.Assign(file.GetPath(),
"");
10631 wxDir dir(file.GetFullPath());
10633 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10635 file.Assign(dir.GetNameWithSep().append(filename));
10636 wxString FormatString =
10637 "<td valign=top><font size=-2><a "
10638 "href=\"%s\">%s</a></font></td>";
10639 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10640 filenameOK = file.GetFullPath();
10642 if (3 * ((
int)filecount / 3) == filecount)
10643 FormatString.Prepend(
"<tr>");
10645 FormatString.Prepend(
10646 "<td>  </td>");
10649 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10650 file.GetFullName());
10653 cont = dir.GetNext(&filename);
10655 objText << AddFiles <<
"</table>";
10657 objText <<
"</font>";
10658 objText <<
"</body></html>";
10660 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10664 if ((!Chs57 && filecount == 1)) {
10666 wxHtmlLinkInfo hli(filenameOK);
10667 wxHtmlLinkEvent hle(1, hli);
10671 if (rule_list) rule_list->Clear();
10674 if (overlay_rule_list) overlay_rule_list->Clear();
10675 delete overlay_rule_list;
10677 if (pi_rule_list) pi_rule_list->Clear();
10678 delete pi_rule_list;
10680 SetCursor(wxCURSOR_ARROW);
10684void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10693 wxSize canvas_size = GetSize();
10700 wxPoint canvas_pos = GetPosition();
10703 bool newFit =
false;
10704 if (canvas_size.x < fitted_size.x) {
10705 fitted_size.x = canvas_size.x - 40;
10706 if (canvas_size.y < fitted_size.y)
10707 fitted_size.y -= 40;
10709 if (canvas_size.y < fitted_size.y) {
10710 fitted_size.y = canvas_size.y - 40;
10711 if (canvas_size.x < fitted_size.x)
10712 fitted_size.x -= 40;
10723 wxString title_base = _(
"Mark Properties");
10725 title_base = _(
"Waypoint Properties");
10730 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10742void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10752 if (g_bresponsive) {
10753 wxSize canvas_size = GetSize();
10754 wxPoint canvas_pos = GetPosition();
10758 if (canvas_size.x < fitted_size.x) {
10759 fitted_size.x = canvas_size.x;
10760 if (canvas_size.y < fitted_size.y)
10761 fitted_size.y -= 20;
10763 if (canvas_size.y < fitted_size.y) {
10764 fitted_size.y = canvas_size.y;
10765 if (canvas_size.x < fitted_size.x)
10766 fitted_size.x -= 20;
10775 wxPoint xxp = ClientToScreen(canvas_pos);
10786void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10798void pupHandler_PasteWaypoint() {
10801 int pasteBuffer = kml.ParsePasteBuffer();
10802 RoutePoint *pasted = kml.GetParsedRoutePoint();
10803 if (!pasted)
return;
10805 double nearby_radius_meters =
10806 g_Platform->GetSelectRadiusPix() /
10807 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10809 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10810 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10812 int answer = wxID_NO;
10816 "There is an existing waypoint at the same location as the one you are "
10817 "pasting. Would you like to merge the pasted data with it?\n\n");
10818 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10819 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10820 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10823 if (answer == wxID_YES) {
10824 nearPoint->SetName(pasted->GetName());
10826 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10827 pRouteManagerDialog->UpdateWptListCtrl();
10830 if (answer == wxID_NO) {
10833 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10836 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10839 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10840 pRouteManagerDialog->UpdateWptListCtrl();
10845 gFrame->InvalidateAllGL();
10846 gFrame->RefreshAllCanvas(
false);
10849void pupHandler_PasteRoute() {
10852 int pasteBuffer = kml.ParsePasteBuffer();
10853 Route *pasted = kml.GetParsedRoute();
10854 if (!pasted)
return;
10856 double nearby_radius_meters =
10857 g_Platform->GetSelectRadiusPix() /
10858 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10864 bool mergepoints =
false;
10865 bool createNewRoute =
true;
10866 int existingWaypointCounter = 0;
10868 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10869 curPoint = pasted->GetPoint(i);
10870 nearPoint = pWayPointMan->GetNearbyWaypoint(
10871 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10873 mergepoints =
true;
10874 existingWaypointCounter++;
10882 int answer = wxID_NO;
10886 "There are existing waypoints at the same location as some of the ones "
10887 "you are pasting. Would you like to just merge the pasted data into "
10889 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10890 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10891 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10893 if (answer == wxID_CANCEL) {
10900 if (mergepoints && answer == wxID_YES &&
10901 existingWaypointCounter == pasted->GetnPoints()) {
10904 createNewRoute =
false;
10910 Route *newRoute = 0;
10913 if (createNewRoute) {
10914 newRoute =
new Route();
10918 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10919 curPoint = pasted->GetPoint(i);
10922 newPoint = pWayPointMan->GetNearbyWaypoint(
10923 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10924 newPoint->SetName(curPoint->GetName());
10927 if (createNewRoute) newRoute->AddPoint(newPoint);
10933 newPoint->SetIconName(
"circle");
10936 newPoint->SetShared(
false);
10938 newRoute->AddPoint(newPoint);
10939 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10942 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10945 if (i > 1 && createNewRoute)
10946 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10947 curPoint->m_lat, curPoint->m_lon,
10948 prevPoint, newPoint, newRoute);
10949 prevPoint = newPoint;
10952 if (createNewRoute) {
10955 NavObj_dB::GetInstance().InsertRoute(newRoute);
10961 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10962 pRouteManagerDialog->UpdateRouteListCtrl();
10963 pRouteManagerDialog->UpdateWptListCtrl();
10965 gFrame->InvalidateAllGL();
10966 gFrame->RefreshAllCanvas(
false);
10972void pupHandler_PasteTrack() {
10975 int pasteBuffer = kml.ParsePasteBuffer();
10976 Track *pasted = kml.GetParsedTrack();
10977 if (!pasted)
return;
10985 newTrack->SetName(pasted->GetName());
10987 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10988 curPoint = pasted->GetPoint(i);
10992 wxDateTime now = wxDateTime::Now();
10995 newTrack->AddPoint(newPoint);
10998 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10999 newPoint->m_lat, newPoint->m_lon,
11000 prevPoint, newPoint, newTrack);
11002 prevPoint = newPoint;
11007 NavObj_dB::GetInstance().InsertTrack(newTrack);
11009 gFrame->InvalidateAllGL();
11010 gFrame->RefreshAllCanvas(
false);
11013bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11016 v[
"CursorPosition_x"] = x;
11017 v[
"CursorPosition_y"] = y;
11020 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11021 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11022 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11027 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11029 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11032#define SELTYPE_UNKNOWN 0x0001
11033#define SELTYPE_ROUTEPOINT 0x0002
11034#define SELTYPE_ROUTESEGMENT 0x0004
11035#define SELTYPE_TIDEPOINT 0x0008
11036#define SELTYPE_CURRENTPOINT 0x0010
11037#define SELTYPE_ROUTECREATE 0x0020
11038#define SELTYPE_AISTARGET 0x0040
11039#define SELTYPE_MARKPOINT 0x0080
11040#define SELTYPE_TRACKSEGMENT 0x0100
11041#define SELTYPE_DRAGHANDLE 0x0200
11044 if (g_bhide_context_menus)
return true;
11046 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11047 m_pIDXCandidate, m_nmea_log);
11050 wxEVT_COMMAND_MENU_SELECTED,
11051 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11057 if (m_inLongPress) {
11058 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11059 m_inLongPress =
false;
11063 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11066 wxEVT_COMMAND_MENU_SELECTED,
11067 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11069 delete m_canvasMenu;
11070 m_canvasMenu = NULL;
11080void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11083 if (m_canvasMenu) {
11084 m_canvasMenu->PopupMenuHandler(event);
11089void ChartCanvas::StartRoute() {
11091 if (g_brouteCreating)
return;
11095 g_brouteCreating =
true;
11097 m_bDrawingRoute =
false;
11098 SetCursor(*pCursorPencil);
11100 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11102 HideGlobalToolbar();
11105 androidSetRouteAnnunciator(
true);
11109wxString ChartCanvas::FinishRoute() {
11111 m_prev_pMousePoint = NULL;
11112 m_bDrawingRoute =
false;
11114 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11117 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11119 androidSetRouteAnnunciator(
false);
11122 SetCursor(*pCursorArrow);
11124 if (m_pMouseRoute) {
11125 if (m_bAppendingRoute) {
11127 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11129 if (m_pMouseRoute->GetnPoints() > 1) {
11131 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11134 m_pMouseRoute = NULL;
11137 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11144 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11145 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11146 pRouteManagerDialog->UpdateRouteListCtrl();
11149 m_bAppendingRoute =
false;
11150 m_pMouseRoute = NULL;
11152 m_pSelectedRoute = NULL;
11154 undo->InvalidateUndo();
11155 gFrame->RefreshAllCanvas(
true);
11159 ShowGlobalToolbar();
11161 g_brouteCreating =
false;
11166void ChartCanvas::HideGlobalToolbar() {
11167 if (m_canvasIndex == 0) {
11168 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11172void ChartCanvas::ShowGlobalToolbar() {
11173 if (m_canvasIndex == 0) {
11174 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11178void ChartCanvas::ShowAISTargetList() {
11179 if (NULL == g_pAISTargetList) {
11183 g_pAISTargetList->UpdateAISTargetList();
11186void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11187 if (!m_bShowOutlines)
return;
11191 int nEntry =
ChartData->GetChartTableEntries();
11193 for (
int i = 0; i < nEntry; i++) {
11197 bool b_group_draw =
false;
11198 if (m_groupIndex > 0) {
11199 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11200 int index = pt->GetGroupArray()[ig];
11201 if (m_groupIndex == index) {
11202 b_group_draw =
true;
11207 b_group_draw =
true;
11209 if (b_group_draw) RenderChartOutline(dc, i, vp);
11215 if (VPoint.b_quilt) {
11216 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11217 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11221 }
else if (m_singleChart &&
11222 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11226 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11229 if (zoom_factor > 8.0) {
11230 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11233 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11237 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11241void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11243 if (g_bopengl && m_glcc) {
11245 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11250 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11251 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11254 float plylat, plylon;
11255 float plylat1, plylon1;
11257 int pixx, pixy, pixx1, pixy1;
11260 ChartData->GetDBBoundingBox(dbIndex, box);
11264 if (box.GetLonRange() == 360)
return;
11266 double lon_bias = 0;
11268 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11270 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11272 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11273 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11275 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11276 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11279 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11282 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11283 if (0 == nAuxPlyEntries)
11287 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11288 plylon += lon_bias;
11294 for (
int i = 0; i < nPly - 1; i++) {
11295 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11296 plylon1 += lon_bias;
11302 int pixxs1 = pixx1;
11303 int pixys1 = pixy1;
11305 bool b_skip =
false;
11309 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11310 pow((
double)(pixy1 - pixy), 2)) /
11316 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11321 if (fabs(dist - distgc) > 10000. * 1852.)
11327 ClipResult res = cohen_sutherland_line_clip_i(
11329 if (res != Invisible && !b_skip)
11330 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11338 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11339 plylon1 += lon_bias;
11345 ClipResult res = cohen_sutherland_line_clip_i(
11347 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11354 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11355 for (
int j = 0; j < nAuxPlyEntries; j++) {
11357 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11362 for (
int i = 0; i < nAuxPly - 1; i++) {
11363 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11369 int pixxs1 = pixx1;
11370 int pixys1 = pixy1;
11372 bool b_skip =
false;
11376 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11377 ((pixy1 - pixy) * (pixy1 - pixy))) /
11382 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11387 if (fabs(dist - distgc) > 10000. * 1852.)
11393 ClipResult res = cohen_sutherland_line_clip_i(
11395 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11403 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11408 ClipResult res = cohen_sutherland_line_clip_i(
11410 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11415static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11416 const wxArrayString &legend) {
11417 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11419 int pointsize = dFont->GetPointSize();
11423 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11424 false, dFont->GetFaceName());
11426 dc.SetFont(*psRLI_font);
11433 int hilite_offset = 3;
11435 for (wxString line : legend) {
11438 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11440 dc.GetTextExtent(line, &wl, &hl);
11449 xp = ref_point.x - w;
11451 yp += hilite_offset;
11453 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11455 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11456 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11458 for (wxString line : legend) {
11459 dc.DrawText(line, xp, yp);
11464void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11465 if (!g_bAllowShipToActive)
return;
11471 wxPoint2DDouble pa, pb;
11478 if (rt->
m_width != wxPENSTYLE_INVALID)
11480 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11481 g_shipToActiveStyle, 5)];
11482 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11484 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11487 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11490 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11493 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11494 (
int)pb.m_y, GetVP(),
true);
11498#ifdef USE_ANDROID_GLES2
11499 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11501 if (style != wxPENSTYLE_SOLID) {
11502 if (glChartCanvas::dash_map.find(style) !=
11503 glChartCanvas::dash_map.end()) {
11504 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11508 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11511 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11512 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11518void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11520 if (m_routeState >= 2) route = m_pMouseRoute;
11521 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11522 route = m_pMeasureRoute;
11524 if (!route)
return;
11532 int np = route->GetnPoints();
11534 if (g_btouch && (np > 1)) np--;
11536 render_lat = rp.m_lat;
11537 render_lon = rp.m_lon;
11540 double rhumbBearing, rhumbDist;
11542 &rhumbBearing, &rhumbDist);
11543 double brg = rhumbBearing;
11544 double dist = rhumbDist;
11548 double gcBearing, gcBearing2, gcDist;
11549 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11552 double gcDistm = gcDist / 1852.0;
11555 rhumbBearing = 90.;
11557 wxPoint destPoint, lastPoint;
11560 int milesDiff = rhumbDist - gcDistm;
11561 if (milesDiff > 1) {
11572 for (
int i = 1; i <= milesDiff; i++) {
11573 double p = (double)i * (1.0 / (
double)milesDiff);
11575 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11576 &pLon, &pLat, &gcBearing2);
11578 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11580 lastPoint = destPoint;
11583 if (r_rband.x && r_rband.y) {
11584 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11586 if (m_bMeasure_DistCircle) {
11587 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11588 powf((
float)(r_rband.y - lastPoint.y), 2));
11591 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11592 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11598 wxString routeInfo;
11599 wxArrayString infoArray;
11602 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11608 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11610 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11611 (
int)varBrg, 0x00B0);
11614 infoArray.Add(routeInfo);
11620 routeInfo <<
"Reverse: ";
11622 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11623 (
int)(brg + 180.) % 360, 0x00B0);
11625 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11626 (
int)(varBrg + 180.) % 360, 0x00B0);
11627 infoArray.Add(routeInfo);
11633 s0.Append(_(
"Route") +
": ");
11635 s0.Append(_(
"Layer Route: "));
11638 if (!g_btouch) disp_length += dist;
11644 RouteLegInfo(dc, r_rband, infoArray);
11646 m_brepaint_piano =
true;
11649void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11650 if (!m_bShowVisibleSectors)
return;
11652 if (g_bDeferredInitDone) {
11654 double rhumbBearing, rhumbDist;
11655 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11656 &rhumbBearing, &rhumbDist);
11658 if (rhumbDist > 0.05)
11660 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11661 m_sectorlegsVisible);
11662 m_sector_glat =
gLat;
11663 m_sector_glon =
gLon;
11665 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11669void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11677void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11678 if (!ps52plib)
return;
11680 if (VPoint.b_quilt) {
11681 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11683 if (m_pQuilt->IsQuiltVector()) {
11684 if (ps52plib->GetStateHash() != m_s52StateHash) {
11686 m_s52StateHash = ps52plib->GetStateHash();
11690 if (ps52plib->GetStateHash() != m_s52StateHash) {
11692 m_s52StateHash = ps52plib->GetStateHash();
11697 bool bSendPlibState =
true;
11698 if (VPoint.b_quilt) {
11699 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11702 if (bSendPlibState) {
11704 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11705 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11706 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11707 v[
"OpenCPN Version Date"] = VERSION_DATE;
11708 v[
"OpenCPN Version Full"] = VERSION_FULL;
11711 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11712 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11713 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11714 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11715 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11716 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11717 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11721 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11722 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11726 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11727 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11728 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11729 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11730 ps52plib->m_bShowS57ImportantTextOnly;
11731 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11732 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11733 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11734 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11735 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11738 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11739 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11740 v[
"OpenCPN Scale Factor Exp"] =
11741 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11748 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11749 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11750 g_lastS52PLIBPluginMessage = out;
11757 wxPaintDC dc(
this);
11767 if (!m_b_paint_enable) {
11775 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11777 if (m_glcc && g_bopengl) {
11778 if (!s_in_update) {
11788 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11790 wxRegion ru = GetUpdateRegion();
11792 int rx, ry, rwidth, rheight;
11793 ru.GetBox(rx, ry, rwidth, rheight);
11795#ifdef ocpnUSE_DIBSECTION
11798 wxMemoryDC temp_dc;
11806 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11807 height += m_Piano->GetHeight();
11809 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11813 int thumbx, thumby, thumbsx, thumbsy;
11814 pthumbwin->GetPosition(&thumbx, &thumby);
11815 pthumbwin->GetSize(&thumbsx, &thumbsy);
11816 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11819 rgn_chart.Subtract(rgn_thumbwin);
11820 ru.Subtract(rgn_thumbwin);
11826 wxRegion rgn_blit = ru;
11827 if (g_bShowChartBar) {
11828 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11829 GetClientSize().x, m_Piano->GetHeight());
11832 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11833 if (style->chartStatusWindowTransparent)
11834 m_brepaint_piano =
true;
11836 ru.Subtract(chart_bar_rect);
11840 if (m_Compass && m_Compass->IsShown()) {
11841 wxRect compassRect = m_Compass->
GetRect();
11842 if (ru.Contains(compassRect) != wxOutRegion) {
11843 ru.Subtract(compassRect);
11847 if (m_notification_button) {
11848 wxRect noteRect = m_notification_button->
GetRect();
11849 if (ru.Contains(noteRect) != wxOutRegion) {
11850 ru.Subtract(noteRect);
11855 bool b_newview =
true;
11860 m_cache_vp.IsValid()) {
11866 bool b_rcache_ok =
false;
11867 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11868 b_rcache_ok = !b_newview;
11871 if (VPoint.b_MercatorProjectionOverride)
11872 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11886 if (b_rcache_ok) chart_get_region.Clear();
11889 if (VPoint.b_quilt)
11891 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11893 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11898 AbstractPlatform::ShowBusySpinner();
11902 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11903 (m_working_bm.GetHeight() != svp.
pix_height))
11907 if (fabs(VPoint.
rotation) < 0.01) {
11908 bool b_save =
true;
11913 m_cache_vp.Invalidate();
11927 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11932 int dy = c_new.y - c_old.y;
11933 int dx = c_new.x - c_old.x;
11938 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11942 temp_dc.SelectObject(m_working_bm);
11944 wxMemoryDC cache_dc;
11945 cache_dc.SelectObject(m_cached_chart_bm);
11949 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11952 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11958 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11961 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11969 update_region.Union(
11972 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11977 update_region.Union(
11980 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11984 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11986 cache_dc.SelectObject(wxNullBitmap);
11990 temp_dc.SelectObject(m_cached_chart_bm);
11993 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11997 temp_dc.SelectObject(m_working_bm);
11998 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12003 temp_dc.SelectObject(m_cached_chart_bm);
12008 temp_dc.SelectObject(m_working_bm);
12009 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12022 wxMemoryDC scratch_dc_0;
12023 scratch_dc_0.SelectObject(m_cached_chart_bm);
12026 scratch_dc_0.SelectObject(wxNullBitmap);
12035 temp_dc.SelectObject(m_working_bm);
12038 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12039 chart_get_all_region);
12042 AbstractPlatform::HideBusySpinner();
12048 if (!m_singleChart) {
12049 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12054 if (!chart_get_region.IsEmpty()) {
12055 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12059 if (temp_dc.IsOk()) {
12064 if (!VPoint.b_quilt) {
12067 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12068 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12075 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12076 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12079 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12081 temp_dc.DestroyClippingRegion();
12086 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12088 if (!backgroundRegion.IsEmpty()) {
12094 wxColour water = pWorldBackgroundChart->water;
12095 if (water.IsOk()) {
12096 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12097 temp_dc.SetBrush(wxBrush(water));
12099 while (upd.HaveRects()) {
12100 wxRect rect = upd.GetRect();
12101 temp_dc.DrawRectangle(rect);
12106 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12107 temp_dc.SetDeviceClippingRegion(*clip_region);
12108 delete clip_region;
12112 SetVPRotation(VPoint.
skew);
12121 wxMemoryDC *pChartDC = &temp_dc;
12122 wxMemoryDC rotd_dc;
12124 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12126 if (!b_rcache_ok) {
12128 wxMemoryDC tbase_dc;
12130 tbase_dc.SelectObject(bm_base);
12132 tbase_dc.SelectObject(wxNullBitmap);
12134 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12137 wxImage base_image;
12138 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12146 bool b_rot_ok =
false;
12147 if (base_image.IsOk()) {
12150 m_b_rot_hidef =
false;
12154 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12155 m_b_rot_hidef, &m_roffset);
12160 rot_vp.IsValid() && (ri.IsOk())) {
12167 m_prot_bm =
new wxBitmap(ri);
12170 m_roffset.x += VPoint.rv_rect.x;
12171 m_roffset.y += VPoint.rv_rect.y;
12174 if (m_prot_bm && m_prot_bm->IsOk()) {
12175 rotd_dc.SelectObject(*m_prot_bm);
12176 pChartDC = &rotd_dc;
12178 pChartDC = &temp_dc;
12179 m_roffset = wxPoint(0, 0);
12182 pChartDC = &temp_dc;
12183 m_roffset = wxPoint(0, 0);
12186 wxPoint offset = m_roffset;
12189 m_cache_vp = VPoint;
12192 wxMemoryDC mscratch_dc;
12193 mscratch_dc.SelectObject(*pscratch_bm);
12195 mscratch_dc.ResetBoundingBox();
12196 mscratch_dc.DestroyClippingRegion();
12197 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12200 wxRegionIterator upd(rgn_blit);
12202 wxRect rect = upd.GetRect();
12204 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12205 rect.x - offset.x, rect.y - offset.y);
12211 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12212 if (
this == wxWindow::FindFocus()) {
12215 wxColour colour = GetGlobalColor(
"BLUE4");
12216 mscratch_dc.SetPen(wxPen(colour));
12217 mscratch_dc.SetBrush(wxBrush(colour));
12219 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12220 mscratch_dc.DrawRectangle(activeRect);
12225 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12226 unsigned int im = stackIndexArray.size();
12227 if (VPoint.b_quilt && im > 0) {
12228 std::vector<int> tiles_to_show;
12229 for (
unsigned int is = 0; is < im; is++) {
12231 ChartData->GetChartTableEntry(stackIndexArray[is]);
12232 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12235 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12236 tiles_to_show.push_back(stackIndexArray[is]);
12240 if (tiles_to_show.size())
12241 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12247 ocpnDC scratch_dc(mscratch_dc);
12248 RenderAlertMessage(mscratch_dc, GetVP());
12254#ifdef ocpnUSE_DIBSECTION
12259 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12260 q_dc.SelectObject(qbm);
12263 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12266 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12267 q_dc.SetBrush(qbr);
12268 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12271 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12274 q_dc.SelectObject(wxNullBitmap);
12283 if( VPoint.b_quilt ) {
12284 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12285 ChartBase *chart = m_pQuilt->GetRefChart();
12286 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12291 ChPI->ClearPLIBTextList();
12294 ps52plib->ClearTextList();
12298 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12300 wxColor maskBackground = wxColour(1,0,0);
12301 t_dc.SelectObject( qbm );
12302 t_dc.SetBackground(wxBrush(maskBackground));
12306 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12309 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12310 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12313 wxRegionIterator upd_final( ru );
12314 while( upd_final ) {
12315 wxRect rect = upd_final.GetRect();
12316 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12320 t_dc.SelectObject( wxNullBitmap );
12326 if (VPoint.b_quilt) {
12327 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12328 ChartBase *chart = m_pQuilt->GetRefChart();
12329 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12333 ChPI->ClearPLIBTextList();
12335 if (ps52plib) ps52plib->ClearTextList();
12340 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12342 if (g_bShowChartBar && m_Piano) {
12343 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12344 GetVP().pix_width, m_Piano->GetHeight());
12347 if (!style->chartStatusWindowTransparent)
12348 chart_all_text_region.Subtract(chart_bar_rect);
12351 if (m_Compass && m_Compass->IsShown()) {
12352 wxRect compassRect = m_Compass->
GetRect();
12353 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12354 chart_all_text_region.Subtract(compassRect);
12358 mscratch_dc.DestroyClippingRegion();
12360 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12361 chart_all_text_region);
12367 ocpnDC scratch_dc(mscratch_dc);
12368 DrawOverlayObjects(scratch_dc, ru);
12371 wxRegionIterator upd_final(rgn_blit);
12372 while (upd_final) {
12373 wxRect rect = upd_final.GetRect();
12374 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12381 temp_dc.SelectObject(wxNullBitmap);
12383 mscratch_dc.SelectObject(wxNullBitmap);
12385 dc.DestroyClippingRegion();
12390void ChartCanvas::PaintCleanup() {
12392 if (m_inPinch)
return;
12403 m_bTCupdate =
false;
12407 WarpPointer(warp_x, warp_y);
12414 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12415 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12419wxColour GetErrorGraphicColor(
double val)
12438 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12439 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12440 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12441 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12442 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12443 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12444 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12445 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12446 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12447 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12448 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12449 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12450 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12451 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12452 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12453 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12454 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12455 else if( val >= 48) c.Set(
"#410000");
12460void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12463 gr_image.InitAlpha();
12465 double maxval = -10000;
12466 double minval = 10000;
12483 maxval = wxMax(maxval, (glat - rlat));
12484 minval = wxMin(minval, (glat - rlat));
12501 double f = ((glat - rlat)-minval)/(maxval - minval);
12503 double dy = (f * 40);
12505 wxColour c = GetErrorGraphicColor(dy);
12506 unsigned char r = c.Red();
12507 unsigned char g = c.Green();
12508 unsigned char b = c.Blue();
12510 gr_image.SetRGB(j, i, r,g,b);
12511 if((glat - rlat )!= 0)
12512 gr_image.SetAlpha(j, i, 128);
12514 gr_image.SetAlpha(j, i, 255);
12521 wxBitmap *pbm =
new wxBitmap(gr_image);
12522 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12523 pbm->SetMask(gr_mask);
12525 pmdc->DrawBitmap(*pbm, 0,0);
12533void ChartCanvas::CancelMouseRoute() {
12535 m_pMouseRoute = NULL;
12536 m_bDrawingRoute =
false;
12539int ChartCanvas::GetNextContextMenuId() {
12540 return CanvasMenuHandler::GetNextContextMenuId();
12543bool ChartCanvas::SetCursor(
const wxCursor &c) {
12545 if (g_bopengl && m_glcc)
12546 return m_glcc->SetCursor(c);
12549 return wxWindow::SetCursor(c);
12552void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12553 if (g_bquiting)
return;
12563 if (!m_RolloverPopupTimer.IsRunning() &&
12564 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12565 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12566 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12567 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12570 if (m_glcc && g_bopengl) {
12573 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12575 m_glcc->Refresh(eraseBackground,
12592 if (m_pCIWin && m_pCIWin->IsShown()) {
12594 m_pCIWin->Refresh(
false);
12602 wxWindow::Refresh(eraseBackground, rect);
12605void ChartCanvas::Update() {
12606 if (m_glcc && g_bopengl) {
12611 wxWindow::Update();
12615 if (!pemboss)
return;
12616 int x = pemboss->x, y = pemboss->y;
12617 const double factor = 200;
12619 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12620 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12621 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12624 wxMemoryDC snip_dc;
12625 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12626 snip_dc.SelectObject(snip_bmp);
12628 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12629 snip_dc.SelectObject(wxNullBitmap);
12631 wxImage snip_img = snip_bmp.ConvertToImage();
12634 unsigned char *pdata = snip_img.GetData();
12636 for (
int y = 0; y < pemboss->height; y++) {
12637 int map_index = (y * pemboss->width);
12638 for (
int x = 0; x < pemboss->width; x++) {
12639 double val = (pemboss->pmap[map_index] * factor) / 256.;
12641 int nred = (int)((*pdata) + val);
12642 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12643 *pdata++ = (
unsigned char)nred;
12645 int ngreen = (int)((*pdata) + val);
12646 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12647 *pdata++ = (
unsigned char)ngreen;
12649 int nblue = (int)((*pdata) + val);
12650 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12651 *pdata++ = (
unsigned char)nblue;
12659 wxBitmap emb_bmp(snip_img);
12662 wxMemoryDC result_dc;
12663 result_dc.SelectObject(emb_bmp);
12666 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12668 result_dc.SelectObject(wxNullBitmap);
12674 if (GetQuiltMode()) {
12676 int refIndex = GetQuiltRefChartdbIndex();
12677 if (refIndex >= 0) {
12679 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12680 if (current_type == CHART_TYPE_MBTILES) {
12681 ChartBase *pChart = m_pQuilt->GetRefChart();
12684 zoom_factor = ptc->GetZoomFactor();
12689 if (zoom_factor <= 3.9)
return NULL;
12691 if (m_singleChart) {
12692 if (zoom_factor <= 3.9)
return NULL;
12697 if (m_pEM_OverZoom) {
12698 m_pEM_OverZoom->x = 4;
12699 m_pEM_OverZoom->y = 0;
12701 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12702 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12705 return m_pEM_OverZoom;
12708void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12721 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12722 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12726 AISDrawAreaNotices(dc, GetVP(),
this);
12728 wxDC *pdc = dc.GetDC();
12730 pdc->DestroyClippingRegion();
12731 wxDCClipper(*pdc, ru);
12734 if (m_bShowNavobjects) {
12735 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12736 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12737 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12738 DrawAnchorWatchPoints(dc);
12740 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12741 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12744 AISDraw(dc, GetVP(),
this);
12748 RenderVisibleSectorLights(dc);
12750 RenderAllChartOutlines(dc, GetVP());
12751 RenderRouteLegs(dc);
12752 RenderShipToActive(dc,
false);
12754 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12756 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12760 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12761 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12764 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12769 RebuildTideSelectList(GetVP().GetBBox());
12770 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12773 if (m_bShowCurrent) {
12774 RebuildCurrentSelectList(GetVP().GetBBox());
12775 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12778 if (!g_PrintingInProgress) {
12779 if (IsPrimaryCanvas()) {
12783 if (IsPrimaryCanvas()) {
12787 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12789 if (m_pTrackRolloverWin) {
12790 m_pTrackRolloverWin->Draw(dc);
12791 m_brepaint_piano =
true;
12794 if (m_pRouteRolloverWin) {
12795 m_pRouteRolloverWin->Draw(dc);
12796 m_brepaint_piano =
true;
12799 if (m_pAISRolloverWin) {
12800 m_pAISRolloverWin->Draw(dc);
12801 m_brepaint_piano =
true;
12803 if (m_brepaint_piano && g_bShowChartBar) {
12804 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12807 if (m_Compass) m_Compass->Paint(dc);
12809 if (!g_CanvasHideNotificationIcon) {
12810 if (IsPrimaryCanvas()) {
12811 auto ¬eman = NotificationManager::GetInstance();
12812 if (noteman.GetNotificationCount()) {
12813 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12814 if (m_notification_button->UpdateStatus()) Refresh();
12815 m_notification_button->Show(
true);
12816 m_notification_button->Paint(dc);
12818 m_notification_button->Show(
false);
12824 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12830 if (!m_bShowDepthUnits)
return NULL;
12832 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12834 if (GetQuiltMode()) {
12835 wxString s = m_pQuilt->GetQuiltDepthUnit();
12838 depth_unit_type = DEPTH_UNIT_FEET;
12839 else if (s.StartsWith(
"FATHOMS"))
12840 depth_unit_type = DEPTH_UNIT_FATHOMS;
12841 else if (s.StartsWith(
"METERS"))
12842 depth_unit_type = DEPTH_UNIT_METERS;
12843 else if (s.StartsWith(
"METRES"))
12844 depth_unit_type = DEPTH_UNIT_METERS;
12845 else if (s.StartsWith(
"METRIC"))
12846 depth_unit_type = DEPTH_UNIT_METERS;
12847 else if (s.StartsWith(
"METER"))
12848 depth_unit_type = DEPTH_UNIT_METERS;
12851 if (m_singleChart) {
12852 depth_unit_type = m_singleChart->GetDepthUnitType();
12853 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12854 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12859 switch (depth_unit_type) {
12860 case DEPTH_UNIT_FEET:
12863 case DEPTH_UNIT_METERS:
12864 ped = m_pEM_Meters;
12866 case DEPTH_UNIT_FATHOMS:
12867 ped = m_pEM_Fathoms;
12873 ped->x = (GetVP().
pix_width - ped->width);
12875 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12876 wxRect r = m_Compass->
GetRect();
12877 ped->y = r.y + r.height;
12884void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12887 if (style->embossFont == wxEmptyString) {
12888 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12890 font.SetPointSize(60);
12891 font.SetWeight(wxFONTWEIGHT_BOLD);
12893 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12894 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12896 int emboss_width = 500;
12897 int emboss_height = 200;
12901 delete m_pEM_Meters;
12902 delete m_pEM_Fathoms;
12906 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12908 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12910 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12913#define OVERZOOM_TEXT _("OverZoom")
12915void ChartCanvas::SetOverzoomFont() {
12920 if (style->embossFont == wxEmptyString) {
12921 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12923 font.SetPointSize(40);
12924 font.SetWeight(wxFONTWEIGHT_BOLD);
12926 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12927 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12929 wxClientDC dc(
this);
12931 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12933 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12934 font.SetPointSize(font.GetPointSize() - 1);
12936 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12938 m_overzoomFont = font;
12939 m_overzoomTextWidth = w;
12940 m_overzoomTextHeight = h;
12943void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12944 delete m_pEM_OverZoom;
12946 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12948 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12949 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12952emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12953 int height,
const wxString &str,
12958 wxBitmap bmp(width, height, -1);
12961 wxMemoryDC temp_dc;
12962 temp_dc.SelectObject(bmp);
12965 temp_dc.SetBackground(*wxWHITE_BRUSH);
12966 temp_dc.SetTextBackground(*wxWHITE);
12967 temp_dc.SetTextForeground(*wxBLACK);
12971 temp_dc.SetFont(font);
12974 temp_dc.GetTextExtent(str, &str_w, &str_h);
12976 temp_dc.DrawText(str, 1, 1);
12979 temp_dc.SelectObject(wxNullBitmap);
12982 wxImage img = bmp.ConvertToImage();
12984 int image_width = str_w * 105 / 100;
12985 int image_height = str_h * 105 / 100;
12986 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12987 wxMin(image_height, img.GetHeight()));
12988 wxImage imgs = img.GetSubImage(r);
12992 case GLOBAL_COLOR_SCHEME_DAY:
12996 case GLOBAL_COLOR_SCHEME_DUSK:
12999 case GLOBAL_COLOR_SCHEME_NIGHT:
13006 const int w = imgs.GetWidth();
13007 const int h = imgs.GetHeight();
13008 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13013 for (
int y = 1; y < h - 1; y++) {
13014 for (
int x = 1; x < w - 1; x++) {
13016 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13017 val = (int)(val * val_factor);
13018 index = (y * w) + x;
13031void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13032 Track *active_track = NULL;
13035 active_track = pTrackDraw;
13039 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13042 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13045void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13046 Track *active_track = NULL;
13049 active_track = pTrackDraw;
13053 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13056void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13057 Route *active_route = NULL;
13059 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13060 active_route = pRouteDraw;
13065 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13070 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13073void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13074 Route *active_route = NULL;
13077 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13078 active_route = pRouteDraw;
13082 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13085void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13086 if (!pWayPointMan)
return;
13088 auto node = pWayPointMan->GetWaypointList()->begin();
13090 while (node != pWayPointMan->GetWaypointList()->end()) {
13099 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13103 if (pWP->GetShowWaypointRangeRings() &&
13104 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13105 double factor = 1.00;
13106 if (pWP->GetWaypointRangeRingsStepUnits() ==
13108 factor = 1 / 1.852;
13110 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13111 pWP->GetWaypointRangeRingsStep() / 60.;
13115 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13116 pWP->m_lat + radius, pWP->m_lon + radius);
13117 if (!BltBBox.IntersectOut(radar_box)) {
13128void ChartCanvas::DrawBlinkObjects() {
13130 wxRect update_rect;
13132 if (!pWayPointMan)
return;
13134 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13141 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13144void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13149 wxPoint lAnchorPoint1, lAnchorPoint2;
13163 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13164 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13166 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13167 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13168 dc.SetBrush(*ppBrush);
13172 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13177 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13182 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13187 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13192double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13195 wxPoint lAnchorPoint;
13198 double tlat1, tlon1;
13200 if (pAnchorWatchPoint) {
13201 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13202 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13203 dabs = fabs(d1 / 1852.);
13204 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13209 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13210 pow((
double)(lAnchorPoint.y - r1.y), 2));
13213 if (d1 < 0) lpp = -lpp;
13221void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13224 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13226 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13232 if ((type ==
't') || (type ==
'T')) {
13233 if (BBox.Contains(lat, lon)) {
13235 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13241void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13244 wxDateTime this_now = gTimeSource;
13245 bool cur_time = !gTimeSource.IsValid();
13246 if (cur_time) this_now = wxDateTime::Now();
13247 time_t t_this_now = this_now.GetTicks();
13249 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13251 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13252 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13253 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13254 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13256 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13257 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13258 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13259 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13260 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13261 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13263 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13264 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13265 int font_size = wxMax(10, dFont->GetPointSize());
13268 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13269 false, dFont->GetFaceName());
13271 dc.SetPen(*pblack_pen);
13272 dc.SetBrush(*pgreen_brush);
13276 case GLOBAL_COLOR_SCHEME_DAY:
13279 case GLOBAL_COLOR_SCHEME_DUSK:
13282 case GLOBAL_COLOR_SCHEME_NIGHT:
13283 bm = m_bmTideNight;
13290 int bmw = bm.GetWidth();
13291 int bmh = bm.GetHeight();
13293 float scale_factor = 1.0;
13297 float icon_pixelRefDim = 45;
13302 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13304 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13306 scale_factor *= pix_factor;
13313 scale_factor *= user_scale_factor;
13314 scale_factor *= GetContentScaleFactor();
13317 double marge = 0.05;
13318 std::vector<LLBBox> drawn_boxes;
13319 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13323 if ((type ==
't') || (type ==
'T'))
13328 if (BBox.ContainsMarge(lat, lon, marge)) {
13330 if (GetVP().chart_scale < 500000) {
13331 bool bdrawn =
false;
13332 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13333 if (drawn_boxes[i].Contains(lat, lon)) {
13338 if (bdrawn)
continue;
13341 this_box.Set(lat, lon, lat, lon);
13342 this_box.EnLarge(.005);
13343 drawn_boxes.push_back(this_box);
13349 if (GetVP().chart_scale > 500000) {
13350 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13354 dc.SetFont(*plabelFont);
13366 if (
ptcmgr->GetTideFlowSens(
13367 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13371 ptcmgr->GetHightOrLowTide(
13372 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13373 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13385 if (tctime > t_this_now)
13386 ptcmgr->GetHightOrLowTide(
13387 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13388 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13392 ptcmgr->GetHightOrLowTide(
13393 t_this_now, FORWARD_TEN_MINUTES_STEP,
13394 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13408 int width = (int)(12 * scale_factor + 0.5);
13409 int height = (int)(45 * scale_factor + 0.5);
13410 int linew = wxMax(1, (
int)(scale_factor));
13411 int xDraw = r.x - (width / 2);
13412 int yDraw = r.y - (height / 2);
13415 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13416 int hs = (httime > lttime) ? -4 : 4;
13417 hs *= (int)(scale_factor + 0.5);
13418 if (ts > 0.995 || ts < 0.005) hs = 0;
13419 int ht_y = (int)(height * ts);
13422 pblack_pen->SetWidth(linew);
13423 dc.SetPen(*pblack_pen);
13424 dc.SetBrush(*pyelo_brush);
13425 dc.DrawRectangle(xDraw, yDraw, width, height);
13429 dc.SetPen(*pblue_pen);
13430 dc.SetBrush(*pblue_brush);
13431 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13432 (width - (4 * linew)), height - ht_y);
13438 arrow[0].x = xDraw + 2 * linew;
13439 arrow[1].x = xDraw + width / 2;
13440 arrow[2].x = xDraw + width - 2 * linew;
13441 pyelo_pen->SetWidth(linew);
13442 pblue_pen->SetWidth(linew);
13443 if (ts > 0.35 || ts < 0.15)
13445 hl = (int)(height * 0.25) + yDraw;
13447 arrow[1].y = hl + hs;
13450 dc.SetPen(*pyelo_pen);
13452 dc.SetPen(*pblue_pen);
13453 dc.DrawLines(3, arrow);
13455 if (ts > 0.60 || ts < 0.40)
13457 hl = (int)(height * 0.5) + yDraw;
13459 arrow[1].y = hl + hs;
13462 dc.SetPen(*pyelo_pen);
13464 dc.SetPen(*pblue_pen);
13465 dc.DrawLines(3, arrow);
13467 if (ts < 0.65 || ts > 0.85)
13469 hl = (int)(height * 0.75) + yDraw;
13471 arrow[1].y = hl + hs;
13474 dc.SetPen(*pyelo_pen);
13476 dc.SetPen(*pblue_pen);
13477 dc.DrawLines(3, arrow);
13481 s.Printf(
"%3.1f", nowlev);
13483 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13485 dc.GetTextExtent(s, &wx1, NULL);
13487 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13502void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13505 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13507 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13513 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13514 if ((BBox.Contains(lat, lon))) {
13516 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13522void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13525 float tcvalue, dir;
13529 double lon_last = 0.;
13530 double lat_last = 0.;
13532 double marge = 0.2;
13533 bool cur_time = !gTimeSource.IsValid();
13535 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13536 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13538 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13540 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13541 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13542 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13543 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13544 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13545 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13546 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13547 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13549 double skew_angle = GetVPRotation();
13551 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13552 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13553 int font_size = wxMax(10, dFont->GetPointSize());
13556 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13557 false, dFont->GetFaceName());
13559 float scale_factor = 1.0;
13565 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13567 float nominal_icon_size_pixels = 15;
13568 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13570 scale_factor *= pix_factor;
13577 scale_factor *= user_scale_factor;
13579 scale_factor *= GetContentScaleFactor();
13582 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13588 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13589 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13594 int dd = (int)(5.0 * scale_factor + 0.5);
13605 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13606 dc.SetPen(*pblack_pen);
13607 dc.SetBrush(*porange_brush);
13608 dc.DrawPolygon(4, d);
13611 dc.SetBrush(*pblack_brush);
13612 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13616 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13630 double a1 = fabs(tcvalue) * 10.;
13632 a1 = wxMax(1.0, a1);
13633 double a2 = log10(a1);
13635 float cscale = scale_factor * a2 * 0.3;
13637 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13638 dc.SetPen(*porange_pen);
13639 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13643 if (bDrawCurrentValues) {
13644 dc.SetFont(*pTCFont);
13645 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13646 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13672 if (!pvIDX)
return;
13677 if (pCwin && pCwin->IsShown()) {
13685 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13700 pCwin =
new TCWin(
this, x, y, pvIDX);
13718#define NUM_CURRENT_ARROW_POINTS 9
13719static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13720 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13721 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13722 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13724void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13726 if (
scale > 1e-2) {
13727 float sin_rot = sin(rot_angle * PI / 180.);
13728 float cos_rot = cos(rot_angle * PI / 180.);
13732 float xt = CurrentArrowArray[0].x;
13733 float yt = CurrentArrowArray[0].y;
13735 float xp = (xt * cos_rot) - (yt * sin_rot);
13736 float yp = (xt * sin_rot) + (yt * cos_rot);
13737 int x1 = (int)(xp *
scale);
13738 int y1 = (int)(yp *
scale);
13741 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13742 xt = CurrentArrowArray[ip].x;
13743 yt = CurrentArrowArray[ip].y;
13745 float xp = (xt * cos_rot) - (yt * sin_rot);
13746 float yp = (xt * sin_rot) + (yt * cos_rot);
13747 int x2 = (int)(xp *
scale);
13748 int y2 = (int)(yp *
scale);
13750 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13758wxString ChartCanvas::FindValidUploadPort() {
13761 if (!g_uploadConnection.IsEmpty() &&
13762 g_uploadConnection.StartsWith(
"Serial")) {
13763 port = g_uploadConnection;
13769 for (
auto *cp : TheConnectionParams()) {
13770 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13771 port <<
"Serial:" << cp->Port;
13777void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13780 if (NULL == g_pais_query_dialog_active) {
13781 int pos_x = g_ais_query_dialog_x;
13782 int pos_y = g_ais_query_dialog_y;
13784 if (g_pais_query_dialog_active) {
13785 g_pais_query_dialog_active->Destroy();
13791 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13792 wxPoint(pos_x, pos_y));
13794 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13795 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13796 g_pais_query_dialog_active->SetMMSI(mmsi);
13797 g_pais_query_dialog_active->UpdateText();
13798 wxSize sz = g_pais_query_dialog_active->GetSize();
13800 bool b_reset_pos =
false;
13805 RECT frame_title_rect;
13806 frame_title_rect.left = pos_x;
13807 frame_title_rect.top = pos_y;
13808 frame_title_rect.right = pos_x + sz.x;
13809 frame_title_rect.bottom = pos_y + 30;
13811 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13812 b_reset_pos =
true;
13817 wxRect window_title_rect;
13818 window_title_rect.x = pos_x;
13819 window_title_rect.y = pos_y;
13820 window_title_rect.width = sz.x;
13821 window_title_rect.height = 30;
13823 wxRect ClientRect = wxGetClientDisplayRect();
13824 ClientRect.Deflate(
13826 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13830 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13833 g_pais_query_dialog_active->SetMMSI(mmsi);
13834 g_pais_query_dialog_active->UpdateText();
13837 g_pais_query_dialog_active->Show();
13840void ChartCanvas::ToggleCanvasQuiltMode() {
13841 bool cur_mode = GetQuiltMode();
13843 if (!GetQuiltMode())
13844 SetQuiltMode(
true);
13845 else if (GetQuiltMode()) {
13846 SetQuiltMode(
false);
13847 g_sticky_chart = GetQuiltReferenceChartIndex();
13850 if (cur_mode != GetQuiltMode()) {
13851 SetupCanvasQuiltMode();
13860 if (ps52plib) ps52plib->GenerateStateHash();
13862 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13863 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13866void ChartCanvas::DoCanvasStackDelta(
int direction) {
13867 if (!GetQuiltMode()) {
13868 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13869 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13870 if ((current_stack_index + direction) < 0)
return;
13872 if (m_bpersistent_quilt ) {
13874 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13876 if (IsChartQuiltableRef(new_dbIndex)) {
13877 ToggleCanvasQuiltMode();
13878 SelectQuiltRefdbChart(new_dbIndex);
13879 m_bpersistent_quilt =
false;
13882 SelectChartFromStack(current_stack_index + direction);
13885 std::vector<int> piano_chart_index_array =
13886 GetQuiltExtendedStackdbIndexArray();
13887 int refdb = GetQuiltRefChartdbIndex();
13890 int current_index = -1;
13891 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13892 if (refdb == piano_chart_index_array[i]) {
13897 if (current_index == -1)
return;
13900 int target_family = ctet.GetChartFamily();
13902 int new_index = -1;
13903 int check_index = current_index + direction;
13904 bool found =
false;
13905 int check_dbIndex = -1;
13906 int new_dbIndex = -1;
13910 (
unsigned int)check_index < piano_chart_index_array.size() &&
13911 (check_index >= 0)) {
13912 check_dbIndex = piano_chart_index_array[check_index];
13914 if (target_family == cte.GetChartFamily()) {
13916 new_index = check_index;
13917 new_dbIndex = check_dbIndex;
13921 check_index += direction;
13924 if (!found)
return;
13926 if (!IsChartQuiltableRef(new_dbIndex)) {
13927 ToggleCanvasQuiltMode();
13928 SelectdbChart(new_dbIndex);
13929 m_bpersistent_quilt =
true;
13931 SelectQuiltRefChart(new_index);
13935 gFrame->UpdateGlobalMenuItems();
13937 SetQuiltChartHiLiteIndex(-1);
13948void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13951 switch (event.GetId()) {
13963 DoCanvasStackDelta(1);
13968 DoCanvasStackDelta(-1);
13978 ShowCurrents(!GetbShowCurrent());
13985 ShowTides(!GetbShowTide());
13992 if (0 == m_routeState) {
13999 androidSetRouteAnnunciator(m_routeState == 1);
14005 SetAISCanvasDisplayStyle(-1);
14017void ChartCanvas::SetShowAIS(
bool show) {
14019 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14020 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14023void ChartCanvas::SetAttenAIS(
bool show) {
14024 m_bShowAISScaled = show;
14025 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14026 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14029void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14032 bool bShowAIS_Array[3] = {
true,
true,
false};
14033 bool bShowScaled_Array[3] = {
false,
true,
true};
14034 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14035 _(
"Attenuate less critical AIS targets"),
14036 _(
"Hide AIS Targets")};
14037 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14039 int AIS_Toolbar_Switch = 0;
14040 if (StyleIndx == -1) {
14042 for (
int i = 1; i < ArraySize; i++) {
14043 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14044 (bShowScaled_Array[i] == m_bShowAISScaled))
14045 AIS_Toolbar_Switch = i;
14047 AIS_Toolbar_Switch++;
14048 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14049 AIS_Toolbar_Switch++;
14052 AIS_Toolbar_Switch = StyleIndx;
14055 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14057 int AIS_Toolbar_Switch_Next =
14058 AIS_Toolbar_Switch + 1;
14059 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14060 AIS_Toolbar_Switch_Next++;
14061 if (AIS_Toolbar_Switch_Next >= ArraySize)
14062 AIS_Toolbar_Switch_Next = 0;
14065 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14066 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14069void ChartCanvas::TouchAISToolActive() {}
14071void ChartCanvas::UpdateAISTBTool() {}
14079void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14081 bool b_update =
false;
14082 int cc1_edge_comp = 2;
14083 wxRect rect = m_Compass->
GetRect();
14084 wxSize parent_size = GetSize();
14086 parent_size *= m_displayScale;
14090 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14091 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14092 wxRect compass_rect(compass_pt, rect.GetSize());
14094 m_Compass->Move(compass_pt);
14096 if (m_Compass && m_Compass->IsShown())
14097 m_Compass->UpdateStatus(b_force_new | b_update);
14099 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14100 scaler = wxMax(scaler, 1.0);
14101 wxPoint note_point = wxPoint(
14102 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14103 if (m_notification_button) {
14104 m_notification_button->Move(note_point);
14105 m_notification_button->UpdateStatus();
14108 if (b_force_new | b_update) Refresh();
14111void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14112 ChartTypeEnum New_Type,
14113 ChartFamilyEnum New_Family) {
14114 if (!GetpCurrentStack())
return;
14117 if (index < GetpCurrentStack()->nEntry) {
14120 pTentative_Chart =
ChartData->OpenStackChartConditional(
14121 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14123 if (pTentative_Chart) {
14124 if (m_singleChart) m_singleChart->Deactivate();
14126 m_singleChart = pTentative_Chart;
14127 m_singleChart->Activate();
14129 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14130 GetpCurrentStack(), m_singleChart->GetFullPath());
14143 double best_scale_ppm = GetBestVPScale(m_singleChart);
14144 double rotation = GetVPRotation();
14145 double oldskew = GetVPSkew();
14146 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14148 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14149 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14150 if (fabs(newskew) > 0.0001) rotation = newskew;
14153 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14155 UpdateGPSCompassStatusBox(
true);
14159 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14160 if (idx < 0)
return;
14162 std::vector<int> piano_active_chart_index_array;
14163 piano_active_chart_index_array.push_back(
14164 GetpCurrentStack()->GetCurrentEntrydbIndex());
14165 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14168void ChartCanvas::SelectdbChart(
int dbindex) {
14169 if (!GetpCurrentStack())
return;
14172 if (dbindex >= 0) {
14175 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14177 if (pTentative_Chart) {
14178 if (m_singleChart) m_singleChart->Deactivate();
14180 m_singleChart = pTentative_Chart;
14181 m_singleChart->Activate();
14183 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14184 GetpCurrentStack(), m_singleChart->GetFullPath());
14197 double best_scale_ppm = GetBestVPScale(m_singleChart);
14201 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14211void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14214 if (!GetQuiltMode()) {
14215 if (GetpCurrentStack()) {
14216 int stack_index = -1;
14217 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14218 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14219 if (check_dbIndex < 0)
continue;
14221 ChartData->GetChartTableEntry(check_dbIndex);
14222 if (type == cte.GetChartType()) {
14225 }
else if (family == cte.GetChartFamily()) {
14231 if (stack_index >= 0) {
14232 SelectChartFromStack(stack_index);
14236 int sel_dbIndex = -1;
14237 std::vector<int> piano_chart_index_array =
14238 GetQuiltExtendedStackdbIndexArray();
14239 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14240 int check_dbIndex = piano_chart_index_array[i];
14242 if (type == cte.GetChartType()) {
14243 if (IsChartQuiltableRef(check_dbIndex)) {
14244 sel_dbIndex = check_dbIndex;
14247 }
else if (family == cte.GetChartFamily()) {
14248 if (IsChartQuiltableRef(check_dbIndex)) {
14249 sel_dbIndex = check_dbIndex;
14255 if (sel_dbIndex >= 0) {
14256 SelectQuiltRefdbChart(sel_dbIndex,
false);
14258 AdjustQuiltRefChart();
14265 SetQuiltChartHiLiteIndex(-1);
14270bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14271 return std::find(m_tile_yesshow_index_array.begin(),
14272 m_tile_yesshow_index_array.end(),
14273 index) != m_tile_yesshow_index_array.end();
14276bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14277 return std::find(m_tile_noshow_index_array.begin(),
14278 m_tile_noshow_index_array.end(),
14279 index) != m_tile_noshow_index_array.end();
14282void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14283 if (std::find(m_tile_noshow_index_array.begin(),
14284 m_tile_noshow_index_array.end(),
14285 index) == m_tile_noshow_index_array.end()) {
14286 m_tile_noshow_index_array.push_back(index);
14296void ChartCanvas::HandlePianoClick(
14297 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14300 if (!m_pCurrentStack)
return;
14316 double distance = 25000;
14317 int closest_index = -1;
14318 for (
int chart_index : selected_dbIndex_array) {
14320 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14321 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14324 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14325 if (test_distance < distance) {
14326 distance = test_distance;
14327 closest_index = chart_index;
14331 int selected_dbIndex = selected_dbIndex_array[0];
14332 if (closest_index >= 0) selected_dbIndex = closest_index;
14334 if (!GetQuiltMode()) {
14335 if (m_bpersistent_quilt ) {
14336 if (IsChartQuiltableRef(selected_dbIndex)) {
14337 ToggleCanvasQuiltMode();
14338 SelectQuiltRefdbChart(selected_dbIndex);
14339 m_bpersistent_quilt =
false;
14341 SelectChartFromStack(selected_index);
14344 SelectChartFromStack(selected_index);
14345 g_sticky_chart = selected_dbIndex;
14349 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14353 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14354 bool bfound =
false;
14355 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14356 if (m_tile_noshow_index_array[i] ==
14357 selected_dbIndex) {
14358 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14365 m_tile_noshow_index_array.push_back(selected_dbIndex);
14369 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14370 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14374 if (IsChartQuiltableRef(selected_dbIndex)) {
14380 bool set_scale =
false;
14381 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14382 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14388 SelectQuiltRefdbChart(selected_dbIndex,
true);
14390 SelectQuiltRefdbChart(selected_dbIndex,
false);
14395 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14397 double proposed_scale_onscreen =
14400 if (g_bPreserveScaleOnX) {
14401 proposed_scale_onscreen =
14402 wxMin(proposed_scale_onscreen,
14404 GetCanvasWidth()));
14406 proposed_scale_onscreen =
14407 wxMin(proposed_scale_onscreen,
14409 GetCanvasWidth()));
14411 proposed_scale_onscreen =
14412 wxMax(proposed_scale_onscreen,
14421 ToggleCanvasQuiltMode();
14422 SelectdbChart(selected_dbIndex);
14423 m_bpersistent_quilt =
true;
14428 SetQuiltChartHiLiteIndex(-1);
14429 gFrame->UpdateGlobalMenuItems();
14431 HideChartInfoWindow();
14436void ChartCanvas::HandlePianoRClick(
14437 int x,
int y,
int selected_index,
14438 const std::vector<int> &selected_dbIndex_array) {
14441 if (!GetpCurrentStack())
return;
14443 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14444 UpdateCanvasControlBar();
14446 SetQuiltChartHiLiteIndex(-1);
14449void ChartCanvas::HandlePianoRollover(
14450 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14451 int n_charts,
int scale) {
14454 if (!GetpCurrentStack())
return;
14459 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14461 if (!GetQuiltMode()) {
14462 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14465 std::vector<int> piano_chart_index_array;
14466 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14467 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14468 if ((GetpCurrentStack()->nEntry > 1) ||
14469 (piano_chart_index_array.size() >= 1)) {
14470 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14472 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14474 }
else if (GetpCurrentStack()->nEntry == 1) {
14476 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14477 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14478 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14480 }
else if ((-1 == selected_index) &&
14481 (0 == selected_dbIndex_array.size())) {
14482 ShowChartInfoWindow(key_location.x, -1);
14486 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14488 if ((GetpCurrentStack()->nEntry > 1) ||
14489 (piano_chart_index_array.size() >= 1)) {
14491 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14492 selected_dbIndex_array);
14493 else if (n_charts == 1)
14494 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14496 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14503void ChartCanvas::ClearPianoRollover() {
14504 ClearQuiltChartHiLiteIndexArray();
14505 ShowChartInfoWindow(0, -1);
14506 std::vector<int> vec;
14507 ShowCompositeInfoWindow(0, 0, 0, vec);
14511void ChartCanvas::UpdateCanvasControlBar() {
14512 if (m_pianoFrozen)
return;
14514 if (!GetpCurrentStack())
return;
14516 if (!g_bShowChartBar)
return;
14519 int sel_family = -1;
14521 std::vector<int> piano_chart_index_array;
14522 std::vector<int> empty_piano_chart_index_array;
14524 wxString old_hash = m_Piano->GetStoredHash();
14526 if (GetQuiltMode()) {
14527 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14528 GetQuiltFullScreendbIndexArray());
14530 std::vector<int> piano_active_chart_index_array =
14531 GetQuiltCandidatedbIndexArray();
14532 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14534 std::vector<int> piano_eclipsed_chart_index_array =
14535 GetQuiltEclipsedStackdbIndexArray();
14536 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14538 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14539 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14541 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14542 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14544 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14545 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14548 if (m_singleChart) {
14549 sel_type = m_singleChart->GetChartType();
14550 sel_family = m_singleChart->GetChartFamily();
14555 std::vector<int> piano_skew_chart_index_array;
14556 std::vector<int> piano_tmerc_chart_index_array;
14557 std::vector<int> piano_poly_chart_index_array;
14559 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14561 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14562 double skew_norm = ctei.GetChartSkew();
14563 if (skew_norm > 180.) skew_norm -= 360.;
14565 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14566 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14569 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14570 if (fabs(skew_norm) > 1.)
14571 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14573 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14574 }
else if (fabs(skew_norm) > 1.)
14575 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14577 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14578 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14579 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14581 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14582 if (new_hash != old_hash) {
14583 m_Piano->FormatKeys();
14584 HideChartInfoWindow();
14585 m_Piano->ResetRollover();
14586 SetQuiltChartHiLiteIndex(-1);
14587 m_brepaint_piano =
true;
14593 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14595 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14596 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14597 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14598 if (e == CHART_FAMILY_RASTER) mask |= 1;
14599 if (e == CHART_FAMILY_VECTOR) {
14600 if (t == CHART_TYPE_CM93COMP)
14607 wxString s_indicated;
14608 if (sel_type == CHART_TYPE_CM93COMP)
14609 s_indicated =
"cm93";
14611 if (sel_family == CHART_FAMILY_RASTER)
14612 s_indicated =
"raster";
14613 else if (sel_family == CHART_FAMILY_VECTOR)
14614 s_indicated =
"vector";
14617 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14620void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14622void ChartCanvas::PianoPopupMenu(
14623 int x,
int y,
int selected_index,
14624 const std::vector<int> &selected_dbIndex_array) {
14625 if (!GetpCurrentStack())
return;
14628 if (!GetQuiltMode())
return;
14630 m_piano_ctx_menu =
new wxMenu();
14632 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14642 menu_selected_dbIndex = selected_dbIndex_array[0];
14643 menu_selected_index = selected_index;
14646 bool b_is_in_noshow =
false;
14647 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14648 if (m_quilt_noshow_index_array[i] ==
14649 menu_selected_dbIndex)
14651 b_is_in_noshow =
true;
14656 if (b_is_in_noshow) {
14657 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14658 _(
"Show This Chart"));
14659 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14660 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14661 }
else if (GetpCurrentStack()->nEntry > 1) {
14662 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14663 _(
"Hide This Chart"));
14664 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14665 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14669 wxPoint pos = wxPoint(x, y - 30);
14672 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14673 PopupMenu(m_piano_ctx_menu, pos);
14675 delete m_piano_ctx_menu;
14676 m_piano_ctx_menu = NULL;
14678 HideChartInfoWindow();
14679 m_Piano->ResetRollover();
14681 SetQuiltChartHiLiteIndex(-1);
14682 ClearQuiltChartHiLiteIndexArray();
14687void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14688 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14689 if (m_quilt_noshow_index_array[i] ==
14690 menu_selected_dbIndex)
14692 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14698void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14699 if (!GetpCurrentStack())
return;
14702 RemoveChartFromQuilt(menu_selected_dbIndex);
14706 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14707 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14709 int i = menu_selected_index + 1;
14710 bool b_success =
false;
14711 while (i < GetpCurrentStack()->nEntry - 1) {
14712 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14713 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14714 SelectQuiltRefChart(i);
14724 i = menu_selected_index - 1;
14726 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14727 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14728 SelectQuiltRefChart(i);
14738void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14740 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14741 if (m_quilt_noshow_index_array[i] ==
14744 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14749 m_quilt_noshow_index_array.push_back(dbIndex);
14752bool ChartCanvas::UpdateS52State() {
14753 bool retval =
false;
14756 ps52plib->SetShowS57Text(m_encShowText);
14757 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14758 ps52plib->m_bShowSoundg = m_encShowDepth;
14759 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14760 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14763 if (!m_encShowLights)
14764 ps52plib->AddObjNoshow(
"LIGHTS");
14766 ps52plib->RemoveObjNoshow(
"LIGHTS");
14767 ps52plib->SetLightsOff(!m_encShowLights);
14768 ps52plib->m_bExtendLightSectors =
true;
14771 ps52plib->SetAnchorOn(m_encShowAnchor);
14772 ps52plib->SetQualityOfData(m_encShowDataQual);
14778void ChartCanvas::SetShowENCDataQual(
bool show) {
14779 m_encShowDataQual = show;
14780 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14781 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14783 m_s52StateHash = 0;
14786void ChartCanvas::SetShowENCText(
bool show) {
14787 m_encShowText = show;
14788 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14789 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14791 m_s52StateHash = 0;
14794void ChartCanvas::SetENCDisplayCategory(
int category) {
14795 m_encDisplayCategory = category;
14796 m_s52StateHash = 0;
14799void ChartCanvas::SetShowENCDepth(
bool show) {
14800 m_encShowDepth = show;
14801 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14802 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14804 m_s52StateHash = 0;
14807void ChartCanvas::SetShowENCLightDesc(
bool show) {
14808 m_encShowLightDesc = show;
14809 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14810 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14812 m_s52StateHash = 0;
14815void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14816 m_encShowBuoyLabels = show;
14817 m_s52StateHash = 0;
14820void ChartCanvas::SetShowENCLights(
bool show) {
14821 m_encShowLights = show;
14822 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14823 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14825 m_s52StateHash = 0;
14828void ChartCanvas::SetShowENCAnchor(
bool show) {
14829 m_encShowAnchor = show;
14830 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14831 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14833 m_s52StateHash = 0;
14836wxRect ChartCanvas::GetMUIBarRect() {
14839 rv = m_muiBar->GetRect();
14845void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14846 if (!GetAlertString().IsEmpty()) {
14847 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14848 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14850 dc.SetFont(*pfont);
14851 dc.SetPen(*wxTRANSPARENT_PEN);
14853 dc.SetBrush(wxColour(243, 229, 47));
14855 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14859 wxRect sbr = GetScaleBarRect();
14860 int xp = sbr.x + sbr.width + 10;
14861 int yp = (sbr.y + sbr.height) - h;
14863 int wdraw = w + 10;
14864 dc.DrawRectangle(xp, yp, wdraw, h);
14865 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14866 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14876#define BRIGHT_XCALIB
14877#define __OPCPN_USEICC__
14880#ifdef __OPCPN_USEICC__
14881int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14882 double co_green,
double co_blue);
14884wxString temp_file_name;
14888class ocpnCurtain:
public wxDialog
14890 DECLARE_CLASS( ocpnCurtain )
14891 DECLARE_EVENT_TABLE()
14894 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14896 bool ProcessEvent(wxEvent& event);
14900IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14902BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14905ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14907 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14910ocpnCurtain::~ocpnCurtain()
14914bool ocpnCurtain::ProcessEvent(wxEvent& event)
14916 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14917 return GetParent()->GetEventHandler()->ProcessEvent(event);
14922#include <windows.h>
14925typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14926typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14927SetDeviceGammaRamp_ptr_type
14928 g_pSetDeviceGammaRamp;
14929GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14931WORD *g_pSavedGammaMap;
14935int InitScreenBrightness() {
14938 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14942 if (NULL == hGDI32DLL) {
14943 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14945 if (NULL != hGDI32DLL) {
14947 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14948 hGDI32DLL,
"SetDeviceGammaRamp");
14949 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14950 hGDI32DLL,
"GetDeviceGammaRamp");
14953 if ((NULL == g_pSetDeviceGammaRamp) ||
14954 (NULL == g_pGetDeviceGammaRamp)) {
14955 FreeLibrary(hGDI32DLL);
14964 if (!g_pSavedGammaMap) {
14965 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14968 bbr = g_pGetDeviceGammaRamp(
14969 hDC, g_pSavedGammaMap);
14970 ReleaseDC(NULL, hDC);
14975 wxRegKey *pRegKey =
new wxRegKey(
14976 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14977 "NT\\CurrentVersion\\ICM");
14978 if (!pRegKey->Exists()) pRegKey->Create();
14979 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14981 g_brightness_init =
true;
14987 if (NULL == g_pcurtain) {
14988 if (gFrame->CanSetTransparent()) {
14990 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14991 wxPoint(0, 0), ::wxGetDisplaySize(),
14992 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14993 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15000 g_pcurtain->Hide();
15002 HWND hWnd = GetHwndOf(g_pcurtain);
15003 SetWindowLong(hWnd, GWL_EXSTYLE,
15004 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15005 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15006 g_pcurtain->SetTransparent(0);
15008 g_pcurtain->Maximize();
15009 g_pcurtain->Show();
15012 g_pcurtain->Enable();
15013 g_pcurtain->Disable();
15020 g_brightness_init =
true;
15026 wxString cmd(
"xcalib -version");
15028 wxArrayString output;
15029 long r = wxExecute(cmd, output);
15032 " External application \"xcalib\" not found. Screen brightness "
15035 g_brightness_init =
true;
15040int RestoreScreenBrightness() {
15043 if (g_pSavedGammaMap) {
15044 HDC hDC = GetDC(NULL);
15045 g_pSetDeviceGammaRamp(hDC,
15047 ReleaseDC(NULL, hDC);
15049 free(g_pSavedGammaMap);
15050 g_pSavedGammaMap = NULL;
15054 g_pcurtain->Close();
15055 g_pcurtain->Destroy();
15059 g_brightness_init =
false;
15064#ifdef BRIGHT_XCALIB
15065 if (g_brightness_init) {
15067 cmd =
"xcalib -clear";
15068 wxExecute(cmd, wxEXEC_ASYNC);
15069 g_brightness_init =
false;
15079int SetScreenBrightness(
int brightness) {
15086 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15088 g_pcurtain->Close();
15089 g_pcurtain->Destroy();
15093 InitScreenBrightness();
15095 if (NULL == hGDI32DLL) {
15097 wchar_t wdll_name[80];
15098 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15099 LPCWSTR cstr = wdll_name;
15101 hGDI32DLL = LoadLibrary(cstr);
15103 if (NULL != hGDI32DLL) {
15105 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15106 hGDI32DLL,
"SetDeviceGammaRamp");
15107 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15108 hGDI32DLL,
"GetDeviceGammaRamp");
15111 if ((NULL == g_pSetDeviceGammaRamp) ||
15112 (NULL == g_pGetDeviceGammaRamp)) {
15113 FreeLibrary(hGDI32DLL);
15120 HDC hDC = GetDC(NULL);
15131 int increment = brightness * 256 / 100;
15134 WORD GammaTable[3][256];
15137 for (
int i = 0; i < 256; i++) {
15138 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15139 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15140 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15142 table_val += increment;
15144 if (table_val > 65535) table_val = 65535;
15147 g_pSetDeviceGammaRamp(hDC, GammaTable);
15148 ReleaseDC(NULL, hDC);
15155 if (g_pSavedGammaMap) {
15156 HDC hDC = GetDC(NULL);
15157 g_pSetDeviceGammaRamp(hDC,
15159 ReleaseDC(NULL, hDC);
15162 if (brightness < 100) {
15163 if (NULL == g_pcurtain) InitScreenBrightness();
15166 int sbrite = wxMax(1, brightness);
15167 sbrite = wxMin(100, sbrite);
15169 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15173 g_pcurtain->Close();
15174 g_pcurtain->Destroy();
15184#ifdef BRIGHT_XCALIB
15186 if (!g_brightness_init) {
15187 last_brightness = 100;
15188 g_brightness_init =
true;
15189 temp_file_name = wxFileName::CreateTempFileName(
"");
15190 InitScreenBrightness();
15193#ifdef __OPCPN_USEICC__
15196 if (!CreateSimpleICCProfileFile(
15197 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15198 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15199 wxString cmd(
"xcalib ");
15200 cmd += temp_file_name;
15202 wxExecute(cmd, wxEXEC_ASYNC);
15211 if (brightness > last_brightness) {
15213 cmd =
"xcalib -clear";
15214 wxExecute(cmd, wxEXEC_ASYNC);
15216 ::wxMilliSleep(10);
15218 int brite_adj = wxMax(1, brightness);
15219 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15220 wxExecute(cmd, wxEXEC_ASYNC);
15222 int brite_adj = wxMax(1, brightness);
15223 int factor = (brite_adj * 100) / last_brightness;
15224 factor = wxMax(1, factor);
15226 cmd.Printf(
"xcalib -co %2d -a", factor);
15227 wxExecute(cmd, wxEXEC_ASYNC);
15232 last_brightness = brightness;
15239#ifdef __OPCPN_USEICC__
15241#define MLUT_TAG 0x6d4c5554L
15242#define VCGT_TAG 0x76636774L
15244int GetIntEndian(
unsigned char *s) {
15249 p = (
unsigned char *)&ret;
15252 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15254 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15259unsigned short GetShortEndian(
unsigned char *s) {
15260 unsigned short ret;
15264 p = (
unsigned char *)&ret;
15267 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15269 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15275int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15276 double co_green,
double co_blue) {
15280 fp = fopen(file_name,
"wb");
15281 if (!fp)
return -1;
15287 for (
int i = 0; i < 128; i++) header[i] = 0;
15289 fwrite(header, 128, 1, fp);
15293 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15294 fwrite(&numTags, 1, 4, fp);
15296 int tagName0 = VCGT_TAG;
15297 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15298 fwrite(&tagName, 1, 4, fp);
15300 int tagOffset0 = 128 + 4 *
sizeof(int);
15301 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15302 fwrite(&tagOffset, 1, 4, fp);
15305 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15306 fwrite(&tagSize, 1, 4, fp);
15308 fwrite(&tagName, 1, 4, fp);
15310 fwrite(&tagName, 1, 4, fp);
15315 int gammatype0 = 0;
15316 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15317 fwrite(&gammatype, 1, 4, fp);
15319 int numChannels0 = 3;
15320 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15321 fwrite(&numChannels, 1, 2, fp);
15323 int numEntries0 = 256;
15324 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15325 fwrite(&numEntries, 1, 2, fp);
15327 int entrySize0 = 1;
15328 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15329 fwrite(&entrySize, 1, 2, fp);
15331 unsigned char ramp[256];
15334 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15335 fwrite(ramp, 256, 1, fp);
15338 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15339 fwrite(ramp, 256, 1, fp);
15342 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15343 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.