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"
116#include "tide_time.h"
123#include "user_colors.h"
125#include "s57_ocpn_utils.h"
128#include "androidUTIL.h"
138#include <wx/msw/msvcrt.h>
147#define printf printf2
149int __cdecl printf2(
const char *format, ...) {
153 va_start(argptr, format);
154 int ret = vsnprintf(str,
sizeof(str), format, argptr);
156 OutputDebugStringA(str);
161#if defined(__MSVC__) && (_MSC_VER < 1700)
162#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
168#define OCPN_ALT_MENUBAR 1
175static bool g_bSmoothRecenter =
true;
176static bool bDrawCurrentValues;
197static bool mouse_leftisdown;
198static bool g_brouteCreating;
199static int r_gamma_mult;
200static int g_gamma_mult;
201static int b_gamma_mult;
202static int gamma_state;
203static bool g_brightness_init;
204static int last_brightness;
205static wxGLContext *g_pGLcontext;
208static wxDialog *g_pcurtain;
210static wxString g_lastS52PLIBPluginMessage;
213#define MAX_BRIGHT 100
220EVT_ACTIVATE(ChartCanvas::OnActivate)
221EVT_SIZE(ChartCanvas::OnSize)
222#ifndef HAVE_WX_GESTURE_EVENTS
223EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
225EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
226EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
227EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
228EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
229EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
230EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
231EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
232EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
233EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
234EVT_KEY_UP(ChartCanvas::OnKeyUp)
235EVT_CHAR(ChartCanvas::OnKeyChar)
236EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
237EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
238EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
239EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
240EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
241EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
242EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
243EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
244EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
245EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
252 m_nmea_log(nmea_log) {
253 parent_frame = frame;
254 m_canvasIndex = canvasIndex;
258 SetBackgroundColour(wxColour(0, 0, 0));
259 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
263 m_bDrawingRoute =
false;
264 m_bRouteEditing =
false;
265 m_bMarkEditing =
false;
266 m_bRoutePoinDragging =
false;
267 m_bIsInRadius =
false;
268 m_bMayToggleMenuBar =
true;
271 m_bShowNavobjects =
true;
273 m_bAppendingRoute =
false;
274 pThumbDIBShow = NULL;
275 m_bShowCurrent =
false;
277 bShowingCurrent =
false;
281 m_b_paint_enable =
true;
284 pss_overlay_bmp = NULL;
285 pss_overlay_mask = NULL;
286 m_bChartDragging =
false;
287 m_bMeasure_Active =
false;
288 m_bMeasure_DistCircle =
false;
289 m_pMeasureRoute = NULL;
290 m_pTrackRolloverWin = NULL;
291 m_pRouteRolloverWin = NULL;
292 m_pAISRolloverWin = NULL;
294 m_disable_edge_pan =
false;
295 m_dragoffsetSet =
false;
299 m_singleChart = NULL;
300 m_upMode = NORTH_UP_MODE;
302 m_bShowAISScaled =
false;
303 m_timed_move_vp_active =
false;
305 m_disable_adjust_on_zoom =
false;
312 m_pSelectedRoute = NULL;
313 m_pSelectedTrack = NULL;
314 m_pRoutePointEditTarget = NULL;
315 m_pFoundPoint = NULL;
316 m_pMouseRoute = NULL;
317 m_prev_pMousePoint = NULL;
318 m_pEditRouteArray = NULL;
319 m_pFoundRoutePoint = NULL;
320 m_FinishRouteOnKillFocus =
true;
322 m_pRolloverRouteSeg = NULL;
323 m_pRolloverTrackSeg = NULL;
324 m_bsectors_shown =
false;
326 m_bbrightdir =
false;
331 m_pos_image_user_day = NULL;
332 m_pos_image_user_dusk = NULL;
333 m_pos_image_user_night = NULL;
334 m_pos_image_user_grey_day = NULL;
335 m_pos_image_user_grey_dusk = NULL;
336 m_pos_image_user_grey_night = NULL;
339 m_rotation_speed = 0;
345 m_pos_image_user_yellow_day = NULL;
346 m_pos_image_user_yellow_dusk = NULL;
347 m_pos_image_user_yellow_night = NULL;
349 SetOwnShipState(SHIP_INVALID);
351 undo =
new Undo(
this);
357 m_focus_indicator_pix = 1;
359 m_pCurrentStack = NULL;
360 m_bpersistent_quilt =
false;
361 m_piano_ctx_menu = NULL;
363 m_NotificationsList = NULL;
364 m_notification_button = NULL;
366 g_ChartNotRenderScaleFactor = 2.0;
367 m_bShowScaleInStatusBar =
true;
370 m_bShowScaleInStatusBar =
false;
371 m_show_focus_bar =
true;
373 m_bShowOutlines =
false;
374 m_bDisplayGrid =
false;
375 m_bShowDepthUnits =
true;
376 m_encDisplayCategory = (int)STANDARD;
378 m_encShowLights =
true;
379 m_encShowAnchor =
true;
380 m_encShowDataQual =
false;
382 m_pQuilt =
new Quilt(
this);
387 g_PrintingInProgress =
false;
389#ifdef HAVE_WX_GESTURE_EVENTS
390 m_oldVPSScale = -1.0;
391 m_popupWanted =
false;
394 m_inLongPress =
false;
397 m_sw_left_down.Start();
398 m_sw_left_up.Start();
402 singleClickEventIsValid =
false;
411 pCursorPencil = NULL;
416 SetCursor(*pCursorArrow);
418 pPanTimer =
new wxTimer(
this, m_MouseDragging);
421 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
422 pMovementTimer->Stop();
424 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
425 pMovementStopTimer->Stop();
427 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
428 pRotDefTimer->Stop();
430 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
431 m_DoubleClickTimer->Stop();
433 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
434 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
435 m_chart_drag_inertia_active =
false;
437 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
438 m_animationActive =
false;
439 m_menuTimer.SetOwner(
this, MENU_TIMER);
440 m_tap_timer.SetOwner(
this, TAP_TIMER);
444 m_panx_target_final = m_pany_target_final = 0;
445 m_panx_target_now = m_pany_target_now = 0;
448 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
449 pCurTrackTimer->Stop();
450 m_curtrack_timer_msec = 10;
452 m_wheelzoom_stop_oneshot = 0;
453 m_last_wheel_dir = 0;
455 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
457 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
459 m_rollover_popup_timer_msec = 20;
461 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
463 m_b_rot_hidef =
true;
468 m_upMode = NORTH_UP_MODE;
469 m_bLookAhead =
false;
473 m_cs = GLOBAL_COLOR_SCHEME_DAY;
476 VPoint.view_scale_ppm = 1;
479 m_ignore_next_leftup =
false;
481 m_canvas_scale_factor = 1.;
483 m_canvas_width = 1000;
485 m_overzoomTextWidth = 0;
486 m_overzoomTextHeight = 0;
495 m_pEM_Fathoms = NULL;
497 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
499 m_pEM_OverZoom = NULL;
501 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
509 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
512 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
515 double factor_dusk = 0.5;
516 double factor_night = 0.25;
519 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
521 int rimg_width = m_os_image_red_day.GetWidth();
522 int rimg_height = m_os_image_red_day.GetHeight();
524 m_os_image_red_dusk = m_os_image_red_day.Copy();
525 m_os_image_red_night = m_os_image_red_day.Copy();
527 for (
int iy = 0; iy < rimg_height; iy++) {
528 for (
int ix = 0; ix < rimg_width; ix++) {
529 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
530 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
531 m_os_image_red_day.GetGreen(ix, iy),
532 m_os_image_red_day.GetBlue(ix, iy));
533 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
534 hsv.value = hsv.value * factor_dusk;
535 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
536 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
538 hsv = wxImage::RGBtoHSV(rgb);
539 hsv.value = hsv.value * factor_night;
540 nrgb = wxImage::HSVtoRGB(hsv);
541 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
547 m_os_image_grey_day =
548 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
550 int gimg_width = m_os_image_grey_day.GetWidth();
551 int gimg_height = m_os_image_grey_day.GetHeight();
553 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
554 m_os_image_grey_night = m_os_image_grey_day.Copy();
556 for (
int iy = 0; iy < gimg_height; iy++) {
557 for (
int ix = 0; ix < gimg_width; ix++) {
558 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
559 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
560 m_os_image_grey_day.GetGreen(ix, iy),
561 m_os_image_grey_day.GetBlue(ix, iy));
562 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
563 hsv.value = hsv.value * factor_dusk;
564 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
565 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
567 hsv = wxImage::RGBtoHSV(rgb);
568 hsv.value = hsv.value * factor_night;
569 nrgb = wxImage::HSVtoRGB(hsv);
570 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
576 m_os_image_yellow_day = m_os_image_red_day.Copy();
578 gimg_width = m_os_image_yellow_day.GetWidth();
579 gimg_height = m_os_image_yellow_day.GetHeight();
581 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
582 m_os_image_yellow_night = m_os_image_red_day.Copy();
584 for (
int iy = 0; iy < gimg_height; iy++) {
585 for (
int ix = 0; ix < gimg_width; ix++) {
586 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
587 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
588 m_os_image_yellow_day.GetGreen(ix, iy),
589 m_os_image_yellow_day.GetBlue(ix, iy));
590 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
591 hsv.hue += 60. / 360.;
592 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
593 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
595 hsv = wxImage::RGBtoHSV(rgb);
596 hsv.value = hsv.value * factor_dusk;
597 hsv.hue += 60. / 360.;
598 nrgb = wxImage::HSVtoRGB(hsv);
599 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
601 hsv = wxImage::RGBtoHSV(rgb);
602 hsv.hue += 60. / 360.;
603 hsv.value = hsv.value * factor_night;
604 nrgb = wxImage::HSVtoRGB(hsv);
605 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
611 m_pos_image_red = &m_os_image_red_day;
612 m_pos_image_yellow = &m_os_image_yellow_day;
613 m_pos_image_grey = &m_os_image_grey_day;
617 m_pBrightPopup = NULL;
620 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
625 m_Piano =
new Piano(
this);
627 m_bShowCompassWin =
true;
629 m_Compass->SetScaleFactor(g_compass_scalefactor);
630 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
632 if (IsPrimaryCanvas()) {
634 m_notification_button->SetScaleFactor(g_compass_scalefactor);
635 m_notification_button->Show(
true);
638 m_pianoFrozen =
false;
640 SetMinSize(wxSize(200, 200));
642 m_displayScale = 1.0;
643#if defined(__WXOSX__) || defined(__WXGTK3__)
645 m_displayScale = GetContentScaleFactor();
647 VPoint.SetPixelScale(m_displayScale);
649#ifdef HAVE_WX_GESTURE_EVENTS
652 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
653 wxLogError(
"Failed to enable touch events");
658 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
659 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
661 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
662 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
664 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
665 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
667 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
668 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
673 auto ¬eman = NotificationManager::GetInstance();
675 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
676 evt_notificationlist_change_listener.Listen(
677 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
678 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
679 if (m_NotificationsList && m_NotificationsList->IsShown()) {
680 m_NotificationsList->ReloadNotificationList();
686ChartCanvas::~ChartCanvas() {
687 delete pThumbDIBShow;
695 delete pCursorPencil;
699 delete pMovementTimer;
700 delete pMovementStopTimer;
701 delete pCurTrackTimer;
703 delete m_DoubleClickTimer;
705 delete m_pTrackRolloverWin;
706 delete m_pRouteRolloverWin;
707 delete m_pAISRolloverWin;
708 delete m_pBrightPopup;
714 m_dc_route.SelectObject(wxNullBitmap);
717 delete pWorldBackgroundChart;
718 delete pss_overlay_bmp;
722 delete m_pEM_Fathoms;
724 delete m_pEM_OverZoom;
729 delete m_pos_image_user_day;
730 delete m_pos_image_user_dusk;
731 delete m_pos_image_user_night;
732 delete m_pos_image_user_grey_day;
733 delete m_pos_image_user_grey_dusk;
734 delete m_pos_image_user_grey_night;
735 delete m_pos_image_user_yellow_day;
736 delete m_pos_image_user_yellow_dusk;
737 delete m_pos_image_user_yellow_night;
741 if (!g_bdisable_opengl) {
744#if wxCHECK_VERSION(2, 9, 0)
745 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
752 MUIBar *muiBar = m_muiBar;
756 delete m_pCurrentStack;
759 delete m_notification_button;
762void ChartCanvas::SetupGridFont() {
763 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
765 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
767 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
768 FALSE, wxString(
"Arial"));
771void ChartCanvas::RebuildCursors() {
777 delete pCursorPencil;
781 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
786 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
787 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
788 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
789 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
790 wxImage ICursorPencil =
791 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
792 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
794#if !defined(__WXMSW__) && !defined(__WXQT__)
795 ICursorLeft.ConvertAlphaToMask(128);
796 ICursorRight.ConvertAlphaToMask(128);
797 ICursorUp.ConvertAlphaToMask(128);
798 ICursorDown.ConvertAlphaToMask(128);
799 ICursorPencil.ConvertAlphaToMask(10);
800 ICursorCross.ConvertAlphaToMask(10);
803 if (ICursorLeft.Ok()) {
804 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
805 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
806 pCursorLeft =
new wxCursor(ICursorLeft);
808 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
810 if (ICursorRight.Ok()) {
811 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
812 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
813 pCursorRight =
new wxCursor(ICursorRight);
815 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
817 if (ICursorUp.Ok()) {
818 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
819 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
820 pCursorUp =
new wxCursor(ICursorUp);
822 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
824 if (ICursorDown.Ok()) {
825 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
826 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
827 pCursorDown =
new wxCursor(ICursorDown);
829 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
831 if (ICursorPencil.Ok()) {
832 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
833 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
834 pCursorPencil =
new wxCursor(ICursorPencil);
836 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
838 if (ICursorCross.Ok()) {
839 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
840 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
841 pCursorCross =
new wxCursor(ICursorCross);
843 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
845 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
846 pPlugIn_Cursor = NULL;
849void ChartCanvas::CanvasApplyLocale() {
850 CreateDepthUnitEmbossMaps(m_cs);
851 CreateOZEmbossMapData(m_cs);
854void ChartCanvas::SetupGlCanvas() {
857 if (!g_bdisable_opengl) {
859 wxLogMessage(
"Creating glChartCanvas");
864 if (IsPrimaryCanvas()) {
871 wxGLContext *pctx =
new wxGLContext(m_glcc);
872 m_glcc->SetContext(pctx);
876 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
878 m_glcc->SetContext(g_pGLcontext);
888 if (!g_bdisable_opengl) {
891 wxLogMessage(
"Creating glChartCanvas");
895 if (IsPrimaryCanvas()) {
896 qDebug() <<
"Creating Primary glChartCanvas";
904 wxGLContext *pctx =
new wxGLContext(m_glcc);
905 m_glcc->SetContext(pctx);
907 m_glcc->m_pParentCanvas =
this;
910 qDebug() <<
"Creating Secondary glChartCanvas";
917 top_frame::Get()->GetWxGlCanvas());
920 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
921 m_glcc->SetContext(pwxctx);
922 m_glcc->m_pParentCanvas =
this;
930void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
931 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
946 if (m_routeState && m_FinishRouteOnKillFocus)
947 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
949 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
953void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
954 m_routeFinishTimer.Stop();
958 top_frame::Get()->UpdateGlobalMenuItems(
this);
960 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
963void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
964 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
967#ifdef HAVE_WX_GESTURE_EVENTS
968void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
975 m_popupWanted =
true;
977 m_inLongPress = !g_bhide_context_menus;
980 m_menuPos =
event.GetPosition();
981 wxMouseEvent ev(wxEVT_LEFT_UP);
982 ev.m_x = m_menuPos.x;
983 ev.m_y = m_menuPos.y;
984 wxPostEvent(
this, ev);
988 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
989 ev_right_click.m_x = m_menuPos.x;
990 ev_right_click.m_y = m_menuPos.y;
991 MouseEvent(ev_right_click);
996void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1000void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1002void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1004void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1006 long dt = m_sw_left_up.Time() - m_sw_up_time;
1007 m_sw_up_time = m_sw_left_up.Time();
1018 wxPoint pos =
event.GetPosition();
1022 if (!m_popupWanted) {
1023 wxMouseEvent ev(wxEVT_LEFT_UP);
1030 m_popupWanted =
false;
1032 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1039void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1044 long dt = m_sw_left_down.Time() - m_sw_down_time;
1045 m_sw_down_time = m_sw_left_down.Time();
1069 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1071 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1072 m_lastTapPos.y - max_double_click_distance,
1073 max_double_click_distance * 2, max_double_click_distance * 2);
1076 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1082 m_lastTapPos =
event.GetPosition();
1083 m_tap_timer.StartOnce(
1087 if (m_tap_count == 2) {
1091 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1104void ChartCanvas::OnMotion(wxMouseEvent &event) {
1109 event.m_leftDown = m_leftdown;
1113void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1115 if (event.IsGestureEnd())
return;
1117 double factor =
event.GetZoomFactor();
1119 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1124 double wanted_factor = m_oldVPSScale / current_vps * factor;
1129 if (event.IsGestureStart()) {
1130 m_zoomStartPoint =
event.GetPosition();
1132 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1134 m_zoomStartPoint =
event.GetPosition();
1138void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1140void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1141 DoRotateCanvas(0.0);
1145void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1150void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1151 m_FinishRouteOnKillFocus =
false;
1152 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1153 m_FinishRouteOnKillFocus =
true;
1156void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1161 m_restore_dbindex = pcc->DBindex;
1163 if (pcc->GroupID < 0) pcc->GroupID = 0;
1168 m_groupIndex = pcc->GroupID;
1170 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1184 m_encDisplayCategory = pcc->nENCDisplayCategory;
1185 m_encShowDepth = pcc->bShowENCDepths;
1186 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1187 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1188 m_encShowLights = pcc->bShowENCLights;
1189 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1190 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1191 m_encShowDataQual = pcc->bShowENCDataQuality;
1195 m_upMode = NORTH_UP_MODE;
1197 m_upMode = COURSE_UP_MODE;
1199 m_upMode = HEAD_UP_MODE;
1203 m_singleChart = NULL;
1206void ChartCanvas::ApplyGlobalSettings() {
1209 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1210 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1212 if (m_notification_button) m_notification_button->UpdateStatus();
1215void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1216 bool groupOK = CheckGroup(m_groupIndex);
1219 SetGroupIndex(m_groupIndex,
true);
1223void ChartCanvas::SetShowGPS(
bool bshow) {
1224 if (m_bShowGPS != bshow) {
1227 m_Compass->SetScaleFactor(g_compass_scalefactor);
1228 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1233void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1234 m_bShowCompassWin = bshow;
1236 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1237 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1241int ChartCanvas::GetPianoHeight() {
1243 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1248void ChartCanvas::ConfigureChartBar() {
1251 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1252 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1254 if (GetQuiltMode()) {
1255 m_Piano->SetRoundedRectangles(
true);
1257 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1258 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1259 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1262void ChartCanvas::ShowTides(
bool bShow) {
1263 top_frame::Get()->LoadHarmonics();
1266 SetbShowTide(bShow);
1268 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1270 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1271 SetbShowTide(
false);
1272 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1275 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1276 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1287void ChartCanvas::ShowCurrents(
bool bShow) {
1288 top_frame::Get()->LoadHarmonics();
1291 SetbShowCurrent(bShow);
1292 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1294 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1295 SetbShowCurrent(
false);
1296 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1299 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1300 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1317void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1319void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1322 int new_index = index;
1325 bool bgroup_override =
false;
1326 int old_group_index = new_index;
1328 if (!CheckGroup(new_index)) {
1330 bgroup_override =
true;
1333 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1337 int current_chart_native_scale = GetCanvasChartNativeScale();
1340 m_groupIndex = new_index;
1346 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1350 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1354 g_sticky_chart = -1;
1358 UpdateCanvasOnGroupChange();
1361 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1363 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1366 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1367 double best_scale = GetBestStartScale(dbi_hint, vp);
1371 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1375 canvasChartsRefresh(dbi_hint);
1377 UpdateCanvasControlBar();
1379 if (!autoSwitch && bgroup_override) {
1381 wxString msg(_(
"Group \""));
1384 msg += pGroup->m_group_name;
1386 msg += _(
"\" is empty.");
1388 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1395 if (bgroup_override) {
1396 wxString msg(_(
"Group \""));
1399 msg += pGroup->m_group_name;
1401 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1403 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1407bool ChartCanvas::CheckGroup(
int igroup) {
1410 if (igroup == 0)
return true;
1417 if (pGroup->m_element_array.empty())
1421 for (
const auto &elem : pGroup->m_element_array) {
1422 for (
unsigned int ic = 0;
1423 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1424 auto &cte =
ChartData->GetChartTableEntry(ic);
1425 wxString chart_full_path(cte.GetpFullPath(), wxConvUTF8);
1427 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1432 for (
const auto &elem : pGroup->m_element_array) {
1433 const wxString &element_root = elem.m_element_name;
1434 wxString test_string =
"GSHH";
1435 if (element_root.Upper().Contains(test_string))
return true;
1441void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1444 AbstractPlatform::ShowBusySpinner();
1448 SetQuiltRefChart(-1);
1450 m_singleChart = NULL;
1456 if (!m_pCurrentStack) {
1458 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1461 if (-1 != dbi_hint) {
1462 if (GetQuiltMode()) {
1463 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1464 SetQuiltRefChart(dbi_hint);
1468 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1470 if (pTentative_Chart) {
1473 if (m_singleChart) m_singleChart->Deactivate();
1475 m_singleChart = pTentative_Chart;
1476 m_singleChart->Activate();
1478 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1479 GetpCurrentStack(), m_singleChart->GetFullPath());
1487 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1488 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1489 SetQuiltRefChart(selected_index);
1493 SetupCanvasQuiltMode();
1494 if (!GetQuiltMode() && m_singleChart == 0) {
1496 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1497 m_singleChart = pDummyChart;
1503 UpdateCanvasControlBar();
1504 UpdateGPSCompassStatusBox(
true);
1506 SetCursor(wxCURSOR_ARROW);
1508 AbstractPlatform::HideBusySpinner();
1511bool ChartCanvas::DoCanvasUpdate() {
1513 double vpLat, vpLon;
1514 bool blong_jump =
false;
1515 meters_to_shift = 0;
1518 bool bNewChart =
false;
1519 bool bNewView =
false;
1520 bool bCanvasChartAutoOpen =
true;
1522 bool bNewPiano =
false;
1523 bool bOpenSpecified;
1529 if (!GetVP().IsValid())
return false;
1530 if (bDBUpdateInProgress)
return false;
1535 if (m_chart_drag_inertia_active)
return false;
1536 if (m_animationActive)
return false;
1562 double dx = m_OSoffsetx;
1563 double dy = m_OSoffsety;
1567 if (GetUpMode() == NORTH_UP_MODE) {
1568 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1570 double offset_angle = atan2(d_north, d_east);
1571 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1572 double chart_angle = GetVPRotation();
1573 double target_angle = chart_angle + offset_angle;
1574 double d_east_mod = offset_distance * cos(target_angle);
1575 double d_north_mod = offset_distance * sin(target_angle);
1576 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1580 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1581 double cog_to_use =
gCog;
1583 (fabs(
gCog - gCog_gt) > 20)) {
1584 cog_to_use = gCog_gt;
1587 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1589 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1591 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1592 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1594 double pixel_delta_tent =
1595 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1597 double pixel_delta = 0;
1602 if (!std::isnan(
gSog)) {
1606 pixel_delta = pixel_delta_tent;
1609 meters_to_shift = 0;
1611 if (!std::isnan(
gCog)) {
1612 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1613 dir_to_shift = cog_to_use;
1614 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1620 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1634 if (GetQuiltMode()) {
1635 int current_db_index = -1;
1636 if (m_pCurrentStack)
1639 ->GetCurrentEntrydbIndex();
1647 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1649 if (m_pCurrentStack->nEntry) {
1650 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1652 SelectQuiltRefdbChart(new_dbIndex,
true);
1653 m_bautofind =
false;
1657 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1658 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1663 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1669 double proposed_scale_onscreen =
1672 int initial_db_index = m_restore_dbindex;
1673 if (initial_db_index < 0) {
1674 if (m_pCurrentStack->nEntry) {
1676 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1681 if (m_pCurrentStack->nEntry) {
1682 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1687 if (!IsChartQuiltableRef(initial_db_index)) {
1691 int stack_index = 0;
1693 if (stack_index >= 0) {
1694 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1695 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1696 if (IsChartQuiltableRef(test_db_index) &&
1698 ChartData->GetDBChartType(initial_db_index))) {
1699 initial_db_index = test_db_index;
1709 SetQuiltRefChart(initial_db_index);
1710 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1718 0, GetVPRotation());
1723 bool super_jump =
false;
1725 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1726 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1727 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1734 pLast_Ch = m_singleChart;
1735 ChartTypeEnum new_open_type;
1736 ChartFamilyEnum new_open_family;
1738 new_open_type = pLast_Ch->GetChartType();
1739 new_open_family = pLast_Ch->GetChartFamily();
1741 new_open_type = CHART_TYPE_KAP;
1742 new_open_family = CHART_FAMILY_RASTER;
1745 bOpenSpecified = m_bFirstAuto;
1748 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1751 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1753 if (NULL == pDummyChart) {
1759 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1761 m_singleChart = pDummyChart;
1766 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1768 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1771 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1772 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1779 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1785 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1790 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1793 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1798 if (NULL != m_singleChart)
1799 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1800 m_singleChart->GetFullPath());
1803 m_pCurrentStack->CurrentStackEntry = tEntry;
1813 if (bCanvasChartAutoOpen) {
1814 bool search_direction =
1816 int start_index = 0;
1820 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1821 (LastStack.nEntry == 0)) {
1822 search_direction =
true;
1823 start_index = m_pCurrentStack->nEntry - 1;
1827 if (bOpenSpecified) {
1828 if (m_restore_dbindex >= 0) {
1830 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
1831 std::vector<int> one_array;
1832 one_array.push_back(m_restore_dbindex);
1833 m_Piano->SetActiveKeyArray(one_array);
1834 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
1835 m_restore_dbindex = -1;
1839 search_direction =
false;
1840 start_index = m_restore_dbindex;
1841 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1844 new_open_type = CHART_TYPE_DONTCARE;
1849 pProposed =
ChartData->OpenStackChartConditional(
1850 m_pCurrentStack, start_index, search_direction, new_open_type,
1854 if (NULL == pProposed)
1855 pProposed =
ChartData->OpenStackChartConditional(
1856 m_pCurrentStack, start_index, search_direction,
1857 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1859 if (NULL == pProposed)
1860 pProposed =
ChartData->OpenStackChartConditional(
1861 m_pCurrentStack, start_index, search_direction,
1862 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1873 if (NULL == pProposed) {
1874 if (NULL == pDummyChart) {
1880 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1882 pProposed = pDummyChart;
1886 if (m_singleChart) m_singleChart->Deactivate();
1887 m_singleChart = pProposed;
1889 if (m_singleChart) {
1890 m_singleChart->Activate();
1891 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1892 m_pCurrentStack, m_singleChart->GetFullPath());
1897 if (NULL != m_singleChart) {
1901 double proposed_scale_onscreen;
1904 double new_scale_ppm =
1905 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1913 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1914 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1915 double equivalent_vp_scale =
1917 double new_scale_ppm =
1918 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1923 proposed_scale_onscreen =
1924 wxMin(proposed_scale_onscreen,
1927 proposed_scale_onscreen =
1928 wxMax(proposed_scale_onscreen,
1936 m_singleChart->GetChartSkew() * PI / 180.,
1944 if ((m_bFollow) && m_singleChart)
1946 m_singleChart->GetChartSkew() * PI / 180.,
1955 m_bFirstAuto =
false;
1959 if (bNewChart && !bNewView) Refresh(
false);
1964 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1967 return bNewChart | bNewView;
1970void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1971 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1973 SetQuiltRefChart(db_index);
1978 double best_scale_ppm = GetBestVPScale(pc);
1982 SetQuiltRefChart(-1);
1984 SetQuiltRefChart(-1);
1987void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1988 std::vector<int> piano_chart_index_array =
1989 GetQuiltExtendedStackdbIndexArray();
1990 int current_db_index = piano_chart_index_array[selected_index];
1992 SelectQuiltRefdbChart(current_db_index);
1995double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1999 if ((g_bPreserveScaleOnX) ||
2000 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2006 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2007 double equivalent_vp_scale =
2009 double new_scale_ppm =
2010 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2017 double max_underzoom_multiplier = 2.0;
2018 if (GetVP().b_quilt) {
2019 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2020 pchart->GetChartType(),
2021 pchart->GetChartFamily());
2022 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2025 proposed_scale_onscreen = wxMin(
2026 proposed_scale_onscreen,
2028 max_underzoom_multiplier);
2031 proposed_scale_onscreen =
2032 wxMax(proposed_scale_onscreen,
2040void ChartCanvas::SetupCanvasQuiltMode() {
2045 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2049 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2050 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2051 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2052 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2054 m_Piano->SetRoundedRectangles(
true);
2057 int target_new_dbindex = -1;
2058 if (m_pCurrentStack) {
2059 target_new_dbindex =
2060 GetQuiltReferenceChartIndex();
2062 if (-1 != target_new_dbindex) {
2063 if (!IsChartQuiltableRef(target_new_dbindex)) {
2064 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2065 int type =
ChartData->GetDBChartType(target_new_dbindex);
2068 int stack_index = m_pCurrentStack->CurrentStackEntry;
2070 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2071 (stack_index >= 0)) {
2072 int proj_tent =
ChartData->GetDBChartProj(
2073 m_pCurrentStack->GetDBIndex(stack_index));
2074 int type_tent =
ChartData->GetDBChartType(
2075 m_pCurrentStack->GetDBIndex(stack_index));
2077 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2078 if ((proj == proj_tent) && (type_tent == type)) {
2079 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2089 if (IsChartQuiltableRef(target_new_dbindex))
2090 SelectQuiltRefdbChart(target_new_dbindex,
2093 int stack_index = m_pCurrentStack->CurrentStackEntry;
2094 SelectQuiltRefdbChart(m_pCurrentStack->GetDBIndex(stack_index),
false);
2097 m_singleChart = NULL;
2100 AdjustQuiltRefChart();
2108 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2112 std::vector<int> empty_array;
2113 m_Piano->SetActiveKeyArray(empty_array);
2114 m_Piano->SetNoshowIndexArray(empty_array);
2115 m_Piano->SetEclipsedIndexArray(empty_array);
2118 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2119 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2120 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2121 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2123 m_Piano->SetRoundedRectangles(
false);
2129 if (!GetQuiltMode()) {
2134 if (m_bFollow ==
true) {
2142 if (!m_singleChart) {
2144 if (GetQuiltReferenceChartIndex() >= 0) {
2145 m_singleChart =
ChartData->OpenChartFromDB(
2146 GetQuiltReferenceChartIndex(), FULL_INIT);
2149 else if (m_restore_dbindex >= 0) {
2151 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
2157 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2165 int cur_max_scale = (int)1e8;
2167 ChartBase *pChart = GetFirstQuiltChart();
2171 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2173 if (pChart->GetNativeScale() < cur_max_scale) {
2174 Candidate_Chart = pChart;
2175 cur_max_scale = pChart->GetNativeScale();
2178 pChart = GetNextQuiltChart();
2181 m_singleChart = Candidate_Chart;
2185 if (NULL == m_singleChart) {
2186 m_singleChart =
ChartData->OpenStackChartConditional(
2187 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2188 CHART_FAMILY_DONTCARE);
2194 InvalidateAllQuiltPatchs();
2196 if (m_singleChart) {
2197 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2198 std::vector<int> one_array;
2199 one_array.push_back(dbi);
2200 m_Piano->SetActiveKeyArray(one_array);
2203 if (m_singleChart) {
2204 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2209 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2213bool ChartCanvas::IsTempMenuBarEnabled() {
2216 wxGetOsVersion(&major);
2224double ChartCanvas::GetCanvasRangeMeters() {
2226 GetSize(&width, &height);
2227 int minDimension = wxMin(width, height);
2230 range *= cos(GetVP().clat * PI / 180.);
2234void ChartCanvas::SetCanvasRangeMeters(
double range) {
2236 GetSize(&width, &height);
2237 int minDimension = wxMin(width, height);
2239 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2243bool ChartCanvas::SetUserOwnship() {
2247 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2248 double factor_dusk = 0.5;
2249 double factor_night = 0.25;
2251 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2252 m_pos_image_user_day =
new wxImage;
2253 *m_pos_image_user_day = pbmp->ConvertToImage();
2254 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2256 int gimg_width = m_pos_image_user_day->GetWidth();
2257 int gimg_height = m_pos_image_user_day->GetHeight();
2260 m_pos_image_user_dusk =
new wxImage;
2261 m_pos_image_user_night =
new wxImage;
2263 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2264 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2266 for (
int iy = 0; iy < gimg_height; iy++) {
2267 for (
int ix = 0; ix < gimg_width; ix++) {
2268 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2269 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2270 m_pos_image_user_day->GetGreen(ix, iy),
2271 m_pos_image_user_day->GetBlue(ix, iy));
2272 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2273 hsv.value = hsv.value * factor_dusk;
2274 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2275 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2278 hsv = wxImage::RGBtoHSV(rgb);
2279 hsv.value = hsv.value * factor_night;
2280 nrgb = wxImage::HSVtoRGB(hsv);
2281 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2288 m_pos_image_user_grey_day =
new wxImage;
2289 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2291 m_pos_image_user_grey_dusk =
new wxImage;
2292 m_pos_image_user_grey_night =
new wxImage;
2294 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2295 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2297 for (
int iy = 0; iy < gimg_height; iy++) {
2298 for (
int ix = 0; ix < gimg_width; ix++) {
2299 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2300 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2301 m_pos_image_user_grey_day->GetGreen(ix, iy),
2302 m_pos_image_user_grey_day->GetBlue(ix, iy));
2303 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2304 hsv.value = hsv.value * factor_dusk;
2305 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2306 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2309 hsv = wxImage::RGBtoHSV(rgb);
2310 hsv.value = hsv.value * factor_night;
2311 nrgb = wxImage::HSVtoRGB(hsv);
2312 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2319 m_pos_image_user_yellow_day =
new wxImage;
2320 m_pos_image_user_yellow_dusk =
new wxImage;
2321 m_pos_image_user_yellow_night =
new wxImage;
2323 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2324 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2325 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2327 for (
int iy = 0; iy < gimg_height; iy++) {
2328 for (
int ix = 0; ix < gimg_width; ix++) {
2329 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2330 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2331 m_pos_image_user_grey_day->GetGreen(ix, iy),
2332 m_pos_image_user_grey_day->GetBlue(ix, iy));
2336 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2337 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2338 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2340 hsv = wxImage::RGBtoHSV(rgb);
2341 hsv.value = hsv.value * factor_dusk;
2342 nrgb = wxImage::HSVtoRGB(hsv);
2343 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2345 hsv = wxImage::RGBtoHSV(rgb);
2346 hsv.value = hsv.value * factor_night;
2347 nrgb = wxImage::HSVtoRGB(hsv);
2348 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2360 m_display_size_mm = size;
2367 double horizontal = sd.x;
2371 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2372 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2376 ps52plib->SetPPMM(m_pix_per_mm);
2381 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2383 m_display_size_mm, sd.x, sd.y);
2389 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2392 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2395void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2397 wxString msg(event.m_string.c_str(), wxConvUTF8);
2399 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2400 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2403 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2405 compress_msg_array.RemoveAt(event.thread);
2406 compress_msg_array.Insert( msg, event.thread);
2409 compress_msg_array.Add(msg);
2412 wxString combined_msg;
2413 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2414 combined_msg += compress_msg_array[i];
2415 combined_msg +=
"\n";
2419 pprog->Update(pprog_count, combined_msg, &skip );
2420 pprog->SetSize(pprog_size);
2425void ChartCanvas::InvalidateGL() {
2426 if (!m_glcc)
return;
2428 if (g_bopengl) m_glcc->Invalidate();
2430 if (m_Compass) m_Compass->UpdateStatus(
true);
2433int ChartCanvas::GetCanvasChartNativeScale() {
2435 if (!VPoint.b_quilt) {
2436 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2438 ret = (int)m_pQuilt->GetRefNativeScale();
2443ChartBase *ChartCanvas::GetChartAtCursor() {
2445 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2446 target_chart = m_singleChart;
2447 else if (VPoint.b_quilt)
2448 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2450 target_chart = NULL;
2451 return target_chart;
2454ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2458 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2460 target_chart = NULL;
2461 return target_chart;
2464int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2465 int new_dbIndex = -1;
2466 if (!VPoint.b_quilt) {
2467 if (m_pCurrentStack) {
2468 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2469 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2471 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2482 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2485 for (
unsigned int is = 0; is < im; is++) {
2487 m_pQuilt->GetExtendedStackIndexArray()[is]);
2488 if ((m.Scale_ge(
scale)) &&
2489 (m_pQuilt->GetRefFamily() == m.GetChartFamily())) {
2490 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2497 if (new_dbIndex < 0) {
2498 for (
unsigned int is = 0; is < im; is++) {
2500 m_pQuilt->GetExtendedStackIndexArray()[is]);
2501 if (m.Scale_ge(
scale)) {
2502 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2513void ChartCanvas::EnablePaint(
bool b_enable) {
2514 m_b_paint_enable = b_enable;
2516 if (m_glcc) m_glcc->EnablePaint(b_enable);
2520bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2522void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2524std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2525 return m_pQuilt->GetQuiltIndexArray();
2529void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2530 VPoint.b_quilt = b_quilt;
2531 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2534bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2536int ChartCanvas::GetQuiltReferenceChartIndex() {
2537 return m_pQuilt->GetRefChartdbIndex();
2540void ChartCanvas::InvalidateAllQuiltPatchs() {
2541 m_pQuilt->InvalidateAllQuiltPatchs();
2544ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2545 return m_pQuilt->GetLargestScaleChart();
2548ChartBase *ChartCanvas::GetFirstQuiltChart() {
2549 return m_pQuilt->GetFirstChart();
2552ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2554int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2556void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2557 m_pQuilt->SetHiliteIndex(dbIndex);
2560void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2561 m_pQuilt->SetHiliteIndexArray(hilite_array);
2564void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2565 m_pQuilt->ClearHiliteIndexArray();
2568std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2570 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2573int ChartCanvas::GetQuiltRefChartdbIndex() {
2574 return m_pQuilt->GetRefChartdbIndex();
2577std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2578 return m_pQuilt->GetExtendedStackIndexArray();
2581std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2582 return m_pQuilt->GetFullscreenIndexArray();
2585std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2586 return m_pQuilt->GetEclipsedStackIndexArray();
2589void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2591double ChartCanvas::GetQuiltMaxErrorFactor() {
2592 return m_pQuilt->GetMaxErrorFactor();
2595bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2596 return m_pQuilt->IsChartQuiltableRef(db_index);
2600 double chartMaxScale =
2602 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2605void ChartCanvas::StartMeasureRoute() {
2606 if (!m_routeState) {
2607 if (m_bMeasure_Active) {
2609 m_pMeasureRoute = NULL;
2612 m_bMeasure_Active =
true;
2613 m_nMeasureState = 1;
2614 m_bDrawingRoute =
false;
2616 SetCursor(*pCursorPencil);
2621void ChartCanvas::CancelMeasureRoute() {
2622 m_bMeasure_Active =
false;
2623 m_nMeasureState = 0;
2624 m_bDrawingRoute =
false;
2627 m_pMeasureRoute = NULL;
2629 SetCursor(*pCursorArrow);
2632ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2634void ChartCanvas::SetVP(
ViewPort &vp) {
2645void ChartCanvas::TriggerDeferredFocus() {
2648 m_deferredFocusTimer.Start(20,
true);
2650#if defined(__WXGTK__) || defined(__WXOSX__)
2651 top_frame::Get()->Raise();
2661void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2666void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2667 if (SendKeyEventToPlugins(event))
2671 int key_char =
event.GetKeyCode();
2674 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2680 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2685 if (g_benable_rotate) {
2706void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2707 if (SendKeyEventToPlugins(event))
2711 bool b_handled =
false;
2713 m_modkeys =
event.GetModifiers();
2715 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2717#ifdef OCPN_ALT_MENUBAR
2723 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2725 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2726 if (!g_bTempShowMenuBar) {
2727 g_bTempShowMenuBar =
true;
2728 top_frame::Get()->ApplyGlobalSettings(
false);
2730 m_bMayToggleMenuBar =
false;
2736 if (event.GetKeyCode() != WXK_ALT) {
2737 m_bMayToggleMenuBar =
false;
2744 switch (event.GetKeyCode()) {
2751 event.GetPosition(&x, &y);
2752 m_FinishRouteOnKillFocus =
false;
2753 CallPopupMenu(x, y);
2754 m_FinishRouteOnKillFocus =
true;
2758 m_modkeys |= wxMOD_ALT;
2762 m_modkeys |= wxMOD_CONTROL;
2767 case WXK_RAW_CONTROL:
2768 m_modkeys |= wxMOD_RAW_CONTROL;
2773 if (m_modkeys == wxMOD_CONTROL)
2774 top_frame::Get()->DoStackDown(
this);
2776 StartTimedMovement();
2786 StartTimedMovement();
2794 if (m_modkeys == wxMOD_CONTROL)
2795 top_frame::Get()->DoStackUp(
this);
2797 StartTimedMovement();
2807 StartTimedMovement();
2815 if (event.ShiftDown()) {
2817 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2819 std::shared_ptr<HostApi> host_api;
2821 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2824 api_121->SelectChartFamily(m_canvasIndex,
2831 if (event.ShiftDown()) {
2833 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2835 std::shared_ptr<HostApi> host_api;
2837 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2840 api_121->SelectChartFamily(m_canvasIndex,
2843 SetShowENCText(!GetShowENCText());
2850 if (!m_bMeasure_Active) {
2851 if (event.ShiftDown())
2852 m_bMeasure_DistCircle =
true;
2854 m_bMeasure_DistCircle =
false;
2856 StartMeasureRoute();
2858 CancelMeasureRoute();
2860 SetCursor(*pCursorArrow);
2870 top_frame::Get()->ToggleColorScheme();
2871 top_frame::Get()->Raise();
2872 TriggerDeferredFocus();
2876 int mod = m_modkeys & wxMOD_SHIFT;
2877 if (mod != m_brightmod) {
2879 m_bbrightdir = !m_bbrightdir;
2882 if (!m_bbrightdir) {
2883 g_nbrightness -= 10;
2884 if (g_nbrightness <= MIN_BRIGHT) {
2885 g_nbrightness = MIN_BRIGHT;
2886 m_bbrightdir =
true;
2889 g_nbrightness += 10;
2890 if (g_nbrightness >= MAX_BRIGHT) {
2891 g_nbrightness = MAX_BRIGHT;
2892 m_bbrightdir =
false;
2896 SetScreenBrightness(g_nbrightness);
2897 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2900 top_frame::Get()->Raise();
2906 top_frame::Get()->DoStackDown(
this);
2910 top_frame::Get()->DoStackUp(
this);
2915 ToggleCanvasQuiltMode();
2921 top_frame::Get()->ToggleFullScreen();
2926 if (m_modkeys == wxMOD_ALT) {
2929 ToggleChartOutlines();
2935 top_frame::Get()->ActivateMOB();
2939 case WXK_NUMPAD_ADD:
2944 case WXK_NUMPAD_SUBTRACT:
2945 case WXK_PAGEDOWN: {
2946 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2951 if (m_bMeasure_Active) {
2952 if (m_nMeasureState > 2) {
2953 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2955 m_pMeasureRoute->GetnPoints();
2957 top_frame::Get()->RefreshAllCanvas();
2959 CancelMeasureRoute();
2960 StartMeasureRoute();
2968 if (event.GetKeyCode() < 128)
2970 int key_char =
event.GetKeyCode();
2974 if (!g_b_assume_azerty) {
2976 if (g_benable_rotate) {
3008 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3015 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3016 m_modkeys & wxMOD_RAW_CONTROL) {
3017 top_frame::Get()->ToggleFullScreen();
3022 if (event.ControlDown()) key_char -= 64;
3024 if (key_char >=
'0' && key_char <=
'9')
3025 SetGroupIndex(key_char -
'0');
3030 SetShowENCAnchor(!GetShowENCAnchor());
3036 top_frame::Get()->ToggleColorScheme();
3041 event.GetPosition(&x, &y);
3042 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3043 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3046 if (VPoint.b_quilt) {
3048 if (m_pQuilt->GetChartAtPix(
3053 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3055 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3060 if (m_singleChart) {
3061 ChartType = m_singleChart->GetChartType();
3062 ChartFam = m_singleChart->GetChartFamily();
3066 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3067 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3069 this, -1, ChartType, ChartFam,
3070 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3071 wxDefaultSize, wxSIMPLE_BORDER,
"");
3084 m_nmea_log->Raise();
3088 SetShowENCLights(!GetShowENCLights());
3094 if (event.ShiftDown())
3095 m_bMeasure_DistCircle =
true;
3097 m_bMeasure_DistCircle =
false;
3099 StartMeasureRoute();
3103 if (g_bInlandEcdis && ps52plib) {
3104 SetENCDisplayCategory((_DisCat)STANDARD);
3109 ToggleChartOutlines();
3113 ToggleCanvasQuiltMode();
3117 top_frame::Get()->ToggleTestPause();
3120 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3121 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3122 g_iNavAidRadarRingsNumberVisible = 1;
3123 else if (!g_bNavAidRadarRingsShown &&
3124 g_iNavAidRadarRingsNumberVisible == 1)
3125 g_iNavAidRadarRingsNumberVisible = 0;
3128 SetShowENCDepth(!m_encShowDepth);
3133 SetShowENCText(!GetShowENCText());
3138 SetShowENCDataQual(!GetShowENCDataQual());
3143 m_bShowNavobjects = !m_bShowNavobjects;
3158 if (g_bShowMenuBar ==
false) top_frame::Get()->ToggleChartBar(
this);
3163 if (event.ControlDown()) top_frame::Get()->DropMarker(
false);
3170 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3171 if ((indexActive + 1) <= r->GetnPoints()) {
3182 if (!g_bShowMenuBar) top_frame::Get()->DropMarker(
true);
3188 if (g_bSpaceDropMark) top_frame::Get()->DropMarker(
true);
3194 if (m_modkeys == wxMOD_CONTROL) top_frame::Get()->ActivateMOB();
3201 top_frame::Get()->DoSettings();
3205 parent_frame->Close();
3221 if (undo->AnythingToRedo()) {
3222 undo->RedoNextAction();
3229 if (event.ShiftDown()) {
3230 if (undo->AnythingToRedo()) {
3231 undo->RedoNextAction();
3236 if (undo->AnythingToUndo()) {
3237 undo->UndoLastAction();
3246 if (m_bMeasure_Active) {
3247 CancelMeasureRoute();
3249 SetCursor(*pCursorArrow);
3252 top_frame::Get()->RefreshAllCanvas();
3266 switch (gamma_state) {
3286 SetScreenBrightness(g_nbrightness);
3291 if (event.ControlDown()) {
3292 m_bShowCompassWin = !m_bShowCompassWin;
3293 SetShowGPSCompassWindow(m_bShowCompassWin);
3310void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3311 if (SendKeyEventToPlugins(event))
3315 switch (event.GetKeyCode()) {
3317 top_frame::Get()->SwitchKBFocus(
this);
3323 if (!m_pany) m_panspeed = 0;
3329 if (!m_panx) m_panspeed = 0;
3332 case WXK_NUMPAD_ADD:
3333 case WXK_NUMPAD_SUBTRACT:
3342 m_modkeys &= ~wxMOD_ALT;
3343#ifdef OCPN_ALT_MENUBAR
3348 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3349 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3350 top_frame::Get()->ApplyGlobalSettings(
false);
3352 m_bMayToggleMenuBar =
true;
3358 m_modkeys &= ~wxMOD_CONTROL;
3362 if (event.GetKeyCode() < 128)
3364 int key_char =
event.GetKeyCode();
3368 if (!g_b_assume_azerty) {
3383 m_rotation_speed = 0;
3401void ChartCanvas::ToggleChartOutlines() {
3402 m_bShowOutlines = !m_bShowOutlines;
3408 if (g_bopengl) InvalidateGL();
3412void ChartCanvas::ToggleLookahead() {
3413 m_bLookAhead = !m_bLookAhead;
3418void ChartCanvas::SetUpMode(
int mode) {
3421 if (mode != NORTH_UP_MODE) {
3424 if (!std::isnan(
gCog)) stuff =
gCog;
3427 auto cog_table = top_frame::Get()->GetCOGTable();
3428 for (
int i = 0; i <
g_COGAvgSec; i++) cog_table[i] = stuff;
3431 top_frame::Get()->StartCogTimer();
3433 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3434 SetVPRotation(GetVPSkew());
3439 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3440 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3442 UpdateGPSCompassStatusBox(
true);
3443 top_frame::Get()->DoChartUpdate();
3446bool ChartCanvas::DoCanvasCOGSet() {
3447 if (GetUpMode() == NORTH_UP_MODE)
return false;
3449 if (g_btenhertz) cog_use =
gCog;
3451 double rotation = 0;
3452 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3453 rotation = -
gHdt * PI / 180.;
3454 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3455 rotation = -cog_use * PI / 180.;
3457 SetVPRotation(rotation);
3461double easeOutCubic(
double t) {
3463 return 1.0 - pow(1.0 - t, 3.0);
3466void ChartCanvas::StartChartDragInertia() {
3467 m_bChartDragging =
false;
3470 m_chart_drag_inertia_time = 750;
3471 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3476 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3480 size_t length = m_drag_vec_t.size();
3481 for (
size_t i = 0; i < n_vel; i++) {
3482 xacc += m_drag_vec_x.at(length - 1 - i);
3483 yacc += m_drag_vec_y.at(length - 1 - i);
3484 tacc += m_drag_vec_t.at(length - 1 - i);
3487 if (tacc == 0)
return;
3489 double drag_velocity_x = xacc / tacc;
3490 double drag_velocity_y = yacc / tacc;
3496 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3498 m_chart_drag_velocity_x = drag_velocity_x;
3499 m_chart_drag_velocity_y = drag_velocity_y;
3501 m_chart_drag_inertia_active =
true;
3503 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3506void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3507 if (!m_chart_drag_inertia_active)
return;
3509 wxLongLong now = wxGetLocalTimeMillis();
3510 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3511 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3512 if (t > 1.0) t = 1.0;
3513 double e = 1.0 - easeOutCubic(t);
3516 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3518 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3520 m_last_elapsed = elapsed;
3524 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3525 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3526 double inertia_lat, inertia_lon;
3530 if (!IsOwnshipOnScreen()) {
3532 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3533 UpdateFollowButtonState();
3544 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3545 m_chart_drag_inertia_timer.Stop();
3548 m_target_lat = GetVP().
clat;
3549 m_target_lon = GetVP().
clon;
3550 m_pan_drag.x = m_pan_drag.y = 0;
3551 m_panx = m_pany = 0;
3552 m_chart_drag_inertia_active =
false;
3556 int target_redraw_interval = 40;
3557 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3561void ChartCanvas::StopMovement() {
3562 m_panx = m_pany = 0;
3565 m_rotation_speed = 0;
3568#if !defined(__WXGTK__) && !defined(__WXQT__)
3570 top_frame::Get()->Raise();
3579bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3581 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3583 if (!pMovementTimer->IsRunning()) {
3584 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3587 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3592 m_last_movement_time = wxDateTime::UNow();
3596void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3599 m_target_lat = target_lat;
3600 m_target_lon = target_lon;
3603 m_start_lat = GetVP().
clat;
3604 m_start_lon = GetVP().
clon;
3606 m_VPMovementTimer.Start(1,
true);
3607 m_timed_move_vp_active =
true;
3609 m_timedVP_step = nstep;
3612void ChartCanvas::DoTimedMovementVP() {
3613 if (!m_timed_move_vp_active)
return;
3614 if (m_stvpc++ > m_timedVP_step * 2) {
3621 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3636 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3637 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3639 m_run_lat = new_lat;
3640 m_run_lon = new_lon;
3645void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3647void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3649void ChartCanvas::StartTimedMovementTarget() {}
3651void ChartCanvas::DoTimedMovementTarget() {}
3653void ChartCanvas::StopMovementTarget() {}
3656void ChartCanvas::DoTimedMovement() {
3657 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3661 wxDateTime now = wxDateTime::UNow();
3663 if (m_last_movement_time.IsValid())
3664 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3666 m_last_movement_time = now;
3676 if (dt == 0) dt = 1;
3679 if (m_mustmove < 0) m_mustmove = 0;
3682 if (m_pan_drag.x || m_pan_drag.y) {
3684 m_pan_drag.x = m_pan_drag.y = 0;
3687 if (m_panx || m_pany) {
3688 const double slowpan = .1, maxpan = 2;
3689 if (m_modkeys == wxMOD_ALT)
3690 m_panspeed = slowpan;
3692 m_panspeed += (double)dt / 500;
3693 m_panspeed = wxMin(maxpan, m_panspeed);
3695 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3698 if (m_zoom_factor != 1) {
3699 double alpha = 400, beta = 1.5;
3700 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3702 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3704 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3709 if (zoom_factor > 1) {
3710 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3714 else if (zoom_factor < 1) {
3715 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3720 if (fabs(zoom_factor - 1) > 1e-4) {
3721 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3726 if (m_wheelzoom_stop_oneshot > 0) {
3727 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3728 m_wheelzoom_stop_oneshot = 0;
3733 if (zoom_factor > 1) {
3735 m_wheelzoom_stop_oneshot = 0;
3738 }
else if (zoom_factor < 1) {
3740 m_wheelzoom_stop_oneshot = 0;
3747 if (m_rotation_speed) {
3748 double speed = m_rotation_speed;
3749 if (m_modkeys == wxMOD_ALT) speed /= 10;
3750 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3754void ChartCanvas::SetColorScheme(ColorScheme cs) {
3759 case GLOBAL_COLOR_SCHEME_DAY:
3760 m_pos_image_red = &m_os_image_red_day;
3761 m_pos_image_grey = &m_os_image_grey_day;
3762 m_pos_image_yellow = &m_os_image_yellow_day;
3763 m_pos_image_user = m_pos_image_user_day;
3764 m_pos_image_user_grey = m_pos_image_user_grey_day;
3765 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3766 m_cTideBitmap = m_bmTideDay;
3767 m_cCurrentBitmap = m_bmCurrentDay;
3770 case GLOBAL_COLOR_SCHEME_DUSK:
3771 m_pos_image_red = &m_os_image_red_dusk;
3772 m_pos_image_grey = &m_os_image_grey_dusk;
3773 m_pos_image_yellow = &m_os_image_yellow_dusk;
3774 m_pos_image_user = m_pos_image_user_dusk;
3775 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3776 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3777 m_cTideBitmap = m_bmTideDusk;
3778 m_cCurrentBitmap = m_bmCurrentDusk;
3780 case GLOBAL_COLOR_SCHEME_NIGHT:
3781 m_pos_image_red = &m_os_image_red_night;
3782 m_pos_image_grey = &m_os_image_grey_night;
3783 m_pos_image_yellow = &m_os_image_yellow_night;
3784 m_pos_image_user = m_pos_image_user_night;
3785 m_pos_image_user_grey = m_pos_image_user_grey_night;
3786 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3787 m_cTideBitmap = m_bmTideNight;
3788 m_cCurrentBitmap = m_bmCurrentNight;
3791 m_pos_image_red = &m_os_image_red_day;
3792 m_pos_image_grey = &m_os_image_grey_day;
3793 m_pos_image_yellow = &m_os_image_yellow_day;
3794 m_pos_image_user = m_pos_image_user_day;
3795 m_pos_image_user_grey = m_pos_image_user_grey_day;
3796 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3797 m_cTideBitmap = m_bmTideDay;
3798 m_cCurrentBitmap = m_bmCurrentDay;
3802 CreateDepthUnitEmbossMaps(cs);
3803 CreateOZEmbossMapData(cs);
3806 m_fog_color = wxColor(
3810 case GLOBAL_COLOR_SCHEME_DUSK:
3813 case GLOBAL_COLOR_SCHEME_NIGHT:
3819 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3820 m_fog_color.Blue() * dim);
3824 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3825 SetBackgroundColour( wxColour(0,0,0) );
3827 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3830 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3832 SetBackgroundColour( wxNullColour );
3839 m_Piano->SetColorScheme(cs);
3841 m_Compass->SetColorScheme(cs);
3843 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3845 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3847 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3848 if (m_notification_button) {
3849 m_notification_button->SetColorScheme(cs);
3853 if (g_bopengl && m_glcc) {
3854 m_glcc->SetColorScheme(cs);
3860 m_brepaint_piano =
true;
3867wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3868 wxImage img = Bitmap.ConvertToImage();
3869 int sx = img.GetWidth();
3870 int sy = img.GetHeight();
3872 wxImage new_img(img);
3874 for (
int i = 0; i < sx; i++) {
3875 for (
int j = 0; j < sy; j++) {
3876 if (!img.IsTransparent(i, j)) {
3877 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3878 (
unsigned char)(img.GetGreen(i, j) * factor),
3879 (
unsigned char)(img.GetBlue(i, j) * factor));
3884 wxBitmap ret = wxBitmap(new_img);
3889void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3892 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3894 if (!m_pBrightPopup) {
3897 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3901 m_pBrightPopup->SetSize(x, y);
3902 m_pBrightPopup->Move(120, 120);
3905 int bmpsx = m_pBrightPopup->GetSize().x;
3906 int bmpsy = m_pBrightPopup->GetSize().y;
3908 wxBitmap bmp(bmpsx, bmpsx);
3909 wxMemoryDC mdc(bmp);
3911 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3912 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3913 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3914 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3917 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3919 mdc.SetFont(*pfont);
3922 if (brightness == max)
3924 else if (brightness == min)
3927 val.Printf(
"%3d", brightness);
3929 mdc.DrawText(val, 0, 0);
3931 mdc.SelectObject(wxNullBitmap);
3933 m_pBrightPopup->SetBitmap(bmp);
3934 m_pBrightPopup->Show();
3935 m_pBrightPopup->Refresh();
3938void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3939 m_b_rot_hidef =
true;
3943void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3946 bool b_need_refresh =
false;
3948 wxSize win_size = GetSize() * m_displayScale;
3952 bool showAISRollover =
false;
3954 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3958 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3959 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3962 showAISRollover =
true;
3964 if (NULL == m_pAISRolloverWin) {
3966 m_pAISRolloverWin->IsActive(
false);
3967 b_need_refresh =
true;
3968 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3969 m_AISRollover_MMSI != FoundAIS_MMSI) {
3975 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3976 m_pAISRolloverWin->IsActive(
false);
3977 m_AISRollover_MMSI = 0;
3982 m_AISRollover_MMSI = FoundAIS_MMSI;
3984 if (!m_pAISRolloverWin->IsActive()) {
3985 wxString s = ptarget->GetRolloverString();
3986 m_pAISRolloverWin->SetString(s);
3988 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3989 AIS_ROLLOVER, win_size);
3990 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3991 m_pAISRolloverWin->IsActive(
true);
3992 b_need_refresh =
true;
3996 m_AISRollover_MMSI = 0;
3997 showAISRollover =
false;
4002 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
4003 m_pAISRolloverWin->IsActive(
false);
4004 m_AISRollover_MMSI = 0;
4005 b_need_refresh =
true;
4010 bool showRouteRollover =
false;
4012 if (NULL == m_pRolloverRouteSeg) {
4016 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4017 SelectableItemList SelList =
pSelect->FindSelectionList(
4019 auto node = SelList.begin();
4020 while (node != SelList.end()) {
4025 if (pr && pr->IsVisible()) {
4026 m_pRolloverRouteSeg = pFindSel;
4027 showRouteRollover =
true;
4029 if (NULL == m_pRouteRolloverWin) {
4031 m_pRouteRolloverWin->IsActive(
false);
4034 if (!m_pRouteRolloverWin->IsActive()) {
4042 DistanceBearingMercator(
4043 segShow_point_b->m_lat, segShow_point_b->m_lon,
4044 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4046 if (!pr->m_bIsInLayer)
4047 s.Append(_(
"Route") +
": ");
4049 s.Append(_(
"Layer Route: "));
4051 if (pr->m_RouteNameString.IsEmpty())
4052 s.Append(_(
"(unnamed)"));
4054 s.Append(pr->m_RouteNameString);
4059 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4060 << segShow_point_b->GetName() <<
"\n";
4063 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4064 (
int)floor(brg + 0.5), 0x00B0);
4067 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4069 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4071 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4073 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4074 (
int)floor(varBrg + 0.5), 0x00B0);
4082 double shiptoEndLeg = 0.;
4083 bool validActive =
false;
4084 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4087 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4088 auto node = pr->pRoutePointList->begin();
4090 float dist_to_endleg = 0;
4093 for (++node; node != pr->pRoutePointList->end(); ++node) {
4100 if (prp->IsSame(segShow_point_a))
break;
4108 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4111 ->GetCurrentRngToActivePoint();
4120 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4125 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4126 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4128 << wxString(ttg_sec > SECONDS_PER_DAY
4129 ? ttg_span.Format(_(
"%Dd %H:%M"))
4130 : ttg_span.Format(_(
"%H:%M")));
4131 wxDateTime dtnow, eta;
4132 eta = dtnow.SetToCurrent().Add(ttg_span);
4133 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4134 << eta.Format(
" %d %H:%M");
4138 m_pRouteRolloverWin->SetString(s);
4140 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4141 LEG_ROLLOVER, win_size);
4142 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4143 m_pRouteRolloverWin->IsActive(
true);
4144 b_need_refresh =
true;
4145 showRouteRollover =
true;
4154 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4156 m_pRolloverRouteSeg))
4157 showRouteRollover =
false;
4158 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4159 showRouteRollover =
false;
4161 showRouteRollover =
true;
4165 if (m_routeState) showRouteRollover =
false;
4168 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4169 showRouteRollover =
false;
4171 if (m_pRouteRolloverWin &&
4172 !showRouteRollover) {
4173 m_pRouteRolloverWin->IsActive(
false);
4174 m_pRolloverRouteSeg = NULL;
4175 m_pRouteRolloverWin->Destroy();
4176 m_pRouteRolloverWin = NULL;
4177 b_need_refresh =
true;
4178 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4179 m_pRouteRolloverWin->IsActive(
true);
4180 b_need_refresh =
true;
4185 bool showTrackRollover =
false;
4187 if (NULL == m_pRolloverTrackSeg) {
4191 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4192 SelectableItemList SelList =
pSelect->FindSelectionList(
4195 auto node = SelList.begin();
4196 while (node != SelList.end()) {
4201 if (pt && pt->IsVisible()) {
4202 m_pRolloverTrackSeg = pFindSel;
4203 showTrackRollover =
true;
4205 if (NULL == m_pTrackRolloverWin) {
4207 m_pTrackRolloverWin->IsActive(
false);
4210 if (!m_pTrackRolloverWin->IsActive()) {
4218 DistanceBearingMercator(
4219 segShow_point_b->m_lat, segShow_point_b->m_lon,
4220 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4222 if (!pt->m_bIsInLayer)
4223 s.Append(_(
"Track") +
": ");
4225 s.Append(_(
"Layer Track: "));
4227 if (pt->GetName().IsEmpty())
4228 s.Append(_(
"(unnamed)"));
4230 s.Append(pt->GetName());
4231 double tlenght = pt->Length();
4233 if (pt->GetLastPoint()->GetTimeString() &&
4234 pt->GetPoint(0)->GetTimeString()) {
4235 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4236 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4237 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4238 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4239 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4240 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4241 << getUsrSpeedUnit();
4242 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4243 : ttime.Format(
" %H:%M"));
4247 if (g_bShowTrackPointTime &&
4248 strlen(segShow_point_b->GetTimeString())) {
4249 wxString stamp = segShow_point_b->GetTimeString();
4250 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4251 if (timestamp.IsValid()) {
4255 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4257 s <<
"\n" << _(
"Segment Created: ") << stamp;
4262 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4267 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4269 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4271 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4273 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4279 if (segShow_point_a->GetTimeString() &&
4280 segShow_point_b->GetTimeString()) {
4281 wxDateTime apoint = segShow_point_a->GetCreateTime();
4282 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4283 if (apoint.IsValid() && bpoint.IsValid()) {
4284 double segmentSpeed = toUsrSpeed(
4285 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4286 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4287 << getUsrSpeedUnit();
4291 m_pTrackRolloverWin->SetString(s);
4293 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4294 LEG_ROLLOVER, win_size);
4295 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4296 m_pTrackRolloverWin->IsActive(
true);
4297 b_need_refresh =
true;
4298 showTrackRollover =
true;
4307 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4309 m_pRolloverTrackSeg))
4310 showTrackRollover =
false;
4311 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4312 showTrackRollover =
false;
4314 showTrackRollover =
true;
4318 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4319 showTrackRollover =
false;
4322 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4323 showTrackRollover =
false;
4329 if (m_pTrackRolloverWin &&
4330 !showTrackRollover) {
4331 m_pTrackRolloverWin->IsActive(
false);
4332 m_pRolloverTrackSeg = NULL;
4333 m_pTrackRolloverWin->Destroy();
4334 m_pTrackRolloverWin = NULL;
4335 b_need_refresh =
true;
4336 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4337 m_pTrackRolloverWin->IsActive(
true);
4338 b_need_refresh =
true;
4341 if (b_need_refresh) Refresh();
4344void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4345 if ((GetShowENCLights() || m_bsectors_shown) &&
4346 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4347 extendedSectorLegs)) {
4348 if (!m_bsectors_shown) {
4350 m_bsectors_shown =
true;
4353 if (m_bsectors_shown) {
4355 m_bsectors_shown =
false;
4363#if defined(__WXGTK__) || defined(__WXQT__)
4368 double cursor_lat, cursor_lon;
4371 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4372 while (cursor_lon < -180.) cursor_lon += 360.;
4374 while (cursor_lon > 180.) cursor_lon -= 360.;
4376 SetCursorStatus(cursor_lat, cursor_lon);
4382void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4383 if (!top_frame::Get()->GetFrameStatusBar())
return;
4387 s1 += toSDMM(1, cursor_lat);
4389 s1 += toSDMM(2, cursor_lon);
4391 if (STAT_FIELD_CURSOR_LL >= 0)
4392 top_frame::Get()->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4394 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4399 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4400 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4401 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4403 wxString s = st + sm;
4416 if (g_bShowLiveETA) {
4419 float boatSpeedDefault = g_defaultBoatSpeed;
4424 if (!std::isnan(
gSog)) {
4426 if (boatSpeed < 0.5) {
4429 realTimeETA = dist / boatSpeed * 60;
4438 s << minutesToHoursDays(realTimeETA);
4443 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4444 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4446 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4451 top_frame::Get()->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4459wxString minutesToHoursDays(
float timeInMinutes) {
4462 if (timeInMinutes == 0) {
4467 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4468 s << wxString::Format(
"%d", (
int)timeInMinutes);
4473 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4476 hours = (int)timeInMinutes / 60;
4477 min = (int)timeInMinutes % 60;
4480 s << wxString::Format(
"%d", hours);
4483 s << wxString::Format(
"%d", hours);
4485 s << wxString::Format(
"%d", min);
4492 else if (timeInMinutes > 24 * 60) {
4495 days = (int)(timeInMinutes / 60) / 24;
4496 hours = (int)(timeInMinutes / 60) % 24;
4499 s << wxString::Format(
"%d", days);
4502 s << wxString::Format(
"%d", days);
4504 s << wxString::Format(
"%d", hours);
4516void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4524 wxPoint2DDouble *r) {
4529 double rlon, wxPoint2DDouble *r) {
4540 if (!g_bopengl && m_singleChart &&
4541 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4542 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4543 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4544 (m_singleChart->GetChartProjectionType() !=
4545 PROJECTION_TRANSVERSE_MERCATOR) &&
4546 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4547 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4548 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4562 Cur_BSB_Ch->SetVPRasterParms(vp);
4563 double rpixxd, rpixyd;
4564 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4590 if (std::isnan(p.m_x)) {
4591 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4595 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4596 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4598 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4617 if (!g_bopengl && m_singleChart &&
4618 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4619 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4620 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4621 (m_singleChart->GetChartProjectionType() !=
4622 PROJECTION_TRANSVERSE_MERCATOR) &&
4623 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4624 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4625 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4636 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4639 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4644 else if (slon > 180.)
4655 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4661 DoZoomCanvas(factor,
false);
4662 extendedSectorLegs.clear();
4667 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4670 if (StartTimedMovement(stoptimer)) {
4672 m_zoom_factor = factor;
4677 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4679 DoZoomCanvas(factor, can_zoom_to_cursor);
4682 extendedSectorLegs.clear();
4685void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4688 if (!m_pCurrentStack)
return;
4694 if (m_bzooming)
return;
4703 double proposed_scale_onscreen =
4706 bool b_do_zoom =
false;
4715 if (!VPoint.b_quilt) {
4718 if (!m_disable_adjust_on_zoom) {
4719 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4720 if (new_db_index >= 0)
4721 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4725 int current_ref_stack_index = -1;
4726 if (m_pCurrentStack->nEntry) {
4728 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4729 m_pQuilt->SetReferenceChart(trial_index);
4730 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4731 if (new_db_index >= 0)
4732 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4736 if (m_pCurrentStack)
4737 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4748 double min_allowed_scale =
4751 if (proposed_scale_onscreen < min_allowed_scale) {
4756 proposed_scale_onscreen = min_allowed_scale;
4760 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4763 }
else if (factor < 1) {
4768 bool b_smallest =
false;
4770 if (!VPoint.b_quilt) {
4775 LLBBox viewbox = VPoint.GetBBox();
4777 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4778 double max_allowed_scale;
4792 if (proposed_scale_onscreen > max_allowed_scale) {
4794 proposed_scale_onscreen = max_allowed_scale;
4799 if (!m_disable_adjust_on_zoom) {
4801 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4802 if (new_db_index >= 0)
4803 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4805 if (m_pCurrentStack)
4806 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4809 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4811 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4812 proposed_scale_onscreen =
4813 wxMin(proposed_scale_onscreen,
4819 m_absolute_min_scale_ppm)
4820 proposed_scale_onscreen =
4829 bool b_allow_ztc =
true;
4830 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4831 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4833 double brg, distance;
4834 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4837 meters_to_shift = distance * 1852;
4845 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4848 if (m_bFollow) DoCanvasUpdate();
4855void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4857 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4861void ChartCanvas::RotateCanvas(
double dir) {
4865 if (StartTimedMovement()) {
4867 m_rotation_speed = dir * 60;
4870 double speed = dir * 10;
4871 if (m_modkeys == wxMOD_ALT) speed /= 20;
4872 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4876void ChartCanvas::DoRotateCanvas(
double rotation) {
4877 while (rotation < 0) rotation += 2 * PI;
4878 while (rotation > 2 * PI) rotation -= 2 * PI;
4880 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4882 SetVPRotation(rotation);
4883 top_frame::Get()->UpdateRotationState(VPoint.
rotation);
4886void ChartCanvas::DoTiltCanvas(
double tilt) {
4887 while (tilt < 0) tilt = 0;
4888 while (tilt > .95) tilt = .95;
4890 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4896void ChartCanvas::TogglebFollow() {
4903void ChartCanvas::ClearbFollow() {
4906 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4908 UpdateFollowButtonState();
4912 top_frame::Get()->SetChartUpdatePeriod();
4915void ChartCanvas::SetbFollow() {
4918 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4919 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4927 p.m_x += m_OSoffsetx;
4928 p.m_y -= m_OSoffsety;
4937 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4938 UpdateFollowButtonState();
4940 if (!g_bSmoothRecenter) {
4944 top_frame::Get()->SetChartUpdatePeriod();
4947void ChartCanvas::UpdateFollowButtonState() {
4950 m_muiBar->SetFollowButtonState(0);
4953 m_muiBar->SetFollowButtonState(2);
4955 m_muiBar->SetFollowButtonState(1);
4961 androidSetFollowTool(0);
4964 androidSetFollowTool(2);
4966 androidSetFollowTool(1);
4973 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4974 if (pic->m_enabled && pic->m_init_state) {
4975 switch (pic->m_api_version) {
4978 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4989void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4990 if (g_bSmoothRecenter && !m_routeState) {
4991 if (StartSmoothJump(lat, lon, scale_ppm))
4995 double gcDist, gcBearingEnd;
4996 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4998 gcBearingEnd += 180;
4999 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
5002 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
5003 double new_lat = lat + (lat_offset / (1852 * 60));
5004 double new_lon = lon + (lon_offset / (1852 * 60));
5007 StartSmoothJump(lat, lon, scale_ppm);
5012 if (lon > 180.0) lon -= 360.0;
5018 if (!GetQuiltMode()) {
5020 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
5021 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
5025 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5026 AdjustQuiltRefChart();
5033 UpdateFollowButtonState();
5041bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5046 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5047 double distance_pixels = gcDist *
GetVPScale();
5048 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5054 m_startLat = m_vLat;
5055 m_startLon = m_vLon;
5060 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5061 m_endScale = scale_ppm;
5064 m_animationDuration = 600;
5065 m_animationStart = wxGetLocalTimeMillis();
5072 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5073 m_animationActive =
true;
5078void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5080 wxLongLong now = wxGetLocalTimeMillis();
5081 double elapsed = (now - m_animationStart).ToDouble();
5082 double t = elapsed / m_animationDuration.ToDouble();
5083 if (t > 1.0) t = 1.0;
5086 double e = easeOutCubic(t);
5089 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5090 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5091 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5096 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5102 m_animationActive =
false;
5103 UpdateFollowButtonState();
5112 extendedSectorLegs.clear();
5121 if (iters++ > 5)
return false;
5122 if (!std::isnan(dlat))
break;
5125 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5131 else if (dlat < -90)
5134 if (dlon > 360.) dlon -= 360.;
5135 if (dlon < -360.) dlon += 360.;
5150 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5154 if (VPoint.b_quilt) {
5155 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5156 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5160 double tweak_scale_ppm =
5166 if (new_ref_dbIndex == -1) {
5167#pragma GCC diagnostic push
5168#pragma GCC diagnostic ignored "-Warray-bounds"
5175 int trial_index = -1;
5176 if (m_pCurrentStack->nEntry) {
5178 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5181 if (trial_index < 0) {
5182 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5183 if (full_screen_array.size())
5184 trial_index = full_screen_array[full_screen_array.size() - 1];
5187 if (trial_index >= 0) {
5188 m_pQuilt->SetReferenceChart(trial_index);
5193#pragma GCC diagnostic pop
5200 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5202 double offset_angle = atan2(offy, offx);
5203 double offset_distance = sqrt((offy * offy) + (offx * offx));
5204 double chart_angle = GetVPRotation();
5205 double target_angle = chart_angle - offset_angle;
5206 double d_east_mod = offset_distance * cos(target_angle);
5207 double d_north_mod = offset_distance * sin(target_angle);
5212 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5213 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5215 UpdateFollowButtonState();
5221 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5226bool ChartCanvas::IsOwnshipOnScreen() {
5229 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5230 ((r.y > 0) && r.y < GetCanvasHeight()))
5236void ChartCanvas::ReloadVP(
bool b_adjust) {
5237 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5239 LoadVP(VPoint, b_adjust);
5242void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5244 if (g_bopengl && m_glcc) {
5245 m_glcc->Invalidate();
5246 if (m_glcc->GetSize() != GetSize()) {
5247 m_glcc->SetSize(GetSize());
5252 m_cache_vp.Invalidate();
5253 m_bm_cache_vp.Invalidate();
5256 VPoint.Invalidate();
5258 if (m_pQuilt) m_pQuilt->Invalidate();
5267 vp.m_projection_type, b_adjust);
5270void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5271 m_pQuilt->SetReferenceChart(dbIndex);
5272 VPoint.Invalidate();
5273 m_pQuilt->Invalidate();
5276double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5278 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5285int ChartCanvas::AdjustQuiltRefChart() {
5290 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5292 double min_ref_scale =
5293 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5294 double max_ref_scale =
5295 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5298 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5299 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5300 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5302 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5305 int target_stack_index = wxNOT_FOUND;
5307 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5308 if (index == m_pQuilt->GetRefChartdbIndex()) {
5309 target_stack_index = il;
5314 if (wxNOT_FOUND == target_stack_index)
5315 target_stack_index = 0;
5317 int ref_family = pc->GetChartFamily();
5318 int extended_array_count =
5319 m_pQuilt->GetExtendedStackIndexArray().size();
5320 while ((!brender_ok) &&
5321 ((
int)target_stack_index < (extended_array_count - 1))) {
5322 target_stack_index++;
5324 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5326 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5327 IsChartQuiltableRef(test_db_index)) {
5330 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5332 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5339 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5340 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5341 IsChartQuiltableRef(new_db_index)) {
5342 m_pQuilt->SetReferenceChart(new_db_index);
5345 ret = m_pQuilt->GetRefChartdbIndex();
5347 ret = m_pQuilt->GetRefChartdbIndex();
5350 ret = m_pQuilt->GetRefChartdbIndex();
5359void ChartCanvas::UpdateCanvasOnGroupChange() {
5360 delete m_pCurrentStack;
5372bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5373 double latNE,
double lonNE) {
5375 double latc = (latSW + latNE) / 2.0;
5376 double lonc = (lonSW + lonNE) / 2.0;
5379 double ne_easting, ne_northing;
5380 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5382 double sw_easting, sw_northing;
5383 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5385 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5392 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5395bool ChartCanvas::SetVPProjection(
int projection) {
5401 double prev_true_scale_ppm = m_true_scale_ppm;
5406 m_absolute_min_scale_ppm));
5414bool ChartCanvas::SetVPRotation(
double angle) {
5416 VPoint.
skew, angle);
5419 double skew,
double rotation,
int projection,
5420 bool b_adjust,
bool b_refresh) {
5426 if (VPoint.IsValid()) {
5427 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5428 (fabs(VPoint.
skew - skew) < 1e-9) &&
5429 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5430 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5431 (VPoint.m_projection_type == projection ||
5432 projection == PROJECTION_UNKNOWN))
5435 if (VPoint.m_projection_type != projection)
5436 VPoint.InvalidateTransformCache();
5446 if (projection != PROJECTION_UNKNOWN)
5447 VPoint.SetProjectionType(projection);
5448 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5449 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5452 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5453 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5454 if (VPoint.
clat > 89.5)
5456 else if (VPoint.
clat < -89.5)
5457 VPoint.
clat = -89.5;
5462 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5463 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5475 bool bwasValid = VPoint.IsValid();
5480 m_cache_vp.Invalidate();
5485 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5489 if (top_frame::Get()->GetCanvasIndexUnderMouse() == m_canvasIndex) {
5490 int mouseX = mouse_x;
5491 int mouseY = mouse_y;
5492 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5494 double lat_mouse, lon_mouse;
5502 if (!VPoint.b_quilt && m_singleChart) {
5507 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5511 if ((!m_cache_vp.IsValid()) ||
5516 wxPoint cp_last, cp_this;
5520 if (cp_last != cp_this) {
5526 if (m_pCurrentStack) {
5528 int current_db_index;
5530 m_pCurrentStack->GetCurrentEntrydbIndex();
5532 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5534 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5537 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5541 if (VPoint.b_quilt) {
5545 m_pQuilt->InvalidateAllQuiltPatchs();
5549 if (!m_pCurrentStack)
return false;
5551 int current_db_index;
5553 m_pCurrentStack->GetCurrentEntrydbIndex();
5555 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5556 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5559 int current_ref_stack_index = -1;
5560 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5561 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5562 current_ref_stack_index = i;
5565 if (g_bFullScreenQuilt) {
5566 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5570 bool b_needNewRef =
false;
5573 if ((-1 == current_ref_stack_index) &&
5574 (m_pQuilt->GetRefChartdbIndex() >= 0))
5575 b_needNewRef =
true;
5582 bool renderable =
true;
5584 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5585 if (referenceChart) {
5586 double chartMaxScale = referenceChart->GetNormalScaleMax(
5588 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5590 if (!renderable) b_needNewRef =
true;
5593 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5595 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5596 int target_scale = cte_ref.GetScale();
5597 int target_type = cte_ref.GetChartType();
5598 int candidate_stack_index;
5605 candidate_stack_index = 0;
5606 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5608 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5609 int candidate_scale = cte_candidate.GetScale();
5610 int candidate_type = cte_candidate.GetChartType();
5612 if ((candidate_scale >= target_scale) &&
5613 (candidate_type == target_type)) {
5614 bool renderable =
true;
5616 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5617 if (tentative_referenceChart) {
5618 double chartMaxScale =
5619 tentative_referenceChart->GetNormalScaleMax(
5621 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5624 if (renderable)
break;
5627 candidate_stack_index++;
5632 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5633 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5634 while (candidate_stack_index >= 0) {
5635 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5639 int candidate_scale = cte_candidate.GetScale();
5640 int candidate_type = cte_candidate.GetChartType();
5642 if ((candidate_scale <= target_scale) &&
5643 (candidate_type == target_type))
5646 candidate_stack_index--;
5651 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5652 (candidate_stack_index < 0))
5653 candidate_stack_index = 0;
5655 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5657 m_pQuilt->SetReferenceChart(new_ref_index);
5663 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5668 bool renderable =
true;
5670 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5671 if (referenceChart) {
5672 double chartMaxScale = referenceChart->GetNormalScaleMax(
5674 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5675 proj =
ChartData->GetDBChartProj(ref_db_index);
5677 proj = PROJECTION_MERCATOR;
5679 VPoint.b_MercatorProjectionOverride =
5680 (m_pQuilt->GetnCharts() == 0 || !renderable);
5682 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5684 VPoint.SetProjectionType(proj);
5689 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5694 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5714 m_pQuilt->Invalidate();
5731 if (b_refresh) Refresh(
false);
5738 }
else if (!g_bopengl) {
5739 OcpnProjType projection = PROJECTION_UNKNOWN;
5742 projection = m_singleChart->GetChartProjectionType();
5743 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5744 VPoint.SetProjectionType(projection);
5748 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5749 m_cache_vp.Invalidate();
5753 UpdateCanvasControlBar();
5757 if (VPoint.GetBBox().GetValid()) {
5760 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5769 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5772 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5779 wxPoint2DDouble r, r1;
5781 double delta_check =
5785 double check_point = wxMin(89., VPoint.
clat);
5787 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5790 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5791 VPoint.
clon, 0, &rhumbDist);
5796 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5797 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5799 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5803 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5809 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5811 if (m_true_scale_ppm)
5812 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5817 double round_factor = 1000.;
5821 round_factor = 100.;
5823 round_factor = 1000.;
5826 double retina_coef = 1;
5830 retina_coef = GetContentScaleFactor();
5841 double true_scale_display =
5842 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5847 if (m_displayed_scale_factor > 10.0)
5848 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5849 m_displayed_scale_factor);
5850 else if (m_displayed_scale_factor > 1.0)
5851 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5852 m_displayed_scale_factor);
5853 else if (m_displayed_scale_factor > 0.1) {
5854 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5855 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5856 }
else if (m_displayed_scale_factor > 0.01) {
5857 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5858 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5861 "%s %4.0f (---)", _(
"Scale"),
5862 true_scale_display);
5865 m_scaleValue = true_scale_display;
5867 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5869 if (m_bShowScaleInStatusBar && top_frame::Get()->GetStatusBar() &&
5870 (top_frame::Get()->GetStatusBar()->GetFieldsCount() >
5871 STAT_FIELD_SCALE)) {
5873 bool b_noshow =
false;
5877 wxClientDC dc(top_frame::Get()->GetStatusBar());
5879 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5880 dc.SetFont(*templateFont);
5881 dc.GetTextExtent(text, &w, &h);
5886 top_frame::Get()->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE,
5888 if (w && w > rect.width) {
5889 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5893 dc.GetTextExtent(text, &w, &h);
5895 if (w && w > rect.width) {
5901 if (!b_noshow) top_frame::Get()->SetStatusText(text, STAT_FIELD_SCALE);
5906 m_vLat = VPoint.
clat;
5907 m_vLon = VPoint.
clon;
5921static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5925static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5926 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5928wxColour ChartCanvas::PredColor() {
5931 if (SHIP_NORMAL == m_ownship_state)
5932 return GetGlobalColor(
"URED");
5934 else if (SHIP_LOWACCURACY == m_ownship_state)
5935 return GetGlobalColor(
"YELO1");
5937 return GetGlobalColor(
"NODTA");
5940wxColour ChartCanvas::ShipColor() {
5944 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5946 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5948 return GetGlobalColor(
"URED");
5951void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5952 wxPoint2DDouble lShipMidPoint) {
5953 dc.SetPen(wxPen(PredColor(), 2));
5955 if (SHIP_NORMAL == m_ownship_state)
5956 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5958 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5960 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5961 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5963 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5965 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5966 lShipMidPoint.m_y + 12);
5969void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5970 wxPoint GPSOffsetPixels,
5971 wxPoint2DDouble lGPSPoint) {
5976 float ref_dim = m_display_size_mm / 24;
5977 ref_dim = wxMin(ref_dim, 12);
5978 ref_dim = wxMax(ref_dim, 6);
5981 cPred.Set(g_cog_predictor_color);
5982 if (cPred == wxNullColour) cPred = PredColor();
5989 double nominal_line_width_pix = wxMax(
5991 floor(m_pix_per_mm / 2));
5995 if (nominal_line_width_pix > g_cog_predictor_width)
5996 g_cog_predictor_width = nominal_line_width_pix;
5999 wxPoint lPredPoint, lHeadPoint;
6001 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6002 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6004 double pred_lat, pred_lon;
6005 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
6006 &pred_lat, &pred_lon);
6017 float ndelta_pix = 10.;
6018 double hdg_pred_lat, hdg_pred_lon;
6019 bool b_render_hdt =
false;
6020 if (!std::isnan(
gHdt)) {
6022 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
6025 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
6026 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
6027 if (dist > ndelta_pix ) {
6028 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
6029 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6034 wxPoint lShipMidPoint;
6035 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6036 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6037 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6038 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6040 if (lpp >= img_height / 2) {
6041 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6042 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6043 !std::isnan(
gSog)) {
6045 float dash_length = ref_dim;
6046 wxDash dash_long[2];
6048 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6049 g_cog_predictor_width);
6050 dash_long[1] = dash_long[0] / 2.0;
6054 if (dash_length > 250.) {
6055 dash_long[0] = 250. / g_cog_predictor_width;
6056 dash_long[1] = dash_long[0] / 2;
6059 wxPen ppPen2(cPred, g_cog_predictor_width,
6060 (wxPenStyle)g_cog_predictor_style);
6061 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6062 ppPen2.SetDashes(2, dash_long);
6065 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6066 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6068 if (g_cog_predictor_width > 1) {
6069 float line_width = g_cog_predictor_width / 3.;
6071 wxDash dash_long3[2];
6072 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6073 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6075 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6076 (wxPenStyle)g_cog_predictor_style);
6077 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6078 ppPen3.SetDashes(2, dash_long3);
6080 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6081 lGPSPoint.m_y + GPSOffsetPixels.y,
6082 lPredPoint.x + GPSOffsetPixels.x,
6083 lPredPoint.y + GPSOffsetPixels.y);
6086 if (g_cog_predictor_endmarker) {
6088 double png_pred_icon_scale_factor = .4;
6089 if (g_ShipScaleFactorExp > 1.0)
6090 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6091 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6095 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6096 (
float)(lPredPoint.x - lShipMidPoint.x));
6097 cog_rad += (float)PI;
6099 for (
int i = 0; i < 4; i++) {
6101 double pxa = (double)(s_png_pred_icon[j]);
6102 double pya = (double)(s_png_pred_icon[j + 1]);
6104 pya *= png_pred_icon_scale_factor;
6105 pxa *= png_pred_icon_scale_factor;
6107 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6108 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6110 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6111 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6115 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6118 dc.SetBrush(wxBrush(cPred));
6120 dc.StrokePolygon(4, icon);
6127 float hdt_dash_length = ref_dim * 0.4;
6129 cPred.Set(g_ownship_HDTpredictor_color);
6130 if (cPred == wxNullColour) cPred = PredColor();
6132 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6133 : g_cog_predictor_width * 0.8);
6134 wxDash dash_short[2];
6136 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6139 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6142 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6143 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6144 ppPen2.SetDashes(2, dash_short);
6148 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6149 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6151 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6153 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6155 if (g_ownship_HDTpredictor_endmarker) {
6156 double nominal_circle_size_pixels = wxMax(
6157 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6160 if (g_ShipScaleFactorExp > 1.0)
6161 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6163 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6164 lHeadPoint.y + GPSOffsetPixels.y,
6165 nominal_circle_size_pixels / 2);
6170 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6171 double factor = 1.00;
6172 if (g_pNavAidRadarRingsStepUnits == 1)
6174 else if (g_pNavAidRadarRingsStepUnits == 2) {
6175 if (std::isnan(
gSog))
6180 factor *= g_fNavAidRadarRingsStep;
6184 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6187 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6188 pow((
double)(lGPSPoint.m_y - r.y), 2));
6189 int pix_radius = (int)lpp;
6191 wxColor rangeringcolour =
6192 user_colors::GetDimColor(g_colourOwnshipRangeRingsColour);
6194 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6197 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6199 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6200 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6205void ChartCanvas::ResetGlGridFont() { GetglCanvas()->ResetGridFont(); }
6206bool ChartCanvas::CanAccelerateGlPanning() {
6207 return GetglCanvas()->CanAcceleratePanning();
6209void ChartCanvas::SetupGlCompression() { GetglCanvas()->SetupCompression(); }
6212void ChartCanvas::ResetGlGridFont() {}
6213bool ChartCanvas::CanAccelerateGlPanning() {
return false; }
6214void ChartCanvas::SetupGlCompression() {}
6217void ChartCanvas::ComputeShipScaleFactor(
6218 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6219 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6220 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6221 float screenResolution = m_pix_per_mm;
6224 double ship_bow_lat, ship_bow_lon;
6225 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6226 &ship_bow_lat, &ship_bow_lon);
6227 wxPoint lShipBowPoint;
6228 wxPoint2DDouble b_point =
6232 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6233 powf((
float)(b_point.m_y - a_point.m_y), 2));
6236 float shipLength_mm = shipLength_px / screenResolution;
6239 float ownship_min_mm = g_n_ownship_min_mm;
6240 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6243 float hdt_ant = icon_hdt + 180.;
6244 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6245 float dx = g_n_gps_antenna_offset_x / 1852.;
6246 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6254 if (shipLength_mm < ownship_min_mm) {
6255 dy /= shipLength_mm / ownship_min_mm;
6256 dx /= shipLength_mm / ownship_min_mm;
6259 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6261 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6262 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6268 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6269 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6271 float scale_factor = shipLength_px / ownShipLength;
6274 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6277 scale_factor = wxMax(scale_factor, scale_factor_min);
6279 scale_factor_y = scale_factor;
6280 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6281 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6284void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6285 if (!GetVP().IsValid())
return;
6287 wxPoint GPSOffsetPixels(0, 0);
6288 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6291 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6292 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6296 lShipMidPoint = lGPSPoint;
6300 float icon_hdt = pCog;
6301 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6304 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6308 double osd_head_lat, osd_head_lon;
6309 wxPoint osd_head_point;
6311 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6316 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6317 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6318 icon_rad += (float)PI;
6320 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6324 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6328 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6329 if (GetVP().chart_scale >
6332 ShipDrawLargeScale(dc, lShipMidPoint);
6338 if (m_pos_image_user)
6339 pos_image = m_pos_image_user->Copy();
6340 else if (SHIP_NORMAL == m_ownship_state)
6341 pos_image = m_pos_image_red->Copy();
6342 if (SHIP_LOWACCURACY == m_ownship_state)
6343 pos_image = m_pos_image_yellow->Copy();
6344 else if (SHIP_NORMAL != m_ownship_state)
6345 pos_image = m_pos_image_grey->Copy();
6348 if (m_pos_image_user) {
6349 pos_image = m_pos_image_user->Copy();
6351 if (SHIP_LOWACCURACY == m_ownship_state)
6352 pos_image = m_pos_image_user_yellow->Copy();
6353 else if (SHIP_NORMAL != m_ownship_state)
6354 pos_image = m_pos_image_user_grey->Copy();
6357 img_height = pos_image.GetHeight();
6359 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6360 g_OwnShipIconType > 0)
6362 int ownShipWidth = 22;
6363 int ownShipLength = 84;
6364 if (g_OwnShipIconType == 1) {
6365 ownShipWidth = pos_image.GetWidth();
6366 ownShipLength = pos_image.GetHeight();
6369 float scale_factor_x, scale_factor_y;
6370 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6371 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6372 scale_factor_x, scale_factor_y);
6374 if (g_OwnShipIconType == 1) {
6375 pos_image.Rescale(ownShipWidth * scale_factor_x,
6376 ownShipLength * scale_factor_y,
6377 wxIMAGE_QUALITY_HIGH);
6378 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6380 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6383 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6384 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6385 if (rot_image.GetAlpha(ip, jp) > 64)
6386 rot_image.SetAlpha(ip, jp, 255);
6388 wxBitmap os_bm(rot_image);
6390 int w = os_bm.GetWidth();
6391 int h = os_bm.GetHeight();
6394 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6395 lShipMidPoint.m_y - h / 2,
true);
6398 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6399 lShipMidPoint.m_y - h / 2);
6400 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6401 lShipMidPoint.m_y - h / 2 + h);
6404 else if (g_OwnShipIconType == 2) {
6405 wxPoint ownship_icon[10];
6407 for (
int i = 0; i < 10; i++) {
6409 float pxa = (float)(s_ownship_icon[j]);
6410 float pya = (float)(s_ownship_icon[j + 1]);
6411 pya *= scale_factor_y;
6412 pxa *= scale_factor_x;
6414 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6415 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6417 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6418 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6421 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6423 dc.SetBrush(wxBrush(ShipColor()));
6425 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6428 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6430 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6434 img_height = ownShipLength * scale_factor_y;
6438 if (m_pos_image_user) circle_rad = 1;
6440 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6441 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6442 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6445 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6447 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6450 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6451 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6452 if (rot_image.GetAlpha(ip, jp) > 64)
6453 rot_image.SetAlpha(ip, jp, 255);
6455 wxBitmap os_bm(rot_image);
6457 if (g_ShipScaleFactorExp > 1) {
6458 wxImage scaled_image = os_bm.ConvertToImage();
6459 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6461 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6462 scaled_image.GetHeight() * factor,
6463 wxIMAGE_QUALITY_HIGH));
6465 int w = os_bm.GetWidth();
6466 int h = os_bm.GetHeight();
6469 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6470 lShipMidPoint.m_y - h / 2,
true);
6474 if (m_pos_image_user) circle_rad = 1;
6476 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6477 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6478 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6481 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6482 lShipMidPoint.m_y - h / 2);
6483 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6484 lShipMidPoint.m_y - h / 2 + h);
6489 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6502void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6503 float &MinorSpacing) {
6508 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6509 {.000001f, 45.0f, 15.0f},
6510 {.0002f, 30.0f, 10.0f},
6511 {.0003f, 10.0f, 2.0f},
6512 {.0008f, 5.0f, 1.0f},
6513 {.001f, 2.0f, 30.0f / 60.0f},
6514 {.003f, 1.0f, 20.0f / 60.0f},
6515 {.006f, 0.5f, 10.0f / 60.0f},
6516 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6517 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6518 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6519 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6520 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6521 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6522 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6523 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6526 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6527 if (view_scale_ppm < lltab[tabi][0])
break;
6528 MajorSpacing = lltab[tabi][1];
6529 MinorSpacing = lltab[tabi][2];
6543wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6544 int deg = (int)fabs(latlon);
6545 float min = fabs((fabs(latlon) - deg) * 60.0);
6555 }
else if (latlon < 0.0) {
6567 if (spacing >= 1.0) {
6568 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6569 }
else if (spacing >= (1.0 / 60.0)) {
6570 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6572 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6589void ChartCanvas::GridDraw(
ocpnDC &dc) {
6590 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6592 double nlat, elon, slat, wlon;
6595 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6597 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6599 if (!m_pgridFont) SetupGridFont();
6600 dc.SetFont(*m_pgridFont);
6601 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6604 h = m_canvas_height;
6615 dlon = dlon + 360.0;
6618 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6621 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6624 while (lat < nlat) {
6627 CalcGridText(lat, gridlatMajor,
true);
6629 dc.
DrawLine(0, r.y, w, r.y,
false);
6630 dc.DrawText(st, 0, r.y);
6631 lat = lat + gridlatMajor;
6633 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6637 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6640 while (lat < nlat) {
6643 dc.
DrawLine(0, r.y, 10, r.y,
false);
6644 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6645 lat = lat + gridlatMinor;
6649 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6652 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6655 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6657 wxString st = CalcGridText(lon, gridlonMajor,
false);
6659 dc.
DrawLine(r.x, 0, r.x, h,
false);
6660 dc.DrawText(st, r.x, 0);
6661 lon = lon + gridlonMajor;
6666 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6670 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6672 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6675 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6676 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6677 lon = lon + gridlonMinor;
6684void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6686 double blat, blon, tlat, tlon;
6689 int x_origin = m_bDisplayGrid ? 60 : 20;
6690 int y_origin = m_canvas_height - 50;
6696 if (GetVP().chart_scale > 80000)
6700 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6701 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6706 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6707 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6711 double rotation = -VPoint.
rotation;
6713 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6715 int l1 = (y_origin - r.y) / count;
6717 for (
int i = 0; i < count; i++) {
6724 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6727 double blat, blon, tlat, tlon;
6734 int y_origin = m_canvas_height - chartbar_height - 5;
6738 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6745 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6750 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6751 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6755 float places = floor(logdist), rem = logdist - places;
6756 dist = pow(10, places);
6763 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6764 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6765 double rotation = -VPoint.
rotation;
6771 int l1 = r.x - x_origin;
6773 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6778 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6779 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6780 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6782 if (!m_pgridFont) SetupGridFont();
6783 dc.SetFont(*m_pgridFont);
6784 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6786 dc.GetTextExtent(s, &w, &h);
6792 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6796void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6801 double ra_max = 40.;
6803 wxPen pen_save = dc.GetPen();
6805 wxDateTime now = wxDateTime::Now();
6811 x0 = x1 = x + radius;
6816 while (angle < 360.) {
6817 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6820 if (angle > 360.) angle = 360.;
6822 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6830 x1 = (int)(x + cos(angle * PI / 180.) * r);
6831 y1 = (int)(y + sin(angle * PI / 180.) * r);
6841 dc.
DrawLine(x + radius, y, x1, y1);
6843 dc.SetPen(pen_save);
6846static bool bAnchorSoundPlaying =
false;
6848static void onAnchorSoundFinished(
void *ptr) {
6849 o_sound::g_anchorwatch_sound->UnLoad();
6850 bAnchorSoundPlaying =
false;
6853void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6854 using namespace o_sound;
6856 bool play_sound =
false;
6858 if (AnchorAlertOn1) {
6859 wxPoint TargetPoint;
6862 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6863 TargetPoint.y, 100);
6867 AnchorAlertOn1 =
false;
6870 if (AnchorAlertOn2) {
6871 wxPoint TargetPoint;
6874 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6875 TargetPoint.y, 100);
6879 AnchorAlertOn2 =
false;
6882 if (!bAnchorSoundPlaying) {
6883 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6884 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6885 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6886 if (g_anchorwatch_sound->IsOk()) {
6887 bAnchorSoundPlaying =
true;
6888 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6889 g_anchorwatch_sound->Play();
6895void ChartCanvas::UpdateShips() {
6898 wxClientDC dc(
this);
6901 if (!dc.IsOk() || dc.GetSize().x < 1 || dc.GetSize().y < 1)
return;
6903 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6904 if (!test_bitmap.IsOk())
return;
6906 wxMemoryDC temp_dc(test_bitmap);
6908 temp_dc.ResetBoundingBox();
6909 temp_dc.DestroyClippingRegion();
6910 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6921 ocpndc.CalcBoundingBox(px.x, px.y);
6926 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6927 temp_dc.MaxY() - temp_dc.MinY());
6929 wxRect own_ship_update_rect = ship_draw_rect;
6931 if (!own_ship_update_rect.IsEmpty()) {
6934 own_ship_update_rect.Union(ship_draw_last_rect);
6935 own_ship_update_rect.Inflate(2);
6938 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6940 ship_draw_last_rect = ship_draw_rect;
6942 temp_dc.SelectObject(wxNullBitmap);
6945void ChartCanvas::UpdateAlerts() {
6950 wxClientDC dc(
this);
6954 dc.GetSize(&sx, &sy);
6957 wxBitmap test_bitmap(sx, sy, -1);
6961 temp_dc.SelectObject(test_bitmap);
6963 temp_dc.ResetBoundingBox();
6964 temp_dc.DestroyClippingRegion();
6965 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6972 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6973 temp_dc.MaxX() - temp_dc.MinX(),
6974 temp_dc.MaxY() - temp_dc.MinY());
6976 if (!alert_rect.IsEmpty())
6977 alert_rect.Inflate(2);
6979 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6982 wxRect alert_update_rect = alert_draw_rect;
6983 alert_update_rect.Union(alert_rect);
6986 RefreshRect(alert_update_rect,
false);
6990 alert_draw_rect = alert_rect;
6992 temp_dc.SelectObject(wxNullBitmap);
6995void ChartCanvas::UpdateAIS() {
7001 wxClientDC dc(
this);
7005 dc.GetSize(&sx, &sy);
7013 if (
g_pAIS->GetTargetList().size() > 10) {
7014 ais_rect = wxRect(0, 0, sx, sy);
7017 wxBitmap test_bitmap(sx, sy, -1);
7021 temp_dc.SelectObject(test_bitmap);
7023 temp_dc.ResetBoundingBox();
7024 temp_dc.DestroyClippingRegion();
7025 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
7029 AISDraw(ocpndc, GetVP(),
this);
7030 AISDrawAreaNotices(ocpndc, GetVP(),
this);
7034 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
7035 temp_dc.MaxY() - temp_dc.MinY());
7037 if (!ais_rect.IsEmpty())
7038 ais_rect.Inflate(2);
7040 temp_dc.SelectObject(wxNullBitmap);
7043 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7046 wxRect ais_update_rect = ais_draw_rect;
7047 ais_update_rect.Union(ais_rect);
7050 RefreshRect(ais_update_rect,
false);
7054 ais_draw_rect = ais_rect;
7057void ChartCanvas::ToggleCPAWarn() {
7058 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7064 g_bTCPA_Max =
false;
7068 if (STAT_FIELD_SCALE >= 4 && top_frame::Get()->GetStatusBar()) {
7069 top_frame::Get()->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7071 if (!g_AisFirstTimeUse) {
7072 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7073 _(
"CPA") +
" " + mess, 4, 4);
7078void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7080void ChartCanvas::OnSize(wxSizeEvent &event) {
7081 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7083 GetClientSize(&m_canvas_width, &m_canvas_height);
7087 m_displayScale = GetContentScaleFactor();
7091 m_canvas_width *= m_displayScale;
7092 m_canvas_height *= m_displayScale;
7105 m_absolute_min_scale_ppm =
7107 (1.2 * WGS84_semimajor_axis_meters * PI);
7110 top_frame::Get()->ProcessCanvasResize();
7120 SetMUIBarPosition();
7121 UpdateFollowButtonState();
7122 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7126 xr_margin = m_canvas_width * 95 / 100;
7127 xl_margin = m_canvas_width * 5 / 100;
7128 yt_margin = m_canvas_height * 5 / 100;
7129 yb_margin = m_canvas_height * 95 / 100;
7132 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7137 m_brepaint_piano =
true;
7140 m_dc_route.SelectObject(wxNullBitmap);
7143 m_dc_route.SelectObject(*proute_bm);
7157 m_glcc->OnSize(event);
7166void ChartCanvas::ProcessNewGUIScale() {
7174void ChartCanvas::CreateMUIBar() {
7175 if (g_useMUI && !m_muiBar) {
7176 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7177 m_muiBar->SetColorScheme(m_cs);
7178 m_muiBarHOSize = m_muiBar->m_size;
7186 SetMUIBarPosition();
7187 UpdateFollowButtonState();
7188 m_muiBar->UpdateDynamicValues();
7189 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7193void ChartCanvas::SetMUIBarPosition() {
7197 int pianoWidth = GetClientSize().x * 0.6f;
7202 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7203 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7205 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7206 m_muiBar->SetColorScheme(m_cs);
7210 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7211 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7213 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7214 m_muiBar->SetColorScheme(m_cs);
7218 m_muiBar->SetBestPosition();
7222void ChartCanvas::DestroyMuiBar() {
7229void ChartCanvas::ShowCompositeInfoWindow(
7230 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7232 if (NULL == m_pCIWin) {
7237 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7240 s = _(
"Composite of ");
7243 s1.Printf(
"%d ", n_charts);
7251 s1.Printf(_(
"Chart scale"));
7254 s2.Printf(
"1:%d\n",
scale);
7258 s1 = _(
"Zoom in for more information");
7262 int char_width = s1.Length();
7263 int char_height = 3;
7265 if (g_bChartBarEx) {
7268 for (
int i : index_vector) {
7270 wxString path = cte.GetFullSystemPath();
7274 char_width = wxMax(char_width, path.Length());
7275 if (j++ >= 9)
break;
7278 s +=
" .\n .\n .\n";
7287 m_pCIWin->SetString(s);
7289 m_pCIWin->FitToChars(char_width, char_height);
7292 p.x = x / GetContentScaleFactor();
7293 if ((p.x + m_pCIWin->GetWinSize().x) >
7294 (m_canvas_width / GetContentScaleFactor()))
7295 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7296 m_pCIWin->GetWinSize().x) /
7299 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7300 4 - m_pCIWin->GetWinSize().y;
7302 m_pCIWin->dbIndex = 0;
7303 m_pCIWin->chart_scale = 0;
7304 m_pCIWin->SetPosition(p);
7305 m_pCIWin->SetBitmap();
7306 m_pCIWin->Refresh();
7310 HideChartInfoWindow();
7314void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7316 if (NULL == m_pCIWin) {
7321 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7330 dbIndex, FULL_INIT);
7332 int char_width, char_height;
7333 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7334 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7336 m_pCIWin->SetString(s);
7337 m_pCIWin->FitToChars(char_width, char_height);
7340 p.x = x / GetContentScaleFactor();
7341 if ((p.x + m_pCIWin->GetWinSize().x) >
7342 (m_canvas_width / GetContentScaleFactor()))
7343 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7344 m_pCIWin->GetWinSize().x) /
7347 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7348 4 - m_pCIWin->GetWinSize().y;
7350 m_pCIWin->dbIndex = dbIndex;
7351 m_pCIWin->SetPosition(p);
7352 m_pCIWin->SetBitmap();
7353 m_pCIWin->Refresh();
7357 HideChartInfoWindow();
7361void ChartCanvas::HideChartInfoWindow() {
7364 m_pCIWin->Destroy();
7368 androidForceFullRepaint();
7373void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7374 wxMouseEvent ev(wxEVT_MOTION);
7377 ev.m_leftDown = mouse_leftisdown;
7379 wxEvtHandler *evthp = GetEventHandler();
7381 ::wxPostEvent(evthp, ev);
7384void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7385 if ((m_panx_target_final - m_panx_target_now) ||
7386 (m_pany_target_final - m_pany_target_now)) {
7387 DoTimedMovementTarget();
7392void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7394bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7396 if (m_disable_edge_pan)
return false;
7399 int pan_margin = m_canvas_width * margin / 100;
7400 int pan_timer_set = 200;
7401 double pan_delta = GetVP().
pix_width * delta / 100;
7405 if (x > m_canvas_width - pan_margin) {
7410 else if (x < pan_margin) {
7415 if (y < pan_margin) {
7420 else if (y > m_canvas_height - pan_margin) {
7429 wxMouseState state = ::wxGetMouseState();
7430#if wxCHECK_VERSION(3, 0, 0)
7431 if (!state.LeftIsDown())
7433 if (!state.LeftDown())
7438 if ((bft) && !pPanTimer->IsRunning()) {
7440 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7446 if ((!bft) && pPanTimer->IsRunning()) {
7456void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7457 bool setBeingEdited) {
7458 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7459 m_pRoutePointEditTarget = NULL;
7460 m_pFoundPoint = NULL;
7463 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7464 SelectableItemList SelList =
pSelect->FindSelectionList(
7474 bool brp_viz =
false;
7475 if (m_pEditRouteArray) {
7476 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7477 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7478 if (pr->IsVisible()) {
7484 brp_viz = frp->IsVisible();
7488 if (m_pEditRouteArray)
7490 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7491 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7494 m_bRouteEditing = setBeingEdited;
7497 frp->m_bRPIsBeingEdited = setBeingEdited;
7498 m_bMarkEditing = setBeingEdited;
7501 m_pRoutePointEditTarget = frp;
7502 m_pFoundPoint = pFind;
7507std::shared_ptr<HostApi121::PiPointContext>
7508ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7522 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7523 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7524 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7525 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7526 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7530 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7533 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7538 int FoundAIS_MMSI = 0;
7540 FoundAIS_MMSI = pFindAIS->GetUserData();
7543 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7544 seltype |= SELTYPE_AISTARGET;
7550 Route *SelectedRoute = NULL;
7556 Route *pSelectedActiveRoute = NULL;
7557 Route *pSelectedVizRoute = NULL;
7560 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7561 SelectableItemList SelList =
7562 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7570 bool brp_viz =
false;
7572 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7574 if (pr->IsVisible()) {
7579 if (!brp_viz && prp->IsShared())
7581 brp_viz = prp->IsVisible();
7584 brp_viz = prp->IsVisible();
7586 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7592 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7595 pSelectedActiveRoute = pr;
7596 pFoundActiveRoutePoint = prp;
7601 if (NULL == pSelectedVizRoute) {
7602 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7604 if (pr->IsVisible()) {
7605 pSelectedVizRoute = pr;
7606 pFoundVizRoutePoint = prp;
7612 delete proute_array;
7617 if (pFoundActiveRoutePoint) {
7618 FoundRoutePoint = pFoundActiveRoutePoint;
7619 SelectedRoute = pSelectedActiveRoute;
7620 }
else if (pFoundVizRoutePoint) {
7621 FoundRoutePoint = pFoundVizRoutePoint;
7622 SelectedRoute = pSelectedVizRoute;
7625 FoundRoutePoint = pFirstVizPoint;
7627 if (SelectedRoute) {
7628 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7629 }
else if (FoundRoutePoint) {
7630 seltype |= SELTYPE_MARKPOINT;
7635 if (m_pFoundRoutePoint) {
7639 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7640 RefreshRect(wp_rect,
true);
7649 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7650 SelectableItemList SelList =
7651 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7653 if (NULL == SelectedRoute)
7658 if (pr->IsVisible()) {
7665 if (SelectedRoute) {
7666 if (NULL == FoundRoutePoint)
7667 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7670 seltype |= SELTYPE_ROUTESEGMENT;
7674 if (pFindTrackSeg) {
7675 m_pSelectedTrack = NULL;
7676 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7677 SelectableItemList SelList =
7678 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7683 if (pt->IsVisible()) {
7684 m_pSelectedTrack = pt;
7688 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7691 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7694 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7695 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7696 rstruct->object_ident =
"";
7698 if (seltype == SELTYPE_AISTARGET) {
7699 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7701 val.Printf(
"%d", FoundAIS_MMSI);
7702 rstruct->object_ident = val.ToStdString();
7703 }
else if (seltype & SELTYPE_MARKPOINT) {
7704 if (FoundRoutePoint) {
7705 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7706 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7708 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7709 if (SelectedRoute) {
7710 rstruct->object_type =
7711 HostApi121::PiContextObjectType::kObjectRoutesegment;
7712 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7714 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7715 if (m_pSelectedTrack) {
7716 rstruct->object_type =
7717 HostApi121::PiContextObjectType::kObjectTracksegment;
7718 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7725void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7726 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7727 singleClickEventIsValid =
false;
7728 m_DoubleClickTimer->Stop();
7733bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7734 if (!m_bChartDragging && !m_bDrawingRoute) {
7739 if (m_Compass && m_Compass->IsShown()) {
7741 bool isInCompass = logicalRect.Contains(event.GetPosition());
7742 if (isInCompass || m_mouseWasInCompass) {
7743 if (m_Compass->MouseEvent(event)) {
7744 cursor_region = CENTER;
7745 if (!g_btouch) SetCanvasCursor(event);
7746 m_mouseWasInCompass = isInCompass;
7750 m_mouseWasInCompass = isInCompass;
7753 if (m_notification_button && m_notification_button->IsShown()) {
7755 bool isinButton = logicalRect.Contains(event.GetPosition());
7757 SetCursor(*pCursorArrow);
7758 if (event.LeftDown()) HandleNotificationMouseClick();
7763 if (MouseEventToolbar(event))
return true;
7765 if (MouseEventChartBar(event))
return true;
7767 if (MouseEventMUIBar(event))
return true;
7769 if (MouseEventIENCBar(event))
return true;
7774void ChartCanvas::HandleNotificationMouseClick() {
7775 if (!m_NotificationsList) {
7779 m_NotificationsList->RecalculateSize();
7780 m_NotificationsList->Hide();
7783 if (m_NotificationsList->IsShown()) {
7784 m_NotificationsList->Hide();
7786 m_NotificationsList->RecalculateSize();
7787 m_NotificationsList->ReloadNotificationList();
7788 m_NotificationsList->Show();
7791bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7792 if (!g_bShowChartBar)
return false;
7794 if (!m_Piano->MouseEvent(event))
return false;
7796 cursor_region = CENTER;
7797 if (!g_btouch) SetCanvasCursor(event);
7801bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7802 if (!IsPrimaryCanvas())
return false;
7811 cursor_region = CENTER;
7812 if (!g_btouch) SetCanvasCursor(event);
7816bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7817 if (!IsPrimaryCanvas())
return false;
7830bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7832 if (!m_muiBar->MouseEvent(event))
return false;
7835 cursor_region = CENTER;
7836 if (!g_btouch) SetCanvasCursor(event);
7848 event.GetPosition(&x, &y);
7850 x *= m_displayScale;
7851 y *= m_displayScale;
7853 m_MouseDragging =
event.Dragging();
7859 if (event.Dragging()) {
7860 if ((x == mouse_x) && (y == mouse_y))
return true;
7866 mouse_leftisdown =
event.LeftDown();
7870 cursor_region = CENTER;
7874 if (m_Compass && m_Compass->IsShown() &&
7875 m_Compass->
GetRect().Contains(event.GetPosition())) {
7876 cursor_region = CENTER;
7877 }
else if (x > xr_margin) {
7878 cursor_region = MID_RIGHT;
7879 }
else if (x < xl_margin) {
7880 cursor_region = MID_LEFT;
7881 }
else if (y > yb_margin - chartbar_height &&
7882 y < m_canvas_height - chartbar_height) {
7883 cursor_region = MID_TOP;
7884 }
else if (y < yt_margin) {
7885 cursor_region = MID_BOT;
7887 cursor_region = CENTER;
7890 if (!g_btouch) SetCanvasCursor(event);
7894 leftIsDown =
event.LeftDown();
7897 if (event.LeftDown()) {
7898 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7901 g_bTempShowMenuBar =
false;
7902 top_frame::Get()->ApplyGlobalSettings(
false);
7910 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7911 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7915 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7916 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7919 event.SetEventObject(
this);
7920 if (SendMouseEventToPlugins(event))
7927 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7928 StartChartDragInertia();
7931 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7932 !singleClickEventIsValid) {
7934 if (m_DoubleClickTimer->IsRunning()) {
7935 m_DoubleClickTimer->Stop();
7940 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7941 singleClickEvent = event;
7942 singleClickEventIsValid =
true;
7951 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7952 if (g_click_stop > 0) {
7960 if (GetUpMode() == COURSE_UP_MODE) {
7961 m_b_rot_hidef =
false;
7962 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7964 pRotDefTimer->Stop();
7967 bool bRoll = !g_btouch;
7972 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7973 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7974 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7975 m_RolloverPopupTimer.Start(
7979 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7983 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7992#if !defined(__WXGTK__) && !defined(__WXQT__)
8000 if ((x >= 0) && (y >= 0))
8005 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
8006 wxPoint p = ClientToScreen(wxPoint(x, y));
8012 if (m_routeState >= 2) {
8015 m_bDrawingRoute =
true;
8017 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8022 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
8025 m_bDrawingRoute =
true;
8027 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8040#if defined(__WXMAC__) || defined(__ANDROID__)
8044 wxClientDC cdc(GetParent());
8056 if (m_pSelectedRoute) {
8058 m_pSelectedRoute->DeSelectRoute();
8060 if (g_bopengl && m_glcc) {
8065 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8068 if (m_pFoundRoutePoint) {
8076 if (g_btouch && m_pRoutePointEditTarget) {
8079 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8083 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8084 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8085 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8086 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8087 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8091 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8094 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8100 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8103 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8104 seltype |= SELTYPE_AISTARGET;
8109 m_pFoundRoutePoint = NULL;
8114 Route *pSelectedActiveRoute = NULL;
8115 Route *pSelectedVizRoute = NULL;
8118 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8119 SelectableItemList SelList =
8120 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8128 bool brp_viz =
false;
8130 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8132 if (pr->IsVisible()) {
8137 if (!brp_viz && prp->IsShared())
8139 brp_viz = prp->IsVisible();
8142 brp_viz = prp->IsVisible();
8144 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8149 m_pSelectedRoute = NULL;
8151 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8154 pSelectedActiveRoute = pr;
8155 pFoundActiveRoutePoint = prp;
8160 if (NULL == pSelectedVizRoute) {
8161 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8163 if (pr->IsVisible()) {
8164 pSelectedVizRoute = pr;
8165 pFoundVizRoutePoint = prp;
8171 delete proute_array;
8176 if (pFoundActiveRoutePoint) {
8177 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8178 m_pSelectedRoute = pSelectedActiveRoute;
8179 }
else if (pFoundVizRoutePoint) {
8180 m_pFoundRoutePoint = pFoundVizRoutePoint;
8181 m_pSelectedRoute = pSelectedVizRoute;
8184 m_pFoundRoutePoint = pFirstVizPoint;
8186 if (m_pSelectedRoute) {
8187 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8188 }
else if (m_pFoundRoutePoint) {
8189 seltype |= SELTYPE_MARKPOINT;
8193 if (m_pFoundRoutePoint) {
8197 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8198 RefreshRect(wp_rect,
true);
8206 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8207 SelectableItemList SelList =
8208 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8210 if (NULL == m_pSelectedRoute)
8215 if (pr->IsVisible()) {
8216 m_pSelectedRoute = pr;
8222 if (m_pSelectedRoute) {
8223 if (NULL == m_pFoundRoutePoint)
8224 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8229 if (g_bopengl && m_glcc) {
8234 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8236 seltype |= SELTYPE_ROUTESEGMENT;
8240 if (pFindTrackSeg) {
8241 m_pSelectedTrack = NULL;
8242 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8243 SelectableItemList SelList =
8244 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8249 if (pt->IsVisible()) {
8250 m_pSelectedTrack = pt;
8254 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8260 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8261 seltype |= SELTYPE_CURRENTPOINT;
8264 else if (pFindTide) {
8265 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8266 seltype |= SELTYPE_TIDEPOINT;
8271 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8276IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8286 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8287 SelectableItemList SelList =
8288 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8291 pFind = *SelList.begin();
8292 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8294 auto node = SelList.begin();
8295 if (SelList.size() > 1) {
8296 for (++node; node != SelList.end(); ++node) {
8299 if (pIDX_candidate->
IDX_type ==
'c') {
8300 pIDX_best_candidate = pIDX_candidate;
8305 pFind = *SelList.begin();
8306 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8309 return pIDX_best_candidate;
8311void ChartCanvas::CallPopupMenu(
int x,
int y) {
8315 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8323 if (SELTYPE_CURRENTPOINT == seltype) {
8329 if (SELTYPE_TIDEPOINT == seltype) {
8335 InvokeCanvasMenu(x, y, seltype);
8338 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8342 m_pSelectedRoute = NULL;
8344 if (m_pFoundRoutePoint) {
8345 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8348 m_pFoundRoutePoint = NULL;
8354bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8362 event.GetPosition(&x, &y);
8368 SelectRadius = g_Platform->GetSelectRadiusPix() /
8369 (m_true_scale_ppm * 1852 * 60);
8376 if (event.LeftDClick() && (cursor_region == CENTER)) {
8377 m_DoubleClickTimer->Start();
8378 singleClickEventIsValid =
false;
8384 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8387 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8390 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8391 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8392 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8398 SelectableItemList rpSelList =
8399 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8400 bool b_onRPtarget =
false;
8403 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8404 b_onRPtarget =
true;
8412 std::unique_ptr<HostApi> host_api =
GetHostApi();
8413 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8415 if (m_pRoutePointEditTarget) {
8417 if ((api_121->GetContextMenuMask() &
8418 api_121->kContextMenuDisableWaypoint))
8420 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8426 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8429 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8430 m_pRoutePointEditTarget = NULL;
8431 RefreshRect(wp_rect,
true);
8435 auto node = rpSelList.begin();
8436 if (node != rpSelList.end()) {
8440 wxArrayPtrVoid *proute_array =
8445 bool brp_viz =
false;
8447 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8449 if (pr->IsVisible()) {
8454 delete proute_array;
8458 brp_viz = frp->IsVisible();
8460 brp_viz = frp->IsVisible();
8463 if ((api_121->GetContextMenuMask() &
8464 api_121->kContextMenuDisableWaypoint))
8467 ShowMarkPropertiesDialog(frp);
8476 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8478 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8481 if (pr->IsVisible()) {
8482 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8487 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8489 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8492 if (pt->IsVisible()) {
8493 ShowTrackPropertiesDialog(pt);
8502 if (m_bShowCurrent) {
8504 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8506 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8508 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8509 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8511 if (pic->m_enabled && pic->m_init_state &&
8512 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8515 if (m_pIDXCandidate) {
8516 info.point_type = CURRENT_STATION;
8520 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8521 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8525 if (plugin) plugin->OnTideCurrentClick(info);
8540 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8542 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8544 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8545 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8547 if (pic->m_enabled && pic->m_init_state &&
8548 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8551 if (m_pIDXCandidate) {
8552 info.point_type = TIDE_STATION;
8556 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8557 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8561 if (plugin) plugin->OnTideCurrentClick(info);
8576 ShowObjectQueryWindow(x, y, zlat, zlon);
8581 if (event.LeftDown()) {
8597 bool appending =
false;
8598 bool inserting =
false;
8601 SetCursor(*pCursorPencil);
8605 m_bRouteEditing =
true;
8607 if (m_routeState == 1) {
8608 m_pMouseRoute =
new Route();
8609 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8619 double nearby_radius_meters =
8620 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8623 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8624 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8625 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8626 wxArrayPtrVoid *proute_array =
8631 bool brp_viz =
false;
8633 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8635 if (pr->IsVisible()) {
8640 delete proute_array;
8642 pNearbyPoint->IsShared())
8645 pNearbyPoint->IsVisible();
8647 brp_viz = pNearbyPoint->IsVisible();
8650 wxString msg = _(
"Use nearby waypoint?");
8652 const bool noname(pNearbyPoint->GetName() ==
"");
8655 _(
"Use nearby nameless waypoint and name it M with"
8656 " a unique number?");
8659 m_FinishRouteOnKillFocus =
false;
8661 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8662 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8663 m_FinishRouteOnKillFocus =
true;
8664 if (dlg_return == wxID_YES) {
8666 if (m_pMouseRoute) {
8667 int last_wp_num = m_pMouseRoute->GetnPoints();
8669 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8670 wxString wp_name = wxString::Format(
8671 "M%002i-%s", last_wp_num + 1, guid_short);
8672 pNearbyPoint->SetName(wp_name);
8674 pNearbyPoint->SetName(
"WPXX");
8676 pMousePoint = pNearbyPoint;
8679 if (m_routeState > 1)
8680 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8681 Undo_HasParent, NULL);
8684 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8685 bool procede =
false;
8689 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8695 m_FinishRouteOnKillFocus =
false;
8701 _(
"Insert first part of this route in the new route?");
8702 if (tail->GetIndexOf(pMousePoint) ==
8705 dmsg = _(
"Insert this route in the new route?");
8707 if (tail->GetIndexOf(pMousePoint) > 0) {
8708 dlg_return = OCPNMessageBox(
8709 this, dmsg, _(
"OpenCPN Route Create"),
8710 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8711 m_FinishRouteOnKillFocus =
true;
8713 if (dlg_return == wxID_YES) {
8720 _(
"Append last part of this route to the new route?");
8721 if (tail->GetIndexOf(pMousePoint) == 1)
8723 "Append this route to the new route?");
8728 if (tail->GetLastPoint() != pMousePoint) {
8729 dlg_return = OCPNMessageBox(
8730 this, dmsg, _(
"OpenCPN Route Create"),
8731 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8732 m_FinishRouteOnKillFocus =
true;
8734 if (dlg_return == wxID_YES) {
8745 if (!FindRouteContainingWaypoint(pMousePoint))
8746 pMousePoint->SetShared(
true);
8751 if (NULL == pMousePoint) {
8752 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8754 pMousePoint->SetNameShown(
false);
8758 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8760 if (m_routeState > 1)
8761 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8762 Undo_IsOrphanded, NULL);
8765 if (m_pMouseRoute) {
8766 if (m_routeState == 1) {
8768 m_pMouseRoute->AddPoint(pMousePoint);
8771 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8772 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8773 &rhumbBearing, &rhumbDist);
8774 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8775 rlat, &gcDist, &gcBearing, NULL);
8776 double gcDistNM = gcDist / 1852.0;
8779 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8780 pow(rhumbDist - gcDistNM - 1, 0.5);
8783 msg << _(
"For this leg the Great Circle route is ")
8785 << _(
" shorter than rhumbline.\n\n")
8786 << _(
"Would you like include the Great Circle routing points "
8789 m_FinishRouteOnKillFocus =
false;
8790 m_disable_edge_pan =
true;
8793 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8794 wxYES_NO | wxNO_DEFAULT);
8796 m_disable_edge_pan =
false;
8797 m_FinishRouteOnKillFocus =
true;
8799 if (answer == wxID_YES) {
8801 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8802 wxRealPoint gcCoord;
8804 for (
int i = 1; i <= segmentCount; i++) {
8805 double fraction = (double)i * (1.0 / (
double)segmentCount);
8806 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8807 gcDist * fraction, gcBearing,
8808 &gcCoord.x, &gcCoord.y, NULL);
8810 if (i < segmentCount) {
8811 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8813 gcPoint->SetNameShown(
false);
8815 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8817 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8820 gcPoint = pMousePoint;
8823 m_pMouseRoute->AddPoint(gcPoint);
8824 pSelect->AddSelectableRouteSegment(
8825 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8826 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8827 prevGcPoint = gcPoint;
8830 undo->CancelUndoableAction(
true);
8833 m_pMouseRoute->AddPoint(pMousePoint);
8834 pSelect->AddSelectableRouteSegment(
8835 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8836 pMousePoint, m_pMouseRoute);
8837 undo->AfterUndoableAction(m_pMouseRoute);
8841 m_pMouseRoute->AddPoint(pMousePoint);
8842 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8843 rlon, m_prev_pMousePoint,
8844 pMousePoint, m_pMouseRoute);
8845 undo->AfterUndoableAction(m_pMouseRoute);
8851 m_prev_pMousePoint = pMousePoint;
8859 int connect = tail->GetIndexOf(pMousePoint);
8864 int length = tail->GetnPoints();
8869 start = connect + 1;
8875 m_pMouseRoute->RemovePoint(m_pMouseRoute->GetLastPoint());
8877 for (i = start; i <= stop; i++) {
8878 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8881 m_pMouseRoute->GetnPoints();
8883 top_frame::Get()->RefreshAllCanvas();
8887 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8889 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8890 m_pMouseRoute->FinalizeForRendering();
8892 top_frame::Get()->RefreshAllCanvas();
8896 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8898 SetCursor(*pCursorPencil);
8900 if (!m_pMeasureRoute) {
8901 m_pMeasureRoute =
new Route();
8905 if (m_nMeasureState == 1) {
8912 wxEmptyString, wxEmptyString);
8914 pMousePoint->SetShowWaypointRangeRings(
false);
8916 m_pMeasureRoute->AddPoint(pMousePoint);
8920 m_prev_pMousePoint = pMousePoint;
8924 top_frame::Get()->RefreshAllCanvas();
8929 FindRoutePointsAtCursor(SelectRadius,
true);
8933 m_last_touch_down_pos =
event.GetPosition();
8935 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8943 if (ret)
return true;
8946 if (event.Dragging()) {
8949 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8951 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8953 SelectableItemList SelList =
pSelect->FindSelectionList(
8957 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8962 if (m_pRoutePointEditTarget &&
8963 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8965 SelectableItemList SelList =
pSelect->FindSelectionList(
8969 if (m_pRoutePointEditTarget == frp) {
8970 m_bIsInRadius =
true;
8975 if (!m_dragoffsetSet) {
8977 .PresetDragOffset(
this, mouse_x, mouse_y);
8978 m_dragoffsetSet =
true;
8983 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8984 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8987 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8989 DraggingAllowed =
false;
8991 if (m_pRoutePointEditTarget &&
8992 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8993 DraggingAllowed =
false;
8995 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8997 if (DraggingAllowed) {
8998 if (!undo->InUndoableAction()) {
8999 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9000 Undo_NeedsCopy, m_pFoundPoint);
9006 if (!g_bopengl && m_pEditRouteArray) {
9007 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9008 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9015 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9016 pre_rect.Union(route_rect);
9024 if (CheckEdgePan(x, y,
true, 5, 2))
9032 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9034 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9035 m_pRoutePointEditTarget,
9036 SELTYPE_DRAGHANDLE);
9037 m_pFoundPoint->m_slat =
9038 m_pRoutePointEditTarget->m_lat;
9039 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9041 m_pRoutePointEditTarget->m_lat =
9043 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9044 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9045 m_pFoundPoint->m_slat =
9047 m_pFoundPoint->m_slon = new_cursor_lon;
9063 if (m_pEditRouteArray) {
9064 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9066 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9069 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9070 post_rect.Union(route_rect);
9076 pre_rect.Union(post_rect);
9077 RefreshRect(pre_rect,
false);
9079 top_frame::Get()->RefreshCanvasOther(
this);
9080 m_bRoutePoinDragging =
true;
9085 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9086 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9089 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9091 DraggingAllowed =
false;
9093 if (m_pRoutePointEditTarget &&
9094 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9095 DraggingAllowed =
false;
9097 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9099 if (DraggingAllowed) {
9100 if (!undo->InUndoableAction()) {
9101 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9102 Undo_NeedsCopy, m_pFoundPoint);
9116 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9122 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9123 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9124 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9125 (
int)(lppmax - (pre_rect.height / 2)));
9133 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9136 m_pRoutePointEditTarget,
9137 SELTYPE_DRAGHANDLE);
9138 m_pFoundPoint->m_slat =
9139 m_pRoutePointEditTarget->m_lat;
9140 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9142 m_pRoutePointEditTarget->m_lat =
9145 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9158 if (!g_btouch) InvalidateGL();
9164 .CalculateDCRect(m_dc_route,
this, &post_rect);
9165 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9166 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9167 (
int)(lppmax - (post_rect.height / 2)));
9170 pre_rect.Union(post_rect);
9171 RefreshRect(pre_rect,
false);
9173 top_frame::Get()->RefreshCanvasOther(
this);
9174 m_bRoutePoinDragging =
true;
9176 ret = g_btouch ? m_bRoutePoinDragging :
true;
9179 if (ret)
return true;
9182 if (event.LeftUp()) {
9183 bool b_startedit_route =
false;
9184 m_dragoffsetSet =
false;
9187 m_bChartDragging =
false;
9188 m_bIsInRadius =
false;
9192 if (m_ignore_next_leftup) {
9193 m_ignore_next_leftup =
false;
9198 m_bedge_pan =
false;
9203 bool appending =
false;
9204 bool inserting =
false;
9210 if (m_pRoutePointEditTarget) {
9216 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9217 RefreshRect(wp_rect,
true);
9219 m_pRoutePointEditTarget = NULL;
9221 m_bRouteEditing =
true;
9223 if (m_routeState == 1) {
9224 m_pMouseRoute =
new Route();
9225 m_pMouseRoute->SetHiLite(50);
9229 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9236 double nearby_radius_meters =
9237 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9240 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9241 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9242 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9245 m_FinishRouteOnKillFocus =
9247 dlg_return = OCPNMessageBox(
9248 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9249 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9250 m_FinishRouteOnKillFocus =
true;
9252 dlg_return = wxID_YES;
9254 if (dlg_return == wxID_YES) {
9255 pMousePoint = pNearbyPoint;
9258 if (m_routeState > 1)
9259 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9260 Undo_HasParent, NULL);
9261 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9263 bool procede =
false;
9267 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9273 m_FinishRouteOnKillFocus =
false;
9274 if (m_routeState == 1) {
9278 _(
"Insert first part of this route in the new route?");
9279 if (tail->GetIndexOf(pMousePoint) ==
9282 dmsg = _(
"Insert this route in the new route?");
9284 if (tail->GetIndexOf(pMousePoint) != 1) {
9286 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9287 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9288 m_FinishRouteOnKillFocus =
true;
9290 if (dlg_return == wxID_YES) {
9297 _(
"Append last part of this route to the new route?");
9298 if (tail->GetIndexOf(pMousePoint) == 1)
9300 "Append this route to the new route?");
9304 if (tail->GetLastPoint() != pMousePoint) {
9306 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9307 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9308 m_FinishRouteOnKillFocus =
true;
9310 if (dlg_return == wxID_YES) {
9321 if (!FindRouteContainingWaypoint(pMousePoint))
9322 pMousePoint->SetShared(
true);
9326 if (NULL == pMousePoint) {
9327 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9329 pMousePoint->SetNameShown(
false);
9331 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9333 if (m_routeState > 1)
9334 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9335 Undo_IsOrphanded, NULL);
9338 if (m_routeState == 1) {
9340 m_pMouseRoute->AddPoint(pMousePoint);
9341 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9345 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9346 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9347 &rhumbBearing, &rhumbDist);
9348 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9349 &gcDist, &gcBearing, NULL);
9350 double gcDistNM = gcDist / 1852.0;
9353 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9354 pow(rhumbDist - gcDistNM - 1, 0.5);
9357 msg << _(
"For this leg the Great Circle route is ")
9359 << _(
" shorter than rhumbline.\n\n")
9360 << _(
"Would you like include the Great Circle routing points "
9364 m_FinishRouteOnKillFocus =
false;
9365 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9366 wxYES_NO | wxNO_DEFAULT);
9367 m_FinishRouteOnKillFocus =
true;
9369 int answer = wxID_NO;
9372 if (answer == wxID_YES) {
9374 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9375 wxRealPoint gcCoord;
9377 for (
int i = 1; i <= segmentCount; i++) {
9378 double fraction = (double)i * (1.0 / (
double)segmentCount);
9379 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9380 gcDist * fraction, gcBearing,
9381 &gcCoord.x, &gcCoord.y, NULL);
9383 if (i < segmentCount) {
9384 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9386 gcPoint->SetNameShown(
false);
9387 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9390 gcPoint = pMousePoint;
9393 m_pMouseRoute->AddPoint(gcPoint);
9394 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9396 pSelect->AddSelectableRouteSegment(
9397 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9398 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9399 prevGcPoint = gcPoint;
9402 undo->CancelUndoableAction(
true);
9405 m_pMouseRoute->AddPoint(pMousePoint);
9406 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9407 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9408 rlon, m_prev_pMousePoint,
9409 pMousePoint, m_pMouseRoute);
9410 undo->AfterUndoableAction(m_pMouseRoute);
9414 m_pMouseRoute->AddPoint(pMousePoint);
9415 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9417 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9418 rlon, m_prev_pMousePoint,
9419 pMousePoint, m_pMouseRoute);
9420 undo->AfterUndoableAction(m_pMouseRoute);
9426 m_prev_pMousePoint = pMousePoint;
9433 int connect = tail->GetIndexOf(pMousePoint);
9438 int length = tail->GetnPoints();
9443 start = connect + 1;
9448 m_pMouseRoute->RemovePoint(
9452 for (i = start; i <= stop; i++) {
9453 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9456 m_pMouseRoute->GetnPoints();
9458 top_frame::Get()->RefreshAllCanvas();
9462 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9464 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9465 m_pMouseRoute->FinalizeForRendering();
9470 }
else if (m_bMeasure_Active && m_nMeasureState)
9473 m_bedge_pan =
false;
9477 if (m_ignore_next_leftup) {
9478 m_ignore_next_leftup =
false;
9482 if (m_nMeasureState == 1) {
9483 m_pMeasureRoute =
new Route();
9489 if (m_pMeasureRoute) {
9492 wxEmptyString, wxEmptyString);
9495 m_pMeasureRoute->AddPoint(pMousePoint);
9499 m_prev_pMousePoint = pMousePoint;
9501 m_pMeasureRoute->GetnPoints();
9505 CancelMeasureRoute();
9511 bool bSelectAllowed =
true;
9513 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9515 bSelectAllowed =
false;
9519 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9520 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9521 significant_drag) ||
9522 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9523 significant_drag)) {
9524 bSelectAllowed =
false;
9532 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9534 if (bSelectAllowed) {
9535 bool b_was_editing_mark = m_bMarkEditing;
9536 bool b_was_editing_route = m_bRouteEditing;
9537 FindRoutePointsAtCursor(SelectRadius,
9543 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9544 m_pRoutePointEditTarget = NULL;
9546 if (!b_was_editing_route) {
9547 if (m_pEditRouteArray) {
9548 b_startedit_route =
true;
9552 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9553 m_pTrackRolloverWin->IsActive(
false);
9555 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9556 m_pRouteRolloverWin->IsActive(
false);
9560 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9562 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9570 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9571 pre_rect.Union(route_rect);
9574 RefreshRect(pre_rect,
true);
9577 b_startedit_route =
false;
9581 if (m_pRoutePointEditTarget) {
9582 if (b_was_editing_mark ||
9583 b_was_editing_route) {
9584 if (m_lastRoutePointEditTarget) {
9588 .EnableDragHandle(
false);
9589 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9590 SELTYPE_DRAGHANDLE);
9594 if (m_pRoutePointEditTarget) {
9597 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9598 wxPoint2DDouble dragHandlePoint =
9600 .GetDragHandlePoint(
this);
9602 dragHandlePoint.m_y, dragHandlePoint.m_x,
9603 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9606 if (m_lastRoutePointEditTarget) {
9610 .EnableDragHandle(
false);
9611 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9612 SELTYPE_DRAGHANDLE);
9615 wxArrayPtrVoid *lastEditRouteArray =
9617 m_lastRoutePointEditTarget);
9618 if (lastEditRouteArray) {
9619 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9621 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9626 delete lastEditRouteArray;
9637 if (m_lastRoutePointEditTarget) {
9640 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9641 RefreshRect(wp_rect,
true);
9644 if (m_pRoutePointEditTarget) {
9647 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9648 RefreshRect(wp_rect,
true);
9656 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9657 bool b_start_rollover =
false;
9661 if (pFind) b_start_rollover =
true;
9664 if (!b_start_rollover && !b_startedit_route) {
9665 SelectableItemList SelList =
pSelect->FindSelectionList(
9669 if (pr && pr->IsVisible()) {
9670 b_start_rollover =
true;
9676 if (!b_start_rollover && !b_startedit_route) {
9677 SelectableItemList SelList =
pSelect->FindSelectionList(
9681 if (tr && tr->IsVisible()) {
9682 b_start_rollover =
true;
9688 if (b_start_rollover)
9689 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9693 bool appending =
false;
9694 bool inserting =
false;
9696 if (m_bRouteEditing ) {
9698 if (m_pRoutePointEditTarget) {
9704 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9705 double nearby_radius_meters =
9706 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9707 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9708 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9709 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9711 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9715 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9717 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9721 std::find(list->begin(), list->end(), pNearbyPoint);
9722 if (pos != list->end()) {
9734 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9739 OCPNMessageBox(
this,
9740 _(
"Replace this RoutePoint by the nearby "
9742 _(
"OpenCPN RoutePoint change"),
9743 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9744 if (dlg_return == wxID_YES) {
9749 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9752 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9754 if (tail && current && (tail != current)) {
9756 connect = tail->GetIndexOf(pNearbyPoint);
9757 int index_current_route =
9758 current->GetIndexOf(m_pRoutePointEditTarget);
9759 index_last = current->GetIndexOf(current->GetLastPoint());
9760 dlg_return1 = wxID_NO;
9762 index_current_route) {
9764 if (connect != tail->GetnPoints()) {
9767 _(
"Last part of route to be appended to dragged "
9771 _(
"Full route to be appended to dragged route?");
9773 dlg_return1 = OCPNMessageBox(
9774 this, dmsg, _(
"OpenCPN Route Create"),
9775 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9776 if (dlg_return1 == wxID_YES) {
9780 }
else if (index_current_route ==
9785 _(
"First part of route to be inserted into dragged "
9787 if (connect == tail->GetnPoints())
9789 "Full route to be inserted into dragged route?");
9791 dlg_return1 = OCPNMessageBox(
9792 this, dmsg, _(
"OpenCPN Route Create"),
9793 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9794 if (dlg_return1 == wxID_YES) {
9801 if (m_pRoutePointEditTarget->IsShared()) {
9803 dlg_return = OCPNMessageBox(
9805 _(
"Do you really want to delete and replace this "
9807 "\n" + _(
"which has been created manually?"),
9808 (
"OpenCPN RoutePoint warning"),
9809 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9812 if (dlg_return == wxID_YES) {
9813 pMousePoint = pNearbyPoint;
9815 pMousePoint->SetShared(
true);
9825 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9827 if (m_pEditRouteArray) {
9828 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9830 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9835 auto pos = std::find(list->begin(), list->end(),
9836 m_pRoutePointEditTarget);
9838 pSelect->DeleteAllSelectableRoutePoints(pr);
9839 pSelect->DeleteAllSelectableRouteSegments(pr);
9842 pos = std::find(list->begin(), list->end(),
9843 m_pRoutePointEditTarget);
9846 pSelect->AddAllSelectableRouteSegments(pr);
9847 pSelect->AddAllSelectableRoutePoints(pr);
9849 pr->FinalizeForRendering();
9850 pr->UpdateSegmentDistances();
9851 if (m_bRoutePoinDragging) {
9853 NavObj_dB::GetInstance().UpdateRoute(pr);
9861 if (m_pEditRouteArray) {
9862 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9864 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9883 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9890 delete m_pRoutePointEditTarget;
9891 m_lastRoutePointEditTarget = NULL;
9892 m_pRoutePointEditTarget = NULL;
9893 undo->AfterUndoableAction(pMousePoint);
9894 undo->InvalidateUndo();
9899 else if (m_bMarkEditing) {
9900 if (m_pRoutePointEditTarget)
9901 if (m_bRoutePoinDragging) {
9903 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9907 if (m_pRoutePointEditTarget)
9908 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9910 if (!m_pRoutePointEditTarget) {
9911 delete m_pEditRouteArray;
9912 m_pEditRouteArray = NULL;
9913 m_bRouteEditing =
false;
9915 m_bRoutePoinDragging =
false;
9922 int length = tail->GetnPoints();
9923 for (
int i = connect + 1; i <= length; i++) {
9924 current->AddPointAndSegment(tail->GetPoint(i),
false);
9927 top_frame::Get()->RefreshAllCanvas();
9930 current->FinalizeForRendering();
9936 pSelect->DeleteAllSelectableRoutePoints(current);
9937 pSelect->DeleteAllSelectableRouteSegments(current);
9938 for (
int i = 1; i < connect; i++) {
9939 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9941 pSelect->AddAllSelectableRouteSegments(current);
9942 pSelect->AddAllSelectableRoutePoints(current);
9943 current->FinalizeForRendering();
9950 if (m_pEditRouteArray) {
9951 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9952 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9965 if (m_bRouteEditing) {
9968 bool appending =
false;
9969 bool inserting =
false;
9972 if (m_pRoutePointEditTarget) {
9973 m_pRoutePointEditTarget->
m_bBlink =
false;
9977 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9978 double nearby_radius_meters =
9979 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9980 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9981 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9982 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9984 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9985 bool duplicate =
false;
9987 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9989 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9993 std::find(list->begin(), list->end(), pNearbyPoint);
9994 if (pos != list->end()) {
10006 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
10011 OCPNMessageBox(
this,
10012 _(
"Replace this RoutePoint by the nearby "
10014 _(
"OpenCPN RoutePoint change"),
10015 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10016 if (dlg_return == wxID_YES) {
10020 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
10023 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
10025 if (tail && current && (tail != current)) {
10027 connect = tail->GetIndexOf(pNearbyPoint);
10028 int index_current_route =
10029 current->GetIndexOf(m_pRoutePointEditTarget);
10030 index_last = current->GetIndexOf(current->GetLastPoint());
10031 dlg_return1 = wxID_NO;
10033 index_current_route) {
10035 if (connect != tail->GetnPoints()) {
10038 _(
"Last part of route to be appended to dragged "
10042 _(
"Full route to be appended to dragged route?");
10044 dlg_return1 = OCPNMessageBox(
10045 this, dmsg, _(
"OpenCPN Route Create"),
10046 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10047 if (dlg_return1 == wxID_YES) {
10051 }
else if (index_current_route ==
10053 if (connect != 1) {
10056 _(
"First part of route to be inserted into dragged "
10058 if (connect == tail->GetnPoints())
10060 "Full route to be inserted into dragged route?");
10062 dlg_return1 = OCPNMessageBox(
10063 this, dmsg, _(
"OpenCPN Route Create"),
10064 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10065 if (dlg_return1 == wxID_YES) {
10072 if (m_pRoutePointEditTarget->IsShared()) {
10073 dlg_return = wxID_NO;
10074 dlg_return = OCPNMessageBox(
10076 _(
"Do you really want to delete and replace this "
10078 "\n" + _(
"which has been created manually?"),
10079 (
"OpenCPN RoutePoint warning"),
10080 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10083 if (dlg_return == wxID_YES) {
10084 pMousePoint = pNearbyPoint;
10086 pMousePoint->SetShared(
true);
10096 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10098 if (m_pEditRouteArray) {
10099 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10101 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10105 auto pos = std::find(list->begin(), list->end(),
10106 m_pRoutePointEditTarget);
10108 pSelect->DeleteAllSelectableRoutePoints(pr);
10109 pSelect->DeleteAllSelectableRouteSegments(pr);
10112 pos = std::find(list->begin(), list->end(),
10113 m_pRoutePointEditTarget);
10114 if (pos != list->end()) list->erase(pos);
10117 pSelect->AddAllSelectableRouteSegments(pr);
10118 pSelect->AddAllSelectableRoutePoints(pr);
10120 pr->FinalizeForRendering();
10121 pr->UpdateSegmentDistances();
10124 if (m_bRoutePoinDragging) {
10129 NavObj_dB::GetInstance().UpdateRoutePoint(
10130 m_pRoutePointEditTarget);
10132 NavObj_dB::GetInstance().UpdateRoute(pr);
10144 int length = tail->GetnPoints();
10145 for (
int i = connect + 1; i <= length; i++) {
10146 current->AddPointAndSegment(tail->GetPoint(i),
false);
10150 top_frame::Get()->RefreshAllCanvas();
10153 current->FinalizeForRendering();
10159 pSelect->DeleteAllSelectableRoutePoints(current);
10160 pSelect->DeleteAllSelectableRouteSegments(current);
10161 for (
int i = 1; i < connect; i++) {
10162 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10164 pSelect->AddAllSelectableRouteSegments(current);
10165 pSelect->AddAllSelectableRoutePoints(current);
10166 current->FinalizeForRendering();
10173 if (m_pEditRouteArray) {
10174 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10176 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10188 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10195 delete m_pRoutePointEditTarget;
10196 m_lastRoutePointEditTarget = NULL;
10197 undo->AfterUndoableAction(pMousePoint);
10198 undo->InvalidateUndo();
10203 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10206 delete m_pEditRouteArray;
10207 m_pEditRouteArray = NULL;
10211 m_bRouteEditing =
false;
10212 m_pRoutePointEditTarget = NULL;
10218 else if (m_bMarkEditing) {
10219 if (m_pRoutePointEditTarget) {
10220 if (m_bRoutePoinDragging) {
10222 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10224 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10229 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10231 RefreshRect(wp_rect,
true);
10234 m_pRoutePointEditTarget = NULL;
10235 m_bMarkEditing =
false;
10240 else if (leftIsDown) {
10241 leftIsDown =
false;
10245 if (!m_bChartDragging && !m_bMeasure_Active) {
10247 m_bChartDragging =
false;
10251 m_bRoutePoinDragging =
false;
10254 if (ret)
return true;
10257 if (event.RightDown()) {
10268 m_FinishRouteOnKillFocus =
false;
10269 CallPopupMenu(mx, my);
10270 m_FinishRouteOnKillFocus =
true;
10280 if (event.ShiftDown()) {
10284 event.GetPosition(&x, &y);
10286 x *= m_displayScale;
10287 y *= m_displayScale;
10293 int wheel_dir =
event.GetWheelRotation();
10296 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10297 wheel_dir = wheel_dir > 0 ? 1 : -1;
10299 double factor = g_mouse_zoom_sensitivity;
10300 if (wheel_dir < 0) factor = 1 / factor;
10303 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10304 if (wheel_dir == m_last_wheel_dir) {
10305 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10310 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10311 m_wheelstopwatch.Start(0);
10316 m_last_wheel_dir = wheel_dir;
10321 if (event.LeftDown()) {
10327 last_drag.x = x, last_drag.y = y;
10328 panleftIsDown =
true;
10331 if (event.LeftUp()) {
10332 if (panleftIsDown) {
10334 panleftIsDown =
false;
10337 if (!m_bChartDragging && !m_bMeasure_Active) {
10338 switch (cursor_region) {
10360 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10365 m_bChartDragging =
false;
10371 if (event.Dragging() && event.LeftIsDown()) {
10387 if (g_btouch && !m_inPinch) {
10388 struct timespec now;
10389 clock_gettime(CLOCK_MONOTONIC, &now);
10390 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10392 bool trigger_hold =
false;
10393 if (
false == m_bChartDragging) {
10394 if (m_DragTrigger < 0) {
10397 m_DragTriggerStartTime = tnow;
10398 trigger_hold =
true;
10400 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10401 m_DragTrigger = -1;
10406 if (trigger_hold)
return true;
10408 if (
false == m_bChartDragging) {
10411 last_drag.x = x - 1, last_drag.y = y - 1;
10412 m_bChartDragging =
true;
10413 m_chart_drag_total_time = 0;
10414 m_chart_drag_total_x = 0;
10415 m_chart_drag_total_y = 0;
10416 m_inertia_last_drag_x = x;
10417 m_inertia_last_drag_y = y;
10418 m_drag_vec_x.clear();
10419 m_drag_vec_y.clear();
10420 m_drag_vec_t.clear();
10421 m_last_drag_time = tnow;
10425 uint64_t delta_t = tnow - m_last_drag_time;
10426 double delta_tf = delta_t / 1e9;
10428 m_chart_drag_total_time += delta_tf;
10429 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10430 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10432 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10433 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10434 m_drag_vec_t.push_back(delta_tf);
10436 m_inertia_last_drag_x = x;
10437 m_inertia_last_drag_y = y;
10438 m_last_drag_time = tnow;
10440 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10441 m_bChartDragging =
true;
10442 StartTimedMovement();
10443 m_pan_drag.x += last_drag.x - x;
10444 m_pan_drag.y += last_drag.y - y;
10445 last_drag.x = x, last_drag.y = y;
10447 }
else if (!g_btouch) {
10448 if ((last_drag.x != x) || (last_drag.y != y)) {
10449 if (!m_routeState) {
10452 m_bChartDragging =
true;
10453 StartTimedMovement();
10454 m_pan_drag.x += last_drag.x - x;
10455 m_pan_drag.y += last_drag.y - y;
10456 last_drag.x = x, last_drag.y = y;
10463 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10465 m_ignore_next_leftup =
true;
10466 m_DoubleClickTimer->Start();
10467 singleClickEventIsValid =
false;
10475void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10476 if (MouseEventOverlayWindows(event))
return;
10480 bool nm = MouseEventProcessObjects(event);
10484void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10487 wxCursor *ptarget_cursor = pCursorArrow;
10488 if (!pPlugIn_Cursor) {
10489 ptarget_cursor = pCursorArrow;
10490 if ((!m_routeState) &&
10491 (!m_bMeasure_Active) ) {
10492 if (cursor_region == MID_RIGHT) {
10493 ptarget_cursor = pCursorRight;
10494 }
else if (cursor_region == MID_LEFT) {
10495 ptarget_cursor = pCursorLeft;
10496 }
else if (cursor_region == MID_TOP) {
10497 ptarget_cursor = pCursorDown;
10498 }
else if (cursor_region == MID_BOT) {
10499 ptarget_cursor = pCursorUp;
10501 ptarget_cursor = pCursorArrow;
10503 }
else if (m_bMeasure_Active ||
10505 ptarget_cursor = pCursorPencil;
10507 ptarget_cursor = pPlugIn_Cursor;
10510 SetCursor(*ptarget_cursor);
10513void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10514 SetCursor(*pCursorArrow);
10517void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10521 wxArrayString files;
10523 ChartBase *target_chart = GetChartAtCursor();
10524 if (target_chart) {
10525 file.Assign(target_chart->GetFullPath());
10526 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10527 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10530 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10532 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10533 unsigned int im = stackIndexArray.size();
10534 int scale = 2147483647;
10535 if (VPoint.b_quilt && im > 0) {
10536 for (
unsigned int is = 0; is < im; is++) {
10537 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10538 CHART_TYPE_MBTILES) {
10539 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10541 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10542 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10544 .Contains(lat, lon)) {
10545 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10548 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10549 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10557 std::vector<Ais8_001_22 *> area_notices;
10559 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10562 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10563 auto target_data = target.second;
10564 if (!target_data->area_notices.empty()) {
10565 for (
auto &ani : target_data->area_notices) {
10570 for (Ais8_001_22_SubAreaList::iterator sa =
10571 area_notice.sub_areas.begin();
10572 sa != area_notice.sub_areas.end(); ++sa) {
10573 switch (sa->shape) {
10574 case AIS8_001_22_SHAPE_CIRCLE: {
10575 wxPoint target_point;
10577 bbox.Expand(target_point);
10578 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10581 case AIS8_001_22_SHAPE_RECT: {
10582 wxPoint target_point;
10584 bbox.Expand(target_point);
10585 if (sa->e_dim_m > sa->n_dim_m)
10586 bbox.EnLarge(sa->e_dim_m * vp_scale);
10588 bbox.EnLarge(sa->n_dim_m * vp_scale);
10591 case AIS8_001_22_SHAPE_POLYGON:
10592 case AIS8_001_22_SHAPE_POLYLINE: {
10593 for (
int i = 0; i < 4; ++i) {
10594 double lat = sa->latitude;
10595 double lon = sa->longitude;
10596 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10598 wxPoint target_point;
10600 bbox.Expand(target_point);
10604 case AIS8_001_22_SHAPE_SECTOR: {
10605 double lat1 = sa->latitude;
10606 double lon1 = sa->longitude;
10608 wxPoint target_point;
10610 bbox.Expand(target_point);
10611 for (
int i = 0; i < 18; ++i) {
10614 sa->left_bound_deg +
10615 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10616 sa->radius_m / 1852.0, &lat, &lon);
10618 bbox.Expand(target_point);
10620 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10623 bbox.Expand(target_point);
10629 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10630 area_notices.push_back(&area_notice);
10637 if (target_chart || !area_notices.empty() || file.HasName()) {
10639 int sel_rad_pix = 5;
10640 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10645 SetCursor(wxCURSOR_WAIT);
10646 bool lightsVis = m_encShowLights;
10647 if (!lightsVis) SetShowENCLights(
true);
10650 ListOfObjRazRules *rule_list = NULL;
10651 ListOfPI_S57Obj *pi_rule_list = NULL;
10654 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10655 else if (target_plugin_chart)
10656 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10657 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10659 ListOfObjRazRules *overlay_rule_list = NULL;
10660 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10663 if (CHs57_Overlay) {
10664 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10665 zlat, zlon, SelectRadius, &GetVP());
10668 if (!lightsVis) SetShowENCLights(
false);
10671 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10672 wxString face = dFont->GetFaceName();
10676 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10677 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10681 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10689 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10690 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10693 int points = dFont->GetPointSize();
10695 int points = dFont->GetPointSize() + 1;
10699 for (
int i = -2; i < 5; i++) {
10700 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10704 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10706 if (overlay_rule_list && CHs57_Overlay) {
10707 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10708 objText <<
"<hr noshade>";
10711 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10712 an != area_notices.end(); ++an) {
10713 objText <<
"<b>AIS Area Notice:</b> ";
10714 objText << ais8_001_22_notice_names[(*an)->notice_type];
10715 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10716 (*an)->sub_areas.begin();
10717 sa != (*an)->sub_areas.end(); ++sa)
10718 if (!sa->text.empty()) objText << sa->text;
10719 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10720 objText <<
"<hr noshade>";
10724 objText << Chs57->CreateObjDescriptions(rule_list);
10725 else if (target_plugin_chart)
10726 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10729 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10732 wxString AddFiles, filenameOK;
10734 if (!target_plugin_chart) {
10737 AddFiles = wxString::Format(
10738 "<hr noshade><br><b>Additional info files attached to: </b> "
10740 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10742 file.GetFullName());
10744 file.Assign(file.GetPath(),
"");
10745 wxDir dir(file.GetFullPath());
10747 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10749 file.Assign(dir.GetNameWithSep().append(filename));
10750 wxString FormatString =
10751 "<td valign=top><font size=-2><a "
10752 "href=\"%s\">%s</a></font></td>";
10753 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10754 filenameOK = file.GetFullPath();
10756 if (3 * ((
int)filecount / 3) == filecount)
10757 FormatString.Prepend(
"<tr>");
10759 FormatString.Prepend(
10760 "<td>  </td>");
10763 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10764 file.GetFullName());
10767 cont = dir.GetNext(&filename);
10769 objText << AddFiles <<
"</table>";
10771 objText <<
"</font>";
10772 objText <<
"</body></html>";
10774 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10778 if ((!Chs57 && filecount == 1)) {
10780 wxHtmlLinkInfo hli(filenameOK);
10781 wxHtmlLinkEvent hle(1, hli);
10785 if (rule_list) rule_list->Clear();
10788 if (overlay_rule_list) overlay_rule_list->Clear();
10789 delete overlay_rule_list;
10791 if (pi_rule_list) pi_rule_list->Clear();
10792 delete pi_rule_list;
10794 SetCursor(wxCURSOR_ARROW);
10798void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10807 wxSize canvas_size = GetSize();
10814 wxPoint canvas_pos = GetPosition();
10817 bool newFit =
false;
10818 if (canvas_size.x < fitted_size.x) {
10819 fitted_size.x = canvas_size.x - 40;
10820 if (canvas_size.y < fitted_size.y)
10821 fitted_size.y -= 40;
10823 if (canvas_size.y < fitted_size.y) {
10824 fitted_size.y = canvas_size.y - 40;
10825 if (canvas_size.x < fitted_size.x)
10826 fitted_size.x -= 40;
10837 wxString title_base = _(
"Mark Properties");
10839 title_base = _(
"Waypoint Properties");
10844 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10856void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10866 if (g_bresponsive) {
10867 wxSize canvas_size = GetSize();
10868 wxPoint canvas_pos = GetPosition();
10872 if (canvas_size.x < fitted_size.x) {
10873 fitted_size.x = canvas_size.x;
10874 if (canvas_size.y < fitted_size.y)
10875 fitted_size.y -= 20;
10877 if (canvas_size.y < fitted_size.y) {
10878 fitted_size.y = canvas_size.y;
10879 if (canvas_size.x < fitted_size.x)
10880 fitted_size.x -= 20;
10889 wxPoint xxp = ClientToScreen(canvas_pos);
10900void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10912void pupHandler_PasteWaypoint() {
10915 int pasteBuffer = kml.ParsePasteBuffer();
10916 RoutePoint *pasted = kml.GetParsedRoutePoint();
10917 if (!pasted)
return;
10919 double nearby_radius_meters =
10920 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10922 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10923 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10925 int answer = wxID_NO;
10929 "There is an existing waypoint at the same location as the one you are "
10930 "pasting. Would you like to merge the pasted data with it?\n\n");
10931 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10932 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10933 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10936 if (answer == wxID_YES) {
10937 nearPoint->SetName(pasted->GetName());
10943 if (answer == wxID_NO) {
10946 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10949 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10958 top_frame::Get()->InvalidateAllGL();
10959 top_frame::Get()->RefreshAllCanvas(
false);
10962void pupHandler_PasteRoute() {
10965 int pasteBuffer = kml.ParsePasteBuffer();
10966 Route *pasted = kml.GetParsedRoute();
10967 if (!pasted)
return;
10969 double nearby_radius_meters =
10970 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10976 bool mergepoints =
false;
10977 bool createNewRoute =
true;
10978 int existingWaypointCounter = 0;
10980 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10981 curPoint = pasted->GetPoint(i);
10982 nearPoint = pWayPointMan->GetNearbyWaypoint(
10983 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10985 mergepoints =
true;
10986 existingWaypointCounter++;
10994 int answer = wxID_NO;
10998 "There are existing waypoints at the same location as some of the ones "
10999 "you are pasting. Would you like to just merge the pasted data into "
11001 msg << _(
"Answering 'No' will create all new waypoints for this route.");
11002 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
11003 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
11005 if (answer == wxID_CANCEL) {
11012 if (mergepoints && answer == wxID_YES &&
11013 existingWaypointCounter == pasted->GetnPoints()) {
11016 createNewRoute =
false;
11022 Route *newRoute = 0;
11025 if (createNewRoute) {
11026 newRoute =
new Route();
11030 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11031 curPoint = pasted->GetPoint(i);
11034 newPoint = pWayPointMan->GetNearbyWaypoint(
11035 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11036 newPoint->SetName(curPoint->GetName());
11039 if (createNewRoute) newRoute->AddPoint(newPoint);
11045 newPoint->SetIconName(
"circle");
11048 newPoint->SetShared(
false);
11050 newRoute->AddPoint(newPoint);
11051 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11054 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11057 if (i > 1 && createNewRoute)
11058 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11059 curPoint->m_lat, curPoint->m_lon,
11060 prevPoint, newPoint, newRoute);
11061 prevPoint = newPoint;
11064 if (createNewRoute) {
11067 NavObj_dB::GetInstance().InsertRoute(newRoute);
11077 top_frame::Get()->InvalidateAllGL();
11078 top_frame::Get()->RefreshAllCanvas(
false);
11084void pupHandler_PasteTrack() {
11087 int pasteBuffer = kml.ParsePasteBuffer();
11088 Track *pasted = kml.GetParsedTrack();
11089 if (!pasted)
return;
11097 newTrack->SetName(pasted->GetName());
11099 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11100 curPoint = pasted->GetPoint(i);
11104 wxDateTime now = wxDateTime::Now();
11107 newTrack->AddPoint(newPoint);
11110 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11111 newPoint->m_lat, newPoint->m_lon,
11112 prevPoint, newPoint, newTrack);
11114 prevPoint = newPoint;
11119 NavObj_dB::GetInstance().InsertTrack(newTrack);
11121 top_frame::Get()->InvalidateAllGL();
11122 top_frame::Get()->RefreshAllCanvas(
false);
11125bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11128 v[
"CursorPosition_x"] = x;
11129 v[
"CursorPosition_y"] = y;
11132 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11133 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11134 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11139 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11141 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11144#define SELTYPE_UNKNOWN 0x0001
11145#define SELTYPE_ROUTEPOINT 0x0002
11146#define SELTYPE_ROUTESEGMENT 0x0004
11147#define SELTYPE_TIDEPOINT 0x0008
11148#define SELTYPE_CURRENTPOINT 0x0010
11149#define SELTYPE_ROUTECREATE 0x0020
11150#define SELTYPE_AISTARGET 0x0040
11151#define SELTYPE_MARKPOINT 0x0080
11152#define SELTYPE_TRACKSEGMENT 0x0100
11153#define SELTYPE_DRAGHANDLE 0x0200
11156 if (g_bhide_context_menus)
return true;
11158 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11159 m_pIDXCandidate, m_nmea_log);
11162 wxEVT_COMMAND_MENU_SELECTED,
11163 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11169 if (m_inLongPress) {
11170 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11171 m_inLongPress =
false;
11175 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11178 wxEVT_COMMAND_MENU_SELECTED,
11179 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11181 delete m_canvasMenu;
11182 m_canvasMenu = NULL;
11192void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11195 if (m_canvasMenu) {
11196 m_canvasMenu->PopupMenuHandler(event);
11201void ChartCanvas::StartRoute() {
11203 if (g_brouteCreating)
return;
11207 g_brouteCreating =
true;
11209 m_bDrawingRoute =
false;
11210 SetCursor(*pCursorPencil);
11212 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11214 HideGlobalToolbar();
11217 androidSetRouteAnnunciator(
true);
11221wxString ChartCanvas::FinishRoute() {
11223 m_prev_pMousePoint = NULL;
11224 m_bDrawingRoute =
false;
11226 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11229 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11231 androidSetRouteAnnunciator(
false);
11234 SetCursor(*pCursorArrow);
11236 if (m_pMouseRoute) {
11237 if (m_bAppendingRoute) {
11239 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11241 if (m_pMouseRoute->GetnPoints() > 1) {
11243 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11246 m_pMouseRoute = NULL;
11249 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11261 m_bAppendingRoute =
false;
11262 m_pMouseRoute = NULL;
11264 m_pSelectedRoute = NULL;
11266 undo->InvalidateUndo();
11267 top_frame::Get()->RefreshAllCanvas(
true);
11271 ShowGlobalToolbar();
11273 g_brouteCreating =
false;
11278void ChartCanvas::HideGlobalToolbar() {
11279 if (m_canvasIndex == 0) {
11280 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11284void ChartCanvas::ShowGlobalToolbar() {
11285 if (m_canvasIndex == 0) {
11286 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11290void ChartCanvas::ShowAISTargetList() {
11291 if (NULL == g_pAISTargetList) {
11295 g_pAISTargetList->UpdateAISTargetList();
11298void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11299 if (!m_bShowOutlines)
return;
11303 int nEntry =
ChartData->GetChartTableEntries();
11305 for (
int i = 0; i < nEntry; i++) {
11309 bool b_group_draw =
false;
11310 if (m_groupIndex > 0) {
11311 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11312 int index = pt->GetGroupArray()[ig];
11313 if (m_groupIndex == index) {
11314 b_group_draw =
true;
11319 b_group_draw =
true;
11321 if (b_group_draw) RenderChartOutline(dc, i, vp);
11327 if (VPoint.b_quilt) {
11328 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11329 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11333 }
else if (m_singleChart &&
11334 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11338 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11341 if (zoom_factor > 8.0) {
11342 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11345 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11349 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11353void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11355 if (g_bopengl && m_glcc) {
11357 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11362 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11363 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11366 float plylat, plylon;
11367 float plylat1, plylon1;
11369 int pixx, pixy, pixx1, pixy1;
11372 ChartData->GetDBBoundingBox(dbIndex, box);
11376 if (box.GetLonRange() == 360)
return;
11378 double lon_bias = 0;
11380 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11382 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11384 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11385 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11387 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11388 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11391 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11394 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11395 if (0 == nAuxPlyEntries)
11399 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11400 plylon += lon_bias;
11406 for (
int i = 0; i < nPly - 1; i++) {
11407 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11408 plylon1 += lon_bias;
11414 int pixxs1 = pixx1;
11415 int pixys1 = pixy1;
11417 bool b_skip =
false;
11421 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11422 pow((
double)(pixy1 - pixy), 2)) /
11428 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11433 if (fabs(dist - distgc) > 10000. * 1852.)
11439 ClipResult res = cohen_sutherland_line_clip_i(
11441 if (res != Invisible && !b_skip)
11442 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11450 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11451 plylon1 += lon_bias;
11457 ClipResult res = cohen_sutherland_line_clip_i(
11459 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11466 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11467 for (
int j = 0; j < nAuxPlyEntries; j++) {
11469 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11474 for (
int i = 0; i < nAuxPly - 1; i++) {
11475 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11481 int pixxs1 = pixx1;
11482 int pixys1 = pixy1;
11484 bool b_skip =
false;
11488 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11489 ((pixy1 - pixy) * (pixy1 - pixy))) /
11494 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11499 if (fabs(dist - distgc) > 10000. * 1852.)
11505 ClipResult res = cohen_sutherland_line_clip_i(
11507 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11515 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11520 ClipResult res = cohen_sutherland_line_clip_i(
11522 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11527static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11528 const wxArrayString &legend) {
11529 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11531 int pointsize = dFont->GetPointSize();
11535 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11536 false, dFont->GetFaceName());
11538 dc.SetFont(*psRLI_font);
11545 int hilite_offset = 3;
11547 for (wxString line : legend) {
11550 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11552 dc.GetTextExtent(line, &wl, &hl);
11561 xp = ref_point.x - w;
11563 yp += hilite_offset;
11565 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11567 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11568 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11570 for (wxString line : legend) {
11571 dc.DrawText(line, xp, yp);
11576void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11577 if (!g_bAllowShipToActive)
return;
11583 wxPoint2DDouble pa, pb;
11590 if (rt->
m_width != wxPENSTYLE_INVALID)
11592 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11593 g_shipToActiveStyle, 5)];
11594 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11596 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11599 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11602 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11605 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11606 (
int)pb.m_y, GetVP(),
true);
11610#ifdef USE_ANDROID_GLES2
11611 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11613 if (style != wxPENSTYLE_SOLID) {
11614 if (glChartCanvas::dash_map.find(style) !=
11615 glChartCanvas::dash_map.end()) {
11616 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11620 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11623 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11624 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11630void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11632 if (m_routeState >= 2) route = m_pMouseRoute;
11633 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11634 route = m_pMeasureRoute;
11636 if (!route)
return;
11644 int np = route->GetnPoints();
11646 if (g_btouch && (np > 1)) np--;
11648 render_lat = rp.m_lat;
11649 render_lon = rp.m_lon;
11652 double rhumbBearing, rhumbDist;
11654 &rhumbBearing, &rhumbDist);
11655 double brg = rhumbBearing;
11656 double dist = rhumbDist;
11660 double gcBearing, gcBearing2, gcDist;
11661 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11664 double gcDistm = gcDist / 1852.0;
11667 rhumbBearing = 90.;
11669 wxPoint destPoint, lastPoint;
11672 int milesDiff = rhumbDist - gcDistm;
11673 if (milesDiff > 1) {
11684 for (
int i = 1; i <= milesDiff; i++) {
11685 double p = (double)i * (1.0 / (
double)milesDiff);
11687 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11688 &pLon, &pLat, &gcBearing2);
11690 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11692 lastPoint = destPoint;
11695 if (r_rband.x && r_rband.y) {
11696 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11698 if (m_bMeasure_DistCircle) {
11699 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11700 powf((
float)(r_rband.y - lastPoint.y), 2));
11703 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11704 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11710 wxString routeInfo;
11711 wxArrayString infoArray;
11714 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11720 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11722 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11723 (
int)varBrg, 0x00B0);
11726 infoArray.Add(routeInfo);
11732 routeInfo <<
"Reverse: ";
11734 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11735 (
int)(brg + 180.) % 360, 0x00B0);
11737 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11738 (
int)(varBrg + 180.) % 360, 0x00B0);
11739 infoArray.Add(routeInfo);
11745 s0.Append(_(
"Route") +
": ");
11747 s0.Append(_(
"Layer Route: "));
11750 if (!g_btouch) disp_length += dist;
11756 RouteLegInfo(dc, r_rband, infoArray);
11758 m_brepaint_piano =
true;
11761void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11762 if (!m_bShowVisibleSectors)
return;
11764 if (g_bDeferredInitDone) {
11766 double rhumbBearing, rhumbDist;
11767 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11768 &rhumbBearing, &rhumbDist);
11770 if (rhumbDist > 0.05)
11772 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11773 m_sectorlegsVisible);
11774 m_sector_glat =
gLat;
11775 m_sector_glon =
gLon;
11777 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11781void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11789void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11790 if (!ps52plib)
return;
11792 if (VPoint.b_quilt) {
11793 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11795 if (m_pQuilt->IsQuiltVector()) {
11796 if (ps52plib->GetStateHash() != m_s52StateHash) {
11798 m_s52StateHash = ps52plib->GetStateHash();
11802 if (ps52plib->GetStateHash() != m_s52StateHash) {
11804 m_s52StateHash = ps52plib->GetStateHash();
11809 bool bSendPlibState =
true;
11810 if (VPoint.b_quilt) {
11811 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11814 if (bSendPlibState) {
11816 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11817 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11818 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11819 v[
"OpenCPN Version Date"] = VERSION_DATE;
11820 v[
"OpenCPN Version Full"] = VERSION_FULL;
11823 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11824 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11825 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11826 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11827 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11828 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11829 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11833 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11834 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11838 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11839 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11840 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11841 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11842 ps52plib->m_bShowS57ImportantTextOnly;
11843 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11844 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11845 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11846 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11847 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11850 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11851 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11852 v[
"OpenCPN Scale Factor Exp"] =
11853 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11860 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11861 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11862 g_lastS52PLIBPluginMessage = out;
11869 wxPaintDC dc(
this);
11879 if (!m_b_paint_enable) {
11887 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11889 if (m_glcc && g_bopengl) {
11890 if (!s_in_update) {
11900 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11902 wxRegion ru = GetUpdateRegion();
11904 int rx, ry, rwidth, rheight;
11905 ru.GetBox(rx, ry, rwidth, rheight);
11907#ifdef ocpnUSE_DIBSECTION
11910 wxMemoryDC temp_dc;
11918 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11919 height += m_Piano->GetHeight();
11921 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11925 int thumbx, thumby, thumbsx, thumbsy;
11926 pthumbwin->GetPosition(&thumbx, &thumby);
11927 pthumbwin->GetSize(&thumbsx, &thumbsy);
11928 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11931 rgn_chart.Subtract(rgn_thumbwin);
11932 ru.Subtract(rgn_thumbwin);
11938 wxRegion rgn_blit = ru;
11939 if (g_bShowChartBar) {
11940 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11941 GetClientSize().x, m_Piano->GetHeight());
11944 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11945 if (style->chartStatusWindowTransparent)
11946 m_brepaint_piano =
true;
11948 ru.Subtract(chart_bar_rect);
11952 if (m_Compass && m_Compass->IsShown()) {
11953 wxRect compassRect = m_Compass->
GetRect();
11954 if (ru.Contains(compassRect) != wxOutRegion) {
11955 ru.Subtract(compassRect);
11959 if (m_notification_button) {
11960 wxRect noteRect = m_notification_button->
GetRect();
11961 if (ru.Contains(noteRect) != wxOutRegion) {
11962 ru.Subtract(noteRect);
11967 bool b_newview =
true;
11972 m_cache_vp.IsValid()) {
11978 bool b_rcache_ok =
false;
11979 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11980 b_rcache_ok = !b_newview;
11983 if (VPoint.b_MercatorProjectionOverride)
11984 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11998 if (b_rcache_ok) chart_get_region.Clear();
12001 if (VPoint.b_quilt)
12003 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
12005 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
12010 AbstractPlatform::ShowBusySpinner();
12014 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
12015 (m_working_bm.GetHeight() != svp.
pix_height))
12019 if (fabs(VPoint.
rotation) < 0.01) {
12020 bool b_save =
true;
12025 m_cache_vp.Invalidate();
12039 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12044 int dy = c_new.y - c_old.y;
12045 int dx = c_new.x - c_old.x;
12050 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12054 temp_dc.SelectObject(m_working_bm);
12056 wxMemoryDC cache_dc;
12057 cache_dc.SelectObject(m_cached_chart_bm);
12061 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12064 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12070 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12073 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12081 update_region.Union(
12084 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12089 update_region.Union(
12092 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12096 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12098 cache_dc.SelectObject(wxNullBitmap);
12102 temp_dc.SelectObject(m_cached_chart_bm);
12105 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12109 temp_dc.SelectObject(m_working_bm);
12110 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12115 temp_dc.SelectObject(m_cached_chart_bm);
12120 temp_dc.SelectObject(m_working_bm);
12121 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12134 wxMemoryDC scratch_dc_0;
12135 scratch_dc_0.SelectObject(m_cached_chart_bm);
12138 scratch_dc_0.SelectObject(wxNullBitmap);
12147 temp_dc.SelectObject(m_working_bm);
12150 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12151 chart_get_all_region);
12154 AbstractPlatform::HideBusySpinner();
12160 if (!m_singleChart) {
12161 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12166 if (!chart_get_region.IsEmpty()) {
12167 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12171 if (temp_dc.IsOk()) {
12176 if (!VPoint.b_quilt) {
12179 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12180 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12187 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12188 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12191 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12193 temp_dc.DestroyClippingRegion();
12198 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12200 if (!backgroundRegion.IsEmpty()) {
12206 wxColour water = pWorldBackgroundChart->water;
12207 if (water.IsOk()) {
12208 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12209 temp_dc.SetBrush(wxBrush(water));
12211 while (upd.HaveRects()) {
12212 wxRect rect = upd.GetRect();
12213 temp_dc.DrawRectangle(rect);
12218 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12219 temp_dc.SetDeviceClippingRegion(*clip_region);
12220 delete clip_region;
12224 SetVPRotation(VPoint.
skew);
12233 wxMemoryDC *pChartDC = &temp_dc;
12234 wxMemoryDC rotd_dc;
12236 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12238 if (!b_rcache_ok) {
12240 wxMemoryDC tbase_dc;
12242 tbase_dc.SelectObject(bm_base);
12244 tbase_dc.SelectObject(wxNullBitmap);
12246 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12249 wxImage base_image;
12250 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12258 bool b_rot_ok =
false;
12259 if (base_image.IsOk()) {
12262 m_b_rot_hidef =
false;
12266 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12267 m_b_rot_hidef, &m_roffset);
12272 rot_vp.IsValid() && (ri.IsOk())) {
12279 m_prot_bm =
new wxBitmap(ri);
12282 m_roffset.x += VPoint.rv_rect.x;
12283 m_roffset.y += VPoint.rv_rect.y;
12286 if (m_prot_bm && m_prot_bm->IsOk()) {
12287 rotd_dc.SelectObject(*m_prot_bm);
12288 pChartDC = &rotd_dc;
12290 pChartDC = &temp_dc;
12291 m_roffset = wxPoint(0, 0);
12294 pChartDC = &temp_dc;
12295 m_roffset = wxPoint(0, 0);
12298 wxPoint offset = m_roffset;
12301 m_cache_vp = VPoint;
12304 wxMemoryDC mscratch_dc;
12305 mscratch_dc.SelectObject(*pscratch_bm);
12307 mscratch_dc.ResetBoundingBox();
12308 mscratch_dc.DestroyClippingRegion();
12309 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12312 wxRegionIterator upd(rgn_blit);
12314 wxRect rect = upd.GetRect();
12316 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12317 rect.x - offset.x, rect.y - offset.y);
12323 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12324 if (
this == wxWindow::FindFocus()) {
12327 wxColour colour = GetGlobalColor(
"BLUE4");
12328 mscratch_dc.SetPen(wxPen(colour));
12329 mscratch_dc.SetBrush(wxBrush(colour));
12331 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12332 mscratch_dc.DrawRectangle(activeRect);
12337 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12338 unsigned int im = stackIndexArray.size();
12339 if (VPoint.b_quilt && im > 0) {
12340 std::vector<int> tiles_to_show;
12341 for (
unsigned int is = 0; is < im; is++) {
12343 ChartData->GetChartTableEntry(stackIndexArray[is]);
12344 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12347 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12348 tiles_to_show.push_back(stackIndexArray[is]);
12352 if (tiles_to_show.size())
12353 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12359 ocpnDC scratch_dc(mscratch_dc);
12360 RenderAlertMessage(mscratch_dc, GetVP());
12366#ifdef ocpnUSE_DIBSECTION
12371 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12372 q_dc.SelectObject(qbm);
12375 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12378 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12379 q_dc.SetBrush(qbr);
12380 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12383 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12386 q_dc.SelectObject(wxNullBitmap);
12395 if( VPoint.b_quilt ) {
12396 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12397 ChartBase *chart = m_pQuilt->GetRefChart();
12398 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12403 ChPI->ClearPLIBTextList();
12406 ps52plib->ClearTextList();
12410 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12412 wxColor maskBackground = wxColour(1,0,0);
12413 t_dc.SelectObject( qbm );
12414 t_dc.SetBackground(wxBrush(maskBackground));
12418 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12421 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12422 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12425 wxRegionIterator upd_final( ru );
12426 while( upd_final ) {
12427 wxRect rect = upd_final.GetRect();
12428 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12432 t_dc.SelectObject( wxNullBitmap );
12438 if (VPoint.b_quilt) {
12439 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12440 ChartBase *chart = m_pQuilt->GetRefChart();
12441 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12445 ChPI->ClearPLIBTextList();
12447 if (ps52plib) ps52plib->ClearTextList();
12452 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12454 if (g_bShowChartBar && m_Piano) {
12455 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12456 GetVP().pix_width, m_Piano->GetHeight());
12459 if (!style->chartStatusWindowTransparent)
12460 chart_all_text_region.Subtract(chart_bar_rect);
12463 if (m_Compass && m_Compass->IsShown()) {
12464 wxRect compassRect = m_Compass->
GetRect();
12465 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12466 chart_all_text_region.Subtract(compassRect);
12470 mscratch_dc.DestroyClippingRegion();
12472 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12473 chart_all_text_region);
12479 ocpnDC scratch_dc(mscratch_dc);
12480 DrawOverlayObjects(scratch_dc, ru);
12483 wxRegionIterator upd_final(rgn_blit);
12484 while (upd_final) {
12485 wxRect rect = upd_final.GetRect();
12486 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12493 temp_dc.SelectObject(wxNullBitmap);
12495 mscratch_dc.SelectObject(wxNullBitmap);
12497 dc.DestroyClippingRegion();
12502void ChartCanvas::PaintCleanup() {
12504 if (m_inPinch)
return;
12515 m_bTCupdate =
false;
12519 WarpPointer(warp_x, warp_y);
12526 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12527 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12531wxColour GetErrorGraphicColor(
double val)
12550 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12551 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12552 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12553 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12554 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12555 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12556 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12557 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12558 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12559 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12560 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12561 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12562 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12563 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12564 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12565 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12566 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12567 else if( val >= 48) c.Set(
"#410000");
12572void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12575 gr_image.InitAlpha();
12577 double maxval = -10000;
12578 double minval = 10000;
12595 maxval = wxMax(maxval, (glat - rlat));
12596 minval = wxMin(minval, (glat - rlat));
12613 double f = ((glat - rlat)-minval)/(maxval - minval);
12615 double dy = (f * 40);
12617 wxColour c = GetErrorGraphicColor(dy);
12618 unsigned char r = c.Red();
12619 unsigned char g = c.Green();
12620 unsigned char b = c.Blue();
12622 gr_image.SetRGB(j, i, r,g,b);
12623 if((glat - rlat )!= 0)
12624 gr_image.SetAlpha(j, i, 128);
12626 gr_image.SetAlpha(j, i, 255);
12633 wxBitmap *pbm =
new wxBitmap(gr_image);
12634 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12635 pbm->SetMask(gr_mask);
12637 pmdc->DrawBitmap(*pbm, 0,0);
12645void ChartCanvas::CancelMouseRoute() {
12647 m_pMouseRoute = NULL;
12648 m_bDrawingRoute =
false;
12651int ChartCanvas::GetNextContextMenuId() {
12652 return CanvasMenuHandler::GetNextContextMenuId();
12655bool ChartCanvas::SetCursor(
const wxCursor &c) {
12657 if (g_bopengl && m_glcc)
12658 return m_glcc->SetCursor(c);
12661 return wxWindow::SetCursor(c);
12664void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12665 if (g_bquiting)
return;
12675 if (!m_RolloverPopupTimer.IsRunning() &&
12676 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12677 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12678 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12679 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12682 if (m_glcc && g_bopengl) {
12685 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12687 m_glcc->Refresh(eraseBackground,
12704 if (m_pCIWin && m_pCIWin->IsShown()) {
12706 m_pCIWin->Refresh(
false);
12714 wxWindow::Refresh(eraseBackground, rect);
12717void ChartCanvas::Update() {
12718 if (m_glcc && g_bopengl) {
12723 wxWindow::Update();
12727 if (!pemboss)
return;
12728 int x = pemboss->x, y = pemboss->y;
12729 const double factor = 200;
12731 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12732 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12733 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12736 wxMemoryDC snip_dc;
12737 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12738 snip_dc.SelectObject(snip_bmp);
12740 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12741 snip_dc.SelectObject(wxNullBitmap);
12743 wxImage snip_img = snip_bmp.ConvertToImage();
12746 unsigned char *pdata = snip_img.GetData();
12748 for (
int y = 0; y < pemboss->height; y++) {
12749 int map_index = (y * pemboss->width);
12750 for (
int x = 0; x < pemboss->width; x++) {
12751 double val = (pemboss->pmap[map_index] * factor) / 256.;
12753 int nred = (int)((*pdata) + val);
12754 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12755 *pdata++ = (
unsigned char)nred;
12757 int ngreen = (int)((*pdata) + val);
12758 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12759 *pdata++ = (
unsigned char)ngreen;
12761 int nblue = (int)((*pdata) + val);
12762 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12763 *pdata++ = (
unsigned char)nblue;
12771 wxBitmap emb_bmp(snip_img);
12774 wxMemoryDC result_dc;
12775 result_dc.SelectObject(emb_bmp);
12778 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12780 result_dc.SelectObject(wxNullBitmap);
12786 if (GetQuiltMode()) {
12788 int refIndex = GetQuiltRefChartdbIndex();
12789 if (refIndex >= 0) {
12791 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12792 if (current_type == CHART_TYPE_MBTILES) {
12793 ChartBase *pChart = m_pQuilt->GetRefChart();
12796 zoom_factor = ptc->GetZoomFactor();
12801 if (zoom_factor <= 3.9)
return NULL;
12803 if (m_singleChart) {
12804 if (zoom_factor <= 3.9)
return NULL;
12809 if (m_pEM_OverZoom) {
12810 m_pEM_OverZoom->x = 4;
12811 m_pEM_OverZoom->y = 0;
12813 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12814 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12817 return m_pEM_OverZoom;
12820void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12833 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12834 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12838 AISDrawAreaNotices(dc, GetVP(),
this);
12840 wxDC *pdc = dc.GetDC();
12842 pdc->DestroyClippingRegion();
12843 wxDCClipper(*pdc, ru);
12846 if (m_bShowNavobjects) {
12847 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12848 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12849 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12850 DrawAnchorWatchPoints(dc);
12852 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12853 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12856 AISDraw(dc, GetVP(),
this);
12860 RenderVisibleSectorLights(dc);
12862 RenderAllChartOutlines(dc, GetVP());
12863 RenderRouteLegs(dc);
12864 RenderShipToActive(dc,
false);
12866 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12868 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12872 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12873 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12876 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12881 RebuildTideSelectList(GetVP().GetBBox());
12882 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12885 if (m_bShowCurrent) {
12886 RebuildCurrentSelectList(GetVP().GetBBox());
12887 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12890 if (!g_PrintingInProgress) {
12891 if (IsPrimaryCanvas()) {
12895 if (IsPrimaryCanvas()) {
12899 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12901 if (m_pTrackRolloverWin) {
12902 m_pTrackRolloverWin->Draw(dc);
12903 m_brepaint_piano =
true;
12906 if (m_pRouteRolloverWin) {
12907 m_pRouteRolloverWin->Draw(dc);
12908 m_brepaint_piano =
true;
12911 if (m_pAISRolloverWin) {
12912 m_pAISRolloverWin->Draw(dc);
12913 m_brepaint_piano =
true;
12915 if (m_brepaint_piano && g_bShowChartBar) {
12916 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12919 if (m_Compass) m_Compass->Paint(dc);
12921 if (!g_CanvasHideNotificationIcon) {
12922 if (IsPrimaryCanvas()) {
12923 auto ¬eman = NotificationManager::GetInstance();
12924 if (noteman.GetNotificationCount()) {
12925 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12926 if (m_notification_button->UpdateStatus()) Refresh();
12927 m_notification_button->Show(
true);
12928 m_notification_button->Paint(dc);
12930 m_notification_button->Show(
false);
12936 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12942 if (!m_bShowDepthUnits)
return NULL;
12944 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12946 if (GetQuiltMode()) {
12947 wxString s = m_pQuilt->GetQuiltDepthUnit();
12950 depth_unit_type = DEPTH_UNIT_FEET;
12951 else if (s.StartsWith(
"FATHOMS"))
12952 depth_unit_type = DEPTH_UNIT_FATHOMS;
12953 else if (s.StartsWith(
"METERS"))
12954 depth_unit_type = DEPTH_UNIT_METERS;
12955 else if (s.StartsWith(
"METRES"))
12956 depth_unit_type = DEPTH_UNIT_METERS;
12957 else if (s.StartsWith(
"METRIC"))
12958 depth_unit_type = DEPTH_UNIT_METERS;
12959 else if (s.StartsWith(
"METER"))
12960 depth_unit_type = DEPTH_UNIT_METERS;
12963 if (m_singleChart) {
12964 depth_unit_type = m_singleChart->GetDepthUnitType();
12965 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12966 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12971 switch (depth_unit_type) {
12972 case DEPTH_UNIT_FEET:
12975 case DEPTH_UNIT_METERS:
12976 ped = m_pEM_Meters;
12978 case DEPTH_UNIT_FATHOMS:
12979 ped = m_pEM_Fathoms;
12985 ped->x = (GetVP().
pix_width - ped->width);
12987 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12988 wxRect r = m_Compass->
GetRect();
12989 ped->y = r.y + r.height;
12996void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12999 if (style->embossFont == wxEmptyString) {
13000 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13002 font.SetPointSize(60);
13003 font.SetWeight(wxFONTWEIGHT_BOLD);
13005 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13006 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13008 int emboss_width = 500;
13009 int emboss_height = 200;
13013 delete m_pEM_Meters;
13014 delete m_pEM_Fathoms;
13018 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
13020 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
13022 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
13025#define OVERZOOM_TEXT _("OverZoom")
13027void ChartCanvas::SetOverzoomFont() {
13032 if (style->embossFont == wxEmptyString) {
13033 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13035 font.SetPointSize(40);
13036 font.SetWeight(wxFONTWEIGHT_BOLD);
13038 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13039 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13041 wxClientDC dc(
this);
13043 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13045 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13046 font.SetPointSize(font.GetPointSize() - 1);
13048 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13050 m_overzoomFont = font;
13051 m_overzoomTextWidth = w;
13052 m_overzoomTextHeight = h;
13055void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13056 delete m_pEM_OverZoom;
13058 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13060 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13061 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13064emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13065 int height,
const wxString &str,
13070 wxBitmap bmp(width, height, -1);
13073 wxMemoryDC temp_dc;
13074 temp_dc.SelectObject(bmp);
13077 temp_dc.SetBackground(*wxWHITE_BRUSH);
13078 temp_dc.SetTextBackground(*wxWHITE);
13079 temp_dc.SetTextForeground(*wxBLACK);
13083 temp_dc.SetFont(font);
13086 temp_dc.GetTextExtent(str, &str_w, &str_h);
13088 temp_dc.DrawText(str, 1, 1);
13091 temp_dc.SelectObject(wxNullBitmap);
13094 wxImage img = bmp.ConvertToImage();
13096 int image_width = str_w * 105 / 100;
13097 int image_height = str_h * 105 / 100;
13098 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13099 wxMin(image_height, img.GetHeight()));
13100 wxImage imgs = img.GetSubImage(r);
13104 case GLOBAL_COLOR_SCHEME_DAY:
13108 case GLOBAL_COLOR_SCHEME_DUSK:
13111 case GLOBAL_COLOR_SCHEME_NIGHT:
13118 const int w = imgs.GetWidth();
13119 const int h = imgs.GetHeight();
13120 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13125 for (
int y = 1; y < h - 1; y++) {
13126 for (
int x = 1; x < w - 1; x++) {
13128 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13129 val = (int)(val * val_factor);
13130 index = (y * w) + x;
13143void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13144 Track *active_track = NULL;
13147 active_track = pTrackDraw;
13151 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13154 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13157void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13158 Track *active_track = NULL;
13161 active_track = pTrackDraw;
13165 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13168void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13169 Route *active_route = NULL;
13171 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13172 active_route = pRouteDraw;
13177 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13182 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13185void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13186 Route *active_route = NULL;
13189 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13190 active_route = pRouteDraw;
13194 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13197void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13198 if (!pWayPointMan)
return;
13200 auto node = pWayPointMan->GetWaypointList()->begin();
13202 while (node != pWayPointMan->GetWaypointList()->end()) {
13211 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13215 if (pWP->GetShowWaypointRangeRings() &&
13216 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13217 double factor = 1.00;
13218 if (pWP->GetWaypointRangeRingsStepUnits() ==
13220 factor = 1 / 1.852;
13222 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13223 pWP->GetWaypointRangeRingsStep() / 60.;
13227 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13228 pWP->m_lat + radius, pWP->m_lon + radius);
13229 if (!BltBBox.IntersectOut(radar_box)) {
13240void ChartCanvas::DrawBlinkObjects() {
13242 wxRect update_rect;
13244 if (!pWayPointMan)
return;
13246 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13253 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13256void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13261 wxPoint lAnchorPoint1, lAnchorPoint2;
13275 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13276 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13278 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13279 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13280 dc.SetBrush(*ppBrush);
13284 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13289 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13294 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13299 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13304double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13307 wxPoint lAnchorPoint;
13310 double tlat1, tlon1;
13312 if (pAnchorWatchPoint) {
13313 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13315 dabs = fabs(d1 / 1852.);
13316 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13321 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13322 pow((
double)(lAnchorPoint.y - r1.y), 2));
13325 if (d1 < 0) lpp = -lpp;
13333void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13336 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13338 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13344 if ((type ==
't') || (type ==
'T')) {
13345 if (BBox.Contains(lat, lon)) {
13347 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13353void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13356 wxDateTime this_now = gTimeSource;
13357 bool cur_time = !gTimeSource.IsValid();
13358 if (cur_time) this_now = wxDateTime::Now();
13359 time_t t_this_now = this_now.GetTicks();
13361 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13363 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13364 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13365 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13366 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13368 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13369 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13370 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13371 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13372 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13373 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13375 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13376 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13377 int font_size = wxMax(10, dFont->GetPointSize());
13380 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13381 false, dFont->GetFaceName());
13383 dc.SetPen(*pblack_pen);
13384 dc.SetBrush(*pgreen_brush);
13388 case GLOBAL_COLOR_SCHEME_DAY:
13391 case GLOBAL_COLOR_SCHEME_DUSK:
13394 case GLOBAL_COLOR_SCHEME_NIGHT:
13395 bm = m_bmTideNight;
13402 int bmw = bm.GetWidth();
13403 int bmh = bm.GetHeight();
13405 float scale_factor = 1.0;
13409 float icon_pixelRefDim = 45;
13414 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13416 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13418 scale_factor *= pix_factor;
13425 scale_factor *= user_scale_factor;
13426 scale_factor *= GetContentScaleFactor();
13429 double marge = 0.05;
13430 std::vector<LLBBox> drawn_boxes;
13431 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13435 if ((type ==
't') || (type ==
'T'))
13440 if (BBox.ContainsMarge(lat, lon, marge)) {
13442 if (GetVP().chart_scale < 500000) {
13443 bool bdrawn =
false;
13444 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13445 if (drawn_boxes[i].Contains(lat, lon)) {
13450 if (bdrawn)
continue;
13453 this_box.Set(lat, lon, lat, lon);
13454 this_box.EnLarge(.005);
13455 drawn_boxes.push_back(this_box);
13461 if (GetVP().chart_scale > 500000) {
13462 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13466 dc.SetFont(*plabelFont);
13478 if (
ptcmgr->GetTideFlowSens(
13479 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13483 ptcmgr->GetHightOrLowTide(
13484 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13485 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13497 if (tctime > t_this_now)
13498 ptcmgr->GetHightOrLowTide(
13499 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13500 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13504 ptcmgr->GetHightOrLowTide(
13505 t_this_now, FORWARD_TEN_MINUTES_STEP,
13506 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13520 int width = (int)(12 * scale_factor + 0.5);
13521 int height = (int)(45 * scale_factor + 0.5);
13522 int linew = wxMax(1, (
int)(scale_factor));
13523 int xDraw = r.x - (width / 2);
13524 int yDraw = r.y - (height / 2);
13527 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13528 int hs = (httime > lttime) ? -4 : 4;
13529 hs *= (int)(scale_factor + 0.5);
13530 if (ts > 0.995 || ts < 0.005) hs = 0;
13531 int ht_y = (int)(height * ts);
13534 pblack_pen->SetWidth(linew);
13535 dc.SetPen(*pblack_pen);
13536 dc.SetBrush(*pyelo_brush);
13537 dc.DrawRectangle(xDraw, yDraw, width, height);
13541 dc.SetPen(*pblue_pen);
13542 dc.SetBrush(*pblue_brush);
13543 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13544 (width - (4 * linew)), height - ht_y);
13550 arrow[0].x = xDraw + 2 * linew;
13551 arrow[1].x = xDraw + width / 2;
13552 arrow[2].x = xDraw + width - 2 * linew;
13553 pyelo_pen->SetWidth(linew);
13554 pblue_pen->SetWidth(linew);
13555 if (ts > 0.35 || ts < 0.15)
13557 hl = (int)(height * 0.25) + yDraw;
13559 arrow[1].y = hl + hs;
13562 dc.SetPen(*pyelo_pen);
13564 dc.SetPen(*pblue_pen);
13565 dc.DrawLines(3, arrow);
13567 if (ts > 0.60 || ts < 0.40)
13569 hl = (int)(height * 0.5) + yDraw;
13571 arrow[1].y = hl + hs;
13574 dc.SetPen(*pyelo_pen);
13576 dc.SetPen(*pblue_pen);
13577 dc.DrawLines(3, arrow);
13579 if (ts < 0.65 || ts > 0.85)
13581 hl = (int)(height * 0.75) + yDraw;
13583 arrow[1].y = hl + hs;
13586 dc.SetPen(*pyelo_pen);
13588 dc.SetPen(*pblue_pen);
13589 dc.DrawLines(3, arrow);
13593 s.Printf(
"%3.1f", nowlev);
13595 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13597 dc.GetTextExtent(s, &wx1, NULL);
13599 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13614void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13617 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13619 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13625 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13626 if ((BBox.Contains(lat, lon))) {
13628 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13634void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13637 float tcvalue, dir;
13641 double lon_last = 0.;
13642 double lat_last = 0.;
13644 double marge = 0.2;
13645 bool cur_time = !gTimeSource.IsValid();
13647 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13648 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13650 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13652 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13653 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13654 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13655 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13656 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13657 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13658 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13659 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13661 double skew_angle = GetVPRotation();
13663 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13664 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13665 int font_size = wxMax(10, dFont->GetPointSize());
13668 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13669 false, dFont->GetFaceName());
13671 float scale_factor = 1.0;
13677 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13679 float nominal_icon_size_pixels = 15;
13680 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13682 scale_factor *= pix_factor;
13689 scale_factor *= user_scale_factor;
13691 scale_factor *= GetContentScaleFactor();
13694 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13700 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13701 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13706 int dd = (int)(5.0 * scale_factor + 0.5);
13717 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13718 dc.SetPen(*pblack_pen);
13719 dc.SetBrush(*porange_brush);
13720 dc.DrawPolygon(4, d);
13723 dc.SetBrush(*pblack_brush);
13724 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13728 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13742 double a1 = fabs(tcvalue) * 10.;
13744 a1 = wxMax(1.0, a1);
13745 double a2 = log10(a1);
13747 float cscale = scale_factor * a2 * 0.3;
13749 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13750 dc.SetPen(*porange_pen);
13751 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13755 if (bDrawCurrentValues) {
13756 dc.SetFont(*pTCFont);
13757 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13758 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13784 if (!pvIDX)
return;
13789 if (pCwin && pCwin->IsShown()) {
13797 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13812 pCwin =
new TCWin(
this, x, y, pvIDX);
13830#define NUM_CURRENT_ARROW_POINTS 9
13831static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13832 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13833 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13834 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13836void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13838 if (
scale > 1e-2) {
13839 float sin_rot = sin(rot_angle * PI / 180.);
13840 float cos_rot = cos(rot_angle * PI / 180.);
13844 float xt = CurrentArrowArray[0].x;
13845 float yt = CurrentArrowArray[0].y;
13847 float xp = (xt * cos_rot) - (yt * sin_rot);
13848 float yp = (xt * sin_rot) + (yt * cos_rot);
13849 int x1 = (int)(xp *
scale);
13850 int y1 = (int)(yp *
scale);
13853 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13854 xt = CurrentArrowArray[ip].x;
13855 yt = CurrentArrowArray[ip].y;
13857 float xp = (xt * cos_rot) - (yt * sin_rot);
13858 float yp = (xt * sin_rot) + (yt * cos_rot);
13859 int x2 = (int)(xp *
scale);
13860 int y2 = (int)(yp *
scale);
13862 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13870wxString ChartCanvas::FindValidUploadPort() {
13873 if (!g_uploadConnection.IsEmpty() &&
13874 g_uploadConnection.StartsWith(
"Serial")) {
13875 port = g_uploadConnection;
13881 for (
auto *cp : TheConnectionParams()) {
13882 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13883 port <<
"Serial:" << cp->Port;
13889void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13892 if (NULL == g_pais_query_dialog_active) {
13893 int pos_x = g_ais_query_dialog_x;
13894 int pos_y = g_ais_query_dialog_y;
13896 if (g_pais_query_dialog_active) {
13897 g_pais_query_dialog_active->Destroy();
13903 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13904 wxPoint(pos_x, pos_y));
13906 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13907 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13908 g_pais_query_dialog_active->SetMMSI(mmsi);
13909 g_pais_query_dialog_active->UpdateText();
13910 wxSize sz = g_pais_query_dialog_active->GetSize();
13912 bool b_reset_pos =
false;
13917 RECT frame_title_rect;
13918 frame_title_rect.left = pos_x;
13919 frame_title_rect.top = pos_y;
13920 frame_title_rect.right = pos_x + sz.x;
13921 frame_title_rect.bottom = pos_y + 30;
13923 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13924 b_reset_pos =
true;
13929 wxRect window_title_rect;
13930 window_title_rect.x = pos_x;
13931 window_title_rect.y = pos_y;
13932 window_title_rect.width = sz.x;
13933 window_title_rect.height = 30;
13935 wxRect ClientRect = wxGetClientDisplayRect();
13936 ClientRect.Deflate(
13938 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13942 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13945 g_pais_query_dialog_active->SetMMSI(mmsi);
13946 g_pais_query_dialog_active->UpdateText();
13949 g_pais_query_dialog_active->Show();
13952void ChartCanvas::ToggleCanvasQuiltMode() {
13953 bool cur_mode = GetQuiltMode();
13955 if (!GetQuiltMode())
13956 SetQuiltMode(
true);
13957 else if (GetQuiltMode()) {
13958 SetQuiltMode(
false);
13959 g_sticky_chart = GetQuiltReferenceChartIndex();
13962 if (cur_mode != GetQuiltMode()) {
13963 SetupCanvasQuiltMode();
13972 if (ps52plib) ps52plib->GenerateStateHash();
13974 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13975 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13978void ChartCanvas::DoCanvasStackDelta(
int direction) {
13979 if (!GetQuiltMode()) {
13980 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13981 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13982 if ((current_stack_index + direction) < 0)
return;
13984 if (m_bpersistent_quilt ) {
13986 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13988 if (IsChartQuiltableRef(new_dbIndex)) {
13989 ToggleCanvasQuiltMode();
13990 SelectQuiltRefdbChart(new_dbIndex);
13991 m_bpersistent_quilt =
false;
13994 SelectChartFromStack(current_stack_index + direction);
13997 std::vector<int> piano_chart_index_array =
13998 GetQuiltExtendedStackdbIndexArray();
13999 int refdb = GetQuiltRefChartdbIndex();
14002 int current_index = -1;
14003 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14004 if (refdb == piano_chart_index_array[i]) {
14009 if (current_index == -1)
return;
14012 int target_family = ctet.GetChartFamily();
14014 int new_index = -1;
14015 int check_index = current_index + direction;
14016 bool found =
false;
14017 int check_dbIndex = -1;
14018 int new_dbIndex = -1;
14022 (
unsigned int)check_index < piano_chart_index_array.size() &&
14023 (check_index >= 0)) {
14024 check_dbIndex = piano_chart_index_array[check_index];
14026 if (target_family == cte.GetChartFamily()) {
14028 new_index = check_index;
14029 new_dbIndex = check_dbIndex;
14033 check_index += direction;
14036 if (!found)
return;
14038 if (!IsChartQuiltableRef(new_dbIndex)) {
14039 ToggleCanvasQuiltMode();
14040 SelectdbChart(new_dbIndex);
14041 m_bpersistent_quilt =
true;
14043 SelectQuiltRefChart(new_index);
14048 top_frame::Get()->UpdateGlobalMenuItems();
14049 SetQuiltChartHiLiteIndex(-1);
14060void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14063 switch (event.GetId()) {
14075 DoCanvasStackDelta(1);
14080 DoCanvasStackDelta(-1);
14090 ShowCurrents(!GetbShowCurrent());
14097 ShowTides(!GetbShowTide());
14104 if (0 == m_routeState) {
14111 androidSetRouteAnnunciator(m_routeState == 1);
14117 SetAISCanvasDisplayStyle(-1);
14129void ChartCanvas::SetShowAIS(
bool show) {
14131 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14132 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14135void ChartCanvas::SetAttenAIS(
bool show) {
14136 m_bShowAISScaled = show;
14137 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14138 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14141void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14144 bool bShowAIS_Array[3] = {
true,
true,
false};
14145 bool bShowScaled_Array[3] = {
false,
true,
true};
14146 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14147 _(
"Attenuate less critical AIS targets"),
14148 _(
"Hide AIS Targets")};
14149 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14151 int AIS_Toolbar_Switch = 0;
14152 if (StyleIndx == -1) {
14154 for (
int i = 1; i < ArraySize; i++) {
14155 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14156 (bShowScaled_Array[i] == m_bShowAISScaled))
14157 AIS_Toolbar_Switch = i;
14159 AIS_Toolbar_Switch++;
14160 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14161 AIS_Toolbar_Switch++;
14164 AIS_Toolbar_Switch = StyleIndx;
14167 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14169 int AIS_Toolbar_Switch_Next =
14170 AIS_Toolbar_Switch + 1;
14171 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14172 AIS_Toolbar_Switch_Next++;
14173 if (AIS_Toolbar_Switch_Next >= ArraySize)
14174 AIS_Toolbar_Switch_Next = 0;
14177 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14178 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14181void ChartCanvas::TouchAISToolActive() {}
14183void ChartCanvas::UpdateAISTBTool() {}
14191void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14193 bool b_update =
false;
14194 int cc1_edge_comp = 2;
14195 wxRect rect = m_Compass->
GetRect();
14196 wxSize parent_size = GetSize();
14198 parent_size *= m_displayScale;
14202 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14203 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14204 wxRect compass_rect(compass_pt, rect.GetSize());
14206 m_Compass->Move(compass_pt);
14208 if (m_Compass && m_Compass->IsShown())
14209 m_Compass->UpdateStatus(b_force_new | b_update);
14211 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14212 scaler = wxMax(scaler, 1.0);
14213 wxPoint note_point = wxPoint(
14214 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14215 if (m_notification_button) {
14216 m_notification_button->Move(note_point);
14217 m_notification_button->UpdateStatus();
14220 if (b_force_new | b_update) Refresh();
14223void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14224 ChartTypeEnum New_Type,
14225 ChartFamilyEnum New_Family) {
14226 if (!GetpCurrentStack())
return;
14229 if (index < GetpCurrentStack()->nEntry) {
14232 pTentative_Chart =
ChartData->OpenStackChartConditional(
14233 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14235 if (pTentative_Chart) {
14236 if (m_singleChart) m_singleChart->Deactivate();
14238 m_singleChart = pTentative_Chart;
14239 m_singleChart->Activate();
14241 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14242 GetpCurrentStack(), m_singleChart->GetFullPath());
14255 double best_scale_ppm = GetBestVPScale(m_singleChart);
14256 double rotation = GetVPRotation();
14257 double oldskew = GetVPSkew();
14258 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14260 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14261 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14262 if (fabs(newskew) > 0.0001) rotation = newskew;
14265 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14267 UpdateGPSCompassStatusBox(
true);
14271 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14272 if (idx < 0)
return;
14274 std::vector<int> piano_active_chart_index_array;
14275 piano_active_chart_index_array.push_back(
14276 GetpCurrentStack()->GetCurrentEntrydbIndex());
14277 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14280void ChartCanvas::SelectdbChart(
int dbindex) {
14281 if (!GetpCurrentStack())
return;
14284 if (dbindex >= 0) {
14287 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14289 if (pTentative_Chart) {
14290 if (m_singleChart) m_singleChart->Deactivate();
14292 m_singleChart = pTentative_Chart;
14293 m_singleChart->Activate();
14295 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14296 GetpCurrentStack(), m_singleChart->GetFullPath());
14309 double best_scale_ppm = GetBestVPScale(m_singleChart);
14313 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14323void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14326 if (!GetQuiltMode()) {
14327 if (GetpCurrentStack()) {
14328 int stack_index = -1;
14329 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14330 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14331 if (check_dbIndex < 0)
continue;
14333 ChartData->GetChartTableEntry(check_dbIndex);
14334 if (type == cte.GetChartType()) {
14337 }
else if (family == cte.GetChartFamily()) {
14343 if (stack_index >= 0) {
14344 SelectChartFromStack(stack_index);
14348 int sel_dbIndex = -1;
14349 std::vector<int> piano_chart_index_array =
14350 GetQuiltExtendedStackdbIndexArray();
14351 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14352 int check_dbIndex = piano_chart_index_array[i];
14354 if (type == cte.GetChartType()) {
14355 if (IsChartQuiltableRef(check_dbIndex)) {
14356 sel_dbIndex = check_dbIndex;
14359 }
else if (family == cte.GetChartFamily()) {
14360 if (IsChartQuiltableRef(check_dbIndex)) {
14361 sel_dbIndex = check_dbIndex;
14367 if (sel_dbIndex >= 0) {
14368 SelectQuiltRefdbChart(sel_dbIndex,
false);
14370 AdjustQuiltRefChart();
14377 SetQuiltChartHiLiteIndex(-1);
14382bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14383 return std::find(m_tile_yesshow_index_array.begin(),
14384 m_tile_yesshow_index_array.end(),
14385 index) != m_tile_yesshow_index_array.end();
14388bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14389 return std::find(m_tile_noshow_index_array.begin(),
14390 m_tile_noshow_index_array.end(),
14391 index) != m_tile_noshow_index_array.end();
14394void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14395 if (std::find(m_tile_noshow_index_array.begin(),
14396 m_tile_noshow_index_array.end(),
14397 index) == m_tile_noshow_index_array.end()) {
14398 m_tile_noshow_index_array.push_back(index);
14408void ChartCanvas::HandlePianoClick(
14409 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14412 if (!m_pCurrentStack)
return;
14428 double distance = 25000;
14429 int closest_index = -1;
14430 for (
int chart_index : selected_dbIndex_array) {
14432 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14433 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14436 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14437 if (test_distance < distance) {
14438 distance = test_distance;
14439 closest_index = chart_index;
14443 int selected_dbIndex = selected_dbIndex_array[0];
14444 if (closest_index >= 0) selected_dbIndex = closest_index;
14446 if (!GetQuiltMode()) {
14447 if (m_bpersistent_quilt ) {
14448 if (IsChartQuiltableRef(selected_dbIndex)) {
14449 ToggleCanvasQuiltMode();
14450 SelectQuiltRefdbChart(selected_dbIndex);
14451 m_bpersistent_quilt =
false;
14453 SelectChartFromStack(selected_index);
14456 SelectChartFromStack(selected_index);
14457 g_sticky_chart = selected_dbIndex;
14461 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14465 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14466 bool bfound =
false;
14467 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14468 if (m_tile_noshow_index_array[i] ==
14469 selected_dbIndex) {
14470 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14477 m_tile_noshow_index_array.push_back(selected_dbIndex);
14481 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14482 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14486 if (IsChartQuiltableRef(selected_dbIndex)) {
14492 bool set_scale =
false;
14493 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14494 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14500 SelectQuiltRefdbChart(selected_dbIndex,
true);
14502 SelectQuiltRefdbChart(selected_dbIndex,
false);
14507 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14509 double proposed_scale_onscreen =
14512 if (g_bPreserveScaleOnX) {
14513 proposed_scale_onscreen =
14514 wxMin(proposed_scale_onscreen,
14516 GetCanvasWidth()));
14518 proposed_scale_onscreen =
14519 wxMin(proposed_scale_onscreen,
14521 GetCanvasWidth()));
14523 proposed_scale_onscreen =
14524 wxMax(proposed_scale_onscreen,
14533 ToggleCanvasQuiltMode();
14534 SelectdbChart(selected_dbIndex);
14535 m_bpersistent_quilt =
true;
14540 SetQuiltChartHiLiteIndex(-1);
14542 top_frame::Get()->UpdateGlobalMenuItems();
14543 HideChartInfoWindow();
14548void ChartCanvas::HandlePianoRClick(
14549 int x,
int y,
int selected_index,
14550 const std::vector<int> &selected_dbIndex_array) {
14553 if (!GetpCurrentStack())
return;
14555 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14556 UpdateCanvasControlBar();
14558 SetQuiltChartHiLiteIndex(-1);
14561void ChartCanvas::HandlePianoRollover(
14562 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14563 int n_charts,
int scale) {
14566 if (!GetpCurrentStack())
return;
14571 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14573 if (!GetQuiltMode()) {
14574 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14577 std::vector<int> piano_chart_index_array;
14578 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14579 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14580 if ((GetpCurrentStack()->nEntry > 1) ||
14581 (piano_chart_index_array.size() >= 1)) {
14582 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14584 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14586 }
else if (GetpCurrentStack()->nEntry == 1) {
14588 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14589 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14590 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14592 }
else if ((-1 == selected_index) &&
14593 (0 == selected_dbIndex_array.size())) {
14594 ShowChartInfoWindow(key_location.x, -1);
14598 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14600 if ((GetpCurrentStack()->nEntry > 1) ||
14601 (piano_chart_index_array.size() >= 1)) {
14603 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14604 selected_dbIndex_array);
14605 else if (n_charts == 1)
14606 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14608 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14615void ChartCanvas::ClearPianoRollover() {
14616 ClearQuiltChartHiLiteIndexArray();
14617 ShowChartInfoWindow(0, -1);
14618 std::vector<int> vec;
14619 ShowCompositeInfoWindow(0, 0, 0, vec);
14623void ChartCanvas::UpdateCanvasControlBar() {
14624 if (m_pianoFrozen)
return;
14626 if (!GetpCurrentStack())
return;
14628 if (!g_bShowChartBar)
return;
14631 int sel_family = -1;
14633 std::vector<int> piano_chart_index_array;
14634 std::vector<int> empty_piano_chart_index_array;
14636 wxString old_hash = m_Piano->GetStoredHash();
14638 if (GetQuiltMode()) {
14639 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14640 GetQuiltFullScreendbIndexArray());
14642 std::vector<int> piano_active_chart_index_array =
14643 GetQuiltCandidatedbIndexArray();
14644 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14646 std::vector<int> piano_eclipsed_chart_index_array =
14647 GetQuiltEclipsedStackdbIndexArray();
14648 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14650 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14651 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14653 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14654 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14656 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14657 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14660 if (m_singleChart) {
14661 sel_type = m_singleChart->GetChartType();
14662 sel_family = m_singleChart->GetChartFamily();
14667 std::vector<int> piano_skew_chart_index_array;
14668 std::vector<int> piano_tmerc_chart_index_array;
14669 std::vector<int> piano_poly_chart_index_array;
14671 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14673 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14674 double skew_norm = ctei.GetChartSkew();
14675 if (skew_norm > 180.) skew_norm -= 360.;
14677 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14678 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14681 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14682 if (fabs(skew_norm) > 1.)
14683 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14685 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14686 }
else if (fabs(skew_norm) > 1.)
14687 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14689 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14690 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14691 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14693 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14694 if (new_hash != old_hash) {
14695 m_Piano->FormatKeys();
14696 HideChartInfoWindow();
14697 m_Piano->ResetRollover();
14698 SetQuiltChartHiLiteIndex(-1);
14699 m_brepaint_piano =
true;
14705 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14707 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14708 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14709 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14710 if (e == CHART_FAMILY_RASTER) mask |= 1;
14711 if (e == CHART_FAMILY_VECTOR) {
14712 if (t == CHART_TYPE_CM93COMP)
14719 wxString s_indicated;
14720 if (sel_type == CHART_TYPE_CM93COMP)
14721 s_indicated =
"cm93";
14723 if (sel_family == CHART_FAMILY_RASTER)
14724 s_indicated =
"raster";
14725 else if (sel_family == CHART_FAMILY_VECTOR)
14726 s_indicated =
"vector";
14729 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14732void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14734void ChartCanvas::PianoPopupMenu(
14735 int x,
int y,
int selected_index,
14736 const std::vector<int> &selected_dbIndex_array) {
14737 if (!GetpCurrentStack())
return;
14740 if (!GetQuiltMode())
return;
14742 m_piano_ctx_menu =
new wxMenu();
14744 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14754 menu_selected_dbIndex = selected_dbIndex_array[0];
14755 menu_selected_index = selected_index;
14758 bool b_is_in_noshow =
false;
14759 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14760 if (m_quilt_noshow_index_array[i] ==
14761 menu_selected_dbIndex)
14763 b_is_in_noshow =
true;
14768 if (b_is_in_noshow) {
14769 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14770 _(
"Show This Chart"));
14771 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14772 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14773 }
else if (GetpCurrentStack()->nEntry > 1) {
14774 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14775 _(
"Hide This Chart"));
14776 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14777 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14781 wxPoint pos = wxPoint(x, y - 30);
14784 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14785 PopupMenu(m_piano_ctx_menu, pos);
14787 delete m_piano_ctx_menu;
14788 m_piano_ctx_menu = NULL;
14790 HideChartInfoWindow();
14791 m_Piano->ResetRollover();
14793 SetQuiltChartHiLiteIndex(-1);
14794 ClearQuiltChartHiLiteIndexArray();
14799void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14800 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14801 if (m_quilt_noshow_index_array[i] ==
14802 menu_selected_dbIndex)
14804 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14810void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14811 if (!GetpCurrentStack())
return;
14814 RemoveChartFromQuilt(menu_selected_dbIndex);
14818 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14819 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14821 int i = menu_selected_index + 1;
14822 bool b_success =
false;
14823 while (i < GetpCurrentStack()->nEntry - 1) {
14824 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14825 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14826 SelectQuiltRefChart(i);
14836 i = menu_selected_index - 1;
14838 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14839 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14840 SelectQuiltRefChart(i);
14850void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14852 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14853 if (m_quilt_noshow_index_array[i] ==
14856 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14861 m_quilt_noshow_index_array.push_back(dbIndex);
14864bool ChartCanvas::UpdateS52State() {
14865 bool retval =
false;
14868 ps52plib->SetShowS57Text(m_encShowText);
14869 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14870 ps52plib->m_bShowSoundg = m_encShowDepth;
14871 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14872 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14875 if (!m_encShowLights)
14876 ps52plib->AddObjNoshow(
"LIGHTS");
14878 ps52plib->RemoveObjNoshow(
"LIGHTS");
14879 ps52plib->SetLightsOff(!m_encShowLights);
14880 ps52plib->m_bExtendLightSectors =
true;
14883 ps52plib->SetAnchorOn(m_encShowAnchor);
14884 ps52plib->SetQualityOfData(m_encShowDataQual);
14890void ChartCanvas::SetShowENCDataQual(
bool show) {
14891 m_encShowDataQual = show;
14892 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14893 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14895 m_s52StateHash = 0;
14898void ChartCanvas::SetShowENCText(
bool show) {
14899 m_encShowText = show;
14900 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14901 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14903 m_s52StateHash = 0;
14906void ChartCanvas::SetENCDisplayCategory(
int category) {
14907 m_encDisplayCategory = category;
14908 m_s52StateHash = 0;
14911void ChartCanvas::SetShowENCDepth(
bool show) {
14912 m_encShowDepth = show;
14913 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14914 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14916 m_s52StateHash = 0;
14919void ChartCanvas::SetShowENCLightDesc(
bool show) {
14920 m_encShowLightDesc = show;
14921 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14922 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14924 m_s52StateHash = 0;
14927void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14928 m_encShowBuoyLabels = show;
14929 m_s52StateHash = 0;
14932void ChartCanvas::SetShowENCLights(
bool show) {
14933 m_encShowLights = show;
14934 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14935 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14937 m_s52StateHash = 0;
14940void ChartCanvas::SetShowENCAnchor(
bool show) {
14941 m_encShowAnchor = show;
14942 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14943 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14945 m_s52StateHash = 0;
14948wxRect ChartCanvas::GetMUIBarRect() {
14951 rv = m_muiBar->GetRect();
14957void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14958 if (!GetAlertString().IsEmpty()) {
14959 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14960 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14962 dc.SetFont(*pfont);
14963 dc.SetPen(*wxTRANSPARENT_PEN);
14965 dc.SetBrush(wxColour(243, 229, 47));
14967 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14971 wxRect sbr = GetScaleBarRect();
14972 int xp = sbr.x + sbr.width + 10;
14973 int yp = (sbr.y + sbr.height) - h;
14975 int wdraw = w + 10;
14976 dc.DrawRectangle(xp, yp, wdraw, h);
14977 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14978 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14988#define BRIGHT_XCALIB
14989#define __OPCPN_USEICC__
14992#ifdef __OPCPN_USEICC__
14993int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14994 double co_green,
double co_blue);
14996wxString temp_file_name;
15000class ocpnCurtain:
public wxDialog
15002 DECLARE_CLASS( ocpnCurtain )
15003 DECLARE_EVENT_TABLE()
15006 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
15008 bool ProcessEvent(wxEvent& event);
15012IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
15014BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
15017ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
15019 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
15022ocpnCurtain::~ocpnCurtain()
15026bool ocpnCurtain::ProcessEvent(wxEvent& event)
15028 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
15029 return GetParent()->GetEventHandler()->ProcessEvent(event);
15034#include <windows.h>
15037typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15038typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15039SetDeviceGammaRamp_ptr_type
15040 g_pSetDeviceGammaRamp;
15041GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15043WORD *g_pSavedGammaMap;
15047int InitScreenBrightness() {
15050 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15054 if (NULL == hGDI32DLL) {
15055 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15057 if (NULL != hGDI32DLL) {
15059 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15060 hGDI32DLL,
"SetDeviceGammaRamp");
15061 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15062 hGDI32DLL,
"GetDeviceGammaRamp");
15065 if ((NULL == g_pSetDeviceGammaRamp) ||
15066 (NULL == g_pGetDeviceGammaRamp)) {
15067 FreeLibrary(hGDI32DLL);
15076 if (!g_pSavedGammaMap) {
15077 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15080 bbr = g_pGetDeviceGammaRamp(
15081 hDC, g_pSavedGammaMap);
15082 ReleaseDC(NULL, hDC);
15087 wxRegKey *pRegKey =
new wxRegKey(
15088 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15089 "NT\\CurrentVersion\\ICM");
15090 if (!pRegKey->Exists()) pRegKey->Create();
15091 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15093 g_brightness_init =
true;
15099 if (NULL == g_pcurtain) {
15100 if (top_frame::Get()->CanSetTransparent()) {
15102 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15103 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15104 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15105 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15112 g_pcurtain->Hide();
15114 HWND hWnd = GetHwndOf(g_pcurtain);
15115 SetWindowLong(hWnd, GWL_EXSTYLE,
15116 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15117 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15118 g_pcurtain->SetTransparent(0);
15120 g_pcurtain->Maximize();
15121 g_pcurtain->Show();
15124 g_pcurtain->Enable();
15125 g_pcurtain->Disable();
15127 top_frame::Get()->Disable();
15128 top_frame::Get()->Enable();
15132 g_brightness_init =
true;
15138 wxString cmd(
"xcalib -version");
15140 wxArrayString output;
15141 long r = wxExecute(cmd, output);
15144 " External application \"xcalib\" not found. Screen brightness "
15147 g_brightness_init =
true;
15152int RestoreScreenBrightness() {
15155 if (g_pSavedGammaMap) {
15156 HDC hDC = GetDC(NULL);
15157 g_pSetDeviceGammaRamp(hDC,
15159 ReleaseDC(NULL, hDC);
15161 free(g_pSavedGammaMap);
15162 g_pSavedGammaMap = NULL;
15166 g_pcurtain->Close();
15167 g_pcurtain->Destroy();
15171 g_brightness_init =
false;
15176#ifdef BRIGHT_XCALIB
15177 if (g_brightness_init) {
15179 cmd =
"xcalib -clear";
15180 wxExecute(cmd, wxEXEC_ASYNC);
15181 g_brightness_init =
false;
15191int SetScreenBrightness(
int brightness) {
15198 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15200 g_pcurtain->Close();
15201 g_pcurtain->Destroy();
15205 InitScreenBrightness();
15207 if (NULL == hGDI32DLL) {
15209 wchar_t wdll_name[80];
15210 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15211 LPCWSTR cstr = wdll_name;
15213 hGDI32DLL = LoadLibrary(cstr);
15215 if (NULL != hGDI32DLL) {
15217 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15218 hGDI32DLL,
"SetDeviceGammaRamp");
15219 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15220 hGDI32DLL,
"GetDeviceGammaRamp");
15223 if ((NULL == g_pSetDeviceGammaRamp) ||
15224 (NULL == g_pGetDeviceGammaRamp)) {
15225 FreeLibrary(hGDI32DLL);
15232 HDC hDC = GetDC(NULL);
15243 int increment = brightness * 256 / 100;
15246 WORD GammaTable[3][256];
15249 for (
int i = 0; i < 256; i++) {
15250 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15251 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15252 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15254 table_val += increment;
15256 if (table_val > 65535) table_val = 65535;
15259 g_pSetDeviceGammaRamp(hDC, GammaTable);
15260 ReleaseDC(NULL, hDC);
15267 if (g_pSavedGammaMap) {
15268 HDC hDC = GetDC(NULL);
15269 g_pSetDeviceGammaRamp(hDC,
15271 ReleaseDC(NULL, hDC);
15274 if (brightness < 100) {
15275 if (NULL == g_pcurtain) InitScreenBrightness();
15278 int sbrite = wxMax(1, brightness);
15279 sbrite = wxMin(100, sbrite);
15281 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15285 g_pcurtain->Close();
15286 g_pcurtain->Destroy();
15296#ifdef BRIGHT_XCALIB
15298 if (!g_brightness_init) {
15299 last_brightness = 100;
15300 g_brightness_init =
true;
15301 temp_file_name = wxFileName::CreateTempFileName(
"");
15302 InitScreenBrightness();
15305#ifdef __OPCPN_USEICC__
15308 if (!CreateSimpleICCProfileFile(
15309 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15310 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15311 wxString cmd(
"xcalib ");
15312 cmd += temp_file_name;
15314 wxExecute(cmd, wxEXEC_ASYNC);
15323 if (brightness > last_brightness) {
15325 cmd =
"xcalib -clear";
15326 wxExecute(cmd, wxEXEC_ASYNC);
15328 ::wxMilliSleep(10);
15330 int brite_adj = wxMax(1, brightness);
15331 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15332 wxExecute(cmd, wxEXEC_ASYNC);
15334 int brite_adj = wxMax(1, brightness);
15335 int factor = (brite_adj * 100) / last_brightness;
15336 factor = wxMax(1, factor);
15338 cmd.Printf(
"xcalib -co %2d -a", factor);
15339 wxExecute(cmd, wxEXEC_ASYNC);
15344 last_brightness = brightness;
15351#ifdef __OPCPN_USEICC__
15353#define MLUT_TAG 0x6d4c5554L
15354#define VCGT_TAG 0x76636774L
15356int GetIntEndian(
unsigned char *s) {
15361 p = (
unsigned char *)&ret;
15364 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15366 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15371unsigned short GetShortEndian(
unsigned char *s) {
15372 unsigned short ret;
15376 p = (
unsigned char *)&ret;
15379 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15381 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15387int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15388 double co_green,
double co_blue) {
15392 fp = fopen(file_name,
"wb");
15393 if (!fp)
return -1;
15399 for (
int i = 0; i < 128; i++) header[i] = 0;
15401 fwrite(header, 128, 1, fp);
15405 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15406 fwrite(&numTags, 1, 4, fp);
15408 int tagName0 = VCGT_TAG;
15409 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15410 fwrite(&tagName, 1, 4, fp);
15412 int tagOffset0 = 128 + 4 *
sizeof(int);
15413 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15414 fwrite(&tagOffset, 1, 4, fp);
15417 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15418 fwrite(&tagSize, 1, 4, fp);
15420 fwrite(&tagName, 1, 4, fp);
15422 fwrite(&tagName, 1, 4, fp);
15427 int gammatype0 = 0;
15428 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15429 fwrite(&gammatype, 1, 4, fp);
15431 int numChannels0 = 3;
15432 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15433 fwrite(&numChannels, 1, 2, fp);
15435 int numEntries0 = 256;
15436 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15437 fwrite(&numEntries, 1, 2, fp);
15439 int entrySize0 = 1;
15440 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15441 fwrite(&entrySize, 1, 2, fp);
15443 unsigned char ramp[256];
15446 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15447 fwrite(ramp, 256, 1, fp);
15450 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15451 fwrite(ramp, 256, 1, fp);
15454 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15455 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.
arrayofCanvasPtr g_canvasArray
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.
Minimal ChartCAnvas interface with very little dependencies.
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.
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.
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
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".
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
int station_tz_offset
Offset in seconds to convert from harmonic data (epochs) to the station time zone.
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.
Data for a loaded plugin, including dl-loaded library.
int m_cap_flag
PlugIn Capabilities descriptor.
PluginLoader is a backend module without any direct GUI functionality.
const ArrayOfPlugIns * GetPlugInArray()
Return list of currently loaded plugins.
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.
double AnchorDistFix(double const d, double const AnchorPointMinDist, double const AnchorPointMaxDist)
Return constrained value of d so that AnchorPointMinDist < abs(d) < AnchorPointMaxDist.
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.
Miscellaneous utilities, many of which string related.
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.
RouteManagerDialog * pRouteManagerDialog
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.
Abstract gFrame/MyFrame interface.
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.