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 (bDBUpdateInProgress)
return false;
1533 if (m_chart_drag_inertia_active)
return false;
1559 double dx = m_OSoffsetx;
1560 double dy = m_OSoffsety;
1564 if (GetUpMode() == NORTH_UP_MODE) {
1565 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1567 double offset_angle = atan2(d_north, d_east);
1568 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1569 double chart_angle = GetVPRotation();
1570 double target_angle = chart_angle + offset_angle;
1571 double d_east_mod = offset_distance * cos(target_angle);
1572 double d_north_mod = offset_distance * sin(target_angle);
1573 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1577 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1578 double cog_to_use =
gCog;
1580 (fabs(
gCog - gCog_gt) > 20)) {
1581 cog_to_use = gCog_gt;
1584 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1586 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1588 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1589 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1591 double pixel_delta_tent =
1592 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1594 double pixel_delta = 0;
1599 if (!std::isnan(
gSog)) {
1603 pixel_delta = pixel_delta_tent;
1606 meters_to_shift = 0;
1608 if (!std::isnan(
gCog)) {
1609 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1610 dir_to_shift = cog_to_use;
1611 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1617 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1631 if (GetQuiltMode()) {
1632 int current_db_index = -1;
1633 if (m_pCurrentStack)
1636 ->GetCurrentEntrydbIndex();
1644 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1646 if (m_pCurrentStack->nEntry) {
1647 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1649 SelectQuiltRefdbChart(new_dbIndex,
true);
1650 m_bautofind =
false;
1654 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1655 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1660 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1666 double proposed_scale_onscreen =
1669 int initial_db_index = m_restore_dbindex;
1670 if (initial_db_index < 0) {
1671 if (m_pCurrentStack->nEntry) {
1673 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1678 if (m_pCurrentStack->nEntry) {
1679 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1684 if (!IsChartQuiltableRef(initial_db_index)) {
1688 int stack_index = 0;
1690 if (stack_index >= 0) {
1691 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1692 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1693 if (IsChartQuiltableRef(test_db_index) &&
1695 ChartData->GetDBChartType(initial_db_index))) {
1696 initial_db_index = test_db_index;
1706 SetQuiltRefChart(initial_db_index);
1707 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1715 0, GetVPRotation());
1720 bool super_jump =
false;
1722 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1723 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1724 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1727 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1729 if (blong_jump) nstep = 20;
1730 StartTimedMovementVP(vpLat, vpLon, nstep);
1741 pLast_Ch = m_singleChart;
1742 ChartTypeEnum new_open_type;
1743 ChartFamilyEnum new_open_family;
1745 new_open_type = pLast_Ch->GetChartType();
1746 new_open_family = pLast_Ch->GetChartFamily();
1748 new_open_type = CHART_TYPE_KAP;
1749 new_open_family = CHART_FAMILY_RASTER;
1752 bOpenSpecified = m_bFirstAuto;
1755 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1758 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1760 if (NULL == pDummyChart) {
1766 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1768 m_singleChart = pDummyChart;
1773 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1775 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1778 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1779 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1786 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1792 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1797 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1800 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1805 if (NULL != m_singleChart)
1806 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1807 m_singleChart->GetFullPath());
1810 m_pCurrentStack->CurrentStackEntry = tEntry;
1820 if (bCanvasChartAutoOpen) {
1821 bool search_direction =
1823 int start_index = 0;
1827 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1828 (LastStack.nEntry == 0)) {
1829 search_direction =
true;
1830 start_index = m_pCurrentStack->nEntry - 1;
1834 if (bOpenSpecified) {
1835 search_direction =
false;
1837 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1840 new_open_type = CHART_TYPE_DONTCARE;
1843 pProposed =
ChartData->OpenStackChartConditional(
1844 m_pCurrentStack, start_index, search_direction, new_open_type,
1848 if (NULL == pProposed)
1849 pProposed =
ChartData->OpenStackChartConditional(
1850 m_pCurrentStack, start_index, search_direction,
1851 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1853 if (NULL == pProposed)
1854 pProposed =
ChartData->OpenStackChartConditional(
1855 m_pCurrentStack, start_index, search_direction,
1856 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1867 if (NULL == pProposed) {
1868 if (NULL == pDummyChart) {
1874 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1876 pProposed = pDummyChart;
1880 if (m_singleChart) m_singleChart->Deactivate();
1881 m_singleChart = pProposed;
1883 if (m_singleChart) {
1884 m_singleChart->Activate();
1885 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1886 m_pCurrentStack, m_singleChart->GetFullPath());
1891 if (NULL != m_singleChart) {
1897 if (!GetVP().IsValid())
1898 set_scale = 1. / 20000.;
1900 double proposed_scale_onscreen;
1903 double new_scale_ppm =
1904 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1912 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1913 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1914 double equivalent_vp_scale =
1916 double new_scale_ppm =
1917 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1922 proposed_scale_onscreen =
1923 wxMin(proposed_scale_onscreen,
1926 proposed_scale_onscreen =
1927 wxMax(proposed_scale_onscreen,
1936 m_singleChart->GetChartSkew() * PI / 180.,
1943 if ((m_bFollow) && m_singleChart)
1945 m_singleChart->GetChartSkew() * PI / 180.,
1954 m_bFirstAuto =
false;
1958 if (bNewChart && !bNewView) Refresh(
false);
1963 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1966 return bNewChart | bNewView;
1969void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1970 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1972 SetQuiltRefChart(db_index);
1977 double best_scale_ppm = GetBestVPScale(pc);
1981 SetQuiltRefChart(-1);
1983 SetQuiltRefChart(-1);
1986void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1987 std::vector<int> piano_chart_index_array =
1988 GetQuiltExtendedStackdbIndexArray();
1989 int current_db_index = piano_chart_index_array[selected_index];
1991 SelectQuiltRefdbChart(current_db_index);
1994double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1998 if ((g_bPreserveScaleOnX) ||
1999 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2005 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2006 double equivalent_vp_scale =
2008 double new_scale_ppm =
2009 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2016 double max_underzoom_multiplier = 2.0;
2017 if (GetVP().b_quilt) {
2018 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2019 pchart->GetChartType(),
2020 pchart->GetChartFamily());
2021 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2024 proposed_scale_onscreen = wxMin(
2025 proposed_scale_onscreen,
2027 max_underzoom_multiplier);
2030 proposed_scale_onscreen =
2031 wxMax(proposed_scale_onscreen,
2039void ChartCanvas::SetupCanvasQuiltMode() {
2044 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2048 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2049 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2050 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2051 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2053 m_Piano->SetRoundedRectangles(
true);
2056 int target_new_dbindex = -1;
2057 if (m_pCurrentStack) {
2058 target_new_dbindex =
2059 GetQuiltReferenceChartIndex();
2061 if (-1 != target_new_dbindex) {
2062 if (!IsChartQuiltableRef(target_new_dbindex)) {
2063 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2064 int type =
ChartData->GetDBChartType(target_new_dbindex);
2067 int stack_index = m_pCurrentStack->CurrentStackEntry;
2069 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2070 (stack_index >= 0)) {
2071 int proj_tent =
ChartData->GetDBChartProj(
2072 m_pCurrentStack->GetDBIndex(stack_index));
2073 int type_tent =
ChartData->GetDBChartType(
2074 m_pCurrentStack->GetDBIndex(stack_index));
2076 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2077 if ((proj == proj_tent) && (type_tent == type)) {
2078 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2088 if (IsChartQuiltableRef(target_new_dbindex))
2089 SelectQuiltRefdbChart(target_new_dbindex,
2092 SelectQuiltRefdbChart(-1,
false);
2094 m_singleChart = NULL;
2097 AdjustQuiltRefChart();
2105 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2109 std::vector<int> empty_array;
2110 m_Piano->SetActiveKeyArray(empty_array);
2111 m_Piano->SetNoshowIndexArray(empty_array);
2112 m_Piano->SetEclipsedIndexArray(empty_array);
2115 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2116 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2117 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2118 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2120 m_Piano->SetRoundedRectangles(
false);
2126 if (!GetQuiltMode()) {
2131 if (m_bFollow ==
true) {
2139 if (!m_singleChart) {
2142 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2150 int cur_max_scale = (int)1e8;
2152 ChartBase *pChart = GetFirstQuiltChart();
2156 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2158 if (pChart->GetNativeScale() < cur_max_scale) {
2159 Candidate_Chart = pChart;
2160 cur_max_scale = pChart->GetNativeScale();
2163 pChart = GetNextQuiltChart();
2166 m_singleChart = Candidate_Chart;
2170 if (NULL == m_singleChart) {
2171 m_singleChart =
ChartData->OpenStackChartConditional(
2172 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2173 CHART_FAMILY_DONTCARE);
2179 InvalidateAllQuiltPatchs();
2181 if (m_singleChart) {
2182 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2183 std::vector<int> one_array;
2184 one_array.push_back(dbi);
2185 m_Piano->SetActiveKeyArray(one_array);
2188 if (m_singleChart) {
2189 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2193 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2197bool ChartCanvas::IsTempMenuBarEnabled() {
2200 wxGetOsVersion(&major);
2208double ChartCanvas::GetCanvasRangeMeters() {
2210 GetSize(&width, &height);
2211 int minDimension = wxMin(width, height);
2214 range *= cos(GetVP().clat * PI / 180.);
2218void ChartCanvas::SetCanvasRangeMeters(
double range) {
2220 GetSize(&width, &height);
2221 int minDimension = wxMin(width, height);
2223 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2227bool ChartCanvas::SetUserOwnship() {
2231 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2232 double factor_dusk = 0.5;
2233 double factor_night = 0.25;
2235 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2236 m_pos_image_user_day =
new wxImage;
2237 *m_pos_image_user_day = pbmp->ConvertToImage();
2238 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2240 int gimg_width = m_pos_image_user_day->GetWidth();
2241 int gimg_height = m_pos_image_user_day->GetHeight();
2244 m_pos_image_user_dusk =
new wxImage;
2245 m_pos_image_user_night =
new wxImage;
2247 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2248 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2250 for (
int iy = 0; iy < gimg_height; iy++) {
2251 for (
int ix = 0; ix < gimg_width; ix++) {
2252 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2253 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2254 m_pos_image_user_day->GetGreen(ix, iy),
2255 m_pos_image_user_day->GetBlue(ix, iy));
2256 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2257 hsv.value = hsv.value * factor_dusk;
2258 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2259 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2262 hsv = wxImage::RGBtoHSV(rgb);
2263 hsv.value = hsv.value * factor_night;
2264 nrgb = wxImage::HSVtoRGB(hsv);
2265 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2272 m_pos_image_user_grey_day =
new wxImage;
2273 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2275 m_pos_image_user_grey_dusk =
new wxImage;
2276 m_pos_image_user_grey_night =
new wxImage;
2278 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2279 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2281 for (
int iy = 0; iy < gimg_height; iy++) {
2282 for (
int ix = 0; ix < gimg_width; ix++) {
2283 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2284 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2285 m_pos_image_user_grey_day->GetGreen(ix, iy),
2286 m_pos_image_user_grey_day->GetBlue(ix, iy));
2287 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2288 hsv.value = hsv.value * factor_dusk;
2289 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2290 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2293 hsv = wxImage::RGBtoHSV(rgb);
2294 hsv.value = hsv.value * factor_night;
2295 nrgb = wxImage::HSVtoRGB(hsv);
2296 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2303 m_pos_image_user_yellow_day =
new wxImage;
2304 m_pos_image_user_yellow_dusk =
new wxImage;
2305 m_pos_image_user_yellow_night =
new wxImage;
2307 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2308 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2309 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2311 for (
int iy = 0; iy < gimg_height; iy++) {
2312 for (
int ix = 0; ix < gimg_width; ix++) {
2313 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2314 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2315 m_pos_image_user_grey_day->GetGreen(ix, iy),
2316 m_pos_image_user_grey_day->GetBlue(ix, iy));
2320 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2321 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2322 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2324 hsv = wxImage::RGBtoHSV(rgb);
2325 hsv.value = hsv.value * factor_dusk;
2326 nrgb = wxImage::HSVtoRGB(hsv);
2327 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2329 hsv = wxImage::RGBtoHSV(rgb);
2330 hsv.value = hsv.value * factor_night;
2331 nrgb = wxImage::HSVtoRGB(hsv);
2332 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2344 m_display_size_mm = size;
2351 double horizontal = sd.x;
2355 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2356 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2360 ps52plib->SetPPMM(m_pix_per_mm);
2365 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2367 m_display_size_mm, sd.x, sd.y);
2373 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2376 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2379void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2381 wxString msg(event.m_string.c_str(), wxConvUTF8);
2383 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2384 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2387 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2389 compress_msg_array.RemoveAt(event.thread);
2390 compress_msg_array.Insert( msg, event.thread);
2393 compress_msg_array.Add(msg);
2396 wxString combined_msg;
2397 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2398 combined_msg += compress_msg_array[i];
2399 combined_msg +=
"\n";
2403 pprog->Update(pprog_count, combined_msg, &skip );
2404 pprog->SetSize(pprog_size);
2409void ChartCanvas::InvalidateGL() {
2410 if (!m_glcc)
return;
2412 if (g_bopengl) m_glcc->Invalidate();
2414 if (m_Compass) m_Compass->UpdateStatus(
true);
2417int ChartCanvas::GetCanvasChartNativeScale() {
2419 if (!VPoint.b_quilt) {
2420 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2422 ret = (int)m_pQuilt->GetRefNativeScale();
2427ChartBase *ChartCanvas::GetChartAtCursor() {
2429 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2430 target_chart = m_singleChart;
2431 else if (VPoint.b_quilt)
2432 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2434 target_chart = NULL;
2435 return target_chart;
2438ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2442 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2444 target_chart = NULL;
2445 return target_chart;
2448int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2449 int new_dbIndex = -1;
2450 if (!VPoint.b_quilt) {
2451 if (m_pCurrentStack) {
2452 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2453 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2455 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2465 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2467 for (
unsigned int is = 0; is < im; is++) {
2469 m_pQuilt->GetExtendedStackIndexArray()[is]);
2472 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2482void ChartCanvas::EnablePaint(
bool b_enable) {
2483 m_b_paint_enable = b_enable;
2485 if (m_glcc) m_glcc->EnablePaint(b_enable);
2489bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2491void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2493std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2494 return m_pQuilt->GetQuiltIndexArray();
2498void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2499 VPoint.b_quilt = b_quilt;
2500 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2503bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2505int ChartCanvas::GetQuiltReferenceChartIndex() {
2506 return m_pQuilt->GetRefChartdbIndex();
2509void ChartCanvas::InvalidateAllQuiltPatchs() {
2510 m_pQuilt->InvalidateAllQuiltPatchs();
2513ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2514 return m_pQuilt->GetLargestScaleChart();
2517ChartBase *ChartCanvas::GetFirstQuiltChart() {
2518 return m_pQuilt->GetFirstChart();
2521ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2523int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2525void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2526 m_pQuilt->SetHiliteIndex(dbIndex);
2529void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2530 m_pQuilt->SetHiliteIndexArray(hilite_array);
2533void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2534 m_pQuilt->ClearHiliteIndexArray();
2537std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2539 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2542int ChartCanvas::GetQuiltRefChartdbIndex() {
2543 return m_pQuilt->GetRefChartdbIndex();
2546std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2547 return m_pQuilt->GetExtendedStackIndexArray();
2550std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2551 return m_pQuilt->GetFullscreenIndexArray();
2554std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2555 return m_pQuilt->GetEclipsedStackIndexArray();
2558void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2560double ChartCanvas::GetQuiltMaxErrorFactor() {
2561 return m_pQuilt->GetMaxErrorFactor();
2564bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2565 return m_pQuilt->IsChartQuiltableRef(db_index);
2569 double chartMaxScale =
2571 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2574void ChartCanvas::StartMeasureRoute() {
2575 if (!m_routeState) {
2576 if (m_bMeasure_Active) {
2578 m_pMeasureRoute = NULL;
2581 m_bMeasure_Active =
true;
2582 m_nMeasureState = 1;
2583 m_bDrawingRoute =
false;
2585 SetCursor(*pCursorPencil);
2590void ChartCanvas::CancelMeasureRoute() {
2591 m_bMeasure_Active =
false;
2592 m_nMeasureState = 0;
2593 m_bDrawingRoute =
false;
2596 m_pMeasureRoute = NULL;
2598 SetCursor(*pCursorArrow);
2601ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2603void ChartCanvas::SetVP(
ViewPort &vp) {
2614void ChartCanvas::TriggerDeferredFocus() {
2617 m_deferredFocusTimer.Start(20,
true);
2619#if defined(__WXGTK__) || defined(__WXOSX__)
2620 top_frame::Get()->Raise();
2630void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2635void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2636 if (SendKeyEventToPlugins(event))
2640 int key_char =
event.GetKeyCode();
2643 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2649 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2654 if (g_benable_rotate) {
2675void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2676 if (SendKeyEventToPlugins(event))
2680 bool b_handled =
false;
2682 m_modkeys =
event.GetModifiers();
2684 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2686#ifdef OCPN_ALT_MENUBAR
2692 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2694 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2695 if (!g_bTempShowMenuBar) {
2696 g_bTempShowMenuBar =
true;
2697 top_frame::Get()->ApplyGlobalSettings(
false);
2699 m_bMayToggleMenuBar =
false;
2705 if (event.GetKeyCode() != WXK_ALT) {
2706 m_bMayToggleMenuBar =
false;
2713 switch (event.GetKeyCode()) {
2720 event.GetPosition(&x, &y);
2721 m_FinishRouteOnKillFocus =
false;
2722 CallPopupMenu(x, y);
2723 m_FinishRouteOnKillFocus =
true;
2727 m_modkeys |= wxMOD_ALT;
2731 m_modkeys |= wxMOD_CONTROL;
2736 case WXK_RAW_CONTROL:
2737 m_modkeys |= wxMOD_RAW_CONTROL;
2742 if (m_modkeys == wxMOD_CONTROL)
2743 top_frame::Get()->DoStackDown(
this);
2745 StartTimedMovement();
2755 StartTimedMovement();
2763 if (m_modkeys == wxMOD_CONTROL)
2764 top_frame::Get()->DoStackUp(
this);
2766 StartTimedMovement();
2776 StartTimedMovement();
2784 if (event.ShiftDown()) {
2786 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2788 std::shared_ptr<HostApi> host_api;
2790 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2793 api_121->SelectChartFamily(m_canvasIndex,
2800 if (event.ShiftDown()) {
2802 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2804 std::shared_ptr<HostApi> host_api;
2806 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2809 api_121->SelectChartFamily(m_canvasIndex,
2812 SetShowENCText(!GetShowENCText());
2819 if (!m_bMeasure_Active) {
2820 if (event.ShiftDown())
2821 m_bMeasure_DistCircle =
true;
2823 m_bMeasure_DistCircle =
false;
2825 StartMeasureRoute();
2827 CancelMeasureRoute();
2829 SetCursor(*pCursorArrow);
2839 top_frame::Get()->ToggleColorScheme();
2840 top_frame::Get()->Raise();
2841 TriggerDeferredFocus();
2845 int mod = m_modkeys & wxMOD_SHIFT;
2846 if (mod != m_brightmod) {
2848 m_bbrightdir = !m_bbrightdir;
2851 if (!m_bbrightdir) {
2852 g_nbrightness -= 10;
2853 if (g_nbrightness <= MIN_BRIGHT) {
2854 g_nbrightness = MIN_BRIGHT;
2855 m_bbrightdir =
true;
2858 g_nbrightness += 10;
2859 if (g_nbrightness >= MAX_BRIGHT) {
2860 g_nbrightness = MAX_BRIGHT;
2861 m_bbrightdir =
false;
2865 SetScreenBrightness(g_nbrightness);
2866 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2869 top_frame::Get()->Raise();
2875 top_frame::Get()->DoStackDown(
this);
2879 top_frame::Get()->DoStackUp(
this);
2884 ToggleCanvasQuiltMode();
2890 top_frame::Get()->ToggleFullScreen();
2895 if (m_modkeys == wxMOD_ALT) {
2898 ToggleChartOutlines();
2904 top_frame::Get()->ActivateMOB();
2908 case WXK_NUMPAD_ADD:
2913 case WXK_NUMPAD_SUBTRACT:
2914 case WXK_PAGEDOWN: {
2915 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2920 if (m_bMeasure_Active) {
2921 if (m_nMeasureState > 2) {
2922 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2924 m_pMeasureRoute->GetnPoints();
2926 top_frame::Get()->RefreshAllCanvas();
2928 CancelMeasureRoute();
2929 StartMeasureRoute();
2937 if (event.GetKeyCode() < 128)
2939 int key_char =
event.GetKeyCode();
2943 if (!g_b_assume_azerty) {
2945 if (g_benable_rotate) {
2977 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2984 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2985 m_modkeys & wxMOD_RAW_CONTROL) {
2986 top_frame::Get()->ToggleFullScreen();
2991 if (event.ControlDown()) key_char -= 64;
2993 if (key_char >=
'0' && key_char <=
'9')
2994 SetGroupIndex(key_char -
'0');
2999 SetShowENCAnchor(!GetShowENCAnchor());
3005 top_frame::Get()->ToggleColorScheme();
3010 event.GetPosition(&x, &y);
3011 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3012 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3015 if (VPoint.b_quilt) {
3017 if (m_pQuilt->GetChartAtPix(
3022 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3024 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3029 if (m_singleChart) {
3030 ChartType = m_singleChart->GetChartType();
3031 ChartFam = m_singleChart->GetChartFamily();
3035 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3036 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3038 this, -1, ChartType, ChartFam,
3039 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3040 wxDefaultSize, wxSIMPLE_BORDER,
"");
3053 m_nmea_log->Raise();
3057 SetShowENCLights(!GetShowENCLights());
3063 if (event.ShiftDown())
3064 m_bMeasure_DistCircle =
true;
3066 m_bMeasure_DistCircle =
false;
3068 StartMeasureRoute();
3072 if (g_bInlandEcdis && ps52plib) {
3073 SetENCDisplayCategory((_DisCat)STANDARD);
3078 ToggleChartOutlines();
3082 ToggleCanvasQuiltMode();
3086 top_frame::Get()->ToggleTestPause();
3089 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3090 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3091 g_iNavAidRadarRingsNumberVisible = 1;
3092 else if (!g_bNavAidRadarRingsShown &&
3093 g_iNavAidRadarRingsNumberVisible == 1)
3094 g_iNavAidRadarRingsNumberVisible = 0;
3097 SetShowENCDepth(!m_encShowDepth);
3102 SetShowENCText(!GetShowENCText());
3107 SetShowENCDataQual(!GetShowENCDataQual());
3112 m_bShowNavobjects = !m_bShowNavobjects;
3127 if (g_bShowMenuBar ==
false) top_frame::Get()->ToggleChartBar(
this);
3132 if (event.ControlDown()) top_frame::Get()->DropMarker(
false);
3139 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3140 if ((indexActive + 1) <= r->GetnPoints()) {
3151 if (!g_bShowMenuBar) top_frame::Get()->DropMarker(
true);
3157 if (g_bSpaceDropMark) top_frame::Get()->DropMarker(
true);
3163 if (m_modkeys == wxMOD_CONTROL) top_frame::Get()->ActivateMOB();
3170 top_frame::Get()->DoSettings();
3174 parent_frame->Close();
3190 if (undo->AnythingToRedo()) {
3191 undo->RedoNextAction();
3198 if (event.ShiftDown()) {
3199 if (undo->AnythingToRedo()) {
3200 undo->RedoNextAction();
3205 if (undo->AnythingToUndo()) {
3206 undo->UndoLastAction();
3215 if (m_bMeasure_Active) {
3216 CancelMeasureRoute();
3218 SetCursor(*pCursorArrow);
3221 top_frame::Get()->RefreshAllCanvas();
3235 switch (gamma_state) {
3255 SetScreenBrightness(g_nbrightness);
3260 if (event.ControlDown()) {
3261 m_bShowCompassWin = !m_bShowCompassWin;
3262 SetShowGPSCompassWindow(m_bShowCompassWin);
3279void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3280 if (SendKeyEventToPlugins(event))
3284 switch (event.GetKeyCode()) {
3286 top_frame::Get()->SwitchKBFocus(
this);
3292 if (!m_pany) m_panspeed = 0;
3298 if (!m_panx) m_panspeed = 0;
3301 case WXK_NUMPAD_ADD:
3302 case WXK_NUMPAD_SUBTRACT:
3311 m_modkeys &= ~wxMOD_ALT;
3312#ifdef OCPN_ALT_MENUBAR
3317 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3318 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3319 top_frame::Get()->ApplyGlobalSettings(
false);
3321 m_bMayToggleMenuBar =
true;
3327 m_modkeys &= ~wxMOD_CONTROL;
3331 if (event.GetKeyCode() < 128)
3333 int key_char =
event.GetKeyCode();
3337 if (!g_b_assume_azerty) {
3352 m_rotation_speed = 0;
3370void ChartCanvas::ToggleChartOutlines() {
3371 m_bShowOutlines = !m_bShowOutlines;
3377 if (g_bopengl) InvalidateGL();
3381void ChartCanvas::ToggleLookahead() {
3382 m_bLookAhead = !m_bLookAhead;
3387void ChartCanvas::SetUpMode(
int mode) {
3390 if (mode != NORTH_UP_MODE) {
3393 if (!std::isnan(
gCog)) stuff =
gCog;
3396 auto cog_table = top_frame::Get()->GetCOGTable();
3397 for (
int i = 0; i <
g_COGAvgSec; i++) cog_table[i] = stuff;
3400 top_frame::Get()->StartCogTimer();
3402 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3403 SetVPRotation(GetVPSkew());
3408 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3409 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3411 UpdateGPSCompassStatusBox(
true);
3412 top_frame::Get()->DoChartUpdate();
3415bool ChartCanvas::DoCanvasCOGSet() {
3416 if (GetUpMode() == NORTH_UP_MODE)
return false;
3418 if (g_btenhertz) cog_use =
gCog;
3420 double rotation = 0;
3421 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3422 rotation = -
gHdt * PI / 180.;
3423 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3424 rotation = -cog_use * PI / 180.;
3426 SetVPRotation(rotation);
3430double easeOutCubic(
double t) {
3432 return 1.0 - pow(1.0 - t, 3.0);
3435void ChartCanvas::StartChartDragInertia() {
3436 m_bChartDragging =
false;
3439 m_chart_drag_inertia_time = 750;
3440 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3445 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3449 size_t length = m_drag_vec_t.size();
3450 for (
size_t i = 0; i < n_vel; i++) {
3451 xacc += m_drag_vec_x.at(length - 1 - i);
3452 yacc += m_drag_vec_y.at(length - 1 - i);
3453 tacc += m_drag_vec_t.at(length - 1 - i);
3456 if (tacc == 0)
return;
3458 double drag_velocity_x = xacc / tacc;
3459 double drag_velocity_y = yacc / tacc;
3465 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3467 m_chart_drag_velocity_x = drag_velocity_x;
3468 m_chart_drag_velocity_y = drag_velocity_y;
3470 m_chart_drag_inertia_active =
true;
3472 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3475void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3476 if (!m_chart_drag_inertia_active)
return;
3478 wxLongLong now = wxGetLocalTimeMillis();
3479 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3480 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3481 if (t > 1.0) t = 1.0;
3482 double e = 1.0 - easeOutCubic(t);
3485 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3487 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3489 m_last_elapsed = elapsed;
3493 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3494 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3495 double inertia_lat, inertia_lon;
3499 if (!IsOwnshipOnScreen()) {
3501 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3502 UpdateFollowButtonState();
3513 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3514 m_chart_drag_inertia_timer.Stop();
3517 m_target_lat = GetVP().
clat;
3518 m_target_lon = GetVP().
clon;
3519 m_pan_drag.x = m_pan_drag.y = 0;
3520 m_panx = m_pany = 0;
3521 m_chart_drag_inertia_active =
false;
3525 int target_redraw_interval = 40;
3526 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3530void ChartCanvas::StopMovement() {
3531 m_panx = m_pany = 0;
3534 m_rotation_speed = 0;
3537#if !defined(__WXGTK__) && !defined(__WXQT__)
3539 top_frame::Get()->Raise();
3548bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3550 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3552 if (!pMovementTimer->IsRunning()) {
3553 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3556 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3561 m_last_movement_time = wxDateTime::UNow();
3565void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3568 m_target_lat = target_lat;
3569 m_target_lon = target_lon;
3572 m_start_lat = GetVP().
clat;
3573 m_start_lon = GetVP().
clon;
3575 m_VPMovementTimer.Start(1,
true);
3576 m_timed_move_vp_active =
true;
3578 m_timedVP_step = nstep;
3581void ChartCanvas::DoTimedMovementVP() {
3582 if (!m_timed_move_vp_active)
return;
3583 if (m_stvpc++ > m_timedVP_step * 2) {
3590 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3605 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3606 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3608 m_run_lat = new_lat;
3609 m_run_lon = new_lon;
3614void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3616void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3618void ChartCanvas::StartTimedMovementTarget() {}
3620void ChartCanvas::DoTimedMovementTarget() {}
3622void ChartCanvas::StopMovementTarget() {}
3625void ChartCanvas::DoTimedMovement() {
3626 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3630 wxDateTime now = wxDateTime::UNow();
3632 if (m_last_movement_time.IsValid())
3633 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3635 m_last_movement_time = now;
3645 if (dt == 0) dt = 1;
3648 if (m_mustmove < 0) m_mustmove = 0;
3651 if (m_pan_drag.x || m_pan_drag.y) {
3653 m_pan_drag.x = m_pan_drag.y = 0;
3656 if (m_panx || m_pany) {
3657 const double slowpan = .1, maxpan = 2;
3658 if (m_modkeys == wxMOD_ALT)
3659 m_panspeed = slowpan;
3661 m_panspeed += (double)dt / 500;
3662 m_panspeed = wxMin(maxpan, m_panspeed);
3664 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3667 if (m_zoom_factor != 1) {
3668 double alpha = 400, beta = 1.5;
3669 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3671 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3673 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3678 if (zoom_factor > 1) {
3679 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3683 else if (zoom_factor < 1) {
3684 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3689 if (fabs(zoom_factor - 1) > 1e-4) {
3690 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3695 if (m_wheelzoom_stop_oneshot > 0) {
3696 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3697 m_wheelzoom_stop_oneshot = 0;
3702 if (zoom_factor > 1) {
3704 m_wheelzoom_stop_oneshot = 0;
3707 }
else if (zoom_factor < 1) {
3709 m_wheelzoom_stop_oneshot = 0;
3716 if (m_rotation_speed) {
3717 double speed = m_rotation_speed;
3718 if (m_modkeys == wxMOD_ALT) speed /= 10;
3719 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3723void ChartCanvas::SetColorScheme(ColorScheme cs) {
3728 case GLOBAL_COLOR_SCHEME_DAY:
3729 m_pos_image_red = &m_os_image_red_day;
3730 m_pos_image_grey = &m_os_image_grey_day;
3731 m_pos_image_yellow = &m_os_image_yellow_day;
3732 m_pos_image_user = m_pos_image_user_day;
3733 m_pos_image_user_grey = m_pos_image_user_grey_day;
3734 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3735 m_cTideBitmap = m_bmTideDay;
3736 m_cCurrentBitmap = m_bmCurrentDay;
3739 case GLOBAL_COLOR_SCHEME_DUSK:
3740 m_pos_image_red = &m_os_image_red_dusk;
3741 m_pos_image_grey = &m_os_image_grey_dusk;
3742 m_pos_image_yellow = &m_os_image_yellow_dusk;
3743 m_pos_image_user = m_pos_image_user_dusk;
3744 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3745 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3746 m_cTideBitmap = m_bmTideDusk;
3747 m_cCurrentBitmap = m_bmCurrentDusk;
3749 case GLOBAL_COLOR_SCHEME_NIGHT:
3750 m_pos_image_red = &m_os_image_red_night;
3751 m_pos_image_grey = &m_os_image_grey_night;
3752 m_pos_image_yellow = &m_os_image_yellow_night;
3753 m_pos_image_user = m_pos_image_user_night;
3754 m_pos_image_user_grey = m_pos_image_user_grey_night;
3755 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3756 m_cTideBitmap = m_bmTideNight;
3757 m_cCurrentBitmap = m_bmCurrentNight;
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;
3771 CreateDepthUnitEmbossMaps(cs);
3772 CreateOZEmbossMapData(cs);
3775 m_fog_color = wxColor(
3779 case GLOBAL_COLOR_SCHEME_DUSK:
3782 case GLOBAL_COLOR_SCHEME_NIGHT:
3788 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3789 m_fog_color.Blue() * dim);
3793 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3794 SetBackgroundColour( wxColour(0,0,0) );
3796 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3799 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3801 SetBackgroundColour( wxNullColour );
3808 m_Piano->SetColorScheme(cs);
3810 m_Compass->SetColorScheme(cs);
3812 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3814 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3816 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3817 if (m_notification_button) {
3818 m_notification_button->SetColorScheme(cs);
3822 if (g_bopengl && m_glcc) {
3823 m_glcc->SetColorScheme(cs);
3829 m_brepaint_piano =
true;
3836wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3837 wxImage img = Bitmap.ConvertToImage();
3838 int sx = img.GetWidth();
3839 int sy = img.GetHeight();
3841 wxImage new_img(img);
3843 for (
int i = 0; i < sx; i++) {
3844 for (
int j = 0; j < sy; j++) {
3845 if (!img.IsTransparent(i, j)) {
3846 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3847 (
unsigned char)(img.GetGreen(i, j) * factor),
3848 (
unsigned char)(img.GetBlue(i, j) * factor));
3853 wxBitmap ret = wxBitmap(new_img);
3858void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3861 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3863 if (!m_pBrightPopup) {
3866 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3870 m_pBrightPopup->SetSize(x, y);
3871 m_pBrightPopup->Move(120, 120);
3874 int bmpsx = m_pBrightPopup->GetSize().x;
3875 int bmpsy = m_pBrightPopup->GetSize().y;
3877 wxBitmap bmp(bmpsx, bmpsx);
3878 wxMemoryDC mdc(bmp);
3880 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3881 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3882 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3883 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3886 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3888 mdc.SetFont(*pfont);
3891 if (brightness == max)
3893 else if (brightness == min)
3896 val.Printf(
"%3d", brightness);
3898 mdc.DrawText(val, 0, 0);
3900 mdc.SelectObject(wxNullBitmap);
3902 m_pBrightPopup->SetBitmap(bmp);
3903 m_pBrightPopup->Show();
3904 m_pBrightPopup->Refresh();
3907void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3908 m_b_rot_hidef =
true;
3912void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3915 bool b_need_refresh =
false;
3917 wxSize win_size = GetSize() * m_displayScale;
3921 bool showAISRollover =
false;
3923 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3927 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3928 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3931 showAISRollover =
true;
3933 if (NULL == m_pAISRolloverWin) {
3935 m_pAISRolloverWin->IsActive(
false);
3936 b_need_refresh =
true;
3937 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3938 m_AISRollover_MMSI != FoundAIS_MMSI) {
3944 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3945 m_pAISRolloverWin->IsActive(
false);
3946 m_AISRollover_MMSI = 0;
3951 m_AISRollover_MMSI = FoundAIS_MMSI;
3953 if (!m_pAISRolloverWin->IsActive()) {
3954 wxString s = ptarget->GetRolloverString();
3955 m_pAISRolloverWin->SetString(s);
3957 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3958 AIS_ROLLOVER, win_size);
3959 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3960 m_pAISRolloverWin->IsActive(
true);
3961 b_need_refresh =
true;
3965 m_AISRollover_MMSI = 0;
3966 showAISRollover =
false;
3971 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3972 m_pAISRolloverWin->IsActive(
false);
3973 m_AISRollover_MMSI = 0;
3974 b_need_refresh =
true;
3979 bool showRouteRollover =
false;
3981 if (NULL == m_pRolloverRouteSeg) {
3985 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3986 SelectableItemList SelList =
pSelect->FindSelectionList(
3988 auto node = SelList.begin();
3989 while (node != SelList.end()) {
3994 if (pr && pr->IsVisible()) {
3995 m_pRolloverRouteSeg = pFindSel;
3996 showRouteRollover =
true;
3998 if (NULL == m_pRouteRolloverWin) {
4000 m_pRouteRolloverWin->IsActive(
false);
4003 if (!m_pRouteRolloverWin->IsActive()) {
4011 DistanceBearingMercator(
4012 segShow_point_b->m_lat, segShow_point_b->m_lon,
4013 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4015 if (!pr->m_bIsInLayer)
4016 s.Append(_(
"Route") +
": ");
4018 s.Append(_(
"Layer Route: "));
4020 if (pr->m_RouteNameString.IsEmpty())
4021 s.Append(_(
"(unnamed)"));
4023 s.Append(pr->m_RouteNameString);
4028 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4029 << segShow_point_b->GetName() <<
"\n";
4032 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4033 (
int)floor(brg + 0.5), 0x00B0);
4036 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4038 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4040 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4042 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4043 (
int)floor(varBrg + 0.5), 0x00B0);
4051 double shiptoEndLeg = 0.;
4052 bool validActive =
false;
4053 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4056 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4057 auto node = pr->pRoutePointList->begin();
4059 float dist_to_endleg = 0;
4062 for (++node; node != pr->pRoutePointList->end(); ++node) {
4069 if (prp->IsSame(segShow_point_a))
break;
4077 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4080 ->GetCurrentRngToActivePoint();
4089 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4094 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4095 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4097 << wxString(ttg_sec > SECONDS_PER_DAY
4098 ? ttg_span.Format(_(
"%Dd %H:%M"))
4099 : ttg_span.Format(_(
"%H:%M")));
4100 wxDateTime dtnow, eta;
4101 eta = dtnow.SetToCurrent().Add(ttg_span);
4102 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4103 << eta.Format(
" %d %H:%M");
4107 m_pRouteRolloverWin->SetString(s);
4109 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4110 LEG_ROLLOVER, win_size);
4111 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4112 m_pRouteRolloverWin->IsActive(
true);
4113 b_need_refresh =
true;
4114 showRouteRollover =
true;
4123 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4125 m_pRolloverRouteSeg))
4126 showRouteRollover =
false;
4127 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4128 showRouteRollover =
false;
4130 showRouteRollover =
true;
4134 if (m_routeState) showRouteRollover =
false;
4137 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4138 showRouteRollover =
false;
4140 if (m_pRouteRolloverWin &&
4141 !showRouteRollover) {
4142 m_pRouteRolloverWin->IsActive(
false);
4143 m_pRolloverRouteSeg = NULL;
4144 m_pRouteRolloverWin->Destroy();
4145 m_pRouteRolloverWin = NULL;
4146 b_need_refresh =
true;
4147 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4148 m_pRouteRolloverWin->IsActive(
true);
4149 b_need_refresh =
true;
4154 bool showTrackRollover =
false;
4156 if (NULL == m_pRolloverTrackSeg) {
4160 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4161 SelectableItemList SelList =
pSelect->FindSelectionList(
4164 auto node = SelList.begin();
4165 while (node != SelList.end()) {
4170 if (pt && pt->IsVisible()) {
4171 m_pRolloverTrackSeg = pFindSel;
4172 showTrackRollover =
true;
4174 if (NULL == m_pTrackRolloverWin) {
4176 m_pTrackRolloverWin->IsActive(
false);
4179 if (!m_pTrackRolloverWin->IsActive()) {
4187 DistanceBearingMercator(
4188 segShow_point_b->m_lat, segShow_point_b->m_lon,
4189 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4191 if (!pt->m_bIsInLayer)
4192 s.Append(_(
"Track") +
": ");
4194 s.Append(_(
"Layer Track: "));
4196 if (pt->GetName().IsEmpty())
4197 s.Append(_(
"(unnamed)"));
4199 s.Append(pt->GetName());
4200 double tlenght = pt->Length();
4202 if (pt->GetLastPoint()->GetTimeString() &&
4203 pt->GetPoint(0)->GetTimeString()) {
4204 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4205 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4206 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4207 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4208 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4209 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4210 << getUsrSpeedUnit();
4211 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4212 : ttime.Format(
" %H:%M"));
4216 if (g_bShowTrackPointTime &&
4217 strlen(segShow_point_b->GetTimeString())) {
4218 wxString stamp = segShow_point_b->GetTimeString();
4219 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4220 if (timestamp.IsValid()) {
4224 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4226 s <<
"\n" << _(
"Segment Created: ") << stamp;
4231 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4236 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4238 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4240 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4242 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4248 if (segShow_point_a->GetTimeString() &&
4249 segShow_point_b->GetTimeString()) {
4250 wxDateTime apoint = segShow_point_a->GetCreateTime();
4251 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4252 if (apoint.IsValid() && bpoint.IsValid()) {
4253 double segmentSpeed = toUsrSpeed(
4254 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4255 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4256 << getUsrSpeedUnit();
4260 m_pTrackRolloverWin->SetString(s);
4262 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4263 LEG_ROLLOVER, win_size);
4264 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4265 m_pTrackRolloverWin->IsActive(
true);
4266 b_need_refresh =
true;
4267 showTrackRollover =
true;
4276 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4278 m_pRolloverTrackSeg))
4279 showTrackRollover =
false;
4280 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4281 showTrackRollover =
false;
4283 showTrackRollover =
true;
4287 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4288 showTrackRollover =
false;
4291 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4292 showTrackRollover =
false;
4298 if (m_pTrackRolloverWin &&
4299 !showTrackRollover) {
4300 m_pTrackRolloverWin->IsActive(
false);
4301 m_pRolloverTrackSeg = NULL;
4302 m_pTrackRolloverWin->Destroy();
4303 m_pTrackRolloverWin = NULL;
4304 b_need_refresh =
true;
4305 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4306 m_pTrackRolloverWin->IsActive(
true);
4307 b_need_refresh =
true;
4310 if (b_need_refresh) Refresh();
4313void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4314 if ((GetShowENCLights() || m_bsectors_shown) &&
4315 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4316 extendedSectorLegs)) {
4317 if (!m_bsectors_shown) {
4319 m_bsectors_shown =
true;
4322 if (m_bsectors_shown) {
4324 m_bsectors_shown =
false;
4332#if defined(__WXGTK__) || defined(__WXQT__)
4337 double cursor_lat, cursor_lon;
4340 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4341 while (cursor_lon < -180.) cursor_lon += 360.;
4343 while (cursor_lon > 180.) cursor_lon -= 360.;
4345 SetCursorStatus(cursor_lat, cursor_lon);
4351void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4352 if (!top_frame::Get()->GetFrameStatusBar())
return;
4356 s1 += toSDMM(1, cursor_lat);
4358 s1 += toSDMM(2, cursor_lon);
4360 if (STAT_FIELD_CURSOR_LL >= 0)
4361 top_frame::Get()->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4363 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4368 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4369 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4370 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4372 wxString s = st + sm;
4385 if (g_bShowLiveETA) {
4388 float boatSpeedDefault = g_defaultBoatSpeed;
4393 if (!std::isnan(
gSog)) {
4395 if (boatSpeed < 0.5) {
4398 realTimeETA = dist / boatSpeed * 60;
4407 s << minutesToHoursDays(realTimeETA);
4412 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4413 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4415 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4420 top_frame::Get()->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4428wxString minutesToHoursDays(
float timeInMinutes) {
4431 if (timeInMinutes == 0) {
4436 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4437 s << wxString::Format(
"%d", (
int)timeInMinutes);
4442 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4445 hours = (int)timeInMinutes / 60;
4446 min = (int)timeInMinutes % 60;
4449 s << wxString::Format(
"%d", hours);
4452 s << wxString::Format(
"%d", hours);
4454 s << wxString::Format(
"%d", min);
4461 else if (timeInMinutes > 24 * 60) {
4464 days = (int)(timeInMinutes / 60) / 24;
4465 hours = (int)(timeInMinutes / 60) % 24;
4468 s << wxString::Format(
"%d", days);
4471 s << wxString::Format(
"%d", days);
4473 s << wxString::Format(
"%d", hours);
4485void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4493 wxPoint2DDouble *r) {
4498 double rlon, wxPoint2DDouble *r) {
4509 if (!g_bopengl && m_singleChart &&
4510 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4511 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4512 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4513 (m_singleChart->GetChartProjectionType() !=
4514 PROJECTION_TRANSVERSE_MERCATOR) &&
4515 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4516 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4517 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4531 Cur_BSB_Ch->SetVPRasterParms(vp);
4532 double rpixxd, rpixyd;
4533 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4559 if (std::isnan(p.m_x)) {
4560 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4564 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4565 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4567 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4586 if (!g_bopengl && m_singleChart &&
4587 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4588 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4589 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4590 (m_singleChart->GetChartProjectionType() !=
4591 PROJECTION_TRANSVERSE_MERCATOR) &&
4592 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4593 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4594 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4605 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4608 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4613 else if (slon > 180.)
4624 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4630 DoZoomCanvas(factor,
false);
4631 extendedSectorLegs.clear();
4636 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4639 if (StartTimedMovement(stoptimer)) {
4641 m_zoom_factor = factor;
4646 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4648 DoZoomCanvas(factor, can_zoom_to_cursor);
4651 extendedSectorLegs.clear();
4654void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4657 if (!m_pCurrentStack)
return;
4663 if (m_bzooming)
return;
4672 double proposed_scale_onscreen =
4675 bool b_do_zoom =
false;
4684 if (!VPoint.b_quilt) {
4687 if (!m_disable_adjust_on_zoom) {
4688 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4689 if (new_db_index >= 0)
4690 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4694 int current_ref_stack_index = -1;
4695 if (m_pCurrentStack->nEntry) {
4697 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4698 m_pQuilt->SetReferenceChart(trial_index);
4699 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4700 if (new_db_index >= 0)
4701 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4705 if (m_pCurrentStack)
4706 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4717 double min_allowed_scale =
4720 if (proposed_scale_onscreen < min_allowed_scale) {
4725 proposed_scale_onscreen = min_allowed_scale;
4729 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4732 }
else if (factor < 1) {
4737 bool b_smallest =
false;
4739 if (!VPoint.b_quilt) {
4744 LLBBox viewbox = VPoint.GetBBox();
4746 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4747 double max_allowed_scale;
4761 if (proposed_scale_onscreen > max_allowed_scale) {
4763 proposed_scale_onscreen = max_allowed_scale;
4768 if (!m_disable_adjust_on_zoom) {
4770 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4771 if (new_db_index >= 0)
4772 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4774 if (m_pCurrentStack)
4775 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4778 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4780 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4781 proposed_scale_onscreen =
4782 wxMin(proposed_scale_onscreen,
4788 m_absolute_min_scale_ppm)
4789 proposed_scale_onscreen =
4798 bool b_allow_ztc =
true;
4799 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4800 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4802 double brg, distance;
4803 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4806 meters_to_shift = distance * 1852;
4814 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4817 if (m_bFollow) DoCanvasUpdate();
4824void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4826 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4830void ChartCanvas::RotateCanvas(
double dir) {
4834 if (StartTimedMovement()) {
4836 m_rotation_speed = dir * 60;
4839 double speed = dir * 10;
4840 if (m_modkeys == wxMOD_ALT) speed /= 20;
4841 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4845void ChartCanvas::DoRotateCanvas(
double rotation) {
4846 while (rotation < 0) rotation += 2 * PI;
4847 while (rotation > 2 * PI) rotation -= 2 * PI;
4849 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4851 SetVPRotation(rotation);
4852 top_frame::Get()->UpdateRotationState(VPoint.
rotation);
4855void ChartCanvas::DoTiltCanvas(
double tilt) {
4856 while (tilt < 0) tilt = 0;
4857 while (tilt > .95) tilt = .95;
4859 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4865void ChartCanvas::TogglebFollow() {
4872void ChartCanvas::ClearbFollow() {
4875 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4877 UpdateFollowButtonState();
4881 top_frame::Get()->SetChartUpdatePeriod();
4884void ChartCanvas::SetbFollow() {
4887 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4888 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4896 p.m_x += m_OSoffsetx;
4897 p.m_y -= m_OSoffsety;
4906 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4907 UpdateFollowButtonState();
4909 if (!g_bSmoothRecenter) {
4913 top_frame::Get()->SetChartUpdatePeriod();
4916void ChartCanvas::UpdateFollowButtonState() {
4919 m_muiBar->SetFollowButtonState(0);
4922 m_muiBar->SetFollowButtonState(2);
4924 m_muiBar->SetFollowButtonState(1);
4930 androidSetFollowTool(0);
4933 androidSetFollowTool(2);
4935 androidSetFollowTool(1);
4942 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4943 if (pic->m_enabled && pic->m_init_state) {
4944 switch (pic->m_api_version) {
4947 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4958void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4959 if (g_bSmoothRecenter && !m_routeState) {
4960 if (StartSmoothJump(lat, lon, scale_ppm))
4964 double gcDist, gcBearingEnd;
4965 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4967 gcBearingEnd += 180;
4968 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4971 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4972 double new_lat = lat + (lat_offset / (1852 * 60));
4973 double new_lon = lon + (lon_offset / (1852 * 60));
4976 StartSmoothJump(lat, lon, scale_ppm);
4981 if (lon > 180.0) lon -= 360.0;
4987 if (!GetQuiltMode()) {
4989 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4990 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4994 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4995 AdjustQuiltRefChart();
5002 UpdateFollowButtonState();
5010bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5015 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5016 double distance_pixels = gcDist *
GetVPScale();
5017 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5023 m_startLat = m_vLat;
5024 m_startLon = m_vLon;
5029 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5030 m_endScale = scale_ppm;
5033 m_animationDuration = 600;
5034 m_animationStart = wxGetLocalTimeMillis();
5041 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5042 m_animationActive =
true;
5047void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5049 wxLongLong now = wxGetLocalTimeMillis();
5050 double elapsed = (now - m_animationStart).ToDouble();
5051 double t = elapsed / m_animationDuration.ToDouble();
5052 if (t > 1.0) t = 1.0;
5055 double e = easeOutCubic(t);
5058 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5059 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5060 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5065 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5071 m_animationActive =
false;
5072 UpdateFollowButtonState();
5081 extendedSectorLegs.clear();
5090 if (iters++ > 5)
return false;
5091 if (!std::isnan(dlat))
break;
5094 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5100 else if (dlat < -90)
5103 if (dlon > 360.) dlon -= 360.;
5104 if (dlon < -360.) dlon += 360.;
5119 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5123 if (VPoint.b_quilt) {
5124 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5125 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5129 double tweak_scale_ppm =
5135 if (new_ref_dbIndex == -1) {
5136#pragma GCC diagnostic push
5137#pragma GCC diagnostic ignored "-Warray-bounds"
5144 int trial_index = -1;
5145 if (m_pCurrentStack->nEntry) {
5147 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5150 if (trial_index < 0) {
5151 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5152 if (full_screen_array.size())
5153 trial_index = full_screen_array[full_screen_array.size() - 1];
5156 if (trial_index >= 0) {
5157 m_pQuilt->SetReferenceChart(trial_index);
5162#pragma GCC diagnostic pop
5169 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5171 double offset_angle = atan2(offy, offx);
5172 double offset_distance = sqrt((offy * offy) + (offx * offx));
5173 double chart_angle = GetVPRotation();
5174 double target_angle = chart_angle - offset_angle;
5175 double d_east_mod = offset_distance * cos(target_angle);
5176 double d_north_mod = offset_distance * sin(target_angle);
5181 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5182 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5184 UpdateFollowButtonState();
5190 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5195bool ChartCanvas::IsOwnshipOnScreen() {
5198 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5199 ((r.y > 0) && r.y < GetCanvasHeight()))
5205void ChartCanvas::ReloadVP(
bool b_adjust) {
5206 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5208 LoadVP(VPoint, b_adjust);
5211void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5213 if (g_bopengl && m_glcc) {
5214 m_glcc->Invalidate();
5215 if (m_glcc->GetSize() != GetSize()) {
5216 m_glcc->SetSize(GetSize());
5221 m_cache_vp.Invalidate();
5222 m_bm_cache_vp.Invalidate();
5225 VPoint.Invalidate();
5227 if (m_pQuilt) m_pQuilt->Invalidate();
5236 vp.m_projection_type, b_adjust);
5239void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5240 m_pQuilt->SetReferenceChart(dbIndex);
5241 VPoint.Invalidate();
5242 m_pQuilt->Invalidate();
5245double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5247 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5254int ChartCanvas::AdjustQuiltRefChart() {
5259 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5261 double min_ref_scale =
5262 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5263 double max_ref_scale =
5264 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5267 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5268 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5269 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5271 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5274 int target_stack_index = wxNOT_FOUND;
5276 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5277 if (index == m_pQuilt->GetRefChartdbIndex()) {
5278 target_stack_index = il;
5283 if (wxNOT_FOUND == target_stack_index)
5284 target_stack_index = 0;
5286 int ref_family = pc->GetChartFamily();
5287 int extended_array_count =
5288 m_pQuilt->GetExtendedStackIndexArray().size();
5289 while ((!brender_ok) &&
5290 ((
int)target_stack_index < (extended_array_count - 1))) {
5291 target_stack_index++;
5293 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5295 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5296 IsChartQuiltableRef(test_db_index)) {
5299 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5301 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5308 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5309 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5310 IsChartQuiltableRef(new_db_index)) {
5311 m_pQuilt->SetReferenceChart(new_db_index);
5314 ret = m_pQuilt->GetRefChartdbIndex();
5316 ret = m_pQuilt->GetRefChartdbIndex();
5319 ret = m_pQuilt->GetRefChartdbIndex();
5328void ChartCanvas::UpdateCanvasOnGroupChange() {
5329 delete m_pCurrentStack;
5341bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5342 double latNE,
double lonNE) {
5344 double latc = (latSW + latNE) / 2.0;
5345 double lonc = (lonSW + lonNE) / 2.0;
5348 double ne_easting, ne_northing;
5349 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5351 double sw_easting, sw_northing;
5352 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5354 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5361 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5364bool ChartCanvas::SetVPProjection(
int projection) {
5370 double prev_true_scale_ppm = m_true_scale_ppm;
5375 m_absolute_min_scale_ppm));
5383bool ChartCanvas::SetVPRotation(
double angle) {
5385 VPoint.
skew, angle);
5388 double skew,
double rotation,
int projection,
5389 bool b_adjust,
bool b_refresh) {
5395 if (VPoint.IsValid()) {
5396 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5397 (fabs(VPoint.
skew - skew) < 1e-9) &&
5398 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5399 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5400 (VPoint.m_projection_type == projection ||
5401 projection == PROJECTION_UNKNOWN))
5404 if (VPoint.m_projection_type != projection)
5405 VPoint.InvalidateTransformCache();
5415 if (projection != PROJECTION_UNKNOWN)
5416 VPoint.SetProjectionType(projection);
5417 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5418 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5421 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5422 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5423 if (VPoint.
clat > 89.5)
5425 else if (VPoint.
clat < -89.5)
5426 VPoint.
clat = -89.5;
5431 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5432 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5444 bool bwasValid = VPoint.IsValid();
5449 m_cache_vp.Invalidate();
5454 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5458 int mouseX = mouse_x;
5459 int mouseY = mouse_y;
5460 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5466 SendCursorLatLonToAllPlugIns(lat, lon);
5469 if (!VPoint.b_quilt && m_singleChart) {
5474 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5478 if ((!m_cache_vp.IsValid()) ||
5483 wxPoint cp_last, cp_this;
5487 if (cp_last != cp_this) {
5493 if (m_pCurrentStack) {
5495 int current_db_index;
5497 m_pCurrentStack->GetCurrentEntrydbIndex();
5499 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5501 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5504 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5508 if (VPoint.b_quilt) {
5512 m_pQuilt->InvalidateAllQuiltPatchs();
5516 if (!m_pCurrentStack)
return false;
5518 int current_db_index;
5520 m_pCurrentStack->GetCurrentEntrydbIndex();
5522 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5523 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5526 int current_ref_stack_index = -1;
5527 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5528 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5529 current_ref_stack_index = i;
5532 if (g_bFullScreenQuilt) {
5533 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5537 bool b_needNewRef =
false;
5540 if ((-1 == current_ref_stack_index) &&
5541 (m_pQuilt->GetRefChartdbIndex() >= 0))
5542 b_needNewRef =
true;
5549 bool renderable =
true;
5551 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5552 if (referenceChart) {
5553 double chartMaxScale = referenceChart->GetNormalScaleMax(
5555 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5557 if (!renderable) b_needNewRef =
true;
5560 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5562 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5563 int target_scale = cte_ref.GetScale();
5564 int target_type = cte_ref.GetChartType();
5565 int candidate_stack_index;
5572 candidate_stack_index = 0;
5573 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5575 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5576 int candidate_scale = cte_candidate.GetScale();
5577 int candidate_type = cte_candidate.GetChartType();
5579 if ((candidate_scale >= target_scale) &&
5580 (candidate_type == target_type)) {
5581 bool renderable =
true;
5583 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5584 if (tentative_referenceChart) {
5585 double chartMaxScale =
5586 tentative_referenceChart->GetNormalScaleMax(
5588 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5591 if (renderable)
break;
5594 candidate_stack_index++;
5599 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5600 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5601 while (candidate_stack_index >= 0) {
5602 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5606 int candidate_scale = cte_candidate.GetScale();
5607 int candidate_type = cte_candidate.GetChartType();
5609 if ((candidate_scale <= target_scale) &&
5610 (candidate_type == target_type))
5613 candidate_stack_index--;
5618 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5619 (candidate_stack_index < 0))
5620 candidate_stack_index = 0;
5622 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5624 m_pQuilt->SetReferenceChart(new_ref_index);
5630 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5635 bool renderable =
true;
5637 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5638 if (referenceChart) {
5639 double chartMaxScale = referenceChart->GetNormalScaleMax(
5641 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5642 proj =
ChartData->GetDBChartProj(ref_db_index);
5644 proj = PROJECTION_MERCATOR;
5646 VPoint.b_MercatorProjectionOverride =
5647 (m_pQuilt->GetnCharts() == 0 || !renderable);
5649 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5651 VPoint.SetProjectionType(proj);
5656 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5661 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5681 m_pQuilt->Invalidate();
5698 if (b_refresh) Refresh(
false);
5705 }
else if (!g_bopengl) {
5706 OcpnProjType projection = PROJECTION_UNKNOWN;
5709 projection = m_singleChart->GetChartProjectionType();
5710 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5711 VPoint.SetProjectionType(projection);
5715 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5716 m_cache_vp.Invalidate();
5720 UpdateCanvasControlBar();
5724 if (VPoint.GetBBox().GetValid()) {
5727 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5736 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5739 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5746 wxPoint2DDouble r, r1;
5748 double delta_check =
5752 double check_point = wxMin(89., VPoint.
clat);
5754 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5757 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5758 VPoint.
clon, 0, &rhumbDist);
5763 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5764 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5766 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5770 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5776 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5778 if (m_true_scale_ppm)
5779 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5784 double round_factor = 1000.;
5788 round_factor = 100.;
5790 round_factor = 1000.;
5793 double retina_coef = 1;
5797 retina_coef = GetContentScaleFactor();
5808 double true_scale_display =
5809 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5814 if (m_displayed_scale_factor > 10.0)
5815 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5816 m_displayed_scale_factor);
5817 else if (m_displayed_scale_factor > 1.0)
5818 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5819 m_displayed_scale_factor);
5820 else if (m_displayed_scale_factor > 0.1) {
5821 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5822 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5823 }
else if (m_displayed_scale_factor > 0.01) {
5824 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5825 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5828 "%s %4.0f (---)", _(
"Scale"),
5829 true_scale_display);
5832 m_scaleValue = true_scale_display;
5834 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5836 if (m_bShowScaleInStatusBar && top_frame::Get()->GetStatusBar() &&
5837 (top_frame::Get()->GetStatusBar()->GetFieldsCount() >
5838 STAT_FIELD_SCALE)) {
5840 bool b_noshow =
false;
5844 wxClientDC dc(top_frame::Get()->GetStatusBar());
5846 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5847 dc.SetFont(*templateFont);
5848 dc.GetTextExtent(text, &w, &h);
5853 top_frame::Get()->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE,
5855 if (w && w > rect.width) {
5856 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5860 dc.GetTextExtent(text, &w, &h);
5862 if (w && w > rect.width) {
5868 if (!b_noshow) top_frame::Get()->SetStatusText(text, STAT_FIELD_SCALE);
5873 m_vLat = VPoint.
clat;
5874 m_vLon = VPoint.
clon;
5888static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5892static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5893 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5895wxColour ChartCanvas::PredColor() {
5898 if (SHIP_NORMAL == m_ownship_state)
5899 return GetGlobalColor(
"URED");
5901 else if (SHIP_LOWACCURACY == m_ownship_state)
5902 return GetGlobalColor(
"YELO1");
5904 return GetGlobalColor(
"NODTA");
5907wxColour ChartCanvas::ShipColor() {
5911 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5913 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5915 return GetGlobalColor(
"URED");
5918void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5919 wxPoint2DDouble lShipMidPoint) {
5920 dc.SetPen(wxPen(PredColor(), 2));
5922 if (SHIP_NORMAL == m_ownship_state)
5923 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5925 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5927 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5928 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5930 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5932 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5933 lShipMidPoint.m_y + 12);
5936void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5937 wxPoint GPSOffsetPixels,
5938 wxPoint2DDouble lGPSPoint) {
5943 float ref_dim = m_display_size_mm / 24;
5944 ref_dim = wxMin(ref_dim, 12);
5945 ref_dim = wxMax(ref_dim, 6);
5948 cPred.Set(g_cog_predictor_color);
5949 if (cPred == wxNullColour) cPred = PredColor();
5956 double nominal_line_width_pix = wxMax(
5958 floor(m_pix_per_mm / 2));
5962 if (nominal_line_width_pix > g_cog_predictor_width)
5963 g_cog_predictor_width = nominal_line_width_pix;
5966 wxPoint lPredPoint, lHeadPoint;
5968 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5969 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5971 double pred_lat, pred_lon;
5972 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5973 &pred_lat, &pred_lon);
5984 float ndelta_pix = 10.;
5985 double hdg_pred_lat, hdg_pred_lon;
5986 bool b_render_hdt =
false;
5987 if (!std::isnan(
gHdt)) {
5989 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5992 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5993 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5994 if (dist > ndelta_pix ) {
5995 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5996 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6001 wxPoint lShipMidPoint;
6002 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6003 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6004 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6005 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6007 if (lpp >= img_height / 2) {
6008 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6009 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6010 !std::isnan(
gSog)) {
6012 float dash_length = ref_dim;
6013 wxDash dash_long[2];
6015 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6016 g_cog_predictor_width);
6017 dash_long[1] = dash_long[0] / 2.0;
6021 if (dash_length > 250.) {
6022 dash_long[0] = 250. / g_cog_predictor_width;
6023 dash_long[1] = dash_long[0] / 2;
6026 wxPen ppPen2(cPred, g_cog_predictor_width,
6027 (wxPenStyle)g_cog_predictor_style);
6028 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6029 ppPen2.SetDashes(2, dash_long);
6032 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6033 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6035 if (g_cog_predictor_width > 1) {
6036 float line_width = g_cog_predictor_width / 3.;
6038 wxDash dash_long3[2];
6039 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6040 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6042 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6043 (wxPenStyle)g_cog_predictor_style);
6044 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6045 ppPen3.SetDashes(2, dash_long3);
6047 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6048 lGPSPoint.m_y + GPSOffsetPixels.y,
6049 lPredPoint.x + GPSOffsetPixels.x,
6050 lPredPoint.y + GPSOffsetPixels.y);
6053 if (g_cog_predictor_endmarker) {
6055 double png_pred_icon_scale_factor = .4;
6056 if (g_ShipScaleFactorExp > 1.0)
6057 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6058 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6062 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6063 (
float)(lPredPoint.x - lShipMidPoint.x));
6064 cog_rad += (float)PI;
6066 for (
int i = 0; i < 4; i++) {
6068 double pxa = (double)(s_png_pred_icon[j]);
6069 double pya = (double)(s_png_pred_icon[j + 1]);
6071 pya *= png_pred_icon_scale_factor;
6072 pxa *= png_pred_icon_scale_factor;
6074 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6075 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6077 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6078 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6082 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6085 dc.SetBrush(wxBrush(cPred));
6087 dc.StrokePolygon(4, icon);
6094 float hdt_dash_length = ref_dim * 0.4;
6096 cPred.Set(g_ownship_HDTpredictor_color);
6097 if (cPred == wxNullColour) cPred = PredColor();
6099 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6100 : g_cog_predictor_width * 0.8);
6101 wxDash dash_short[2];
6103 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6106 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6109 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6110 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6111 ppPen2.SetDashes(2, dash_short);
6115 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6116 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6118 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6120 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6122 if (g_ownship_HDTpredictor_endmarker) {
6123 double nominal_circle_size_pixels = wxMax(
6124 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6127 if (g_ShipScaleFactorExp > 1.0)
6128 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6130 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6131 lHeadPoint.y + GPSOffsetPixels.y,
6132 nominal_circle_size_pixels / 2);
6137 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6138 double factor = 1.00;
6139 if (g_pNavAidRadarRingsStepUnits == 1)
6141 else if (g_pNavAidRadarRingsStepUnits == 2) {
6142 if (std::isnan(
gSog))
6147 factor *= g_fNavAidRadarRingsStep;
6151 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6154 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6155 pow((
double)(lGPSPoint.m_y - r.y), 2));
6156 int pix_radius = (int)lpp;
6158 wxColor rangeringcolour =
6159 user_colors::GetDimColor(g_colourOwnshipRangeRingsColour);
6161 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6164 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6166 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6167 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6172void ChartCanvas::ResetGlGridFont() { GetglCanvas()->ResetGridFont(); }
6173bool ChartCanvas::CanAccelerateGlPanning() {
6174 return GetglCanvas()->CanAcceleratePanning();
6176void ChartCanvas::SetupGlCompression() { GetglCanvas()->SetupCompression(); }
6179void ChartCanvas::ResetGlGridFont() {}
6180bool ChartCanvas::CanAccelerateGlPanning() {
return false; }
6181void ChartCanvas::SetupGlCompression() {}
6184void ChartCanvas::ComputeShipScaleFactor(
6185 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6186 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6187 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6188 float screenResolution = m_pix_per_mm;
6191 double ship_bow_lat, ship_bow_lon;
6192 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6193 &ship_bow_lat, &ship_bow_lon);
6194 wxPoint lShipBowPoint;
6195 wxPoint2DDouble b_point =
6199 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6200 powf((
float)(b_point.m_y - a_point.m_y), 2));
6203 float shipLength_mm = shipLength_px / screenResolution;
6206 float ownship_min_mm = g_n_ownship_min_mm;
6207 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6210 float hdt_ant = icon_hdt + 180.;
6211 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6212 float dx = g_n_gps_antenna_offset_x / 1852.;
6213 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6221 if (shipLength_mm < ownship_min_mm) {
6222 dy /= shipLength_mm / ownship_min_mm;
6223 dx /= shipLength_mm / ownship_min_mm;
6226 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6228 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6229 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6235 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6236 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6238 float scale_factor = shipLength_px / ownShipLength;
6241 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6244 scale_factor = wxMax(scale_factor, scale_factor_min);
6246 scale_factor_y = scale_factor;
6247 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6248 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6251void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6252 if (!GetVP().IsValid())
return;
6254 wxPoint GPSOffsetPixels(0, 0);
6255 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6258 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6259 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6263 lShipMidPoint = lGPSPoint;
6267 float icon_hdt = pCog;
6268 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6271 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6275 double osd_head_lat, osd_head_lon;
6276 wxPoint osd_head_point;
6278 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6283 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6284 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6285 icon_rad += (float)PI;
6287 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6291 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6295 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6296 if (GetVP().chart_scale >
6299 ShipDrawLargeScale(dc, lShipMidPoint);
6305 if (m_pos_image_user)
6306 pos_image = m_pos_image_user->Copy();
6307 else if (SHIP_NORMAL == m_ownship_state)
6308 pos_image = m_pos_image_red->Copy();
6309 if (SHIP_LOWACCURACY == m_ownship_state)
6310 pos_image = m_pos_image_yellow->Copy();
6311 else if (SHIP_NORMAL != m_ownship_state)
6312 pos_image = m_pos_image_grey->Copy();
6315 if (m_pos_image_user) {
6316 pos_image = m_pos_image_user->Copy();
6318 if (SHIP_LOWACCURACY == m_ownship_state)
6319 pos_image = m_pos_image_user_yellow->Copy();
6320 else if (SHIP_NORMAL != m_ownship_state)
6321 pos_image = m_pos_image_user_grey->Copy();
6324 img_height = pos_image.GetHeight();
6326 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6327 g_OwnShipIconType > 0)
6329 int ownShipWidth = 22;
6330 int ownShipLength = 84;
6331 if (g_OwnShipIconType == 1) {
6332 ownShipWidth = pos_image.GetWidth();
6333 ownShipLength = pos_image.GetHeight();
6336 float scale_factor_x, scale_factor_y;
6337 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6338 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6339 scale_factor_x, scale_factor_y);
6341 if (g_OwnShipIconType == 1) {
6342 pos_image.Rescale(ownShipWidth * scale_factor_x,
6343 ownShipLength * scale_factor_y,
6344 wxIMAGE_QUALITY_HIGH);
6345 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6347 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6350 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6351 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6352 if (rot_image.GetAlpha(ip, jp) > 64)
6353 rot_image.SetAlpha(ip, jp, 255);
6355 wxBitmap os_bm(rot_image);
6357 int w = os_bm.GetWidth();
6358 int h = os_bm.GetHeight();
6361 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6362 lShipMidPoint.m_y - h / 2,
true);
6365 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6366 lShipMidPoint.m_y - h / 2);
6367 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6368 lShipMidPoint.m_y - h / 2 + h);
6371 else if (g_OwnShipIconType == 2) {
6372 wxPoint ownship_icon[10];
6374 for (
int i = 0; i < 10; i++) {
6376 float pxa = (float)(s_ownship_icon[j]);
6377 float pya = (float)(s_ownship_icon[j + 1]);
6378 pya *= scale_factor_y;
6379 pxa *= scale_factor_x;
6381 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6382 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6384 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6385 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6388 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6390 dc.SetBrush(wxBrush(ShipColor()));
6392 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6395 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6397 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6401 img_height = ownShipLength * scale_factor_y;
6405 if (m_pos_image_user) circle_rad = 1;
6407 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6408 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6409 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6412 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6414 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6417 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6418 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6419 if (rot_image.GetAlpha(ip, jp) > 64)
6420 rot_image.SetAlpha(ip, jp, 255);
6422 wxBitmap os_bm(rot_image);
6424 if (g_ShipScaleFactorExp > 1) {
6425 wxImage scaled_image = os_bm.ConvertToImage();
6426 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6428 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6429 scaled_image.GetHeight() * factor,
6430 wxIMAGE_QUALITY_HIGH));
6432 int w = os_bm.GetWidth();
6433 int h = os_bm.GetHeight();
6436 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6437 lShipMidPoint.m_y - h / 2,
true);
6441 if (m_pos_image_user) circle_rad = 1;
6443 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6444 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6445 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6448 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6449 lShipMidPoint.m_y - h / 2);
6450 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6451 lShipMidPoint.m_y - h / 2 + h);
6456 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6469void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6470 float &MinorSpacing) {
6475 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6476 {.000001f, 45.0f, 15.0f},
6477 {.0002f, 30.0f, 10.0f},
6478 {.0003f, 10.0f, 2.0f},
6479 {.0008f, 5.0f, 1.0f},
6480 {.001f, 2.0f, 30.0f / 60.0f},
6481 {.003f, 1.0f, 20.0f / 60.0f},
6482 {.006f, 0.5f, 10.0f / 60.0f},
6483 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6484 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6485 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6486 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6487 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6488 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6489 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6490 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6493 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6494 if (view_scale_ppm < lltab[tabi][0])
break;
6495 MajorSpacing = lltab[tabi][1];
6496 MinorSpacing = lltab[tabi][2];
6510wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6511 int deg = (int)fabs(latlon);
6512 float min = fabs((fabs(latlon) - deg) * 60.0);
6522 }
else if (latlon < 0.0) {
6534 if (spacing >= 1.0) {
6535 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6536 }
else if (spacing >= (1.0 / 60.0)) {
6537 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6539 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6556void ChartCanvas::GridDraw(
ocpnDC &dc) {
6557 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6559 double nlat, elon, slat, wlon;
6562 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6564 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6566 if (!m_pgridFont) SetupGridFont();
6567 dc.SetFont(*m_pgridFont);
6568 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6571 h = m_canvas_height;
6582 dlon = dlon + 360.0;
6585 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6588 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6591 while (lat < nlat) {
6594 CalcGridText(lat, gridlatMajor,
true);
6596 dc.
DrawLine(0, r.y, w, r.y,
false);
6597 dc.DrawText(st, 0, r.y);
6598 lat = lat + gridlatMajor;
6600 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6604 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6607 while (lat < nlat) {
6610 dc.
DrawLine(0, r.y, 10, r.y,
false);
6611 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6612 lat = lat + gridlatMinor;
6616 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6619 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6622 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6624 wxString st = CalcGridText(lon, gridlonMajor,
false);
6626 dc.
DrawLine(r.x, 0, r.x, h,
false);
6627 dc.DrawText(st, r.x, 0);
6628 lon = lon + gridlonMajor;
6633 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6637 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6639 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6642 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6643 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6644 lon = lon + gridlonMinor;
6651void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6653 double blat, blon, tlat, tlon;
6656 int x_origin = m_bDisplayGrid ? 60 : 20;
6657 int y_origin = m_canvas_height - 50;
6663 if (GetVP().chart_scale > 80000)
6667 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6668 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6673 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6674 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6678 double rotation = -VPoint.
rotation;
6680 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6682 int l1 = (y_origin - r.y) / count;
6684 for (
int i = 0; i < count; i++) {
6691 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6694 double blat, blon, tlat, tlon;
6701 int y_origin = m_canvas_height - chartbar_height - 5;
6705 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6712 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6717 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6718 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6722 float places = floor(logdist), rem = logdist - places;
6723 dist = pow(10, places);
6730 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6731 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6732 double rotation = -VPoint.
rotation;
6738 int l1 = r.x - x_origin;
6740 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6745 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6746 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6747 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6749 if (!m_pgridFont) SetupGridFont();
6750 dc.SetFont(*m_pgridFont);
6751 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6753 dc.GetTextExtent(s, &w, &h);
6759 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6763void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6768 double ra_max = 40.;
6770 wxPen pen_save = dc.GetPen();
6772 wxDateTime now = wxDateTime::Now();
6778 x0 = x1 = x + radius;
6783 while (angle < 360.) {
6784 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6787 if (angle > 360.) angle = 360.;
6789 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6797 x1 = (int)(x + cos(angle * PI / 180.) * r);
6798 y1 = (int)(y + sin(angle * PI / 180.) * r);
6808 dc.
DrawLine(x + radius, y, x1, y1);
6810 dc.SetPen(pen_save);
6813static bool bAnchorSoundPlaying =
false;
6815static void onAnchorSoundFinished(
void *ptr) {
6816 o_sound::g_anchorwatch_sound->UnLoad();
6817 bAnchorSoundPlaying =
false;
6820void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6821 using namespace o_sound;
6823 bool play_sound =
false;
6825 if (AnchorAlertOn1) {
6826 wxPoint TargetPoint;
6829 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6830 TargetPoint.y, 100);
6834 AnchorAlertOn1 =
false;
6837 if (AnchorAlertOn2) {
6838 wxPoint TargetPoint;
6841 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6842 TargetPoint.y, 100);
6846 AnchorAlertOn2 =
false;
6849 if (!bAnchorSoundPlaying) {
6850 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6851 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6852 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6853 if (g_anchorwatch_sound->IsOk()) {
6854 bAnchorSoundPlaying =
true;
6855 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6856 g_anchorwatch_sound->Play();
6862void ChartCanvas::UpdateShips() {
6865 wxClientDC dc(
this);
6866 if (!dc.IsOk())
return;
6868 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6869 if (!test_bitmap.IsOk())
return;
6871 wxMemoryDC temp_dc(test_bitmap);
6873 temp_dc.ResetBoundingBox();
6874 temp_dc.DestroyClippingRegion();
6875 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6886 ocpndc.CalcBoundingBox(px.x, px.y);
6891 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6892 temp_dc.MaxY() - temp_dc.MinY());
6894 wxRect own_ship_update_rect = ship_draw_rect;
6896 if (!own_ship_update_rect.IsEmpty()) {
6899 own_ship_update_rect.Union(ship_draw_last_rect);
6900 own_ship_update_rect.Inflate(2);
6903 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6905 ship_draw_last_rect = ship_draw_rect;
6907 temp_dc.SelectObject(wxNullBitmap);
6910void ChartCanvas::UpdateAlerts() {
6915 wxClientDC dc(
this);
6919 dc.GetSize(&sx, &sy);
6922 wxBitmap test_bitmap(sx, sy, -1);
6926 temp_dc.SelectObject(test_bitmap);
6928 temp_dc.ResetBoundingBox();
6929 temp_dc.DestroyClippingRegion();
6930 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6937 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6938 temp_dc.MaxX() - temp_dc.MinX(),
6939 temp_dc.MaxY() - temp_dc.MinY());
6941 if (!alert_rect.IsEmpty())
6942 alert_rect.Inflate(2);
6944 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6947 wxRect alert_update_rect = alert_draw_rect;
6948 alert_update_rect.Union(alert_rect);
6951 RefreshRect(alert_update_rect,
false);
6955 alert_draw_rect = alert_rect;
6957 temp_dc.SelectObject(wxNullBitmap);
6960void ChartCanvas::UpdateAIS() {
6966 wxClientDC dc(
this);
6970 dc.GetSize(&sx, &sy);
6978 if (
g_pAIS->GetTargetList().size() > 10) {
6979 ais_rect = wxRect(0, 0, sx, sy);
6982 wxBitmap test_bitmap(sx, sy, -1);
6986 temp_dc.SelectObject(test_bitmap);
6988 temp_dc.ResetBoundingBox();
6989 temp_dc.DestroyClippingRegion();
6990 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6994 AISDraw(ocpndc, GetVP(),
this);
6995 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6999 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
7000 temp_dc.MaxY() - temp_dc.MinY());
7002 if (!ais_rect.IsEmpty())
7003 ais_rect.Inflate(2);
7005 temp_dc.SelectObject(wxNullBitmap);
7008 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7011 wxRect ais_update_rect = ais_draw_rect;
7012 ais_update_rect.Union(ais_rect);
7015 RefreshRect(ais_update_rect,
false);
7019 ais_draw_rect = ais_rect;
7022void ChartCanvas::ToggleCPAWarn() {
7023 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7029 g_bTCPA_Max =
false;
7033 if (STAT_FIELD_SCALE >= 4 && top_frame::Get()->GetStatusBar()) {
7034 top_frame::Get()->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7036 if (!g_AisFirstTimeUse) {
7037 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7038 _(
"CPA") +
" " + mess, 4, 4);
7043void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7045void ChartCanvas::OnSize(wxSizeEvent &event) {
7046 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7048 GetClientSize(&m_canvas_width, &m_canvas_height);
7052 m_displayScale = GetContentScaleFactor();
7056 m_canvas_width *= m_displayScale;
7057 m_canvas_height *= m_displayScale;
7070 m_absolute_min_scale_ppm =
7072 (1.2 * WGS84_semimajor_axis_meters * PI);
7075 top_frame::Get()->ProcessCanvasResize();
7085 SetMUIBarPosition();
7086 UpdateFollowButtonState();
7087 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7091 xr_margin = m_canvas_width * 95 / 100;
7092 xl_margin = m_canvas_width * 5 / 100;
7093 yt_margin = m_canvas_height * 5 / 100;
7094 yb_margin = m_canvas_height * 95 / 100;
7097 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7102 m_brepaint_piano =
true;
7105 m_dc_route.SelectObject(wxNullBitmap);
7108 m_dc_route.SelectObject(*proute_bm);
7122 m_glcc->OnSize(event);
7131void ChartCanvas::ProcessNewGUIScale() {
7139void ChartCanvas::CreateMUIBar() {
7140 if (g_useMUI && !m_muiBar) {
7141 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7142 m_muiBar->SetColorScheme(m_cs);
7143 m_muiBarHOSize = m_muiBar->m_size;
7151 SetMUIBarPosition();
7152 UpdateFollowButtonState();
7153 m_muiBar->UpdateDynamicValues();
7154 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7158void ChartCanvas::SetMUIBarPosition() {
7162 int pianoWidth = GetClientSize().x * 0.6f;
7167 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7168 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7170 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7171 m_muiBar->SetColorScheme(m_cs);
7175 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7176 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7178 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7179 m_muiBar->SetColorScheme(m_cs);
7183 m_muiBar->SetBestPosition();
7187void ChartCanvas::DestroyMuiBar() {
7194void ChartCanvas::ShowCompositeInfoWindow(
7195 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7197 if (NULL == m_pCIWin) {
7202 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7205 s = _(
"Composite of ");
7208 s1.Printf(
"%d ", n_charts);
7216 s1.Printf(_(
"Chart scale"));
7219 s2.Printf(
"1:%d\n",
scale);
7223 s1 = _(
"Zoom in for more information");
7227 int char_width = s1.Length();
7228 int char_height = 3;
7230 if (g_bChartBarEx) {
7233 for (
int i : index_vector) {
7235 wxString path = cte.GetFullSystemPath();
7239 char_width = wxMax(char_width, path.Length());
7240 if (j++ >= 9)
break;
7243 s +=
" .\n .\n .\n";
7252 m_pCIWin->SetString(s);
7254 m_pCIWin->FitToChars(char_width, char_height);
7257 p.x = x / GetContentScaleFactor();
7258 if ((p.x + m_pCIWin->GetWinSize().x) >
7259 (m_canvas_width / GetContentScaleFactor()))
7260 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7261 m_pCIWin->GetWinSize().x) /
7264 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7265 4 - m_pCIWin->GetWinSize().y;
7267 m_pCIWin->dbIndex = 0;
7268 m_pCIWin->chart_scale = 0;
7269 m_pCIWin->SetPosition(p);
7270 m_pCIWin->SetBitmap();
7271 m_pCIWin->Refresh();
7275 HideChartInfoWindow();
7279void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7281 if (NULL == m_pCIWin) {
7286 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7295 dbIndex, FULL_INIT);
7297 int char_width, char_height;
7298 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7299 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7301 m_pCIWin->SetString(s);
7302 m_pCIWin->FitToChars(char_width, char_height);
7305 p.x = x / GetContentScaleFactor();
7306 if ((p.x + m_pCIWin->GetWinSize().x) >
7307 (m_canvas_width / GetContentScaleFactor()))
7308 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7309 m_pCIWin->GetWinSize().x) /
7312 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7313 4 - m_pCIWin->GetWinSize().y;
7315 m_pCIWin->dbIndex = dbIndex;
7316 m_pCIWin->SetPosition(p);
7317 m_pCIWin->SetBitmap();
7318 m_pCIWin->Refresh();
7322 HideChartInfoWindow();
7326void ChartCanvas::HideChartInfoWindow() {
7329 m_pCIWin->Destroy();
7333 androidForceFullRepaint();
7338void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7339 wxMouseEvent ev(wxEVT_MOTION);
7342 ev.m_leftDown = mouse_leftisdown;
7344 wxEvtHandler *evthp = GetEventHandler();
7346 ::wxPostEvent(evthp, ev);
7349void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7350 if ((m_panx_target_final - m_panx_target_now) ||
7351 (m_pany_target_final - m_pany_target_now)) {
7352 DoTimedMovementTarget();
7357void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7359bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7361 if (m_disable_edge_pan)
return false;
7364 int pan_margin = m_canvas_width * margin / 100;
7365 int pan_timer_set = 200;
7366 double pan_delta = GetVP().
pix_width * delta / 100;
7370 if (x > m_canvas_width - pan_margin) {
7375 else if (x < pan_margin) {
7380 if (y < pan_margin) {
7385 else if (y > m_canvas_height - pan_margin) {
7394 wxMouseState state = ::wxGetMouseState();
7395#if wxCHECK_VERSION(3, 0, 0)
7396 if (!state.LeftIsDown())
7398 if (!state.LeftDown())
7403 if ((bft) && !pPanTimer->IsRunning()) {
7405 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7411 if ((!bft) && pPanTimer->IsRunning()) {
7421void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7422 bool setBeingEdited) {
7423 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7424 m_pRoutePointEditTarget = NULL;
7425 m_pFoundPoint = NULL;
7428 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7429 SelectableItemList SelList =
pSelect->FindSelectionList(
7439 bool brp_viz =
false;
7440 if (m_pEditRouteArray) {
7441 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7442 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7443 if (pr->IsVisible()) {
7449 brp_viz = frp->IsVisible();
7453 if (m_pEditRouteArray)
7455 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7456 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7459 m_bRouteEditing = setBeingEdited;
7462 frp->m_bRPIsBeingEdited = setBeingEdited;
7463 m_bMarkEditing = setBeingEdited;
7466 m_pRoutePointEditTarget = frp;
7467 m_pFoundPoint = pFind;
7472std::shared_ptr<HostApi121::PiPointContext>
7473ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7487 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7488 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7489 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7490 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7491 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7495 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7498 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7503 int FoundAIS_MMSI = 0;
7505 FoundAIS_MMSI = pFindAIS->GetUserData();
7508 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7509 seltype |= SELTYPE_AISTARGET;
7515 Route *SelectedRoute = NULL;
7521 Route *pSelectedActiveRoute = NULL;
7522 Route *pSelectedVizRoute = NULL;
7525 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7526 SelectableItemList SelList =
7527 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7535 bool brp_viz =
false;
7537 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7539 if (pr->IsVisible()) {
7544 if (!brp_viz && prp->IsShared())
7546 brp_viz = prp->IsVisible();
7549 brp_viz = prp->IsVisible();
7551 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7557 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7560 pSelectedActiveRoute = pr;
7561 pFoundActiveRoutePoint = prp;
7566 if (NULL == pSelectedVizRoute) {
7567 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7569 if (pr->IsVisible()) {
7570 pSelectedVizRoute = pr;
7571 pFoundVizRoutePoint = prp;
7577 delete proute_array;
7582 if (pFoundActiveRoutePoint) {
7583 FoundRoutePoint = pFoundActiveRoutePoint;
7584 SelectedRoute = pSelectedActiveRoute;
7585 }
else if (pFoundVizRoutePoint) {
7586 FoundRoutePoint = pFoundVizRoutePoint;
7587 SelectedRoute = pSelectedVizRoute;
7590 FoundRoutePoint = pFirstVizPoint;
7592 if (SelectedRoute) {
7593 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7594 }
else if (FoundRoutePoint) {
7595 seltype |= SELTYPE_MARKPOINT;
7600 if (m_pFoundRoutePoint) {
7604 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7605 RefreshRect(wp_rect,
true);
7614 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7615 SelectableItemList SelList =
7616 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7618 if (NULL == SelectedRoute)
7623 if (pr->IsVisible()) {
7630 if (SelectedRoute) {
7631 if (NULL == FoundRoutePoint)
7632 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7635 seltype |= SELTYPE_ROUTESEGMENT;
7639 if (pFindTrackSeg) {
7640 m_pSelectedTrack = NULL;
7641 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7642 SelectableItemList SelList =
7643 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7648 if (pt->IsVisible()) {
7649 m_pSelectedTrack = pt;
7653 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7656 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7659 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7660 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7661 rstruct->object_ident =
"";
7663 if (seltype == SELTYPE_AISTARGET) {
7664 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7666 val.Printf(
"%d", FoundAIS_MMSI);
7667 rstruct->object_ident = val.ToStdString();
7668 }
else if (seltype & SELTYPE_MARKPOINT) {
7669 if (FoundRoutePoint) {
7670 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7671 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7673 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7674 if (SelectedRoute) {
7675 rstruct->object_type =
7676 HostApi121::PiContextObjectType::kObjectRoutesegment;
7677 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7679 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7680 if (m_pSelectedTrack) {
7681 rstruct->object_type =
7682 HostApi121::PiContextObjectType::kObjectTracksegment;
7683 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7690void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7691 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7692 singleClickEventIsValid =
false;
7693 m_DoubleClickTimer->Stop();
7698bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7699 if (!m_bChartDragging && !m_bDrawingRoute) {
7704 if (m_Compass && m_Compass->IsShown()) {
7706 bool isInCompass = logicalRect.Contains(event.GetPosition());
7707 if (isInCompass || m_mouseWasInCompass) {
7708 if (m_Compass->MouseEvent(event)) {
7709 cursor_region = CENTER;
7710 if (!g_btouch) SetCanvasCursor(event);
7711 m_mouseWasInCompass = isInCompass;
7715 m_mouseWasInCompass = isInCompass;
7718 if (m_notification_button && m_notification_button->IsShown()) {
7720 bool isinButton = logicalRect.Contains(event.GetPosition());
7722 SetCursor(*pCursorArrow);
7723 if (event.LeftDown()) HandleNotificationMouseClick();
7728 if (MouseEventToolbar(event))
return true;
7730 if (MouseEventChartBar(event))
return true;
7732 if (MouseEventMUIBar(event))
return true;
7734 if (MouseEventIENCBar(event))
return true;
7739void ChartCanvas::HandleNotificationMouseClick() {
7740 if (!m_NotificationsList) {
7744 m_NotificationsList->RecalculateSize();
7745 m_NotificationsList->Hide();
7748 if (m_NotificationsList->IsShown()) {
7749 m_NotificationsList->Hide();
7751 m_NotificationsList->RecalculateSize();
7752 m_NotificationsList->ReloadNotificationList();
7753 m_NotificationsList->Show();
7756bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7757 if (!g_bShowChartBar)
return false;
7759 if (!m_Piano->MouseEvent(event))
return false;
7761 cursor_region = CENTER;
7762 if (!g_btouch) SetCanvasCursor(event);
7766bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7767 if (!IsPrimaryCanvas())
return false;
7776 cursor_region = CENTER;
7777 if (!g_btouch) SetCanvasCursor(event);
7781bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7782 if (!IsPrimaryCanvas())
return false;
7795bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7797 if (!m_muiBar->MouseEvent(event))
return false;
7800 cursor_region = CENTER;
7801 if (!g_btouch) SetCanvasCursor(event);
7813 event.GetPosition(&x, &y);
7815 x *= m_displayScale;
7816 y *= m_displayScale;
7818 m_MouseDragging =
event.Dragging();
7824 if (event.Dragging()) {
7825 if ((x == mouse_x) && (y == mouse_y))
return true;
7831 mouse_leftisdown =
event.LeftDown();
7835 cursor_region = CENTER;
7839 if (m_Compass && m_Compass->IsShown() &&
7840 m_Compass->
GetRect().Contains(event.GetPosition())) {
7841 cursor_region = CENTER;
7842 }
else if (x > xr_margin) {
7843 cursor_region = MID_RIGHT;
7844 }
else if (x < xl_margin) {
7845 cursor_region = MID_LEFT;
7846 }
else if (y > yb_margin - chartbar_height &&
7847 y < m_canvas_height - chartbar_height) {
7848 cursor_region = MID_TOP;
7849 }
else if (y < yt_margin) {
7850 cursor_region = MID_BOT;
7852 cursor_region = CENTER;
7855 if (!g_btouch) SetCanvasCursor(event);
7859 leftIsDown =
event.LeftDown();
7862 if (event.LeftDown()) {
7863 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7866 g_bTempShowMenuBar =
false;
7867 top_frame::Get()->ApplyGlobalSettings(
false);
7875 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7876 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7880 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7881 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7884 event.SetEventObject(
this);
7885 if (SendMouseEventToPlugins(event))
7892 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7893 StartChartDragInertia();
7896 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7897 !singleClickEventIsValid) {
7899 if (m_DoubleClickTimer->IsRunning()) {
7900 m_DoubleClickTimer->Stop();
7905 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7906 singleClickEvent = event;
7907 singleClickEventIsValid =
true;
7916 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7917 if (g_click_stop > 0) {
7925 if (GetUpMode() == COURSE_UP_MODE) {
7926 m_b_rot_hidef =
false;
7927 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7929 pRotDefTimer->Stop();
7932 bool bRoll = !g_btouch;
7937 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7938 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7939 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7940 m_RolloverPopupTimer.Start(
7944 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7948 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7957#if !defined(__WXGTK__) && !defined(__WXQT__)
7965 if ((x >= 0) && (y >= 0))
7970 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7971 wxPoint p = ClientToScreen(wxPoint(x, y));
7977 if (m_routeState >= 2) {
7980 m_bDrawingRoute =
true;
7982 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7987 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7990 m_bDrawingRoute =
true;
7992 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8005#if defined(__WXMAC__) || defined(__ANDROID__)
8009 wxClientDC cdc(GetParent());
8021 if (m_pSelectedRoute) {
8023 m_pSelectedRoute->DeSelectRoute();
8025 if (g_bopengl && m_glcc) {
8030 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8033 if (m_pFoundRoutePoint) {
8041 if (g_btouch && m_pRoutePointEditTarget) {
8044 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8048 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8049 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8050 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8051 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8052 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8056 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8059 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8065 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8068 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8069 seltype |= SELTYPE_AISTARGET;
8074 m_pFoundRoutePoint = NULL;
8079 Route *pSelectedActiveRoute = NULL;
8080 Route *pSelectedVizRoute = NULL;
8083 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8084 SelectableItemList SelList =
8085 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8093 bool brp_viz =
false;
8095 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8097 if (pr->IsVisible()) {
8102 if (!brp_viz && prp->IsShared())
8104 brp_viz = prp->IsVisible();
8107 brp_viz = prp->IsVisible();
8109 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8114 m_pSelectedRoute = NULL;
8116 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8119 pSelectedActiveRoute = pr;
8120 pFoundActiveRoutePoint = prp;
8125 if (NULL == pSelectedVizRoute) {
8126 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8128 if (pr->IsVisible()) {
8129 pSelectedVizRoute = pr;
8130 pFoundVizRoutePoint = prp;
8136 delete proute_array;
8141 if (pFoundActiveRoutePoint) {
8142 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8143 m_pSelectedRoute = pSelectedActiveRoute;
8144 }
else if (pFoundVizRoutePoint) {
8145 m_pFoundRoutePoint = pFoundVizRoutePoint;
8146 m_pSelectedRoute = pSelectedVizRoute;
8149 m_pFoundRoutePoint = pFirstVizPoint;
8151 if (m_pSelectedRoute) {
8152 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8153 }
else if (m_pFoundRoutePoint) {
8154 seltype |= SELTYPE_MARKPOINT;
8158 if (m_pFoundRoutePoint) {
8162 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8163 RefreshRect(wp_rect,
true);
8171 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8172 SelectableItemList SelList =
8173 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8175 if (NULL == m_pSelectedRoute)
8180 if (pr->IsVisible()) {
8181 m_pSelectedRoute = pr;
8187 if (m_pSelectedRoute) {
8188 if (NULL == m_pFoundRoutePoint)
8189 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8194 if (g_bopengl && m_glcc) {
8199 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8201 seltype |= SELTYPE_ROUTESEGMENT;
8205 if (pFindTrackSeg) {
8206 m_pSelectedTrack = NULL;
8207 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8208 SelectableItemList SelList =
8209 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8214 if (pt->IsVisible()) {
8215 m_pSelectedTrack = pt;
8219 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8225 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8226 seltype |= SELTYPE_CURRENTPOINT;
8229 else if (pFindTide) {
8230 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8231 seltype |= SELTYPE_TIDEPOINT;
8236 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8241IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8251 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8252 SelectableItemList SelList =
8253 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8256 pFind = *SelList.begin();
8257 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8259 auto node = SelList.begin();
8260 if (SelList.size() > 1) {
8261 for (++node; node != SelList.end(); ++node) {
8264 if (pIDX_candidate->
IDX_type ==
'c') {
8265 pIDX_best_candidate = pIDX_candidate;
8270 pFind = *SelList.begin();
8271 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8274 return pIDX_best_candidate;
8276void ChartCanvas::CallPopupMenu(
int x,
int y) {
8280 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8288 if (SELTYPE_CURRENTPOINT == seltype) {
8294 if (SELTYPE_TIDEPOINT == seltype) {
8300 InvokeCanvasMenu(x, y, seltype);
8303 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8307 m_pSelectedRoute = NULL;
8309 if (m_pFoundRoutePoint) {
8310 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8313 m_pFoundRoutePoint = NULL;
8319bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8327 event.GetPosition(&x, &y);
8333 SelectRadius = g_Platform->GetSelectRadiusPix() /
8334 (m_true_scale_ppm * 1852 * 60);
8341 if (event.LeftDClick() && (cursor_region == CENTER)) {
8342 m_DoubleClickTimer->Start();
8343 singleClickEventIsValid =
false;
8349 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8352 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8355 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8356 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8357 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8363 SelectableItemList rpSelList =
8364 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8365 bool b_onRPtarget =
false;
8368 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8369 b_onRPtarget =
true;
8377 std::unique_ptr<HostApi> host_api =
GetHostApi();
8378 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8380 if (m_pRoutePointEditTarget) {
8382 if ((api_121->GetContextMenuMask() &
8383 api_121->kContextMenuDisableWaypoint))
8385 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8391 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8394 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8395 m_pRoutePointEditTarget = NULL;
8396 RefreshRect(wp_rect,
true);
8400 auto node = rpSelList.begin();
8401 if (node != rpSelList.end()) {
8405 wxArrayPtrVoid *proute_array =
8410 bool brp_viz =
false;
8412 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8414 if (pr->IsVisible()) {
8419 delete proute_array;
8423 brp_viz = frp->IsVisible();
8425 brp_viz = frp->IsVisible();
8428 if ((api_121->GetContextMenuMask() &
8429 api_121->kContextMenuDisableWaypoint))
8432 ShowMarkPropertiesDialog(frp);
8441 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8443 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8446 if (pr->IsVisible()) {
8447 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8452 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8454 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8457 if (pt->IsVisible()) {
8458 ShowTrackPropertiesDialog(pt);
8467 if (m_bShowCurrent) {
8469 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8471 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8473 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8474 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8476 if (pic->m_enabled && pic->m_init_state &&
8477 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8480 if (m_pIDXCandidate) {
8481 info.point_type = CURRENT_STATION;
8485 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8486 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8490 if (plugin) plugin->OnTideCurrentClick(info);
8505 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8507 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8509 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8510 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8512 if (pic->m_enabled && pic->m_init_state &&
8513 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8516 if (m_pIDXCandidate) {
8517 info.point_type = TIDE_STATION;
8521 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8522 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8526 if (plugin) plugin->OnTideCurrentClick(info);
8541 ShowObjectQueryWindow(x, y, zlat, zlon);
8546 if (event.LeftDown()) {
8562 bool appending =
false;
8563 bool inserting =
false;
8566 SetCursor(*pCursorPencil);
8570 m_bRouteEditing =
true;
8572 if (m_routeState == 1) {
8573 m_pMouseRoute =
new Route();
8574 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8584 double nearby_radius_meters =
8585 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8588 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8589 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8590 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8591 wxArrayPtrVoid *proute_array =
8596 bool brp_viz =
false;
8598 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8600 if (pr->IsVisible()) {
8605 delete proute_array;
8607 pNearbyPoint->IsShared())
8610 pNearbyPoint->IsVisible();
8612 brp_viz = pNearbyPoint->IsVisible();
8615 wxString msg = _(
"Use nearby waypoint?");
8617 const bool noname(pNearbyPoint->GetName() ==
"");
8620 _(
"Use nearby nameless waypoint and name it M with"
8621 " a unique number?");
8624 m_FinishRouteOnKillFocus =
false;
8626 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8627 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8628 m_FinishRouteOnKillFocus =
true;
8629 if (dlg_return == wxID_YES) {
8631 if (m_pMouseRoute) {
8632 int last_wp_num = m_pMouseRoute->GetnPoints();
8634 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8635 wxString wp_name = wxString::Format(
8636 "M%002i-%s", last_wp_num + 1, guid_short);
8637 pNearbyPoint->SetName(wp_name);
8639 pNearbyPoint->SetName(
"WPXX");
8641 pMousePoint = pNearbyPoint;
8644 if (m_routeState > 1)
8645 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8646 Undo_HasParent, NULL);
8649 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8650 bool procede =
false;
8654 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8660 m_FinishRouteOnKillFocus =
false;
8666 _(
"Insert first part of this route in the new route?");
8667 if (tail->GetIndexOf(pMousePoint) ==
8670 dmsg = _(
"Insert this route in the new route?");
8672 if (tail->GetIndexOf(pMousePoint) != 1) {
8673 dlg_return = OCPNMessageBox(
8674 this, dmsg, _(
"OpenCPN Route Create"),
8675 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8676 m_FinishRouteOnKillFocus =
true;
8678 if (dlg_return == wxID_YES) {
8685 _(
"Append last part of this route to the new route?");
8686 if (tail->GetIndexOf(pMousePoint) == 1)
8688 "Append this route to the new route?");
8693 if (tail->GetLastPoint() != pMousePoint) {
8694 dlg_return = OCPNMessageBox(
8695 this, dmsg, _(
"OpenCPN Route Create"),
8696 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8697 m_FinishRouteOnKillFocus =
true;
8699 if (dlg_return == wxID_YES) {
8710 if (!FindRouteContainingWaypoint(pMousePoint))
8711 pMousePoint->SetShared(
true);
8716 if (NULL == pMousePoint) {
8717 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8719 pMousePoint->SetNameShown(
false);
8723 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8725 if (m_routeState > 1)
8726 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8727 Undo_IsOrphanded, NULL);
8730 if (m_pMouseRoute) {
8731 if (m_routeState == 1) {
8733 m_pMouseRoute->AddPoint(pMousePoint);
8737 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8738 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8739 &rhumbBearing, &rhumbDist);
8740 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8741 rlat, &gcDist, &gcBearing, NULL);
8742 double gcDistNM = gcDist / 1852.0;
8745 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8746 pow(rhumbDist - gcDistNM - 1, 0.5);
8749 msg << _(
"For this leg the Great Circle route is ")
8751 << _(
" shorter than rhumbline.\n\n")
8752 << _(
"Would you like include the Great Circle routing points "
8755 m_FinishRouteOnKillFocus =
false;
8756 m_disable_edge_pan =
true;
8759 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8760 wxYES_NO | wxNO_DEFAULT);
8762 m_disable_edge_pan =
false;
8763 m_FinishRouteOnKillFocus =
true;
8765 if (answer == wxID_YES) {
8767 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8768 wxRealPoint gcCoord;
8770 for (
int i = 1; i <= segmentCount; i++) {
8771 double fraction = (double)i * (1.0 / (
double)segmentCount);
8772 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8773 gcDist * fraction, gcBearing,
8774 &gcCoord.x, &gcCoord.y, NULL);
8776 if (i < segmentCount) {
8777 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8779 gcPoint->SetNameShown(
false);
8781 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8783 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8786 gcPoint = pMousePoint;
8789 m_pMouseRoute->AddPoint(gcPoint);
8790 pSelect->AddSelectableRouteSegment(
8791 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8792 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8793 prevGcPoint = gcPoint;
8796 undo->CancelUndoableAction(
true);
8799 m_pMouseRoute->AddPoint(pMousePoint);
8800 pSelect->AddSelectableRouteSegment(
8801 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8802 pMousePoint, m_pMouseRoute);
8803 undo->AfterUndoableAction(m_pMouseRoute);
8807 m_pMouseRoute->AddPoint(pMousePoint);
8808 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8809 rlon, m_prev_pMousePoint,
8810 pMousePoint, m_pMouseRoute);
8811 undo->AfterUndoableAction(m_pMouseRoute);
8817 m_prev_pMousePoint = pMousePoint;
8825 int connect = tail->GetIndexOf(pMousePoint);
8830 int length = tail->GetnPoints();
8835 start = connect + 1;
8840 m_pMouseRoute->RemovePoint(
8844 for (i = start; i <= stop; i++) {
8845 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8848 m_pMouseRoute->GetnPoints();
8850 top_frame::Get()->RefreshAllCanvas();
8854 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8856 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8857 m_pMouseRoute->FinalizeForRendering();
8859 top_frame::Get()->RefreshAllCanvas();
8863 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8865 SetCursor(*pCursorPencil);
8867 if (!m_pMeasureRoute) {
8868 m_pMeasureRoute =
new Route();
8872 if (m_nMeasureState == 1) {
8879 wxEmptyString, wxEmptyString);
8881 pMousePoint->SetShowWaypointRangeRings(
false);
8883 m_pMeasureRoute->AddPoint(pMousePoint);
8887 m_prev_pMousePoint = pMousePoint;
8891 top_frame::Get()->RefreshAllCanvas();
8896 FindRoutePointsAtCursor(SelectRadius,
true);
8900 m_last_touch_down_pos =
event.GetPosition();
8902 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8910 if (ret)
return true;
8913 if (event.Dragging()) {
8916 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8918 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8920 SelectableItemList SelList =
pSelect->FindSelectionList(
8924 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8929 if (m_pRoutePointEditTarget &&
8930 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8932 SelectableItemList SelList =
pSelect->FindSelectionList(
8936 if (m_pRoutePointEditTarget == frp) {
8937 m_bIsInRadius =
true;
8942 if (!m_dragoffsetSet) {
8944 .PresetDragOffset(
this, mouse_x, mouse_y);
8945 m_dragoffsetSet =
true;
8950 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8951 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8954 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8956 DraggingAllowed =
false;
8958 if (m_pRoutePointEditTarget &&
8959 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8960 DraggingAllowed =
false;
8962 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8964 if (DraggingAllowed) {
8965 if (!undo->InUndoableAction()) {
8966 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8967 Undo_NeedsCopy, m_pFoundPoint);
8973 if (!g_bopengl && m_pEditRouteArray) {
8974 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8975 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8982 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8983 pre_rect.Union(route_rect);
8991 if (CheckEdgePan(x, y,
true, 5, 2))
8999 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9001 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9002 m_pRoutePointEditTarget,
9003 SELTYPE_DRAGHANDLE);
9004 m_pFoundPoint->m_slat =
9005 m_pRoutePointEditTarget->m_lat;
9006 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9008 m_pRoutePointEditTarget->m_lat =
9010 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9011 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9012 m_pFoundPoint->m_slat =
9014 m_pFoundPoint->m_slon = new_cursor_lon;
9030 if (m_pEditRouteArray) {
9031 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9033 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9036 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9037 post_rect.Union(route_rect);
9043 pre_rect.Union(post_rect);
9044 RefreshRect(pre_rect,
false);
9046 top_frame::Get()->RefreshCanvasOther(
this);
9047 m_bRoutePoinDragging =
true;
9052 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9053 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9056 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9058 DraggingAllowed =
false;
9060 if (m_pRoutePointEditTarget &&
9061 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9062 DraggingAllowed =
false;
9064 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9066 if (DraggingAllowed) {
9067 if (!undo->InUndoableAction()) {
9068 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9069 Undo_NeedsCopy, m_pFoundPoint);
9083 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9089 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9090 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9091 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9092 (
int)(lppmax - (pre_rect.height / 2)));
9100 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9103 m_pRoutePointEditTarget,
9104 SELTYPE_DRAGHANDLE);
9105 m_pFoundPoint->m_slat =
9106 m_pRoutePointEditTarget->m_lat;
9107 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9109 m_pRoutePointEditTarget->m_lat =
9112 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9125 if (!g_btouch) InvalidateGL();
9131 .CalculateDCRect(m_dc_route,
this, &post_rect);
9132 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9133 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9134 (
int)(lppmax - (post_rect.height / 2)));
9137 pre_rect.Union(post_rect);
9138 RefreshRect(pre_rect,
false);
9140 top_frame::Get()->RefreshCanvasOther(
this);
9141 m_bRoutePoinDragging =
true;
9143 ret = g_btouch ? m_bRoutePoinDragging :
true;
9146 if (ret)
return true;
9149 if (event.LeftUp()) {
9150 bool b_startedit_route =
false;
9151 m_dragoffsetSet =
false;
9154 m_bChartDragging =
false;
9155 m_bIsInRadius =
false;
9159 if (m_ignore_next_leftup) {
9160 m_ignore_next_leftup =
false;
9165 m_bedge_pan =
false;
9170 bool appending =
false;
9171 bool inserting =
false;
9177 if (m_pRoutePointEditTarget) {
9183 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9184 RefreshRect(wp_rect,
true);
9186 m_pRoutePointEditTarget = NULL;
9188 m_bRouteEditing =
true;
9190 if (m_routeState == 1) {
9191 m_pMouseRoute =
new Route();
9192 m_pMouseRoute->SetHiLite(50);
9196 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9203 double nearby_radius_meters =
9204 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9207 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9208 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9209 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9212 m_FinishRouteOnKillFocus =
9214 dlg_return = OCPNMessageBox(
9215 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9216 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9217 m_FinishRouteOnKillFocus =
true;
9219 dlg_return = wxID_YES;
9221 if (dlg_return == wxID_YES) {
9222 pMousePoint = pNearbyPoint;
9225 if (m_routeState > 1)
9226 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9227 Undo_HasParent, NULL);
9228 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9230 bool procede =
false;
9234 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9240 m_FinishRouteOnKillFocus =
false;
9241 if (m_routeState == 1) {
9245 _(
"Insert first part of this route in the new route?");
9246 if (tail->GetIndexOf(pMousePoint) ==
9249 dmsg = _(
"Insert this route in the new route?");
9251 if (tail->GetIndexOf(pMousePoint) != 1) {
9253 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9254 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9255 m_FinishRouteOnKillFocus =
true;
9257 if (dlg_return == wxID_YES) {
9264 _(
"Append last part of this route to the new route?");
9265 if (tail->GetIndexOf(pMousePoint) == 1)
9267 "Append this route to the new route?");
9271 if (tail->GetLastPoint() != pMousePoint) {
9273 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9274 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9275 m_FinishRouteOnKillFocus =
true;
9277 if (dlg_return == wxID_YES) {
9288 if (!FindRouteContainingWaypoint(pMousePoint))
9289 pMousePoint->SetShared(
true);
9293 if (NULL == pMousePoint) {
9294 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9296 pMousePoint->SetNameShown(
false);
9298 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9300 if (m_routeState > 1)
9301 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9302 Undo_IsOrphanded, NULL);
9305 if (m_routeState == 1) {
9307 m_pMouseRoute->AddPoint(pMousePoint);
9308 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9312 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9313 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9314 &rhumbBearing, &rhumbDist);
9315 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9316 &gcDist, &gcBearing, NULL);
9317 double gcDistNM = gcDist / 1852.0;
9320 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9321 pow(rhumbDist - gcDistNM - 1, 0.5);
9324 msg << _(
"For this leg the Great Circle route is ")
9326 << _(
" shorter than rhumbline.\n\n")
9327 << _(
"Would you like include the Great Circle routing points "
9331 m_FinishRouteOnKillFocus =
false;
9332 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9333 wxYES_NO | wxNO_DEFAULT);
9334 m_FinishRouteOnKillFocus =
true;
9336 int answer = wxID_NO;
9339 if (answer == wxID_YES) {
9341 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9342 wxRealPoint gcCoord;
9344 for (
int i = 1; i <= segmentCount; i++) {
9345 double fraction = (double)i * (1.0 / (
double)segmentCount);
9346 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9347 gcDist * fraction, gcBearing,
9348 &gcCoord.x, &gcCoord.y, NULL);
9350 if (i < segmentCount) {
9351 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9353 gcPoint->SetNameShown(
false);
9354 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9357 gcPoint = pMousePoint;
9360 m_pMouseRoute->AddPoint(gcPoint);
9361 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9363 pSelect->AddSelectableRouteSegment(
9364 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9365 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9366 prevGcPoint = gcPoint;
9369 undo->CancelUndoableAction(
true);
9372 m_pMouseRoute->AddPoint(pMousePoint);
9373 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9374 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9375 rlon, m_prev_pMousePoint,
9376 pMousePoint, m_pMouseRoute);
9377 undo->AfterUndoableAction(m_pMouseRoute);
9381 m_pMouseRoute->AddPoint(pMousePoint);
9382 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9384 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9385 rlon, m_prev_pMousePoint,
9386 pMousePoint, m_pMouseRoute);
9387 undo->AfterUndoableAction(m_pMouseRoute);
9393 m_prev_pMousePoint = pMousePoint;
9400 int connect = tail->GetIndexOf(pMousePoint);
9405 int length = tail->GetnPoints();
9410 start = connect + 1;
9415 m_pMouseRoute->RemovePoint(
9419 for (i = start; i <= stop; i++) {
9420 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9423 m_pMouseRoute->GetnPoints();
9425 top_frame::Get()->RefreshAllCanvas();
9429 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9431 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9432 m_pMouseRoute->FinalizeForRendering();
9437 }
else if (m_bMeasure_Active && m_nMeasureState)
9440 m_bedge_pan =
false;
9444 if (m_ignore_next_leftup) {
9445 m_ignore_next_leftup =
false;
9449 if (m_nMeasureState == 1) {
9450 m_pMeasureRoute =
new Route();
9456 if (m_pMeasureRoute) {
9459 wxEmptyString, wxEmptyString);
9462 m_pMeasureRoute->AddPoint(pMousePoint);
9466 m_prev_pMousePoint = pMousePoint;
9468 m_pMeasureRoute->GetnPoints();
9472 CancelMeasureRoute();
9478 bool bSelectAllowed =
true;
9480 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9482 bSelectAllowed =
false;
9486 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9487 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9488 significant_drag) ||
9489 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9490 significant_drag)) {
9491 bSelectAllowed =
false;
9499 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9501 if (bSelectAllowed) {
9502 bool b_was_editing_mark = m_bMarkEditing;
9503 bool b_was_editing_route = m_bRouteEditing;
9504 FindRoutePointsAtCursor(SelectRadius,
9510 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9511 m_pRoutePointEditTarget = NULL;
9513 if (!b_was_editing_route) {
9514 if (m_pEditRouteArray) {
9515 b_startedit_route =
true;
9519 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9520 m_pTrackRolloverWin->IsActive(
false);
9522 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9523 m_pRouteRolloverWin->IsActive(
false);
9527 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9529 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9537 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9538 pre_rect.Union(route_rect);
9541 RefreshRect(pre_rect,
true);
9544 b_startedit_route =
false;
9548 if (m_pRoutePointEditTarget) {
9549 if (b_was_editing_mark ||
9550 b_was_editing_route) {
9551 if (m_lastRoutePointEditTarget) {
9555 .EnableDragHandle(
false);
9556 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9557 SELTYPE_DRAGHANDLE);
9561 if (m_pRoutePointEditTarget) {
9564 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9565 wxPoint2DDouble dragHandlePoint =
9567 .GetDragHandlePoint(
this);
9569 dragHandlePoint.m_y, dragHandlePoint.m_x,
9570 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9573 if (m_lastRoutePointEditTarget) {
9577 .EnableDragHandle(
false);
9578 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9579 SELTYPE_DRAGHANDLE);
9582 wxArrayPtrVoid *lastEditRouteArray =
9584 m_lastRoutePointEditTarget);
9585 if (lastEditRouteArray) {
9586 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9588 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9593 delete lastEditRouteArray;
9604 if (m_lastRoutePointEditTarget) {
9607 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9608 RefreshRect(wp_rect,
true);
9611 if (m_pRoutePointEditTarget) {
9614 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9615 RefreshRect(wp_rect,
true);
9623 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9624 bool b_start_rollover =
false;
9628 if (pFind) b_start_rollover =
true;
9631 if (!b_start_rollover && !b_startedit_route) {
9632 SelectableItemList SelList =
pSelect->FindSelectionList(
9636 if (pr && pr->IsVisible()) {
9637 b_start_rollover =
true;
9643 if (!b_start_rollover && !b_startedit_route) {
9644 SelectableItemList SelList =
pSelect->FindSelectionList(
9648 if (tr && tr->IsVisible()) {
9649 b_start_rollover =
true;
9655 if (b_start_rollover)
9656 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9660 bool appending =
false;
9661 bool inserting =
false;
9663 if (m_bRouteEditing ) {
9665 if (m_pRoutePointEditTarget) {
9671 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9672 double nearby_radius_meters =
9673 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9674 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9675 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9676 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9678 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9682 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9684 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9688 std::find(list->begin(), list->end(), pNearbyPoint);
9689 if (pos != list->end()) {
9701 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9706 OCPNMessageBox(
this,
9707 _(
"Replace this RoutePoint by the nearby "
9709 _(
"OpenCPN RoutePoint change"),
9710 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9711 if (dlg_return == wxID_YES) {
9716 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9719 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9721 if (tail && current && (tail != current)) {
9723 connect = tail->GetIndexOf(pNearbyPoint);
9724 int index_current_route =
9725 current->GetIndexOf(m_pRoutePointEditTarget);
9726 index_last = current->GetIndexOf(current->GetLastPoint());
9727 dlg_return1 = wxID_NO;
9729 index_current_route) {
9731 if (connect != tail->GetnPoints()) {
9734 _(
"Last part of route to be appended to dragged "
9738 _(
"Full route to be appended to dragged route?");
9740 dlg_return1 = OCPNMessageBox(
9741 this, dmsg, _(
"OpenCPN Route Create"),
9742 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9743 if (dlg_return1 == wxID_YES) {
9747 }
else if (index_current_route ==
9752 _(
"First part of route to be inserted into dragged "
9754 if (connect == tail->GetnPoints())
9756 "Full route to be inserted into dragged route?");
9758 dlg_return1 = OCPNMessageBox(
9759 this, dmsg, _(
"OpenCPN Route Create"),
9760 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9761 if (dlg_return1 == wxID_YES) {
9768 if (m_pRoutePointEditTarget->IsShared()) {
9770 dlg_return = OCPNMessageBox(
9772 _(
"Do you really want to delete and replace this "
9774 "\n" + _(
"which has been created manually?"),
9775 (
"OpenCPN RoutePoint warning"),
9776 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9779 if (dlg_return == wxID_YES) {
9780 pMousePoint = pNearbyPoint;
9782 pMousePoint->SetShared(
true);
9792 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9794 if (m_pEditRouteArray) {
9795 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9797 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9802 auto pos = std::find(list->begin(), list->end(),
9803 m_pRoutePointEditTarget);
9805 pSelect->DeleteAllSelectableRoutePoints(pr);
9806 pSelect->DeleteAllSelectableRouteSegments(pr);
9809 pos = std::find(list->begin(), list->end(),
9810 m_pRoutePointEditTarget);
9813 pSelect->AddAllSelectableRouteSegments(pr);
9814 pSelect->AddAllSelectableRoutePoints(pr);
9816 pr->FinalizeForRendering();
9817 pr->UpdateSegmentDistances();
9818 if (m_bRoutePoinDragging) {
9820 NavObj_dB::GetInstance().UpdateRoute(pr);
9828 if (m_pEditRouteArray) {
9829 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9831 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9850 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9857 delete m_pRoutePointEditTarget;
9858 m_lastRoutePointEditTarget = NULL;
9859 m_pRoutePointEditTarget = NULL;
9860 undo->AfterUndoableAction(pMousePoint);
9861 undo->InvalidateUndo();
9866 else if (m_bMarkEditing) {
9867 if (m_pRoutePointEditTarget)
9868 if (m_bRoutePoinDragging) {
9870 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9874 if (m_pRoutePointEditTarget)
9875 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9877 if (!m_pRoutePointEditTarget) {
9878 delete m_pEditRouteArray;
9879 m_pEditRouteArray = NULL;
9880 m_bRouteEditing =
false;
9882 m_bRoutePoinDragging =
false;
9889 int length = tail->GetnPoints();
9890 for (
int i = connect + 1; i <= length; i++) {
9891 current->AddPointAndSegment(tail->GetPoint(i),
false);
9894 top_frame::Get()->RefreshAllCanvas();
9897 current->FinalizeForRendering();
9903 pSelect->DeleteAllSelectableRoutePoints(current);
9904 pSelect->DeleteAllSelectableRouteSegments(current);
9905 for (
int i = 1; i < connect; i++) {
9906 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9908 pSelect->AddAllSelectableRouteSegments(current);
9909 pSelect->AddAllSelectableRoutePoints(current);
9910 current->FinalizeForRendering();
9917 if (m_pEditRouteArray) {
9918 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9919 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9932 if (m_bRouteEditing) {
9935 bool appending =
false;
9936 bool inserting =
false;
9939 if (m_pRoutePointEditTarget) {
9940 m_pRoutePointEditTarget->
m_bBlink =
false;
9944 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9945 double nearby_radius_meters =
9946 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9947 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9948 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9949 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9951 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9952 bool duplicate =
false;
9954 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9956 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9960 std::find(list->begin(), list->end(), pNearbyPoint);
9961 if (pos != list->end()) {
9973 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9978 OCPNMessageBox(
this,
9979 _(
"Replace this RoutePoint by the nearby "
9981 _(
"OpenCPN RoutePoint change"),
9982 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9983 if (dlg_return == wxID_YES) {
9987 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9990 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9992 if (tail && current && (tail != current)) {
9994 connect = tail->GetIndexOf(pNearbyPoint);
9995 int index_current_route =
9996 current->GetIndexOf(m_pRoutePointEditTarget);
9997 index_last = current->GetIndexOf(current->GetLastPoint());
9998 dlg_return1 = wxID_NO;
10000 index_current_route) {
10002 if (connect != tail->GetnPoints()) {
10005 _(
"Last part of route to be appended to dragged "
10009 _(
"Full route to be appended to dragged route?");
10011 dlg_return1 = OCPNMessageBox(
10012 this, dmsg, _(
"OpenCPN Route Create"),
10013 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10014 if (dlg_return1 == wxID_YES) {
10018 }
else if (index_current_route ==
10020 if (connect != 1) {
10023 _(
"First part of route to be inserted into dragged "
10025 if (connect == tail->GetnPoints())
10027 "Full route to be inserted into dragged route?");
10029 dlg_return1 = OCPNMessageBox(
10030 this, dmsg, _(
"OpenCPN Route Create"),
10031 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10032 if (dlg_return1 == wxID_YES) {
10039 if (m_pRoutePointEditTarget->IsShared()) {
10040 dlg_return = wxID_NO;
10041 dlg_return = OCPNMessageBox(
10043 _(
"Do you really want to delete and replace this "
10045 "\n" + _(
"which has been created manually?"),
10046 (
"OpenCPN RoutePoint warning"),
10047 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10050 if (dlg_return == wxID_YES) {
10051 pMousePoint = pNearbyPoint;
10053 pMousePoint->SetShared(
true);
10063 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10065 if (m_pEditRouteArray) {
10066 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10068 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10072 auto pos = std::find(list->begin(), list->end(),
10073 m_pRoutePointEditTarget);
10075 pSelect->DeleteAllSelectableRoutePoints(pr);
10076 pSelect->DeleteAllSelectableRouteSegments(pr);
10079 pos = std::find(list->begin(), list->end(),
10080 m_pRoutePointEditTarget);
10081 if (pos != list->end()) list->erase(pos);
10084 pSelect->AddAllSelectableRouteSegments(pr);
10085 pSelect->AddAllSelectableRoutePoints(pr);
10087 pr->FinalizeForRendering();
10088 pr->UpdateSegmentDistances();
10091 if (m_bRoutePoinDragging) {
10096 NavObj_dB::GetInstance().UpdateRoutePoint(
10097 m_pRoutePointEditTarget);
10099 NavObj_dB::GetInstance().UpdateRoute(pr);
10111 int length = tail->GetnPoints();
10112 for (
int i = connect + 1; i <= length; i++) {
10113 current->AddPointAndSegment(tail->GetPoint(i),
false);
10117 top_frame::Get()->RefreshAllCanvas();
10120 current->FinalizeForRendering();
10126 pSelect->DeleteAllSelectableRoutePoints(current);
10127 pSelect->DeleteAllSelectableRouteSegments(current);
10128 for (
int i = 1; i < connect; i++) {
10129 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10131 pSelect->AddAllSelectableRouteSegments(current);
10132 pSelect->AddAllSelectableRoutePoints(current);
10133 current->FinalizeForRendering();
10140 if (m_pEditRouteArray) {
10141 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10143 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10155 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10162 delete m_pRoutePointEditTarget;
10163 m_lastRoutePointEditTarget = NULL;
10164 undo->AfterUndoableAction(pMousePoint);
10165 undo->InvalidateUndo();
10170 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10173 delete m_pEditRouteArray;
10174 m_pEditRouteArray = NULL;
10178 m_bRouteEditing =
false;
10179 m_pRoutePointEditTarget = NULL;
10185 else if (m_bMarkEditing) {
10186 if (m_pRoutePointEditTarget) {
10187 if (m_bRoutePoinDragging) {
10189 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10191 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10196 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10198 RefreshRect(wp_rect,
true);
10201 m_pRoutePointEditTarget = NULL;
10202 m_bMarkEditing =
false;
10207 else if (leftIsDown) {
10208 leftIsDown =
false;
10212 if (!m_bChartDragging && !m_bMeasure_Active) {
10214 m_bChartDragging =
false;
10218 m_bRoutePoinDragging =
false;
10221 if (ret)
return true;
10224 if (event.RightDown()) {
10235 m_FinishRouteOnKillFocus =
false;
10236 CallPopupMenu(mx, my);
10237 m_FinishRouteOnKillFocus =
true;
10247 if (event.ShiftDown()) {
10251 event.GetPosition(&x, &y);
10253 x *= m_displayScale;
10254 y *= m_displayScale;
10260 int wheel_dir =
event.GetWheelRotation();
10263 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10264 wheel_dir = wheel_dir > 0 ? 1 : -1;
10266 double factor = g_mouse_zoom_sensitivity;
10267 if (wheel_dir < 0) factor = 1 / factor;
10270 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10271 if (wheel_dir == m_last_wheel_dir) {
10272 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10277 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10278 m_wheelstopwatch.Start(0);
10283 m_last_wheel_dir = wheel_dir;
10288 if (event.LeftDown()) {
10294 last_drag.x = x, last_drag.y = y;
10295 panleftIsDown =
true;
10298 if (event.LeftUp()) {
10299 if (panleftIsDown) {
10301 panleftIsDown =
false;
10304 if (!m_bChartDragging && !m_bMeasure_Active) {
10305 switch (cursor_region) {
10327 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10332 m_bChartDragging =
false;
10338 if (event.Dragging() && event.LeftIsDown()) {
10354 if (g_btouch && !m_inPinch) {
10355 struct timespec now;
10356 clock_gettime(CLOCK_MONOTONIC, &now);
10357 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10359 bool trigger_hold =
false;
10360 if (
false == m_bChartDragging) {
10361 if (m_DragTrigger < 0) {
10364 m_DragTriggerStartTime = tnow;
10365 trigger_hold =
true;
10367 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10368 m_DragTrigger = -1;
10373 if (trigger_hold)
return true;
10375 if (
false == m_bChartDragging) {
10378 last_drag.x = x - 1, last_drag.y = y - 1;
10379 m_bChartDragging =
true;
10380 m_chart_drag_total_time = 0;
10381 m_chart_drag_total_x = 0;
10382 m_chart_drag_total_y = 0;
10383 m_inertia_last_drag_x = x;
10384 m_inertia_last_drag_y = y;
10385 m_drag_vec_x.clear();
10386 m_drag_vec_y.clear();
10387 m_drag_vec_t.clear();
10388 m_last_drag_time = tnow;
10392 uint64_t delta_t = tnow - m_last_drag_time;
10393 double delta_tf = delta_t / 1e9;
10395 m_chart_drag_total_time += delta_tf;
10396 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10397 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10399 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10400 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10401 m_drag_vec_t.push_back(delta_tf);
10403 m_inertia_last_drag_x = x;
10404 m_inertia_last_drag_y = y;
10405 m_last_drag_time = tnow;
10407 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10408 m_bChartDragging =
true;
10409 StartTimedMovement();
10410 m_pan_drag.x += last_drag.x - x;
10411 m_pan_drag.y += last_drag.y - y;
10412 last_drag.x = x, last_drag.y = y;
10414 }
else if (!g_btouch) {
10415 if ((last_drag.x != x) || (last_drag.y != y)) {
10416 if (!m_routeState) {
10419 m_bChartDragging =
true;
10420 StartTimedMovement();
10421 m_pan_drag.x += last_drag.x - x;
10422 m_pan_drag.y += last_drag.y - y;
10423 last_drag.x = x, last_drag.y = y;
10430 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10432 m_ignore_next_leftup =
true;
10433 m_DoubleClickTimer->Start();
10434 singleClickEventIsValid =
false;
10442void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10443 if (MouseEventOverlayWindows(event))
return;
10447 bool nm = MouseEventProcessObjects(event);
10451void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10454 wxCursor *ptarget_cursor = pCursorArrow;
10455 if (!pPlugIn_Cursor) {
10456 ptarget_cursor = pCursorArrow;
10457 if ((!m_routeState) &&
10458 (!m_bMeasure_Active) ) {
10459 if (cursor_region == MID_RIGHT) {
10460 ptarget_cursor = pCursorRight;
10461 }
else if (cursor_region == MID_LEFT) {
10462 ptarget_cursor = pCursorLeft;
10463 }
else if (cursor_region == MID_TOP) {
10464 ptarget_cursor = pCursorDown;
10465 }
else if (cursor_region == MID_BOT) {
10466 ptarget_cursor = pCursorUp;
10468 ptarget_cursor = pCursorArrow;
10470 }
else if (m_bMeasure_Active ||
10472 ptarget_cursor = pCursorPencil;
10474 ptarget_cursor = pPlugIn_Cursor;
10477 SetCursor(*ptarget_cursor);
10480void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10481 SetCursor(*pCursorArrow);
10484void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10488 wxArrayString files;
10490 ChartBase *target_chart = GetChartAtCursor();
10491 if (target_chart) {
10492 file.Assign(target_chart->GetFullPath());
10493 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10494 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10497 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10499 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10500 unsigned int im = stackIndexArray.size();
10501 int scale = 2147483647;
10502 if (VPoint.b_quilt && im > 0) {
10503 for (
unsigned int is = 0; is < im; is++) {
10504 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10505 CHART_TYPE_MBTILES) {
10506 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10508 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10509 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10511 .Contains(lat, lon)) {
10512 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10515 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10516 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10524 std::vector<Ais8_001_22 *> area_notices;
10526 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10529 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10530 auto target_data = target.second;
10531 if (!target_data->area_notices.empty()) {
10532 for (
auto &ani : target_data->area_notices) {
10537 for (Ais8_001_22_SubAreaList::iterator sa =
10538 area_notice.sub_areas.begin();
10539 sa != area_notice.sub_areas.end(); ++sa) {
10540 switch (sa->shape) {
10541 case AIS8_001_22_SHAPE_CIRCLE: {
10542 wxPoint target_point;
10544 bbox.Expand(target_point);
10545 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10548 case AIS8_001_22_SHAPE_RECT: {
10549 wxPoint target_point;
10551 bbox.Expand(target_point);
10552 if (sa->e_dim_m > sa->n_dim_m)
10553 bbox.EnLarge(sa->e_dim_m * vp_scale);
10555 bbox.EnLarge(sa->n_dim_m * vp_scale);
10558 case AIS8_001_22_SHAPE_POLYGON:
10559 case AIS8_001_22_SHAPE_POLYLINE: {
10560 for (
int i = 0; i < 4; ++i) {
10561 double lat = sa->latitude;
10562 double lon = sa->longitude;
10563 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10565 wxPoint target_point;
10567 bbox.Expand(target_point);
10571 case AIS8_001_22_SHAPE_SECTOR: {
10572 double lat1 = sa->latitude;
10573 double lon1 = sa->longitude;
10575 wxPoint target_point;
10577 bbox.Expand(target_point);
10578 for (
int i = 0; i < 18; ++i) {
10581 sa->left_bound_deg +
10582 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10583 sa->radius_m / 1852.0, &lat, &lon);
10585 bbox.Expand(target_point);
10587 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10590 bbox.Expand(target_point);
10596 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10597 area_notices.push_back(&area_notice);
10604 if (target_chart || !area_notices.empty() || file.HasName()) {
10606 int sel_rad_pix = 5;
10607 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10612 SetCursor(wxCURSOR_WAIT);
10613 bool lightsVis = m_encShowLights;
10614 if (!lightsVis) SetShowENCLights(
true);
10617 ListOfObjRazRules *rule_list = NULL;
10618 ListOfPI_S57Obj *pi_rule_list = NULL;
10621 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10622 else if (target_plugin_chart)
10623 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10624 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10626 ListOfObjRazRules *overlay_rule_list = NULL;
10627 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10630 if (CHs57_Overlay) {
10631 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10632 zlat, zlon, SelectRadius, &GetVP());
10635 if (!lightsVis) SetShowENCLights(
false);
10638 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10639 wxString face = dFont->GetFaceName();
10643 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10644 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10648 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10656 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10657 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10660 int points = dFont->GetPointSize();
10662 int points = dFont->GetPointSize() + 1;
10666 for (
int i = -2; i < 5; i++) {
10667 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10671 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10673 if (overlay_rule_list && CHs57_Overlay) {
10674 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10675 objText <<
"<hr noshade>";
10678 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10679 an != area_notices.end(); ++an) {
10680 objText <<
"<b>AIS Area Notice:</b> ";
10681 objText << ais8_001_22_notice_names[(*an)->notice_type];
10682 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10683 (*an)->sub_areas.begin();
10684 sa != (*an)->sub_areas.end(); ++sa)
10685 if (!sa->text.empty()) objText << sa->text;
10686 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10687 objText <<
"<hr noshade>";
10691 objText << Chs57->CreateObjDescriptions(rule_list);
10692 else if (target_plugin_chart)
10693 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10696 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10699 wxString AddFiles, filenameOK;
10701 if (!target_plugin_chart) {
10704 AddFiles = wxString::Format(
10705 "<hr noshade><br><b>Additional info files attached to: </b> "
10707 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10709 file.GetFullName());
10711 file.Assign(file.GetPath(),
"");
10712 wxDir dir(file.GetFullPath());
10714 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10716 file.Assign(dir.GetNameWithSep().append(filename));
10717 wxString FormatString =
10718 "<td valign=top><font size=-2><a "
10719 "href=\"%s\">%s</a></font></td>";
10720 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10721 filenameOK = file.GetFullPath();
10723 if (3 * ((
int)filecount / 3) == filecount)
10724 FormatString.Prepend(
"<tr>");
10726 FormatString.Prepend(
10727 "<td>  </td>");
10730 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10731 file.GetFullName());
10734 cont = dir.GetNext(&filename);
10736 objText << AddFiles <<
"</table>";
10738 objText <<
"</font>";
10739 objText <<
"</body></html>";
10741 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10745 if ((!Chs57 && filecount == 1)) {
10747 wxHtmlLinkInfo hli(filenameOK);
10748 wxHtmlLinkEvent hle(1, hli);
10752 if (rule_list) rule_list->Clear();
10755 if (overlay_rule_list) overlay_rule_list->Clear();
10756 delete overlay_rule_list;
10758 if (pi_rule_list) pi_rule_list->Clear();
10759 delete pi_rule_list;
10761 SetCursor(wxCURSOR_ARROW);
10765void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10774 wxSize canvas_size = GetSize();
10781 wxPoint canvas_pos = GetPosition();
10784 bool newFit =
false;
10785 if (canvas_size.x < fitted_size.x) {
10786 fitted_size.x = canvas_size.x - 40;
10787 if (canvas_size.y < fitted_size.y)
10788 fitted_size.y -= 40;
10790 if (canvas_size.y < fitted_size.y) {
10791 fitted_size.y = canvas_size.y - 40;
10792 if (canvas_size.x < fitted_size.x)
10793 fitted_size.x -= 40;
10804 wxString title_base = _(
"Mark Properties");
10806 title_base = _(
"Waypoint Properties");
10811 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10823void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10833 if (g_bresponsive) {
10834 wxSize canvas_size = GetSize();
10835 wxPoint canvas_pos = GetPosition();
10839 if (canvas_size.x < fitted_size.x) {
10840 fitted_size.x = canvas_size.x;
10841 if (canvas_size.y < fitted_size.y)
10842 fitted_size.y -= 20;
10844 if (canvas_size.y < fitted_size.y) {
10845 fitted_size.y = canvas_size.y;
10846 if (canvas_size.x < fitted_size.x)
10847 fitted_size.x -= 20;
10856 wxPoint xxp = ClientToScreen(canvas_pos);
10867void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10879void pupHandler_PasteWaypoint() {
10882 int pasteBuffer = kml.ParsePasteBuffer();
10883 RoutePoint *pasted = kml.GetParsedRoutePoint();
10884 if (!pasted)
return;
10886 double nearby_radius_meters =
10887 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10889 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10890 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10892 int answer = wxID_NO;
10896 "There is an existing waypoint at the same location as the one you are "
10897 "pasting. Would you like to merge the pasted data with it?\n\n");
10898 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10899 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10900 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10903 if (answer == wxID_YES) {
10904 nearPoint->SetName(pasted->GetName());
10910 if (answer == wxID_NO) {
10913 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10916 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10925 top_frame::Get()->InvalidateAllGL();
10926 top_frame::Get()->RefreshAllCanvas(
false);
10929void pupHandler_PasteRoute() {
10932 int pasteBuffer = kml.ParsePasteBuffer();
10933 Route *pasted = kml.GetParsedRoute();
10934 if (!pasted)
return;
10936 double nearby_radius_meters =
10937 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10943 bool mergepoints =
false;
10944 bool createNewRoute =
true;
10945 int existingWaypointCounter = 0;
10947 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10948 curPoint = pasted->GetPoint(i);
10949 nearPoint = pWayPointMan->GetNearbyWaypoint(
10950 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10952 mergepoints =
true;
10953 existingWaypointCounter++;
10961 int answer = wxID_NO;
10965 "There are existing waypoints at the same location as some of the ones "
10966 "you are pasting. Would you like to just merge the pasted data into "
10968 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10969 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10970 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10972 if (answer == wxID_CANCEL) {
10979 if (mergepoints && answer == wxID_YES &&
10980 existingWaypointCounter == pasted->GetnPoints()) {
10983 createNewRoute =
false;
10989 Route *newRoute = 0;
10992 if (createNewRoute) {
10993 newRoute =
new Route();
10997 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10998 curPoint = pasted->GetPoint(i);
11001 newPoint = pWayPointMan->GetNearbyWaypoint(
11002 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11003 newPoint->SetName(curPoint->GetName());
11006 if (createNewRoute) newRoute->AddPoint(newPoint);
11012 newPoint->SetIconName(
"circle");
11015 newPoint->SetShared(
false);
11017 newRoute->AddPoint(newPoint);
11018 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11021 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11024 if (i > 1 && createNewRoute)
11025 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11026 curPoint->m_lat, curPoint->m_lon,
11027 prevPoint, newPoint, newRoute);
11028 prevPoint = newPoint;
11031 if (createNewRoute) {
11034 NavObj_dB::GetInstance().InsertRoute(newRoute);
11044 top_frame::Get()->InvalidateAllGL();
11045 top_frame::Get()->RefreshAllCanvas(
false);
11051void pupHandler_PasteTrack() {
11054 int pasteBuffer = kml.ParsePasteBuffer();
11055 Track *pasted = kml.GetParsedTrack();
11056 if (!pasted)
return;
11064 newTrack->SetName(pasted->GetName());
11066 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11067 curPoint = pasted->GetPoint(i);
11071 wxDateTime now = wxDateTime::Now();
11074 newTrack->AddPoint(newPoint);
11077 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11078 newPoint->m_lat, newPoint->m_lon,
11079 prevPoint, newPoint, newTrack);
11081 prevPoint = newPoint;
11086 NavObj_dB::GetInstance().InsertTrack(newTrack);
11088 top_frame::Get()->InvalidateAllGL();
11089 top_frame::Get()->RefreshAllCanvas(
false);
11092bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11095 v[
"CursorPosition_x"] = x;
11096 v[
"CursorPosition_y"] = y;
11099 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11100 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11101 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11106 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11108 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11111#define SELTYPE_UNKNOWN 0x0001
11112#define SELTYPE_ROUTEPOINT 0x0002
11113#define SELTYPE_ROUTESEGMENT 0x0004
11114#define SELTYPE_TIDEPOINT 0x0008
11115#define SELTYPE_CURRENTPOINT 0x0010
11116#define SELTYPE_ROUTECREATE 0x0020
11117#define SELTYPE_AISTARGET 0x0040
11118#define SELTYPE_MARKPOINT 0x0080
11119#define SELTYPE_TRACKSEGMENT 0x0100
11120#define SELTYPE_DRAGHANDLE 0x0200
11123 if (g_bhide_context_menus)
return true;
11125 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11126 m_pIDXCandidate, m_nmea_log);
11129 wxEVT_COMMAND_MENU_SELECTED,
11130 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11136 if (m_inLongPress) {
11137 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11138 m_inLongPress =
false;
11142 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11145 wxEVT_COMMAND_MENU_SELECTED,
11146 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11148 delete m_canvasMenu;
11149 m_canvasMenu = NULL;
11159void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11162 if (m_canvasMenu) {
11163 m_canvasMenu->PopupMenuHandler(event);
11168void ChartCanvas::StartRoute() {
11170 if (g_brouteCreating)
return;
11174 g_brouteCreating =
true;
11176 m_bDrawingRoute =
false;
11177 SetCursor(*pCursorPencil);
11179 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11181 HideGlobalToolbar();
11184 androidSetRouteAnnunciator(
true);
11188wxString ChartCanvas::FinishRoute() {
11190 m_prev_pMousePoint = NULL;
11191 m_bDrawingRoute =
false;
11193 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11196 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11198 androidSetRouteAnnunciator(
false);
11201 SetCursor(*pCursorArrow);
11203 if (m_pMouseRoute) {
11204 if (m_bAppendingRoute) {
11206 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11208 if (m_pMouseRoute->GetnPoints() > 1) {
11210 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11213 m_pMouseRoute = NULL;
11216 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11228 m_bAppendingRoute =
false;
11229 m_pMouseRoute = NULL;
11231 m_pSelectedRoute = NULL;
11233 undo->InvalidateUndo();
11234 top_frame::Get()->RefreshAllCanvas(
true);
11238 ShowGlobalToolbar();
11240 g_brouteCreating =
false;
11245void ChartCanvas::HideGlobalToolbar() {
11246 if (m_canvasIndex == 0) {
11247 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11251void ChartCanvas::ShowGlobalToolbar() {
11252 if (m_canvasIndex == 0) {
11253 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11257void ChartCanvas::ShowAISTargetList() {
11258 if (NULL == g_pAISTargetList) {
11262 g_pAISTargetList->UpdateAISTargetList();
11265void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11266 if (!m_bShowOutlines)
return;
11270 int nEntry =
ChartData->GetChartTableEntries();
11272 for (
int i = 0; i < nEntry; i++) {
11276 bool b_group_draw =
false;
11277 if (m_groupIndex > 0) {
11278 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11279 int index = pt->GetGroupArray()[ig];
11280 if (m_groupIndex == index) {
11281 b_group_draw =
true;
11286 b_group_draw =
true;
11288 if (b_group_draw) RenderChartOutline(dc, i, vp);
11294 if (VPoint.b_quilt) {
11295 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11296 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11300 }
else if (m_singleChart &&
11301 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11305 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11308 if (zoom_factor > 8.0) {
11309 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11312 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11316 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11320void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11322 if (g_bopengl && m_glcc) {
11324 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11329 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11330 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11333 float plylat, plylon;
11334 float plylat1, plylon1;
11336 int pixx, pixy, pixx1, pixy1;
11339 ChartData->GetDBBoundingBox(dbIndex, box);
11343 if (box.GetLonRange() == 360)
return;
11345 double lon_bias = 0;
11347 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11349 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11351 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11352 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11354 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11355 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11358 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11361 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11362 if (0 == nAuxPlyEntries)
11366 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11367 plylon += lon_bias;
11373 for (
int i = 0; i < nPly - 1; i++) {
11374 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11375 plylon1 += lon_bias;
11381 int pixxs1 = pixx1;
11382 int pixys1 = pixy1;
11384 bool b_skip =
false;
11388 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11389 pow((
double)(pixy1 - pixy), 2)) /
11395 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11400 if (fabs(dist - distgc) > 10000. * 1852.)
11406 ClipResult res = cohen_sutherland_line_clip_i(
11408 if (res != Invisible && !b_skip)
11409 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11417 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11418 plylon1 += lon_bias;
11424 ClipResult res = cohen_sutherland_line_clip_i(
11426 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11433 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11434 for (
int j = 0; j < nAuxPlyEntries; j++) {
11436 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11441 for (
int i = 0; i < nAuxPly - 1; i++) {
11442 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11448 int pixxs1 = pixx1;
11449 int pixys1 = pixy1;
11451 bool b_skip =
false;
11455 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11456 ((pixy1 - pixy) * (pixy1 - pixy))) /
11461 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11466 if (fabs(dist - distgc) > 10000. * 1852.)
11472 ClipResult res = cohen_sutherland_line_clip_i(
11474 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11482 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11487 ClipResult res = cohen_sutherland_line_clip_i(
11489 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11494static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11495 const wxArrayString &legend) {
11496 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11498 int pointsize = dFont->GetPointSize();
11502 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11503 false, dFont->GetFaceName());
11505 dc.SetFont(*psRLI_font);
11512 int hilite_offset = 3;
11514 for (wxString line : legend) {
11517 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11519 dc.GetTextExtent(line, &wl, &hl);
11528 xp = ref_point.x - w;
11530 yp += hilite_offset;
11532 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11534 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11535 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11537 for (wxString line : legend) {
11538 dc.DrawText(line, xp, yp);
11543void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11544 if (!g_bAllowShipToActive)
return;
11550 wxPoint2DDouble pa, pb;
11557 if (rt->
m_width != wxPENSTYLE_INVALID)
11559 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11560 g_shipToActiveStyle, 5)];
11561 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11563 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11566 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11569 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11572 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11573 (
int)pb.m_y, GetVP(),
true);
11577#ifdef USE_ANDROID_GLES2
11578 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11580 if (style != wxPENSTYLE_SOLID) {
11581 if (glChartCanvas::dash_map.find(style) !=
11582 glChartCanvas::dash_map.end()) {
11583 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11587 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11590 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11591 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11597void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11599 if (m_routeState >= 2) route = m_pMouseRoute;
11600 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11601 route = m_pMeasureRoute;
11603 if (!route)
return;
11611 int np = route->GetnPoints();
11613 if (g_btouch && (np > 1)) np--;
11615 render_lat = rp.m_lat;
11616 render_lon = rp.m_lon;
11619 double rhumbBearing, rhumbDist;
11621 &rhumbBearing, &rhumbDist);
11622 double brg = rhumbBearing;
11623 double dist = rhumbDist;
11627 double gcBearing, gcBearing2, gcDist;
11628 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11631 double gcDistm = gcDist / 1852.0;
11634 rhumbBearing = 90.;
11636 wxPoint destPoint, lastPoint;
11639 int milesDiff = rhumbDist - gcDistm;
11640 if (milesDiff > 1) {
11651 for (
int i = 1; i <= milesDiff; i++) {
11652 double p = (double)i * (1.0 / (
double)milesDiff);
11654 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11655 &pLon, &pLat, &gcBearing2);
11657 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11659 lastPoint = destPoint;
11662 if (r_rband.x && r_rband.y) {
11663 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11665 if (m_bMeasure_DistCircle) {
11666 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11667 powf((
float)(r_rband.y - lastPoint.y), 2));
11670 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11671 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11677 wxString routeInfo;
11678 wxArrayString infoArray;
11681 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11687 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11689 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11690 (
int)varBrg, 0x00B0);
11693 infoArray.Add(routeInfo);
11699 routeInfo <<
"Reverse: ";
11701 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11702 (
int)(brg + 180.) % 360, 0x00B0);
11704 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11705 (
int)(varBrg + 180.) % 360, 0x00B0);
11706 infoArray.Add(routeInfo);
11712 s0.Append(_(
"Route") +
": ");
11714 s0.Append(_(
"Layer Route: "));
11717 if (!g_btouch) disp_length += dist;
11723 RouteLegInfo(dc, r_rband, infoArray);
11725 m_brepaint_piano =
true;
11728void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11729 if (!m_bShowVisibleSectors)
return;
11731 if (g_bDeferredInitDone) {
11733 double rhumbBearing, rhumbDist;
11734 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11735 &rhumbBearing, &rhumbDist);
11737 if (rhumbDist > 0.05)
11739 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11740 m_sectorlegsVisible);
11741 m_sector_glat =
gLat;
11742 m_sector_glon =
gLon;
11744 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11748void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11756void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11757 if (!ps52plib)
return;
11759 if (VPoint.b_quilt) {
11760 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11762 if (m_pQuilt->IsQuiltVector()) {
11763 if (ps52plib->GetStateHash() != m_s52StateHash) {
11765 m_s52StateHash = ps52plib->GetStateHash();
11769 if (ps52plib->GetStateHash() != m_s52StateHash) {
11771 m_s52StateHash = ps52plib->GetStateHash();
11776 bool bSendPlibState =
true;
11777 if (VPoint.b_quilt) {
11778 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11781 if (bSendPlibState) {
11783 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11784 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11785 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11786 v[
"OpenCPN Version Date"] = VERSION_DATE;
11787 v[
"OpenCPN Version Full"] = VERSION_FULL;
11790 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11791 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11792 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11793 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11794 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11795 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11796 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11800 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11801 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11805 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11806 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11807 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11808 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11809 ps52plib->m_bShowS57ImportantTextOnly;
11810 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11811 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11812 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11813 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11814 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11817 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11818 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11819 v[
"OpenCPN Scale Factor Exp"] =
11820 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11827 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11828 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11829 g_lastS52PLIBPluginMessage = out;
11836 wxPaintDC dc(
this);
11846 if (!m_b_paint_enable) {
11854 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11856 if (m_glcc && g_bopengl) {
11857 if (!s_in_update) {
11867 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11869 wxRegion ru = GetUpdateRegion();
11871 int rx, ry, rwidth, rheight;
11872 ru.GetBox(rx, ry, rwidth, rheight);
11874#ifdef ocpnUSE_DIBSECTION
11877 wxMemoryDC temp_dc;
11885 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11886 height += m_Piano->GetHeight();
11888 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11892 int thumbx, thumby, thumbsx, thumbsy;
11893 pthumbwin->GetPosition(&thumbx, &thumby);
11894 pthumbwin->GetSize(&thumbsx, &thumbsy);
11895 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11898 rgn_chart.Subtract(rgn_thumbwin);
11899 ru.Subtract(rgn_thumbwin);
11905 wxRegion rgn_blit = ru;
11906 if (g_bShowChartBar) {
11907 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11908 GetClientSize().x, m_Piano->GetHeight());
11911 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11912 if (style->chartStatusWindowTransparent)
11913 m_brepaint_piano =
true;
11915 ru.Subtract(chart_bar_rect);
11919 if (m_Compass && m_Compass->IsShown()) {
11920 wxRect compassRect = m_Compass->
GetRect();
11921 if (ru.Contains(compassRect) != wxOutRegion) {
11922 ru.Subtract(compassRect);
11926 if (m_notification_button) {
11927 wxRect noteRect = m_notification_button->
GetRect();
11928 if (ru.Contains(noteRect) != wxOutRegion) {
11929 ru.Subtract(noteRect);
11934 bool b_newview =
true;
11939 m_cache_vp.IsValid()) {
11945 bool b_rcache_ok =
false;
11946 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11947 b_rcache_ok = !b_newview;
11950 if (VPoint.b_MercatorProjectionOverride)
11951 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11965 if (b_rcache_ok) chart_get_region.Clear();
11968 if (VPoint.b_quilt)
11970 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11972 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11977 AbstractPlatform::ShowBusySpinner();
11981 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11982 (m_working_bm.GetHeight() != svp.
pix_height))
11986 if (fabs(VPoint.
rotation) < 0.01) {
11987 bool b_save =
true;
11992 m_cache_vp.Invalidate();
12006 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12011 int dy = c_new.y - c_old.y;
12012 int dx = c_new.x - c_old.x;
12017 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12021 temp_dc.SelectObject(m_working_bm);
12023 wxMemoryDC cache_dc;
12024 cache_dc.SelectObject(m_cached_chart_bm);
12028 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12031 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12037 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12040 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12048 update_region.Union(
12051 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12056 update_region.Union(
12059 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12063 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12065 cache_dc.SelectObject(wxNullBitmap);
12069 temp_dc.SelectObject(m_cached_chart_bm);
12072 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12076 temp_dc.SelectObject(m_working_bm);
12077 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12082 temp_dc.SelectObject(m_cached_chart_bm);
12087 temp_dc.SelectObject(m_working_bm);
12088 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12101 wxMemoryDC scratch_dc_0;
12102 scratch_dc_0.SelectObject(m_cached_chart_bm);
12105 scratch_dc_0.SelectObject(wxNullBitmap);
12114 temp_dc.SelectObject(m_working_bm);
12117 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12118 chart_get_all_region);
12121 AbstractPlatform::HideBusySpinner();
12127 if (!m_singleChart) {
12128 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12133 if (!chart_get_region.IsEmpty()) {
12134 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12138 if (temp_dc.IsOk()) {
12143 if (!VPoint.b_quilt) {
12146 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12147 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12154 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12155 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12158 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12160 temp_dc.DestroyClippingRegion();
12165 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12167 if (!backgroundRegion.IsEmpty()) {
12173 wxColour water = pWorldBackgroundChart->water;
12174 if (water.IsOk()) {
12175 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12176 temp_dc.SetBrush(wxBrush(water));
12178 while (upd.HaveRects()) {
12179 wxRect rect = upd.GetRect();
12180 temp_dc.DrawRectangle(rect);
12185 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12186 temp_dc.SetDeviceClippingRegion(*clip_region);
12187 delete clip_region;
12191 SetVPRotation(VPoint.
skew);
12200 wxMemoryDC *pChartDC = &temp_dc;
12201 wxMemoryDC rotd_dc;
12203 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12205 if (!b_rcache_ok) {
12207 wxMemoryDC tbase_dc;
12209 tbase_dc.SelectObject(bm_base);
12211 tbase_dc.SelectObject(wxNullBitmap);
12213 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12216 wxImage base_image;
12217 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12225 bool b_rot_ok =
false;
12226 if (base_image.IsOk()) {
12229 m_b_rot_hidef =
false;
12233 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12234 m_b_rot_hidef, &m_roffset);
12239 rot_vp.IsValid() && (ri.IsOk())) {
12246 m_prot_bm =
new wxBitmap(ri);
12249 m_roffset.x += VPoint.rv_rect.x;
12250 m_roffset.y += VPoint.rv_rect.y;
12253 if (m_prot_bm && m_prot_bm->IsOk()) {
12254 rotd_dc.SelectObject(*m_prot_bm);
12255 pChartDC = &rotd_dc;
12257 pChartDC = &temp_dc;
12258 m_roffset = wxPoint(0, 0);
12261 pChartDC = &temp_dc;
12262 m_roffset = wxPoint(0, 0);
12265 wxPoint offset = m_roffset;
12268 m_cache_vp = VPoint;
12271 wxMemoryDC mscratch_dc;
12272 mscratch_dc.SelectObject(*pscratch_bm);
12274 mscratch_dc.ResetBoundingBox();
12275 mscratch_dc.DestroyClippingRegion();
12276 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12279 wxRegionIterator upd(rgn_blit);
12281 wxRect rect = upd.GetRect();
12283 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12284 rect.x - offset.x, rect.y - offset.y);
12290 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12291 if (
this == wxWindow::FindFocus()) {
12294 wxColour colour = GetGlobalColor(
"BLUE4");
12295 mscratch_dc.SetPen(wxPen(colour));
12296 mscratch_dc.SetBrush(wxBrush(colour));
12298 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12299 mscratch_dc.DrawRectangle(activeRect);
12304 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12305 unsigned int im = stackIndexArray.size();
12306 if (VPoint.b_quilt && im > 0) {
12307 std::vector<int> tiles_to_show;
12308 for (
unsigned int is = 0; is < im; is++) {
12310 ChartData->GetChartTableEntry(stackIndexArray[is]);
12311 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12314 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12315 tiles_to_show.push_back(stackIndexArray[is]);
12319 if (tiles_to_show.size())
12320 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12326 ocpnDC scratch_dc(mscratch_dc);
12327 RenderAlertMessage(mscratch_dc, GetVP());
12333#ifdef ocpnUSE_DIBSECTION
12338 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12339 q_dc.SelectObject(qbm);
12342 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12345 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12346 q_dc.SetBrush(qbr);
12347 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12350 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12353 q_dc.SelectObject(wxNullBitmap);
12362 if( VPoint.b_quilt ) {
12363 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12364 ChartBase *chart = m_pQuilt->GetRefChart();
12365 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12370 ChPI->ClearPLIBTextList();
12373 ps52plib->ClearTextList();
12377 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12379 wxColor maskBackground = wxColour(1,0,0);
12380 t_dc.SelectObject( qbm );
12381 t_dc.SetBackground(wxBrush(maskBackground));
12385 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12388 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12389 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12392 wxRegionIterator upd_final( ru );
12393 while( upd_final ) {
12394 wxRect rect = upd_final.GetRect();
12395 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12399 t_dc.SelectObject( wxNullBitmap );
12405 if (VPoint.b_quilt) {
12406 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12407 ChartBase *chart = m_pQuilt->GetRefChart();
12408 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12412 ChPI->ClearPLIBTextList();
12414 if (ps52plib) ps52plib->ClearTextList();
12419 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12421 if (g_bShowChartBar && m_Piano) {
12422 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12423 GetVP().pix_width, m_Piano->GetHeight());
12426 if (!style->chartStatusWindowTransparent)
12427 chart_all_text_region.Subtract(chart_bar_rect);
12430 if (m_Compass && m_Compass->IsShown()) {
12431 wxRect compassRect = m_Compass->
GetRect();
12432 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12433 chart_all_text_region.Subtract(compassRect);
12437 mscratch_dc.DestroyClippingRegion();
12439 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12440 chart_all_text_region);
12446 ocpnDC scratch_dc(mscratch_dc);
12447 DrawOverlayObjects(scratch_dc, ru);
12450 wxRegionIterator upd_final(rgn_blit);
12451 while (upd_final) {
12452 wxRect rect = upd_final.GetRect();
12453 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12460 temp_dc.SelectObject(wxNullBitmap);
12462 mscratch_dc.SelectObject(wxNullBitmap);
12464 dc.DestroyClippingRegion();
12469void ChartCanvas::PaintCleanup() {
12471 if (m_inPinch)
return;
12482 m_bTCupdate =
false;
12486 WarpPointer(warp_x, warp_y);
12493 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12494 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12498wxColour GetErrorGraphicColor(
double val)
12517 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12518 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12519 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12520 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12521 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12522 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12523 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12524 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12525 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12526 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12527 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12528 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12529 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12530 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12531 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12532 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12533 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12534 else if( val >= 48) c.Set(
"#410000");
12539void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12542 gr_image.InitAlpha();
12544 double maxval = -10000;
12545 double minval = 10000;
12562 maxval = wxMax(maxval, (glat - rlat));
12563 minval = wxMin(minval, (glat - rlat));
12580 double f = ((glat - rlat)-minval)/(maxval - minval);
12582 double dy = (f * 40);
12584 wxColour c = GetErrorGraphicColor(dy);
12585 unsigned char r = c.Red();
12586 unsigned char g = c.Green();
12587 unsigned char b = c.Blue();
12589 gr_image.SetRGB(j, i, r,g,b);
12590 if((glat - rlat )!= 0)
12591 gr_image.SetAlpha(j, i, 128);
12593 gr_image.SetAlpha(j, i, 255);
12600 wxBitmap *pbm =
new wxBitmap(gr_image);
12601 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12602 pbm->SetMask(gr_mask);
12604 pmdc->DrawBitmap(*pbm, 0,0);
12612void ChartCanvas::CancelMouseRoute() {
12614 m_pMouseRoute = NULL;
12615 m_bDrawingRoute =
false;
12618int ChartCanvas::GetNextContextMenuId() {
12619 return CanvasMenuHandler::GetNextContextMenuId();
12622bool ChartCanvas::SetCursor(
const wxCursor &c) {
12624 if (g_bopengl && m_glcc)
12625 return m_glcc->SetCursor(c);
12628 return wxWindow::SetCursor(c);
12631void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12632 if (g_bquiting)
return;
12642 if (!m_RolloverPopupTimer.IsRunning() &&
12643 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12644 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12645 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12646 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12649 if (m_glcc && g_bopengl) {
12652 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12654 m_glcc->Refresh(eraseBackground,
12671 if (m_pCIWin && m_pCIWin->IsShown()) {
12673 m_pCIWin->Refresh(
false);
12681 wxWindow::Refresh(eraseBackground, rect);
12684void ChartCanvas::Update() {
12685 if (m_glcc && g_bopengl) {
12690 wxWindow::Update();
12694 if (!pemboss)
return;
12695 int x = pemboss->x, y = pemboss->y;
12696 const double factor = 200;
12698 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12699 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12700 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12703 wxMemoryDC snip_dc;
12704 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12705 snip_dc.SelectObject(snip_bmp);
12707 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12708 snip_dc.SelectObject(wxNullBitmap);
12710 wxImage snip_img = snip_bmp.ConvertToImage();
12713 unsigned char *pdata = snip_img.GetData();
12715 for (
int y = 0; y < pemboss->height; y++) {
12716 int map_index = (y * pemboss->width);
12717 for (
int x = 0; x < pemboss->width; x++) {
12718 double val = (pemboss->pmap[map_index] * factor) / 256.;
12720 int nred = (int)((*pdata) + val);
12721 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12722 *pdata++ = (
unsigned char)nred;
12724 int ngreen = (int)((*pdata) + val);
12725 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12726 *pdata++ = (
unsigned char)ngreen;
12728 int nblue = (int)((*pdata) + val);
12729 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12730 *pdata++ = (
unsigned char)nblue;
12738 wxBitmap emb_bmp(snip_img);
12741 wxMemoryDC result_dc;
12742 result_dc.SelectObject(emb_bmp);
12745 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12747 result_dc.SelectObject(wxNullBitmap);
12753 if (GetQuiltMode()) {
12755 int refIndex = GetQuiltRefChartdbIndex();
12756 if (refIndex >= 0) {
12758 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12759 if (current_type == CHART_TYPE_MBTILES) {
12760 ChartBase *pChart = m_pQuilt->GetRefChart();
12763 zoom_factor = ptc->GetZoomFactor();
12768 if (zoom_factor <= 3.9)
return NULL;
12770 if (m_singleChart) {
12771 if (zoom_factor <= 3.9)
return NULL;
12776 if (m_pEM_OverZoom) {
12777 m_pEM_OverZoom->x = 4;
12778 m_pEM_OverZoom->y = 0;
12780 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12781 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12784 return m_pEM_OverZoom;
12787void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12800 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12801 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12805 AISDrawAreaNotices(dc, GetVP(),
this);
12807 wxDC *pdc = dc.GetDC();
12809 pdc->DestroyClippingRegion();
12810 wxDCClipper(*pdc, ru);
12813 if (m_bShowNavobjects) {
12814 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12815 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12816 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12817 DrawAnchorWatchPoints(dc);
12819 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12820 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12823 AISDraw(dc, GetVP(),
this);
12827 RenderVisibleSectorLights(dc);
12829 RenderAllChartOutlines(dc, GetVP());
12830 RenderRouteLegs(dc);
12831 RenderShipToActive(dc,
false);
12833 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12835 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12839 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12840 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12843 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12848 RebuildTideSelectList(GetVP().GetBBox());
12849 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12852 if (m_bShowCurrent) {
12853 RebuildCurrentSelectList(GetVP().GetBBox());
12854 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12857 if (!g_PrintingInProgress) {
12858 if (IsPrimaryCanvas()) {
12862 if (IsPrimaryCanvas()) {
12866 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12868 if (m_pTrackRolloverWin) {
12869 m_pTrackRolloverWin->Draw(dc);
12870 m_brepaint_piano =
true;
12873 if (m_pRouteRolloverWin) {
12874 m_pRouteRolloverWin->Draw(dc);
12875 m_brepaint_piano =
true;
12878 if (m_pAISRolloverWin) {
12879 m_pAISRolloverWin->Draw(dc);
12880 m_brepaint_piano =
true;
12882 if (m_brepaint_piano && g_bShowChartBar) {
12883 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12886 if (m_Compass) m_Compass->Paint(dc);
12888 if (!g_CanvasHideNotificationIcon) {
12889 if (IsPrimaryCanvas()) {
12890 auto ¬eman = NotificationManager::GetInstance();
12891 if (noteman.GetNotificationCount()) {
12892 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12893 if (m_notification_button->UpdateStatus()) Refresh();
12894 m_notification_button->Show(
true);
12895 m_notification_button->Paint(dc);
12897 m_notification_button->Show(
false);
12903 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12909 if (!m_bShowDepthUnits)
return NULL;
12911 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12913 if (GetQuiltMode()) {
12914 wxString s = m_pQuilt->GetQuiltDepthUnit();
12917 depth_unit_type = DEPTH_UNIT_FEET;
12918 else if (s.StartsWith(
"FATHOMS"))
12919 depth_unit_type = DEPTH_UNIT_FATHOMS;
12920 else if (s.StartsWith(
"METERS"))
12921 depth_unit_type = DEPTH_UNIT_METERS;
12922 else if (s.StartsWith(
"METRES"))
12923 depth_unit_type = DEPTH_UNIT_METERS;
12924 else if (s.StartsWith(
"METRIC"))
12925 depth_unit_type = DEPTH_UNIT_METERS;
12926 else if (s.StartsWith(
"METER"))
12927 depth_unit_type = DEPTH_UNIT_METERS;
12930 if (m_singleChart) {
12931 depth_unit_type = m_singleChart->GetDepthUnitType();
12932 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12933 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12938 switch (depth_unit_type) {
12939 case DEPTH_UNIT_FEET:
12942 case DEPTH_UNIT_METERS:
12943 ped = m_pEM_Meters;
12945 case DEPTH_UNIT_FATHOMS:
12946 ped = m_pEM_Fathoms;
12952 ped->x = (GetVP().
pix_width - ped->width);
12954 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12955 wxRect r = m_Compass->
GetRect();
12956 ped->y = r.y + r.height;
12963void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12966 if (style->embossFont == wxEmptyString) {
12967 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12969 font.SetPointSize(60);
12970 font.SetWeight(wxFONTWEIGHT_BOLD);
12972 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12973 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12975 int emboss_width = 500;
12976 int emboss_height = 200;
12980 delete m_pEM_Meters;
12981 delete m_pEM_Fathoms;
12985 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12987 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12989 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12992#define OVERZOOM_TEXT _("OverZoom")
12994void ChartCanvas::SetOverzoomFont() {
12999 if (style->embossFont == wxEmptyString) {
13000 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13002 font.SetPointSize(40);
13003 font.SetWeight(wxFONTWEIGHT_BOLD);
13005 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13006 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13008 wxClientDC dc(
this);
13010 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13012 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13013 font.SetPointSize(font.GetPointSize() - 1);
13015 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13017 m_overzoomFont = font;
13018 m_overzoomTextWidth = w;
13019 m_overzoomTextHeight = h;
13022void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13023 delete m_pEM_OverZoom;
13025 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13027 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13028 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13031emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13032 int height,
const wxString &str,
13037 wxBitmap bmp(width, height, -1);
13040 wxMemoryDC temp_dc;
13041 temp_dc.SelectObject(bmp);
13044 temp_dc.SetBackground(*wxWHITE_BRUSH);
13045 temp_dc.SetTextBackground(*wxWHITE);
13046 temp_dc.SetTextForeground(*wxBLACK);
13050 temp_dc.SetFont(font);
13053 temp_dc.GetTextExtent(str, &str_w, &str_h);
13055 temp_dc.DrawText(str, 1, 1);
13058 temp_dc.SelectObject(wxNullBitmap);
13061 wxImage img = bmp.ConvertToImage();
13063 int image_width = str_w * 105 / 100;
13064 int image_height = str_h * 105 / 100;
13065 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13066 wxMin(image_height, img.GetHeight()));
13067 wxImage imgs = img.GetSubImage(r);
13071 case GLOBAL_COLOR_SCHEME_DAY:
13075 case GLOBAL_COLOR_SCHEME_DUSK:
13078 case GLOBAL_COLOR_SCHEME_NIGHT:
13085 const int w = imgs.GetWidth();
13086 const int h = imgs.GetHeight();
13087 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13092 for (
int y = 1; y < h - 1; y++) {
13093 for (
int x = 1; x < w - 1; x++) {
13095 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13096 val = (int)(val * val_factor);
13097 index = (y * w) + x;
13110void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13111 Track *active_track = NULL;
13114 active_track = pTrackDraw;
13118 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13121 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13124void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13125 Track *active_track = NULL;
13128 active_track = pTrackDraw;
13132 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13135void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13136 Route *active_route = NULL;
13138 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13139 active_route = pRouteDraw;
13144 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13149 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13152void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13153 Route *active_route = NULL;
13156 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13157 active_route = pRouteDraw;
13161 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13164void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13165 if (!pWayPointMan)
return;
13167 auto node = pWayPointMan->GetWaypointList()->begin();
13169 while (node != pWayPointMan->GetWaypointList()->end()) {
13178 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13182 if (pWP->GetShowWaypointRangeRings() &&
13183 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13184 double factor = 1.00;
13185 if (pWP->GetWaypointRangeRingsStepUnits() ==
13187 factor = 1 / 1.852;
13189 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13190 pWP->GetWaypointRangeRingsStep() / 60.;
13194 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13195 pWP->m_lat + radius, pWP->m_lon + radius);
13196 if (!BltBBox.IntersectOut(radar_box)) {
13207void ChartCanvas::DrawBlinkObjects() {
13209 wxRect update_rect;
13211 if (!pWayPointMan)
return;
13213 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13220 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13223void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13228 wxPoint lAnchorPoint1, lAnchorPoint2;
13242 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13243 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13245 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13246 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13247 dc.SetBrush(*ppBrush);
13251 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13256 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13261 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13266 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13271double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13274 wxPoint lAnchorPoint;
13277 double tlat1, tlon1;
13279 if (pAnchorWatchPoint) {
13280 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13282 dabs = fabs(d1 / 1852.);
13283 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13288 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13289 pow((
double)(lAnchorPoint.y - r1.y), 2));
13292 if (d1 < 0) lpp = -lpp;
13300void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13303 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13305 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13311 if ((type ==
't') || (type ==
'T')) {
13312 if (BBox.Contains(lat, lon)) {
13314 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13320void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13323 wxDateTime this_now = gTimeSource;
13324 bool cur_time = !gTimeSource.IsValid();
13325 if (cur_time) this_now = wxDateTime::Now();
13326 time_t t_this_now = this_now.GetTicks();
13328 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13330 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13331 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13332 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13333 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13335 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13336 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13337 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13338 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13339 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13340 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13342 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13343 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13344 int font_size = wxMax(10, dFont->GetPointSize());
13347 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13348 false, dFont->GetFaceName());
13350 dc.SetPen(*pblack_pen);
13351 dc.SetBrush(*pgreen_brush);
13355 case GLOBAL_COLOR_SCHEME_DAY:
13358 case GLOBAL_COLOR_SCHEME_DUSK:
13361 case GLOBAL_COLOR_SCHEME_NIGHT:
13362 bm = m_bmTideNight;
13369 int bmw = bm.GetWidth();
13370 int bmh = bm.GetHeight();
13372 float scale_factor = 1.0;
13376 float icon_pixelRefDim = 45;
13381 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13383 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13385 scale_factor *= pix_factor;
13392 scale_factor *= user_scale_factor;
13393 scale_factor *= GetContentScaleFactor();
13396 double marge = 0.05;
13397 std::vector<LLBBox> drawn_boxes;
13398 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13402 if ((type ==
't') || (type ==
'T'))
13407 if (BBox.ContainsMarge(lat, lon, marge)) {
13409 if (GetVP().chart_scale < 500000) {
13410 bool bdrawn =
false;
13411 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13412 if (drawn_boxes[i].Contains(lat, lon)) {
13417 if (bdrawn)
continue;
13420 this_box.Set(lat, lon, lat, lon);
13421 this_box.EnLarge(.005);
13422 drawn_boxes.push_back(this_box);
13428 if (GetVP().chart_scale > 500000) {
13429 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13433 dc.SetFont(*plabelFont);
13445 if (
ptcmgr->GetTideFlowSens(
13446 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13450 ptcmgr->GetHightOrLowTide(
13451 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13452 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13464 if (tctime > t_this_now)
13465 ptcmgr->GetHightOrLowTide(
13466 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13467 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13471 ptcmgr->GetHightOrLowTide(
13472 t_this_now, FORWARD_TEN_MINUTES_STEP,
13473 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13487 int width = (int)(12 * scale_factor + 0.5);
13488 int height = (int)(45 * scale_factor + 0.5);
13489 int linew = wxMax(1, (
int)(scale_factor));
13490 int xDraw = r.x - (width / 2);
13491 int yDraw = r.y - (height / 2);
13494 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13495 int hs = (httime > lttime) ? -4 : 4;
13496 hs *= (int)(scale_factor + 0.5);
13497 if (ts > 0.995 || ts < 0.005) hs = 0;
13498 int ht_y = (int)(height * ts);
13501 pblack_pen->SetWidth(linew);
13502 dc.SetPen(*pblack_pen);
13503 dc.SetBrush(*pyelo_brush);
13504 dc.DrawRectangle(xDraw, yDraw, width, height);
13508 dc.SetPen(*pblue_pen);
13509 dc.SetBrush(*pblue_brush);
13510 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13511 (width - (4 * linew)), height - ht_y);
13517 arrow[0].x = xDraw + 2 * linew;
13518 arrow[1].x = xDraw + width / 2;
13519 arrow[2].x = xDraw + width - 2 * linew;
13520 pyelo_pen->SetWidth(linew);
13521 pblue_pen->SetWidth(linew);
13522 if (ts > 0.35 || ts < 0.15)
13524 hl = (int)(height * 0.25) + yDraw;
13526 arrow[1].y = hl + hs;
13529 dc.SetPen(*pyelo_pen);
13531 dc.SetPen(*pblue_pen);
13532 dc.DrawLines(3, arrow);
13534 if (ts > 0.60 || ts < 0.40)
13536 hl = (int)(height * 0.5) + yDraw;
13538 arrow[1].y = hl + hs;
13541 dc.SetPen(*pyelo_pen);
13543 dc.SetPen(*pblue_pen);
13544 dc.DrawLines(3, arrow);
13546 if (ts < 0.65 || ts > 0.85)
13548 hl = (int)(height * 0.75) + yDraw;
13550 arrow[1].y = hl + hs;
13553 dc.SetPen(*pyelo_pen);
13555 dc.SetPen(*pblue_pen);
13556 dc.DrawLines(3, arrow);
13560 s.Printf(
"%3.1f", nowlev);
13562 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13564 dc.GetTextExtent(s, &wx1, NULL);
13566 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13581void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13584 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13586 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13592 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13593 if ((BBox.Contains(lat, lon))) {
13595 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13601void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13604 float tcvalue, dir;
13608 double lon_last = 0.;
13609 double lat_last = 0.;
13611 double marge = 0.2;
13612 bool cur_time = !gTimeSource.IsValid();
13614 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13615 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13617 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13619 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13620 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13621 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13622 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13623 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13624 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13625 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13626 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13628 double skew_angle = GetVPRotation();
13630 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13631 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13632 int font_size = wxMax(10, dFont->GetPointSize());
13635 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13636 false, dFont->GetFaceName());
13638 float scale_factor = 1.0;
13644 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13646 float nominal_icon_size_pixels = 15;
13647 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13649 scale_factor *= pix_factor;
13656 scale_factor *= user_scale_factor;
13658 scale_factor *= GetContentScaleFactor();
13661 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13667 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13668 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13673 int dd = (int)(5.0 * scale_factor + 0.5);
13684 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13685 dc.SetPen(*pblack_pen);
13686 dc.SetBrush(*porange_brush);
13687 dc.DrawPolygon(4, d);
13690 dc.SetBrush(*pblack_brush);
13691 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13695 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13709 double a1 = fabs(tcvalue) * 10.;
13711 a1 = wxMax(1.0, a1);
13712 double a2 = log10(a1);
13714 float cscale = scale_factor * a2 * 0.3;
13716 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13717 dc.SetPen(*porange_pen);
13718 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13722 if (bDrawCurrentValues) {
13723 dc.SetFont(*pTCFont);
13724 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13725 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13751 if (!pvIDX)
return;
13756 if (pCwin && pCwin->IsShown()) {
13764 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13779 pCwin =
new TCWin(
this, x, y, pvIDX);
13797#define NUM_CURRENT_ARROW_POINTS 9
13798static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13799 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13800 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13801 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13803void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13805 if (
scale > 1e-2) {
13806 float sin_rot = sin(rot_angle * PI / 180.);
13807 float cos_rot = cos(rot_angle * PI / 180.);
13811 float xt = CurrentArrowArray[0].x;
13812 float yt = CurrentArrowArray[0].y;
13814 float xp = (xt * cos_rot) - (yt * sin_rot);
13815 float yp = (xt * sin_rot) + (yt * cos_rot);
13816 int x1 = (int)(xp *
scale);
13817 int y1 = (int)(yp *
scale);
13820 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13821 xt = CurrentArrowArray[ip].x;
13822 yt = CurrentArrowArray[ip].y;
13824 float xp = (xt * cos_rot) - (yt * sin_rot);
13825 float yp = (xt * sin_rot) + (yt * cos_rot);
13826 int x2 = (int)(xp *
scale);
13827 int y2 = (int)(yp *
scale);
13829 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13837wxString ChartCanvas::FindValidUploadPort() {
13840 if (!g_uploadConnection.IsEmpty() &&
13841 g_uploadConnection.StartsWith(
"Serial")) {
13842 port = g_uploadConnection;
13848 for (
auto *cp : TheConnectionParams()) {
13849 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13850 port <<
"Serial:" << cp->Port;
13856void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13859 if (NULL == g_pais_query_dialog_active) {
13860 int pos_x = g_ais_query_dialog_x;
13861 int pos_y = g_ais_query_dialog_y;
13863 if (g_pais_query_dialog_active) {
13864 g_pais_query_dialog_active->Destroy();
13870 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13871 wxPoint(pos_x, pos_y));
13873 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13874 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13875 g_pais_query_dialog_active->SetMMSI(mmsi);
13876 g_pais_query_dialog_active->UpdateText();
13877 wxSize sz = g_pais_query_dialog_active->GetSize();
13879 bool b_reset_pos =
false;
13884 RECT frame_title_rect;
13885 frame_title_rect.left = pos_x;
13886 frame_title_rect.top = pos_y;
13887 frame_title_rect.right = pos_x + sz.x;
13888 frame_title_rect.bottom = pos_y + 30;
13890 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13891 b_reset_pos =
true;
13896 wxRect window_title_rect;
13897 window_title_rect.x = pos_x;
13898 window_title_rect.y = pos_y;
13899 window_title_rect.width = sz.x;
13900 window_title_rect.height = 30;
13902 wxRect ClientRect = wxGetClientDisplayRect();
13903 ClientRect.Deflate(
13905 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13909 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13912 g_pais_query_dialog_active->SetMMSI(mmsi);
13913 g_pais_query_dialog_active->UpdateText();
13916 g_pais_query_dialog_active->Show();
13919void ChartCanvas::ToggleCanvasQuiltMode() {
13920 bool cur_mode = GetQuiltMode();
13922 if (!GetQuiltMode())
13923 SetQuiltMode(
true);
13924 else if (GetQuiltMode()) {
13925 SetQuiltMode(
false);
13926 g_sticky_chart = GetQuiltReferenceChartIndex();
13929 if (cur_mode != GetQuiltMode()) {
13930 SetupCanvasQuiltMode();
13939 if (ps52plib) ps52plib->GenerateStateHash();
13941 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13942 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13945void ChartCanvas::DoCanvasStackDelta(
int direction) {
13946 if (!GetQuiltMode()) {
13947 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13948 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13949 if ((current_stack_index + direction) < 0)
return;
13951 if (m_bpersistent_quilt ) {
13953 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13955 if (IsChartQuiltableRef(new_dbIndex)) {
13956 ToggleCanvasQuiltMode();
13957 SelectQuiltRefdbChart(new_dbIndex);
13958 m_bpersistent_quilt =
false;
13961 SelectChartFromStack(current_stack_index + direction);
13964 std::vector<int> piano_chart_index_array =
13965 GetQuiltExtendedStackdbIndexArray();
13966 int refdb = GetQuiltRefChartdbIndex();
13969 int current_index = -1;
13970 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13971 if (refdb == piano_chart_index_array[i]) {
13976 if (current_index == -1)
return;
13979 int target_family = ctet.GetChartFamily();
13981 int new_index = -1;
13982 int check_index = current_index + direction;
13983 bool found =
false;
13984 int check_dbIndex = -1;
13985 int new_dbIndex = -1;
13989 (
unsigned int)check_index < piano_chart_index_array.size() &&
13990 (check_index >= 0)) {
13991 check_dbIndex = piano_chart_index_array[check_index];
13993 if (target_family == cte.GetChartFamily()) {
13995 new_index = check_index;
13996 new_dbIndex = check_dbIndex;
14000 check_index += direction;
14003 if (!found)
return;
14005 if (!IsChartQuiltableRef(new_dbIndex)) {
14006 ToggleCanvasQuiltMode();
14007 SelectdbChart(new_dbIndex);
14008 m_bpersistent_quilt =
true;
14010 SelectQuiltRefChart(new_index);
14015 top_frame::Get()->UpdateGlobalMenuItems();
14016 SetQuiltChartHiLiteIndex(-1);
14027void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14030 switch (event.GetId()) {
14042 DoCanvasStackDelta(1);
14047 DoCanvasStackDelta(-1);
14057 ShowCurrents(!GetbShowCurrent());
14064 ShowTides(!GetbShowTide());
14071 if (0 == m_routeState) {
14078 androidSetRouteAnnunciator(m_routeState == 1);
14084 SetAISCanvasDisplayStyle(-1);
14096void ChartCanvas::SetShowAIS(
bool show) {
14098 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14099 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14102void ChartCanvas::SetAttenAIS(
bool show) {
14103 m_bShowAISScaled = show;
14104 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14105 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14108void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14111 bool bShowAIS_Array[3] = {
true,
true,
false};
14112 bool bShowScaled_Array[3] = {
false,
true,
true};
14113 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14114 _(
"Attenuate less critical AIS targets"),
14115 _(
"Hide AIS Targets")};
14116 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14118 int AIS_Toolbar_Switch = 0;
14119 if (StyleIndx == -1) {
14121 for (
int i = 1; i < ArraySize; i++) {
14122 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14123 (bShowScaled_Array[i] == m_bShowAISScaled))
14124 AIS_Toolbar_Switch = i;
14126 AIS_Toolbar_Switch++;
14127 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14128 AIS_Toolbar_Switch++;
14131 AIS_Toolbar_Switch = StyleIndx;
14134 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14136 int AIS_Toolbar_Switch_Next =
14137 AIS_Toolbar_Switch + 1;
14138 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14139 AIS_Toolbar_Switch_Next++;
14140 if (AIS_Toolbar_Switch_Next >= ArraySize)
14141 AIS_Toolbar_Switch_Next = 0;
14144 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14145 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14148void ChartCanvas::TouchAISToolActive() {}
14150void ChartCanvas::UpdateAISTBTool() {}
14158void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14160 bool b_update =
false;
14161 int cc1_edge_comp = 2;
14162 wxRect rect = m_Compass->
GetRect();
14163 wxSize parent_size = GetSize();
14165 parent_size *= m_displayScale;
14169 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14170 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14171 wxRect compass_rect(compass_pt, rect.GetSize());
14173 m_Compass->Move(compass_pt);
14175 if (m_Compass && m_Compass->IsShown())
14176 m_Compass->UpdateStatus(b_force_new | b_update);
14178 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14179 scaler = wxMax(scaler, 1.0);
14180 wxPoint note_point = wxPoint(
14181 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14182 if (m_notification_button) {
14183 m_notification_button->Move(note_point);
14184 m_notification_button->UpdateStatus();
14187 if (b_force_new | b_update) Refresh();
14190void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14191 ChartTypeEnum New_Type,
14192 ChartFamilyEnum New_Family) {
14193 if (!GetpCurrentStack())
return;
14196 if (index < GetpCurrentStack()->nEntry) {
14199 pTentative_Chart =
ChartData->OpenStackChartConditional(
14200 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14202 if (pTentative_Chart) {
14203 if (m_singleChart) m_singleChart->Deactivate();
14205 m_singleChart = pTentative_Chart;
14206 m_singleChart->Activate();
14208 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14209 GetpCurrentStack(), m_singleChart->GetFullPath());
14222 double best_scale_ppm = GetBestVPScale(m_singleChart);
14223 double rotation = GetVPRotation();
14224 double oldskew = GetVPSkew();
14225 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14227 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14228 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14229 if (fabs(newskew) > 0.0001) rotation = newskew;
14232 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14234 UpdateGPSCompassStatusBox(
true);
14238 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14239 if (idx < 0)
return;
14241 std::vector<int> piano_active_chart_index_array;
14242 piano_active_chart_index_array.push_back(
14243 GetpCurrentStack()->GetCurrentEntrydbIndex());
14244 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14247void ChartCanvas::SelectdbChart(
int dbindex) {
14248 if (!GetpCurrentStack())
return;
14251 if (dbindex >= 0) {
14254 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14256 if (pTentative_Chart) {
14257 if (m_singleChart) m_singleChart->Deactivate();
14259 m_singleChart = pTentative_Chart;
14260 m_singleChart->Activate();
14262 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14263 GetpCurrentStack(), m_singleChart->GetFullPath());
14276 double best_scale_ppm = GetBestVPScale(m_singleChart);
14280 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14290void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14293 if (!GetQuiltMode()) {
14294 if (GetpCurrentStack()) {
14295 int stack_index = -1;
14296 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14297 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14298 if (check_dbIndex < 0)
continue;
14300 ChartData->GetChartTableEntry(check_dbIndex);
14301 if (type == cte.GetChartType()) {
14304 }
else if (family == cte.GetChartFamily()) {
14310 if (stack_index >= 0) {
14311 SelectChartFromStack(stack_index);
14315 int sel_dbIndex = -1;
14316 std::vector<int> piano_chart_index_array =
14317 GetQuiltExtendedStackdbIndexArray();
14318 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14319 int check_dbIndex = piano_chart_index_array[i];
14321 if (type == cte.GetChartType()) {
14322 if (IsChartQuiltableRef(check_dbIndex)) {
14323 sel_dbIndex = check_dbIndex;
14326 }
else if (family == cte.GetChartFamily()) {
14327 if (IsChartQuiltableRef(check_dbIndex)) {
14328 sel_dbIndex = check_dbIndex;
14334 if (sel_dbIndex >= 0) {
14335 SelectQuiltRefdbChart(sel_dbIndex,
false);
14337 AdjustQuiltRefChart();
14344 SetQuiltChartHiLiteIndex(-1);
14349bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14350 return std::find(m_tile_yesshow_index_array.begin(),
14351 m_tile_yesshow_index_array.end(),
14352 index) != m_tile_yesshow_index_array.end();
14355bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14356 return std::find(m_tile_noshow_index_array.begin(),
14357 m_tile_noshow_index_array.end(),
14358 index) != m_tile_noshow_index_array.end();
14361void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14362 if (std::find(m_tile_noshow_index_array.begin(),
14363 m_tile_noshow_index_array.end(),
14364 index) == m_tile_noshow_index_array.end()) {
14365 m_tile_noshow_index_array.push_back(index);
14375void ChartCanvas::HandlePianoClick(
14376 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14379 if (!m_pCurrentStack)
return;
14395 double distance = 25000;
14396 int closest_index = -1;
14397 for (
int chart_index : selected_dbIndex_array) {
14399 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14400 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14403 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14404 if (test_distance < distance) {
14405 distance = test_distance;
14406 closest_index = chart_index;
14410 int selected_dbIndex = selected_dbIndex_array[0];
14411 if (closest_index >= 0) selected_dbIndex = closest_index;
14413 if (!GetQuiltMode()) {
14414 if (m_bpersistent_quilt ) {
14415 if (IsChartQuiltableRef(selected_dbIndex)) {
14416 ToggleCanvasQuiltMode();
14417 SelectQuiltRefdbChart(selected_dbIndex);
14418 m_bpersistent_quilt =
false;
14420 SelectChartFromStack(selected_index);
14423 SelectChartFromStack(selected_index);
14424 g_sticky_chart = selected_dbIndex;
14428 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14432 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14433 bool bfound =
false;
14434 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14435 if (m_tile_noshow_index_array[i] ==
14436 selected_dbIndex) {
14437 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14444 m_tile_noshow_index_array.push_back(selected_dbIndex);
14448 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14449 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14453 if (IsChartQuiltableRef(selected_dbIndex)) {
14459 bool set_scale =
false;
14460 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14461 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14467 SelectQuiltRefdbChart(selected_dbIndex,
true);
14469 SelectQuiltRefdbChart(selected_dbIndex,
false);
14474 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14476 double proposed_scale_onscreen =
14479 if (g_bPreserveScaleOnX) {
14480 proposed_scale_onscreen =
14481 wxMin(proposed_scale_onscreen,
14483 GetCanvasWidth()));
14485 proposed_scale_onscreen =
14486 wxMin(proposed_scale_onscreen,
14488 GetCanvasWidth()));
14490 proposed_scale_onscreen =
14491 wxMax(proposed_scale_onscreen,
14500 ToggleCanvasQuiltMode();
14501 SelectdbChart(selected_dbIndex);
14502 m_bpersistent_quilt =
true;
14507 SetQuiltChartHiLiteIndex(-1);
14509 top_frame::Get()->UpdateGlobalMenuItems();
14510 HideChartInfoWindow();
14515void ChartCanvas::HandlePianoRClick(
14516 int x,
int y,
int selected_index,
14517 const std::vector<int> &selected_dbIndex_array) {
14520 if (!GetpCurrentStack())
return;
14522 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14523 UpdateCanvasControlBar();
14525 SetQuiltChartHiLiteIndex(-1);
14528void ChartCanvas::HandlePianoRollover(
14529 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14530 int n_charts,
int scale) {
14533 if (!GetpCurrentStack())
return;
14538 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14540 if (!GetQuiltMode()) {
14541 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14544 std::vector<int> piano_chart_index_array;
14545 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14546 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14547 if ((GetpCurrentStack()->nEntry > 1) ||
14548 (piano_chart_index_array.size() >= 1)) {
14549 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14551 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14553 }
else if (GetpCurrentStack()->nEntry == 1) {
14555 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14556 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14557 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14559 }
else if ((-1 == selected_index) &&
14560 (0 == selected_dbIndex_array.size())) {
14561 ShowChartInfoWindow(key_location.x, -1);
14565 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14567 if ((GetpCurrentStack()->nEntry > 1) ||
14568 (piano_chart_index_array.size() >= 1)) {
14570 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14571 selected_dbIndex_array);
14572 else if (n_charts == 1)
14573 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14575 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14582void ChartCanvas::ClearPianoRollover() {
14583 ClearQuiltChartHiLiteIndexArray();
14584 ShowChartInfoWindow(0, -1);
14585 std::vector<int> vec;
14586 ShowCompositeInfoWindow(0, 0, 0, vec);
14590void ChartCanvas::UpdateCanvasControlBar() {
14591 if (m_pianoFrozen)
return;
14593 if (!GetpCurrentStack())
return;
14595 if (!g_bShowChartBar)
return;
14598 int sel_family = -1;
14600 std::vector<int> piano_chart_index_array;
14601 std::vector<int> empty_piano_chart_index_array;
14603 wxString old_hash = m_Piano->GetStoredHash();
14605 if (GetQuiltMode()) {
14606 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14607 GetQuiltFullScreendbIndexArray());
14609 std::vector<int> piano_active_chart_index_array =
14610 GetQuiltCandidatedbIndexArray();
14611 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14613 std::vector<int> piano_eclipsed_chart_index_array =
14614 GetQuiltEclipsedStackdbIndexArray();
14615 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14617 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14618 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14620 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14621 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14623 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14624 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14627 if (m_singleChart) {
14628 sel_type = m_singleChart->GetChartType();
14629 sel_family = m_singleChart->GetChartFamily();
14634 std::vector<int> piano_skew_chart_index_array;
14635 std::vector<int> piano_tmerc_chart_index_array;
14636 std::vector<int> piano_poly_chart_index_array;
14638 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14640 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14641 double skew_norm = ctei.GetChartSkew();
14642 if (skew_norm > 180.) skew_norm -= 360.;
14644 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14645 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14648 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14649 if (fabs(skew_norm) > 1.)
14650 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14652 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14653 }
else if (fabs(skew_norm) > 1.)
14654 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14656 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14657 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14658 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14660 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14661 if (new_hash != old_hash) {
14662 m_Piano->FormatKeys();
14663 HideChartInfoWindow();
14664 m_Piano->ResetRollover();
14665 SetQuiltChartHiLiteIndex(-1);
14666 m_brepaint_piano =
true;
14672 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14674 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14675 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14676 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14677 if (e == CHART_FAMILY_RASTER) mask |= 1;
14678 if (e == CHART_FAMILY_VECTOR) {
14679 if (t == CHART_TYPE_CM93COMP)
14686 wxString s_indicated;
14687 if (sel_type == CHART_TYPE_CM93COMP)
14688 s_indicated =
"cm93";
14690 if (sel_family == CHART_FAMILY_RASTER)
14691 s_indicated =
"raster";
14692 else if (sel_family == CHART_FAMILY_VECTOR)
14693 s_indicated =
"vector";
14696 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14699void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14701void ChartCanvas::PianoPopupMenu(
14702 int x,
int y,
int selected_index,
14703 const std::vector<int> &selected_dbIndex_array) {
14704 if (!GetpCurrentStack())
return;
14707 if (!GetQuiltMode())
return;
14709 m_piano_ctx_menu =
new wxMenu();
14711 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14721 menu_selected_dbIndex = selected_dbIndex_array[0];
14722 menu_selected_index = selected_index;
14725 bool b_is_in_noshow =
false;
14726 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14727 if (m_quilt_noshow_index_array[i] ==
14728 menu_selected_dbIndex)
14730 b_is_in_noshow =
true;
14735 if (b_is_in_noshow) {
14736 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14737 _(
"Show This Chart"));
14738 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14739 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14740 }
else if (GetpCurrentStack()->nEntry > 1) {
14741 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14742 _(
"Hide This Chart"));
14743 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14744 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14748 wxPoint pos = wxPoint(x, y - 30);
14751 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14752 PopupMenu(m_piano_ctx_menu, pos);
14754 delete m_piano_ctx_menu;
14755 m_piano_ctx_menu = NULL;
14757 HideChartInfoWindow();
14758 m_Piano->ResetRollover();
14760 SetQuiltChartHiLiteIndex(-1);
14761 ClearQuiltChartHiLiteIndexArray();
14766void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14767 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14768 if (m_quilt_noshow_index_array[i] ==
14769 menu_selected_dbIndex)
14771 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14777void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14778 if (!GetpCurrentStack())
return;
14781 RemoveChartFromQuilt(menu_selected_dbIndex);
14785 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14786 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14788 int i = menu_selected_index + 1;
14789 bool b_success =
false;
14790 while (i < GetpCurrentStack()->nEntry - 1) {
14791 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14792 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14793 SelectQuiltRefChart(i);
14803 i = menu_selected_index - 1;
14805 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14806 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14807 SelectQuiltRefChart(i);
14817void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14819 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14820 if (m_quilt_noshow_index_array[i] ==
14823 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14828 m_quilt_noshow_index_array.push_back(dbIndex);
14831bool ChartCanvas::UpdateS52State() {
14832 bool retval =
false;
14835 ps52plib->SetShowS57Text(m_encShowText);
14836 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14837 ps52plib->m_bShowSoundg = m_encShowDepth;
14838 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14839 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14842 if (!m_encShowLights)
14843 ps52plib->AddObjNoshow(
"LIGHTS");
14845 ps52plib->RemoveObjNoshow(
"LIGHTS");
14846 ps52plib->SetLightsOff(!m_encShowLights);
14847 ps52plib->m_bExtendLightSectors =
true;
14850 ps52plib->SetAnchorOn(m_encShowAnchor);
14851 ps52plib->SetQualityOfData(m_encShowDataQual);
14857void ChartCanvas::SetShowENCDataQual(
bool show) {
14858 m_encShowDataQual = show;
14859 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14860 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14862 m_s52StateHash = 0;
14865void ChartCanvas::SetShowENCText(
bool show) {
14866 m_encShowText = show;
14867 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14868 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14870 m_s52StateHash = 0;
14873void ChartCanvas::SetENCDisplayCategory(
int category) {
14874 m_encDisplayCategory = category;
14875 m_s52StateHash = 0;
14878void ChartCanvas::SetShowENCDepth(
bool show) {
14879 m_encShowDepth = show;
14880 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14881 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14883 m_s52StateHash = 0;
14886void ChartCanvas::SetShowENCLightDesc(
bool show) {
14887 m_encShowLightDesc = show;
14888 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14889 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14891 m_s52StateHash = 0;
14894void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14895 m_encShowBuoyLabels = show;
14896 m_s52StateHash = 0;
14899void ChartCanvas::SetShowENCLights(
bool show) {
14900 m_encShowLights = show;
14901 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14902 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14904 m_s52StateHash = 0;
14907void ChartCanvas::SetShowENCAnchor(
bool show) {
14908 m_encShowAnchor = show;
14909 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14910 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14912 m_s52StateHash = 0;
14915wxRect ChartCanvas::GetMUIBarRect() {
14918 rv = m_muiBar->GetRect();
14924void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14925 if (!GetAlertString().IsEmpty()) {
14926 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14927 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14929 dc.SetFont(*pfont);
14930 dc.SetPen(*wxTRANSPARENT_PEN);
14932 dc.SetBrush(wxColour(243, 229, 47));
14934 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14938 wxRect sbr = GetScaleBarRect();
14939 int xp = sbr.x + sbr.width + 10;
14940 int yp = (sbr.y + sbr.height) - h;
14942 int wdraw = w + 10;
14943 dc.DrawRectangle(xp, yp, wdraw, h);
14944 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14945 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14955#define BRIGHT_XCALIB
14956#define __OPCPN_USEICC__
14959#ifdef __OPCPN_USEICC__
14960int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14961 double co_green,
double co_blue);
14963wxString temp_file_name;
14967class ocpnCurtain:
public wxDialog
14969 DECLARE_CLASS( ocpnCurtain )
14970 DECLARE_EVENT_TABLE()
14973 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14975 bool ProcessEvent(wxEvent& event);
14979IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14981BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14984ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14986 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14989ocpnCurtain::~ocpnCurtain()
14993bool ocpnCurtain::ProcessEvent(wxEvent& event)
14995 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14996 return GetParent()->GetEventHandler()->ProcessEvent(event);
15001#include <windows.h>
15004typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15005typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15006SetDeviceGammaRamp_ptr_type
15007 g_pSetDeviceGammaRamp;
15008GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15010WORD *g_pSavedGammaMap;
15014int InitScreenBrightness() {
15017 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15021 if (NULL == hGDI32DLL) {
15022 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15024 if (NULL != hGDI32DLL) {
15026 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15027 hGDI32DLL,
"SetDeviceGammaRamp");
15028 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15029 hGDI32DLL,
"GetDeviceGammaRamp");
15032 if ((NULL == g_pSetDeviceGammaRamp) ||
15033 (NULL == g_pGetDeviceGammaRamp)) {
15034 FreeLibrary(hGDI32DLL);
15043 if (!g_pSavedGammaMap) {
15044 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15047 bbr = g_pGetDeviceGammaRamp(
15048 hDC, g_pSavedGammaMap);
15049 ReleaseDC(NULL, hDC);
15054 wxRegKey *pRegKey =
new wxRegKey(
15055 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15056 "NT\\CurrentVersion\\ICM");
15057 if (!pRegKey->Exists()) pRegKey->Create();
15058 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15060 g_brightness_init =
true;
15066 if (NULL == g_pcurtain) {
15067 if (top_frame::Get()->CanSetTransparent()) {
15069 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15070 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15071 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15072 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15079 g_pcurtain->Hide();
15081 HWND hWnd = GetHwndOf(g_pcurtain);
15082 SetWindowLong(hWnd, GWL_EXSTYLE,
15083 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15084 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15085 g_pcurtain->SetTransparent(0);
15087 g_pcurtain->Maximize();
15088 g_pcurtain->Show();
15091 g_pcurtain->Enable();
15092 g_pcurtain->Disable();
15094 top_frame::Get()->Disable();
15095 top_frame::Get()->Enable();
15099 g_brightness_init =
true;
15105 wxString cmd(
"xcalib -version");
15107 wxArrayString output;
15108 long r = wxExecute(cmd, output);
15111 " External application \"xcalib\" not found. Screen brightness "
15114 g_brightness_init =
true;
15119int RestoreScreenBrightness() {
15122 if (g_pSavedGammaMap) {
15123 HDC hDC = GetDC(NULL);
15124 g_pSetDeviceGammaRamp(hDC,
15126 ReleaseDC(NULL, hDC);
15128 free(g_pSavedGammaMap);
15129 g_pSavedGammaMap = NULL;
15133 g_pcurtain->Close();
15134 g_pcurtain->Destroy();
15138 g_brightness_init =
false;
15143#ifdef BRIGHT_XCALIB
15144 if (g_brightness_init) {
15146 cmd =
"xcalib -clear";
15147 wxExecute(cmd, wxEXEC_ASYNC);
15148 g_brightness_init =
false;
15158int SetScreenBrightness(
int brightness) {
15165 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15167 g_pcurtain->Close();
15168 g_pcurtain->Destroy();
15172 InitScreenBrightness();
15174 if (NULL == hGDI32DLL) {
15176 wchar_t wdll_name[80];
15177 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15178 LPCWSTR cstr = wdll_name;
15180 hGDI32DLL = LoadLibrary(cstr);
15182 if (NULL != hGDI32DLL) {
15184 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15185 hGDI32DLL,
"SetDeviceGammaRamp");
15186 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15187 hGDI32DLL,
"GetDeviceGammaRamp");
15190 if ((NULL == g_pSetDeviceGammaRamp) ||
15191 (NULL == g_pGetDeviceGammaRamp)) {
15192 FreeLibrary(hGDI32DLL);
15199 HDC hDC = GetDC(NULL);
15210 int increment = brightness * 256 / 100;
15213 WORD GammaTable[3][256];
15216 for (
int i = 0; i < 256; i++) {
15217 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15218 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15219 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15221 table_val += increment;
15223 if (table_val > 65535) table_val = 65535;
15226 g_pSetDeviceGammaRamp(hDC, GammaTable);
15227 ReleaseDC(NULL, hDC);
15234 if (g_pSavedGammaMap) {
15235 HDC hDC = GetDC(NULL);
15236 g_pSetDeviceGammaRamp(hDC,
15238 ReleaseDC(NULL, hDC);
15241 if (brightness < 100) {
15242 if (NULL == g_pcurtain) InitScreenBrightness();
15245 int sbrite = wxMax(1, brightness);
15246 sbrite = wxMin(100, sbrite);
15248 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15252 g_pcurtain->Close();
15253 g_pcurtain->Destroy();
15263#ifdef BRIGHT_XCALIB
15265 if (!g_brightness_init) {
15266 last_brightness = 100;
15267 g_brightness_init =
true;
15268 temp_file_name = wxFileName::CreateTempFileName(
"");
15269 InitScreenBrightness();
15272#ifdef __OPCPN_USEICC__
15275 if (!CreateSimpleICCProfileFile(
15276 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15277 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15278 wxString cmd(
"xcalib ");
15279 cmd += temp_file_name;
15281 wxExecute(cmd, wxEXEC_ASYNC);
15290 if (brightness > last_brightness) {
15292 cmd =
"xcalib -clear";
15293 wxExecute(cmd, wxEXEC_ASYNC);
15295 ::wxMilliSleep(10);
15297 int brite_adj = wxMax(1, brightness);
15298 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15299 wxExecute(cmd, wxEXEC_ASYNC);
15301 int brite_adj = wxMax(1, brightness);
15302 int factor = (brite_adj * 100) / last_brightness;
15303 factor = wxMax(1, factor);
15305 cmd.Printf(
"xcalib -co %2d -a", factor);
15306 wxExecute(cmd, wxEXEC_ASYNC);
15311 last_brightness = brightness;
15318#ifdef __OPCPN_USEICC__
15320#define MLUT_TAG 0x6d4c5554L
15321#define VCGT_TAG 0x76636774L
15323int GetIntEndian(
unsigned char *s) {
15328 p = (
unsigned char *)&ret;
15331 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15333 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15338unsigned short GetShortEndian(
unsigned char *s) {
15339 unsigned short ret;
15343 p = (
unsigned char *)&ret;
15346 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15348 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15354int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15355 double co_green,
double co_blue) {
15359 fp = fopen(file_name,
"wb");
15360 if (!fp)
return -1;
15366 for (
int i = 0; i < 128; i++) header[i] = 0;
15368 fwrite(header, 128, 1, fp);
15372 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15373 fwrite(&numTags, 1, 4, fp);
15375 int tagName0 = VCGT_TAG;
15376 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15377 fwrite(&tagName, 1, 4, fp);
15379 int tagOffset0 = 128 + 4 *
sizeof(int);
15380 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15381 fwrite(&tagOffset, 1, 4, fp);
15384 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15385 fwrite(&tagSize, 1, 4, fp);
15387 fwrite(&tagName, 1, 4, fp);
15389 fwrite(&tagName, 1, 4, fp);
15394 int gammatype0 = 0;
15395 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15396 fwrite(&gammatype, 1, 4, fp);
15398 int numChannels0 = 3;
15399 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15400 fwrite(&numChannels, 1, 2, fp);
15402 int numEntries0 = 256;
15403 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15404 fwrite(&numEntries, 1, 2, fp);
15406 int entrySize0 = 1;
15407 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15408 fwrite(&entrySize, 1, 2, fp);
15410 unsigned char ramp[256];
15413 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15414 fwrite(ramp, 256, 1, fp);
15417 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15418 fwrite(ramp, 256, 1, fp);
15421 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15422 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.