35#include <wx/graphics.h>
36#include <wx/clipbrd.h>
37#include <wx/aui/aui.h>
41#include "o_sound/o_sound.h"
48#include "model/geodesic.h"
54#include "model/nav_object_database.h"
116#include "tide_time.h"
123#include "user_colors.h"
125#include "s57_ocpn_utils.h"
128#include "androidUTIL.h"
138#include <wx/msw/msvcrt.h>
147#define printf printf2
149int __cdecl printf2(
const char *format, ...) {
153 va_start(argptr, format);
154 int ret = vsnprintf(str,
sizeof(str), format, argptr);
156 OutputDebugStringA(str);
161#if defined(__MSVC__) && (_MSC_VER < 1700)
162#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
168#define OCPN_ALT_MENUBAR 1
175static bool g_bSmoothRecenter =
true;
176static bool bDrawCurrentValues;
197static bool mouse_leftisdown;
198static bool g_brouteCreating;
199static int r_gamma_mult;
200static int g_gamma_mult;
201static int b_gamma_mult;
202static int gamma_state;
203static bool g_brightness_init;
204static int last_brightness;
205static wxGLContext *g_pGLcontext;
208static wxDialog *g_pcurtain;
210static wxString g_lastS52PLIBPluginMessage;
213#define MAX_BRIGHT 100
220EVT_ACTIVATE(ChartCanvas::OnActivate)
221EVT_SIZE(ChartCanvas::OnSize)
222#ifndef HAVE_WX_GESTURE_EVENTS
223EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
225EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
226EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
227EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
228EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
229EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
230EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
231EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
232EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
233EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
234EVT_KEY_UP(ChartCanvas::OnKeyUp)
235EVT_CHAR(ChartCanvas::OnKeyChar)
236EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
237EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
238EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
239EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
240EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
241EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
242EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
243EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
244EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
245EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
252 m_nmea_log(nmea_log) {
253 parent_frame = frame;
254 m_canvasIndex = canvasIndex;
258 SetBackgroundColour(wxColour(0, 0, 0));
259 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
263 m_bDrawingRoute =
false;
264 m_bRouteEditing =
false;
265 m_bMarkEditing =
false;
266 m_bRoutePoinDragging =
false;
267 m_bIsInRadius =
false;
268 m_bMayToggleMenuBar =
true;
271 m_bShowNavobjects =
true;
273 m_bAppendingRoute =
false;
274 pThumbDIBShow = NULL;
275 m_bShowCurrent =
false;
277 bShowingCurrent =
false;
281 m_b_paint_enable =
true;
284 pss_overlay_bmp = NULL;
285 pss_overlay_mask = NULL;
286 m_bChartDragging =
false;
287 m_bMeasure_Active =
false;
288 m_bMeasure_DistCircle =
false;
289 m_pMeasureRoute = NULL;
290 m_pTrackRolloverWin = NULL;
291 m_pRouteRolloverWin = NULL;
292 m_pAISRolloverWin = NULL;
294 m_disable_edge_pan =
false;
295 m_dragoffsetSet =
false;
299 m_singleChart = NULL;
300 m_upMode = NORTH_UP_MODE;
302 m_bShowAISScaled =
false;
303 m_timed_move_vp_active =
false;
305 m_disable_adjust_on_zoom =
false;
312 m_pSelectedRoute = NULL;
313 m_pSelectedTrack = NULL;
314 m_pRoutePointEditTarget = NULL;
315 m_pFoundPoint = NULL;
316 m_pMouseRoute = NULL;
317 m_prev_pMousePoint = NULL;
318 m_pEditRouteArray = NULL;
319 m_pFoundRoutePoint = NULL;
320 m_FinishRouteOnKillFocus =
true;
322 m_pRolloverRouteSeg = NULL;
323 m_pRolloverTrackSeg = NULL;
324 m_bsectors_shown =
false;
326 m_bbrightdir =
false;
331 m_pos_image_user_day = NULL;
332 m_pos_image_user_dusk = NULL;
333 m_pos_image_user_night = NULL;
334 m_pos_image_user_grey_day = NULL;
335 m_pos_image_user_grey_dusk = NULL;
336 m_pos_image_user_grey_night = NULL;
339 m_rotation_speed = 0;
345 m_pos_image_user_yellow_day = NULL;
346 m_pos_image_user_yellow_dusk = NULL;
347 m_pos_image_user_yellow_night = NULL;
349 SetOwnShipState(SHIP_INVALID);
351 undo =
new Undo(
this);
357 m_focus_indicator_pix = 1;
359 m_pCurrentStack = NULL;
360 m_bpersistent_quilt =
false;
361 m_piano_ctx_menu = NULL;
363 m_NotificationsList = NULL;
364 m_notification_button = NULL;
366 g_ChartNotRenderScaleFactor = 2.0;
367 m_bShowScaleInStatusBar =
true;
370 m_bShowScaleInStatusBar =
false;
371 m_show_focus_bar =
true;
373 m_bShowOutlines =
false;
374 m_bDisplayGrid =
false;
375 m_bShowDepthUnits =
true;
376 m_encDisplayCategory = (int)STANDARD;
378 m_encShowLights =
true;
379 m_encShowAnchor =
true;
380 m_encShowDataQual =
false;
382 m_pQuilt =
new Quilt(
this);
387 g_PrintingInProgress =
false;
389#ifdef HAVE_WX_GESTURE_EVENTS
390 m_oldVPSScale = -1.0;
391 m_popupWanted =
false;
394 m_inLongPress =
false;
397 m_sw_left_down.Start();
398 m_sw_left_up.Start();
402 singleClickEventIsValid =
false;
411 pCursorPencil = NULL;
416 SetCursor(*pCursorArrow);
418 pPanTimer =
new wxTimer(
this, m_MouseDragging);
421 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
422 pMovementTimer->Stop();
424 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
425 pMovementStopTimer->Stop();
427 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
428 pRotDefTimer->Stop();
430 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
431 m_DoubleClickTimer->Stop();
433 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
434 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
435 m_chart_drag_inertia_active =
false;
437 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
438 m_animationActive =
false;
439 m_menuTimer.SetOwner(
this, MENU_TIMER);
440 m_tap_timer.SetOwner(
this, TAP_TIMER);
444 m_panx_target_final = m_pany_target_final = 0;
445 m_panx_target_now = m_pany_target_now = 0;
448 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
449 pCurTrackTimer->Stop();
450 m_curtrack_timer_msec = 10;
452 m_wheelzoom_stop_oneshot = 0;
453 m_last_wheel_dir = 0;
455 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
457 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
459 m_rollover_popup_timer_msec = 20;
461 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
463 m_b_rot_hidef =
true;
468 m_upMode = NORTH_UP_MODE;
469 m_bLookAhead =
false;
473 m_cs = GLOBAL_COLOR_SCHEME_DAY;
476 VPoint.view_scale_ppm = 1;
479 m_ignore_next_leftup =
false;
481 m_canvas_scale_factor = 1.;
483 m_canvas_width = 1000;
485 m_overzoomTextWidth = 0;
486 m_overzoomTextHeight = 0;
495 m_pEM_Fathoms = NULL;
497 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
499 m_pEM_OverZoom = NULL;
501 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
509 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
512 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
515 double factor_dusk = 0.5;
516 double factor_night = 0.25;
519 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
521 int rimg_width = m_os_image_red_day.GetWidth();
522 int rimg_height = m_os_image_red_day.GetHeight();
524 m_os_image_red_dusk = m_os_image_red_day.Copy();
525 m_os_image_red_night = m_os_image_red_day.Copy();
527 for (
int iy = 0; iy < rimg_height; iy++) {
528 for (
int ix = 0; ix < rimg_width; ix++) {
529 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
530 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
531 m_os_image_red_day.GetGreen(ix, iy),
532 m_os_image_red_day.GetBlue(ix, iy));
533 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
534 hsv.value = hsv.value * factor_dusk;
535 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
536 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
538 hsv = wxImage::RGBtoHSV(rgb);
539 hsv.value = hsv.value * factor_night;
540 nrgb = wxImage::HSVtoRGB(hsv);
541 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
547 m_os_image_grey_day =
548 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
550 int gimg_width = m_os_image_grey_day.GetWidth();
551 int gimg_height = m_os_image_grey_day.GetHeight();
553 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
554 m_os_image_grey_night = m_os_image_grey_day.Copy();
556 for (
int iy = 0; iy < gimg_height; iy++) {
557 for (
int ix = 0; ix < gimg_width; ix++) {
558 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
559 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
560 m_os_image_grey_day.GetGreen(ix, iy),
561 m_os_image_grey_day.GetBlue(ix, iy));
562 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
563 hsv.value = hsv.value * factor_dusk;
564 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
565 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
567 hsv = wxImage::RGBtoHSV(rgb);
568 hsv.value = hsv.value * factor_night;
569 nrgb = wxImage::HSVtoRGB(hsv);
570 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
576 m_os_image_yellow_day = m_os_image_red_day.Copy();
578 gimg_width = m_os_image_yellow_day.GetWidth();
579 gimg_height = m_os_image_yellow_day.GetHeight();
581 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
582 m_os_image_yellow_night = m_os_image_red_day.Copy();
584 for (
int iy = 0; iy < gimg_height; iy++) {
585 for (
int ix = 0; ix < gimg_width; ix++) {
586 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
587 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
588 m_os_image_yellow_day.GetGreen(ix, iy),
589 m_os_image_yellow_day.GetBlue(ix, iy));
590 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
591 hsv.hue += 60. / 360.;
592 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
593 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
595 hsv = wxImage::RGBtoHSV(rgb);
596 hsv.value = hsv.value * factor_dusk;
597 hsv.hue += 60. / 360.;
598 nrgb = wxImage::HSVtoRGB(hsv);
599 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
601 hsv = wxImage::RGBtoHSV(rgb);
602 hsv.hue += 60. / 360.;
603 hsv.value = hsv.value * factor_night;
604 nrgb = wxImage::HSVtoRGB(hsv);
605 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
611 m_pos_image_red = &m_os_image_red_day;
612 m_pos_image_yellow = &m_os_image_yellow_day;
613 m_pos_image_grey = &m_os_image_grey_day;
617 m_pBrightPopup = NULL;
620 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
625 m_Piano =
new Piano(
this);
627 m_bShowCompassWin =
true;
629 m_Compass->SetScaleFactor(g_compass_scalefactor);
630 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
632 if (IsPrimaryCanvas()) {
634 m_notification_button->SetScaleFactor(g_compass_scalefactor);
635 m_notification_button->Show(
true);
638 m_pianoFrozen =
false;
640 SetMinSize(wxSize(200, 200));
642 m_displayScale = 1.0;
643#if defined(__WXOSX__) || defined(__WXGTK3__)
645 m_displayScale = GetContentScaleFactor();
647 VPoint.SetPixelScale(m_displayScale);
649#ifdef HAVE_WX_GESTURE_EVENTS
652 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
653 wxLogError(
"Failed to enable touch events");
658 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
659 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
661 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
662 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
664 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
665 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
667 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
668 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
673 auto ¬eman = NotificationManager::GetInstance();
675 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
676 evt_notificationlist_change_listener.Listen(
677 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
678 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
679 if (m_NotificationsList && m_NotificationsList->IsShown()) {
680 m_NotificationsList->ReloadNotificationList();
686ChartCanvas::~ChartCanvas() {
687 delete pThumbDIBShow;
695 delete pCursorPencil;
699 delete pMovementTimer;
700 delete pMovementStopTimer;
701 delete pCurTrackTimer;
703 delete m_DoubleClickTimer;
705 delete m_pTrackRolloverWin;
706 delete m_pRouteRolloverWin;
707 delete m_pAISRolloverWin;
708 delete m_pBrightPopup;
714 m_dc_route.SelectObject(wxNullBitmap);
717 delete pWorldBackgroundChart;
718 delete pss_overlay_bmp;
722 delete m_pEM_Fathoms;
724 delete m_pEM_OverZoom;
729 delete m_pos_image_user_day;
730 delete m_pos_image_user_dusk;
731 delete m_pos_image_user_night;
732 delete m_pos_image_user_grey_day;
733 delete m_pos_image_user_grey_dusk;
734 delete m_pos_image_user_grey_night;
735 delete m_pos_image_user_yellow_day;
736 delete m_pos_image_user_yellow_dusk;
737 delete m_pos_image_user_yellow_night;
741 if (!g_bdisable_opengl) {
744#if wxCHECK_VERSION(2, 9, 0)
745 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
752 MUIBar *muiBar = m_muiBar;
756 delete m_pCurrentStack;
759 delete m_notification_button;
762void ChartCanvas::SetupGridFont() {
763 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
765 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
767 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
768 FALSE, wxString(
"Arial"));
771void ChartCanvas::RebuildCursors() {
777 delete pCursorPencil;
781 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
786 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
787 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
788 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
789 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
790 wxImage ICursorPencil =
791 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
792 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
794#if !defined(__WXMSW__) && !defined(__WXQT__)
795 ICursorLeft.ConvertAlphaToMask(128);
796 ICursorRight.ConvertAlphaToMask(128);
797 ICursorUp.ConvertAlphaToMask(128);
798 ICursorDown.ConvertAlphaToMask(128);
799 ICursorPencil.ConvertAlphaToMask(10);
800 ICursorCross.ConvertAlphaToMask(10);
803 if (ICursorLeft.Ok()) {
804 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
805 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
806 pCursorLeft =
new wxCursor(ICursorLeft);
808 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
810 if (ICursorRight.Ok()) {
811 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
812 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
813 pCursorRight =
new wxCursor(ICursorRight);
815 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
817 if (ICursorUp.Ok()) {
818 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
819 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
820 pCursorUp =
new wxCursor(ICursorUp);
822 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
824 if (ICursorDown.Ok()) {
825 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
826 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
827 pCursorDown =
new wxCursor(ICursorDown);
829 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
831 if (ICursorPencil.Ok()) {
832 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
833 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
834 pCursorPencil =
new wxCursor(ICursorPencil);
836 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
838 if (ICursorCross.Ok()) {
839 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
840 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
841 pCursorCross =
new wxCursor(ICursorCross);
843 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
845 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
846 pPlugIn_Cursor = NULL;
849void ChartCanvas::CanvasApplyLocale() {
850 CreateDepthUnitEmbossMaps(m_cs);
851 CreateOZEmbossMapData(m_cs);
854void ChartCanvas::SetupGlCanvas() {
857 if (!g_bdisable_opengl) {
859 wxLogMessage(
"Creating glChartCanvas");
864 if (IsPrimaryCanvas()) {
871 wxGLContext *pctx =
new wxGLContext(m_glcc);
872 m_glcc->SetContext(pctx);
876 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
878 m_glcc->SetContext(g_pGLcontext);
888 if (!g_bdisable_opengl) {
891 wxLogMessage(
"Creating glChartCanvas");
895 if (IsPrimaryCanvas()) {
896 qDebug() <<
"Creating Primary glChartCanvas";
904 wxGLContext *pctx =
new wxGLContext(m_glcc);
905 m_glcc->SetContext(pctx);
907 m_glcc->m_pParentCanvas =
this;
910 qDebug() <<
"Creating Secondary glChartCanvas";
917 top_frame::Get()->GetWxGlCanvas());
920 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
921 m_glcc->SetContext(pwxctx);
922 m_glcc->m_pParentCanvas =
this;
930void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
931 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
946 if (m_routeState && m_FinishRouteOnKillFocus)
947 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
949 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
953void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
954 m_routeFinishTimer.Stop();
958 top_frame::Get()->UpdateGlobalMenuItems(
this);
960 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
963void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
964 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
967#ifdef HAVE_WX_GESTURE_EVENTS
968void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
975 m_popupWanted =
true;
977 m_inLongPress = !g_bhide_context_menus;
980 m_menuPos =
event.GetPosition();
981 wxMouseEvent ev(wxEVT_LEFT_UP);
982 ev.m_x = m_menuPos.x;
983 ev.m_y = m_menuPos.y;
984 wxPostEvent(
this, ev);
988 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
989 ev_right_click.m_x = m_menuPos.x;
990 ev_right_click.m_y = m_menuPos.y;
991 MouseEvent(ev_right_click);
996void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1000void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1002void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1004void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1006 long dt = m_sw_left_up.Time() - m_sw_up_time;
1007 m_sw_up_time = m_sw_left_up.Time();
1018 wxPoint pos =
event.GetPosition();
1022 if (!m_popupWanted) {
1023 wxMouseEvent ev(wxEVT_LEFT_UP);
1030 m_popupWanted =
false;
1032 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1039void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1044 long dt = m_sw_left_down.Time() - m_sw_down_time;
1045 m_sw_down_time = m_sw_left_down.Time();
1069 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1071 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1072 m_lastTapPos.y - max_double_click_distance,
1073 max_double_click_distance * 2, max_double_click_distance * 2);
1076 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1082 m_lastTapPos =
event.GetPosition();
1083 m_tap_timer.StartOnce(
1087 if (m_tap_count == 2) {
1091 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1104void ChartCanvas::OnMotion(wxMouseEvent &event) {
1109 event.m_leftDown = m_leftdown;
1113void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1115 if (event.IsGestureEnd())
return;
1117 double factor =
event.GetZoomFactor();
1119 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1124 double wanted_factor = m_oldVPSScale / current_vps * factor;
1129 if (event.IsGestureStart()) {
1130 m_zoomStartPoint =
event.GetPosition();
1132 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1134 m_zoomStartPoint =
event.GetPosition();
1138void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1140void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1141 DoRotateCanvas(0.0);
1145void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1150void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1151 m_FinishRouteOnKillFocus =
false;
1152 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1153 m_FinishRouteOnKillFocus =
true;
1156void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1161 m_restore_dbindex = pcc->DBindex;
1163 if (pcc->GroupID < 0) pcc->GroupID = 0;
1168 m_groupIndex = pcc->GroupID;
1170 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1184 m_encDisplayCategory = pcc->nENCDisplayCategory;
1185 m_encShowDepth = pcc->bShowENCDepths;
1186 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1187 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1188 m_encShowLights = pcc->bShowENCLights;
1189 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1190 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1191 m_encShowDataQual = pcc->bShowENCDataQuality;
1195 m_upMode = NORTH_UP_MODE;
1197 m_upMode = COURSE_UP_MODE;
1199 m_upMode = HEAD_UP_MODE;
1203 m_singleChart = NULL;
1206void ChartCanvas::ApplyGlobalSettings() {
1209 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1210 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1212 if (m_notification_button) m_notification_button->UpdateStatus();
1215void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1216 bool groupOK = CheckGroup(m_groupIndex);
1219 SetGroupIndex(m_groupIndex,
true);
1223void ChartCanvas::SetShowGPS(
bool bshow) {
1224 if (m_bShowGPS != bshow) {
1227 m_Compass->SetScaleFactor(g_compass_scalefactor);
1228 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1233void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1234 m_bShowCompassWin = bshow;
1236 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1237 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1241int ChartCanvas::GetPianoHeight() {
1243 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1248void ChartCanvas::ConfigureChartBar() {
1251 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1252 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1254 if (GetQuiltMode()) {
1255 m_Piano->SetRoundedRectangles(
true);
1257 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1258 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1259 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1262void ChartCanvas::ShowTides(
bool bShow) {
1263 top_frame::Get()->LoadHarmonics();
1266 SetbShowTide(bShow);
1268 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1270 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1271 SetbShowTide(
false);
1272 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1275 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1276 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1287void ChartCanvas::ShowCurrents(
bool bShow) {
1288 top_frame::Get()->LoadHarmonics();
1291 SetbShowCurrent(bShow);
1292 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1294 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1295 SetbShowCurrent(
false);
1296 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1299 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1300 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1317void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1319void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1322 int new_index = index;
1325 bool bgroup_override =
false;
1326 int old_group_index = new_index;
1328 if (!CheckGroup(new_index)) {
1330 bgroup_override =
true;
1333 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1337 int current_chart_native_scale = GetCanvasChartNativeScale();
1340 m_groupIndex = new_index;
1346 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1350 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1354 g_sticky_chart = -1;
1358 UpdateCanvasOnGroupChange();
1361 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1363 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1366 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1367 double best_scale = GetBestStartScale(dbi_hint, vp);
1371 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1375 canvasChartsRefresh(dbi_hint);
1377 UpdateCanvasControlBar();
1379 if (!autoSwitch && bgroup_override) {
1381 wxString msg(_(
"Group \""));
1384 msg += pGroup->m_group_name;
1386 msg += _(
"\" is empty.");
1388 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1395 if (bgroup_override) {
1396 wxString msg(_(
"Group \""));
1399 msg += pGroup->m_group_name;
1401 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1403 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1407bool ChartCanvas::CheckGroup(
int igroup) {
1410 if (igroup == 0)
return true;
1417 if (pGroup->m_element_array.empty())
1421 for (
const auto &elem : pGroup->m_element_array) {
1422 for (
unsigned int ic = 0;
1423 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1424 auto &cte =
ChartData->GetChartTableEntry(ic);
1425 wxString chart_full_path(cte.GetpFullPath(), wxConvUTF8);
1427 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1432 for (
const auto &elem : pGroup->m_element_array) {
1433 const wxString &element_root = elem.m_element_name;
1434 wxString test_string =
"GSHH";
1435 if (element_root.Upper().Contains(test_string))
return true;
1441void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1444 AbstractPlatform::ShowBusySpinner();
1448 SetQuiltRefChart(-1);
1450 m_singleChart = NULL;
1456 if (!m_pCurrentStack) {
1458 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1461 if (-1 != dbi_hint) {
1462 if (GetQuiltMode()) {
1463 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1464 SetQuiltRefChart(dbi_hint);
1468 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1470 if (pTentative_Chart) {
1473 if (m_singleChart) m_singleChart->Deactivate();
1475 m_singleChart = pTentative_Chart;
1476 m_singleChart->Activate();
1478 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1479 GetpCurrentStack(), m_singleChart->GetFullPath());
1487 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1488 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1489 SetQuiltRefChart(selected_index);
1493 SetupCanvasQuiltMode();
1494 if (!GetQuiltMode() && m_singleChart == 0) {
1496 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1497 m_singleChart = pDummyChart;
1503 UpdateCanvasControlBar();
1504 UpdateGPSCompassStatusBox(
true);
1506 SetCursor(wxCURSOR_ARROW);
1508 AbstractPlatform::HideBusySpinner();
1511bool ChartCanvas::DoCanvasUpdate() {
1513 double vpLat, vpLon;
1514 bool blong_jump =
false;
1515 meters_to_shift = 0;
1518 bool bNewChart =
false;
1519 bool bNewView =
false;
1520 bool bCanvasChartAutoOpen =
true;
1522 bool bNewPiano =
false;
1523 bool bOpenSpecified;
1529 if (!GetVP().IsValid())
return false;
1530 if (bDBUpdateInProgress)
return false;
1535 if (m_chart_drag_inertia_active)
return false;
1536 if (m_animationActive)
return false;
1562 double dx = m_OSoffsetx;
1563 double dy = m_OSoffsety;
1567 if (GetUpMode() == NORTH_UP_MODE) {
1568 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1570 double offset_angle = atan2(d_north, d_east);
1571 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1572 double chart_angle = GetVPRotation();
1573 double target_angle = chart_angle + offset_angle;
1574 double d_east_mod = offset_distance * cos(target_angle);
1575 double d_north_mod = offset_distance * sin(target_angle);
1576 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1580 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1581 double cog_to_use =
gCog;
1583 (fabs(
gCog - gCog_gt) > 20)) {
1584 cog_to_use = gCog_gt;
1587 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1589 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1591 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1592 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1594 double pixel_delta_tent =
1595 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1597 double pixel_delta = 0;
1602 if (!std::isnan(
gSog)) {
1606 pixel_delta = pixel_delta_tent;
1609 meters_to_shift = 0;
1611 if (!std::isnan(
gCog)) {
1612 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1613 dir_to_shift = cog_to_use;
1614 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1620 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1634 if (GetQuiltMode()) {
1635 int current_db_index = -1;
1636 if (m_pCurrentStack)
1639 ->GetCurrentEntrydbIndex();
1647 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1649 if (m_pCurrentStack->nEntry) {
1650 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1652 SelectQuiltRefdbChart(new_dbIndex,
true);
1653 m_bautofind =
false;
1657 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1658 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1663 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1669 double proposed_scale_onscreen =
1672 int initial_db_index = m_restore_dbindex;
1673 if (initial_db_index < 0) {
1674 if (m_pCurrentStack->nEntry) {
1676 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1681 if (m_pCurrentStack->nEntry) {
1682 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1687 if (!IsChartQuiltableRef(initial_db_index)) {
1691 int stack_index = 0;
1693 if (stack_index >= 0) {
1694 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1695 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1696 if (IsChartQuiltableRef(test_db_index) &&
1698 ChartData->GetDBChartType(initial_db_index))) {
1699 initial_db_index = test_db_index;
1709 SetQuiltRefChart(initial_db_index);
1710 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1718 0, GetVPRotation());
1723 bool super_jump =
false;
1725 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1726 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1727 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1734 pLast_Ch = m_singleChart;
1735 ChartTypeEnum new_open_type;
1736 ChartFamilyEnum new_open_family;
1738 new_open_type = pLast_Ch->GetChartType();
1739 new_open_family = pLast_Ch->GetChartFamily();
1741 new_open_type = CHART_TYPE_KAP;
1742 new_open_family = CHART_FAMILY_RASTER;
1745 bOpenSpecified = m_bFirstAuto;
1748 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1751 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1753 if (NULL == pDummyChart) {
1759 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1761 m_singleChart = pDummyChart;
1766 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1768 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1771 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1772 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1779 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1785 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1790 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1793 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1798 if (NULL != m_singleChart)
1799 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1800 m_singleChart->GetFullPath());
1803 m_pCurrentStack->CurrentStackEntry = tEntry;
1813 if (bCanvasChartAutoOpen) {
1814 bool search_direction =
1816 int start_index = 0;
1820 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1821 (LastStack.nEntry == 0)) {
1822 search_direction =
true;
1823 start_index = m_pCurrentStack->nEntry - 1;
1827 if (bOpenSpecified) {
1828 if (m_restore_dbindex >= 0) {
1830 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
1831 std::vector<int> one_array;
1832 one_array.push_back(m_restore_dbindex);
1833 m_Piano->SetActiveKeyArray(one_array);
1834 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
1835 m_restore_dbindex = -1;
1839 search_direction =
false;
1840 start_index = m_restore_dbindex;
1841 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1844 new_open_type = CHART_TYPE_DONTCARE;
1849 pProposed =
ChartData->OpenStackChartConditional(
1850 m_pCurrentStack, start_index, search_direction, new_open_type,
1854 if (NULL == pProposed)
1855 pProposed =
ChartData->OpenStackChartConditional(
1856 m_pCurrentStack, start_index, search_direction,
1857 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1859 if (NULL == pProposed)
1860 pProposed =
ChartData->OpenStackChartConditional(
1861 m_pCurrentStack, start_index, search_direction,
1862 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1873 if (NULL == pProposed) {
1874 if (NULL == pDummyChart) {
1880 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1882 pProposed = pDummyChart;
1886 if (m_singleChart) m_singleChart->Deactivate();
1887 m_singleChart = pProposed;
1889 if (m_singleChart) {
1890 m_singleChart->Activate();
1891 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1892 m_pCurrentStack, m_singleChart->GetFullPath());
1897 if (NULL != m_singleChart) {
1901 double proposed_scale_onscreen;
1904 double new_scale_ppm =
1905 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1913 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1914 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1915 double equivalent_vp_scale =
1917 double new_scale_ppm =
1918 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1923 proposed_scale_onscreen =
1924 wxMin(proposed_scale_onscreen,
1927 proposed_scale_onscreen =
1928 wxMax(proposed_scale_onscreen,
1936 m_singleChart->GetChartSkew() * PI / 180.,
1944 if ((m_bFollow) && m_singleChart)
1946 m_singleChart->GetChartSkew() * PI / 180.,
1955 m_bFirstAuto =
false;
1959 if (bNewChart && !bNewView) Refresh(
false);
1964 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1967 return bNewChart | bNewView;
1970void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1971 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1973 SetQuiltRefChart(db_index);
1978 double best_scale_ppm = GetBestVPScale(pc);
1982 SetQuiltRefChart(-1);
1984 SetQuiltRefChart(-1);
1987void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1988 std::vector<int> piano_chart_index_array =
1989 GetQuiltExtendedStackdbIndexArray();
1990 int current_db_index = piano_chart_index_array[selected_index];
1992 SelectQuiltRefdbChart(current_db_index);
1995double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1999 if ((g_bPreserveScaleOnX) ||
2000 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2006 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2007 double equivalent_vp_scale =
2009 double new_scale_ppm =
2010 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2017 double max_underzoom_multiplier = 2.0;
2018 if (GetVP().b_quilt) {
2019 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2020 pchart->GetChartType(),
2021 pchart->GetChartFamily());
2022 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2025 proposed_scale_onscreen = wxMin(
2026 proposed_scale_onscreen,
2028 max_underzoom_multiplier);
2031 proposed_scale_onscreen =
2032 wxMax(proposed_scale_onscreen,
2040void ChartCanvas::SetupCanvasQuiltMode() {
2045 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2049 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2050 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2051 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2052 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2054 m_Piano->SetRoundedRectangles(
true);
2057 int target_new_dbindex = -1;
2058 if (m_pCurrentStack) {
2059 target_new_dbindex =
2060 GetQuiltReferenceChartIndex();
2062 if (-1 != target_new_dbindex) {
2063 if (!IsChartQuiltableRef(target_new_dbindex)) {
2064 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2065 int type =
ChartData->GetDBChartType(target_new_dbindex);
2068 int stack_index = m_pCurrentStack->CurrentStackEntry;
2070 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2071 (stack_index >= 0)) {
2072 int proj_tent =
ChartData->GetDBChartProj(
2073 m_pCurrentStack->GetDBIndex(stack_index));
2074 int type_tent =
ChartData->GetDBChartType(
2075 m_pCurrentStack->GetDBIndex(stack_index));
2077 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2078 if ((proj == proj_tent) && (type_tent == type)) {
2079 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2089 if (IsChartQuiltableRef(target_new_dbindex))
2090 SelectQuiltRefdbChart(target_new_dbindex,
2093 int stack_index = m_pCurrentStack->CurrentStackEntry;
2094 SelectQuiltRefdbChart(m_pCurrentStack->GetDBIndex(stack_index),
false);
2097 m_singleChart = NULL;
2100 AdjustQuiltRefChart();
2108 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2112 std::vector<int> empty_array;
2113 m_Piano->SetActiveKeyArray(empty_array);
2114 m_Piano->SetNoshowIndexArray(empty_array);
2115 m_Piano->SetEclipsedIndexArray(empty_array);
2118 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2119 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2120 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2121 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2123 m_Piano->SetRoundedRectangles(
false);
2129 if (!GetQuiltMode()) {
2134 if (m_bFollow ==
true) {
2142 if (!m_singleChart) {
2144 if (GetQuiltReferenceChartIndex() >= 0) {
2145 m_singleChart =
ChartData->OpenChartFromDB(
2146 GetQuiltReferenceChartIndex(), FULL_INIT);
2149 else if (m_restore_dbindex >= 0) {
2151 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
2157 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2165 int cur_max_scale = (int)1e8;
2167 ChartBase *pChart = GetFirstQuiltChart();
2171 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2173 if (pChart->GetNativeScale() < cur_max_scale) {
2174 Candidate_Chart = pChart;
2175 cur_max_scale = pChart->GetNativeScale();
2178 pChart = GetNextQuiltChart();
2181 m_singleChart = Candidate_Chart;
2185 if (NULL == m_singleChart) {
2186 m_singleChart =
ChartData->OpenStackChartConditional(
2187 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2188 CHART_FAMILY_DONTCARE);
2194 InvalidateAllQuiltPatchs();
2196 if (m_singleChart) {
2197 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2198 std::vector<int> one_array;
2199 one_array.push_back(dbi);
2200 m_Piano->SetActiveKeyArray(one_array);
2203 if (m_singleChart) {
2204 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2209 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2213bool ChartCanvas::IsTempMenuBarEnabled() {
2216 wxGetOsVersion(&major);
2224double ChartCanvas::GetCanvasRangeMeters() {
2226 GetSize(&width, &height);
2227 int minDimension = wxMin(width, height);
2230 range *= cos(GetVP().clat * PI / 180.);
2234void ChartCanvas::SetCanvasRangeMeters(
double range) {
2236 GetSize(&width, &height);
2237 int minDimension = wxMin(width, height);
2239 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2243bool ChartCanvas::SetUserOwnship() {
2247 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2248 double factor_dusk = 0.5;
2249 double factor_night = 0.25;
2251 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2252 m_pos_image_user_day =
new wxImage;
2253 *m_pos_image_user_day = pbmp->ConvertToImage();
2254 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2256 int gimg_width = m_pos_image_user_day->GetWidth();
2257 int gimg_height = m_pos_image_user_day->GetHeight();
2260 m_pos_image_user_dusk =
new wxImage;
2261 m_pos_image_user_night =
new wxImage;
2263 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2264 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2266 for (
int iy = 0; iy < gimg_height; iy++) {
2267 for (
int ix = 0; ix < gimg_width; ix++) {
2268 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2269 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2270 m_pos_image_user_day->GetGreen(ix, iy),
2271 m_pos_image_user_day->GetBlue(ix, iy));
2272 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2273 hsv.value = hsv.value * factor_dusk;
2274 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2275 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2278 hsv = wxImage::RGBtoHSV(rgb);
2279 hsv.value = hsv.value * factor_night;
2280 nrgb = wxImage::HSVtoRGB(hsv);
2281 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2288 m_pos_image_user_grey_day =
new wxImage;
2289 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2291 m_pos_image_user_grey_dusk =
new wxImage;
2292 m_pos_image_user_grey_night =
new wxImage;
2294 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2295 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2297 for (
int iy = 0; iy < gimg_height; iy++) {
2298 for (
int ix = 0; ix < gimg_width; ix++) {
2299 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2300 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2301 m_pos_image_user_grey_day->GetGreen(ix, iy),
2302 m_pos_image_user_grey_day->GetBlue(ix, iy));
2303 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2304 hsv.value = hsv.value * factor_dusk;
2305 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2306 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2309 hsv = wxImage::RGBtoHSV(rgb);
2310 hsv.value = hsv.value * factor_night;
2311 nrgb = wxImage::HSVtoRGB(hsv);
2312 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2319 m_pos_image_user_yellow_day =
new wxImage;
2320 m_pos_image_user_yellow_dusk =
new wxImage;
2321 m_pos_image_user_yellow_night =
new wxImage;
2323 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2324 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2325 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2327 for (
int iy = 0; iy < gimg_height; iy++) {
2328 for (
int ix = 0; ix < gimg_width; ix++) {
2329 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2330 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2331 m_pos_image_user_grey_day->GetGreen(ix, iy),
2332 m_pos_image_user_grey_day->GetBlue(ix, iy));
2336 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2337 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2338 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2340 hsv = wxImage::RGBtoHSV(rgb);
2341 hsv.value = hsv.value * factor_dusk;
2342 nrgb = wxImage::HSVtoRGB(hsv);
2343 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2345 hsv = wxImage::RGBtoHSV(rgb);
2346 hsv.value = hsv.value * factor_night;
2347 nrgb = wxImage::HSVtoRGB(hsv);
2348 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2360 m_display_size_mm = size;
2367 double horizontal = sd.x;
2371 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2372 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2376 ps52plib->SetPPMM(m_pix_per_mm);
2381 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2383 m_display_size_mm, sd.x, sd.y);
2389 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2392 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2395void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2397 wxString msg(event.m_string.c_str(), wxConvUTF8);
2399 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2400 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2403 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2405 compress_msg_array.RemoveAt(event.thread);
2406 compress_msg_array.Insert( msg, event.thread);
2409 compress_msg_array.Add(msg);
2412 wxString combined_msg;
2413 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2414 combined_msg += compress_msg_array[i];
2415 combined_msg +=
"\n";
2419 pprog->Update(pprog_count, combined_msg, &skip );
2420 pprog->SetSize(pprog_size);
2425void ChartCanvas::InvalidateGL() {
2426 if (!m_glcc)
return;
2428 if (g_bopengl) m_glcc->Invalidate();
2430 if (m_Compass) m_Compass->UpdateStatus(
true);
2433int ChartCanvas::GetCanvasChartNativeScale() {
2435 if (!VPoint.b_quilt) {
2436 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2438 ret = (int)m_pQuilt->GetRefNativeScale();
2443ChartBase *ChartCanvas::GetChartAtCursor() {
2445 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2446 target_chart = m_singleChart;
2447 else if (VPoint.b_quilt)
2448 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2450 target_chart = NULL;
2451 return target_chart;
2454ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2458 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2460 target_chart = NULL;
2461 return target_chart;
2464int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2465 int new_dbIndex = -1;
2466 if (!VPoint.b_quilt) {
2467 if (m_pCurrentStack) {
2468 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2469 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2471 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2481 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2483 for (
unsigned int is = 0; is < im; is++) {
2485 m_pQuilt->GetExtendedStackIndexArray()[is]);
2488 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2498void ChartCanvas::EnablePaint(
bool b_enable) {
2499 m_b_paint_enable = b_enable;
2501 if (m_glcc) m_glcc->EnablePaint(b_enable);
2505bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2507void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2509std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2510 return m_pQuilt->GetQuiltIndexArray();
2514void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2515 VPoint.b_quilt = b_quilt;
2516 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2519bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2521int ChartCanvas::GetQuiltReferenceChartIndex() {
2522 return m_pQuilt->GetRefChartdbIndex();
2525void ChartCanvas::InvalidateAllQuiltPatchs() {
2526 m_pQuilt->InvalidateAllQuiltPatchs();
2529ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2530 return m_pQuilt->GetLargestScaleChart();
2533ChartBase *ChartCanvas::GetFirstQuiltChart() {
2534 return m_pQuilt->GetFirstChart();
2537ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2539int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2541void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2542 m_pQuilt->SetHiliteIndex(dbIndex);
2545void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2546 m_pQuilt->SetHiliteIndexArray(hilite_array);
2549void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2550 m_pQuilt->ClearHiliteIndexArray();
2553std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2555 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2558int ChartCanvas::GetQuiltRefChartdbIndex() {
2559 return m_pQuilt->GetRefChartdbIndex();
2562std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2563 return m_pQuilt->GetExtendedStackIndexArray();
2566std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2567 return m_pQuilt->GetFullscreenIndexArray();
2570std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2571 return m_pQuilt->GetEclipsedStackIndexArray();
2574void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2576double ChartCanvas::GetQuiltMaxErrorFactor() {
2577 return m_pQuilt->GetMaxErrorFactor();
2580bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2581 return m_pQuilt->IsChartQuiltableRef(db_index);
2585 double chartMaxScale =
2587 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2590void ChartCanvas::StartMeasureRoute() {
2591 if (!m_routeState) {
2592 if (m_bMeasure_Active) {
2594 m_pMeasureRoute = NULL;
2597 m_bMeasure_Active =
true;
2598 m_nMeasureState = 1;
2599 m_bDrawingRoute =
false;
2601 SetCursor(*pCursorPencil);
2606void ChartCanvas::CancelMeasureRoute() {
2607 m_bMeasure_Active =
false;
2608 m_nMeasureState = 0;
2609 m_bDrawingRoute =
false;
2612 m_pMeasureRoute = NULL;
2614 SetCursor(*pCursorArrow);
2617ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2619void ChartCanvas::SetVP(
ViewPort &vp) {
2630void ChartCanvas::TriggerDeferredFocus() {
2633 m_deferredFocusTimer.Start(20,
true);
2635#if defined(__WXGTK__) || defined(__WXOSX__)
2636 top_frame::Get()->Raise();
2646void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2651void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2652 if (SendKeyEventToPlugins(event))
2656 int key_char =
event.GetKeyCode();
2659 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2665 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2670 if (g_benable_rotate) {
2691void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2692 if (SendKeyEventToPlugins(event))
2696 bool b_handled =
false;
2698 m_modkeys =
event.GetModifiers();
2700 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2702#ifdef OCPN_ALT_MENUBAR
2708 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2710 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2711 if (!g_bTempShowMenuBar) {
2712 g_bTempShowMenuBar =
true;
2713 top_frame::Get()->ApplyGlobalSettings(
false);
2715 m_bMayToggleMenuBar =
false;
2721 if (event.GetKeyCode() != WXK_ALT) {
2722 m_bMayToggleMenuBar =
false;
2729 switch (event.GetKeyCode()) {
2736 event.GetPosition(&x, &y);
2737 m_FinishRouteOnKillFocus =
false;
2738 CallPopupMenu(x, y);
2739 m_FinishRouteOnKillFocus =
true;
2743 m_modkeys |= wxMOD_ALT;
2747 m_modkeys |= wxMOD_CONTROL;
2752 case WXK_RAW_CONTROL:
2753 m_modkeys |= wxMOD_RAW_CONTROL;
2758 if (m_modkeys == wxMOD_CONTROL)
2759 top_frame::Get()->DoStackDown(
this);
2761 StartTimedMovement();
2771 StartTimedMovement();
2779 if (m_modkeys == wxMOD_CONTROL)
2780 top_frame::Get()->DoStackUp(
this);
2782 StartTimedMovement();
2792 StartTimedMovement();
2800 if (event.ShiftDown()) {
2802 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2804 std::shared_ptr<HostApi> host_api;
2806 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2809 api_121->SelectChartFamily(m_canvasIndex,
2816 if (event.ShiftDown()) {
2818 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2820 std::shared_ptr<HostApi> host_api;
2822 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2825 api_121->SelectChartFamily(m_canvasIndex,
2828 SetShowENCText(!GetShowENCText());
2835 if (!m_bMeasure_Active) {
2836 if (event.ShiftDown())
2837 m_bMeasure_DistCircle =
true;
2839 m_bMeasure_DistCircle =
false;
2841 StartMeasureRoute();
2843 CancelMeasureRoute();
2845 SetCursor(*pCursorArrow);
2855 top_frame::Get()->ToggleColorScheme();
2856 top_frame::Get()->Raise();
2857 TriggerDeferredFocus();
2861 int mod = m_modkeys & wxMOD_SHIFT;
2862 if (mod != m_brightmod) {
2864 m_bbrightdir = !m_bbrightdir;
2867 if (!m_bbrightdir) {
2868 g_nbrightness -= 10;
2869 if (g_nbrightness <= MIN_BRIGHT) {
2870 g_nbrightness = MIN_BRIGHT;
2871 m_bbrightdir =
true;
2874 g_nbrightness += 10;
2875 if (g_nbrightness >= MAX_BRIGHT) {
2876 g_nbrightness = MAX_BRIGHT;
2877 m_bbrightdir =
false;
2881 SetScreenBrightness(g_nbrightness);
2882 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2885 top_frame::Get()->Raise();
2891 top_frame::Get()->DoStackDown(
this);
2895 top_frame::Get()->DoStackUp(
this);
2900 ToggleCanvasQuiltMode();
2906 top_frame::Get()->ToggleFullScreen();
2911 if (m_modkeys == wxMOD_ALT) {
2914 ToggleChartOutlines();
2920 top_frame::Get()->ActivateMOB();
2924 case WXK_NUMPAD_ADD:
2929 case WXK_NUMPAD_SUBTRACT:
2930 case WXK_PAGEDOWN: {
2931 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2936 if (m_bMeasure_Active) {
2937 if (m_nMeasureState > 2) {
2938 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2940 m_pMeasureRoute->GetnPoints();
2942 top_frame::Get()->RefreshAllCanvas();
2944 CancelMeasureRoute();
2945 StartMeasureRoute();
2953 if (event.GetKeyCode() < 128)
2955 int key_char =
event.GetKeyCode();
2959 if (!g_b_assume_azerty) {
2961 if (g_benable_rotate) {
2993 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3000 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3001 m_modkeys & wxMOD_RAW_CONTROL) {
3002 top_frame::Get()->ToggleFullScreen();
3007 if (event.ControlDown()) key_char -= 64;
3009 if (key_char >=
'0' && key_char <=
'9')
3010 SetGroupIndex(key_char -
'0');
3015 SetShowENCAnchor(!GetShowENCAnchor());
3021 top_frame::Get()->ToggleColorScheme();
3026 event.GetPosition(&x, &y);
3027 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3028 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3031 if (VPoint.b_quilt) {
3033 if (m_pQuilt->GetChartAtPix(
3038 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3040 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3045 if (m_singleChart) {
3046 ChartType = m_singleChart->GetChartType();
3047 ChartFam = m_singleChart->GetChartFamily();
3051 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3052 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3054 this, -1, ChartType, ChartFam,
3055 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3056 wxDefaultSize, wxSIMPLE_BORDER,
"");
3069 m_nmea_log->Raise();
3073 SetShowENCLights(!GetShowENCLights());
3079 if (event.ShiftDown())
3080 m_bMeasure_DistCircle =
true;
3082 m_bMeasure_DistCircle =
false;
3084 StartMeasureRoute();
3088 if (g_bInlandEcdis && ps52plib) {
3089 SetENCDisplayCategory((_DisCat)STANDARD);
3094 ToggleChartOutlines();
3098 ToggleCanvasQuiltMode();
3102 top_frame::Get()->ToggleTestPause();
3105 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3106 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3107 g_iNavAidRadarRingsNumberVisible = 1;
3108 else if (!g_bNavAidRadarRingsShown &&
3109 g_iNavAidRadarRingsNumberVisible == 1)
3110 g_iNavAidRadarRingsNumberVisible = 0;
3113 SetShowENCDepth(!m_encShowDepth);
3118 SetShowENCText(!GetShowENCText());
3123 SetShowENCDataQual(!GetShowENCDataQual());
3128 m_bShowNavobjects = !m_bShowNavobjects;
3143 if (g_bShowMenuBar ==
false) top_frame::Get()->ToggleChartBar(
this);
3148 if (event.ControlDown()) top_frame::Get()->DropMarker(
false);
3155 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3156 if ((indexActive + 1) <= r->GetnPoints()) {
3167 if (!g_bShowMenuBar) top_frame::Get()->DropMarker(
true);
3173 if (g_bSpaceDropMark) top_frame::Get()->DropMarker(
true);
3179 if (m_modkeys == wxMOD_CONTROL) top_frame::Get()->ActivateMOB();
3186 top_frame::Get()->DoSettings();
3190 parent_frame->Close();
3206 if (undo->AnythingToRedo()) {
3207 undo->RedoNextAction();
3214 if (event.ShiftDown()) {
3215 if (undo->AnythingToRedo()) {
3216 undo->RedoNextAction();
3221 if (undo->AnythingToUndo()) {
3222 undo->UndoLastAction();
3231 if (m_bMeasure_Active) {
3232 CancelMeasureRoute();
3234 SetCursor(*pCursorArrow);
3237 top_frame::Get()->RefreshAllCanvas();
3251 switch (gamma_state) {
3271 SetScreenBrightness(g_nbrightness);
3276 if (event.ControlDown()) {
3277 m_bShowCompassWin = !m_bShowCompassWin;
3278 SetShowGPSCompassWindow(m_bShowCompassWin);
3295void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3296 if (SendKeyEventToPlugins(event))
3300 switch (event.GetKeyCode()) {
3302 top_frame::Get()->SwitchKBFocus(
this);
3308 if (!m_pany) m_panspeed = 0;
3314 if (!m_panx) m_panspeed = 0;
3317 case WXK_NUMPAD_ADD:
3318 case WXK_NUMPAD_SUBTRACT:
3327 m_modkeys &= ~wxMOD_ALT;
3328#ifdef OCPN_ALT_MENUBAR
3333 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3334 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3335 top_frame::Get()->ApplyGlobalSettings(
false);
3337 m_bMayToggleMenuBar =
true;
3343 m_modkeys &= ~wxMOD_CONTROL;
3347 if (event.GetKeyCode() < 128)
3349 int key_char =
event.GetKeyCode();
3353 if (!g_b_assume_azerty) {
3368 m_rotation_speed = 0;
3386void ChartCanvas::ToggleChartOutlines() {
3387 m_bShowOutlines = !m_bShowOutlines;
3393 if (g_bopengl) InvalidateGL();
3397void ChartCanvas::ToggleLookahead() {
3398 m_bLookAhead = !m_bLookAhead;
3403void ChartCanvas::SetUpMode(
int mode) {
3406 if (mode != NORTH_UP_MODE) {
3409 if (!std::isnan(
gCog)) stuff =
gCog;
3412 auto cog_table = top_frame::Get()->GetCOGTable();
3413 for (
int i = 0; i <
g_COGAvgSec; i++) cog_table[i] = stuff;
3416 top_frame::Get()->StartCogTimer();
3418 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3419 SetVPRotation(GetVPSkew());
3424 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3425 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3427 UpdateGPSCompassStatusBox(
true);
3428 top_frame::Get()->DoChartUpdate();
3431bool ChartCanvas::DoCanvasCOGSet() {
3432 if (GetUpMode() == NORTH_UP_MODE)
return false;
3434 if (g_btenhertz) cog_use =
gCog;
3436 double rotation = 0;
3437 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3438 rotation = -
gHdt * PI / 180.;
3439 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3440 rotation = -cog_use * PI / 180.;
3442 SetVPRotation(rotation);
3446double easeOutCubic(
double t) {
3448 return 1.0 - pow(1.0 - t, 3.0);
3451void ChartCanvas::StartChartDragInertia() {
3452 m_bChartDragging =
false;
3455 m_chart_drag_inertia_time = 750;
3456 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3461 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3465 size_t length = m_drag_vec_t.size();
3466 for (
size_t i = 0; i < n_vel; i++) {
3467 xacc += m_drag_vec_x.at(length - 1 - i);
3468 yacc += m_drag_vec_y.at(length - 1 - i);
3469 tacc += m_drag_vec_t.at(length - 1 - i);
3472 if (tacc == 0)
return;
3474 double drag_velocity_x = xacc / tacc;
3475 double drag_velocity_y = yacc / tacc;
3481 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3483 m_chart_drag_velocity_x = drag_velocity_x;
3484 m_chart_drag_velocity_y = drag_velocity_y;
3486 m_chart_drag_inertia_active =
true;
3488 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3491void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3492 if (!m_chart_drag_inertia_active)
return;
3494 wxLongLong now = wxGetLocalTimeMillis();
3495 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3496 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3497 if (t > 1.0) t = 1.0;
3498 double e = 1.0 - easeOutCubic(t);
3501 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3503 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3505 m_last_elapsed = elapsed;
3509 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3510 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3511 double inertia_lat, inertia_lon;
3515 if (!IsOwnshipOnScreen()) {
3517 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3518 UpdateFollowButtonState();
3529 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3530 m_chart_drag_inertia_timer.Stop();
3533 m_target_lat = GetVP().
clat;
3534 m_target_lon = GetVP().
clon;
3535 m_pan_drag.x = m_pan_drag.y = 0;
3536 m_panx = m_pany = 0;
3537 m_chart_drag_inertia_active =
false;
3541 int target_redraw_interval = 40;
3542 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3546void ChartCanvas::StopMovement() {
3547 m_panx = m_pany = 0;
3550 m_rotation_speed = 0;
3553#if !defined(__WXGTK__) && !defined(__WXQT__)
3555 top_frame::Get()->Raise();
3564bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3566 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3568 if (!pMovementTimer->IsRunning()) {
3569 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3572 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3577 m_last_movement_time = wxDateTime::UNow();
3581void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3584 m_target_lat = target_lat;
3585 m_target_lon = target_lon;
3588 m_start_lat = GetVP().
clat;
3589 m_start_lon = GetVP().
clon;
3591 m_VPMovementTimer.Start(1,
true);
3592 m_timed_move_vp_active =
true;
3594 m_timedVP_step = nstep;
3597void ChartCanvas::DoTimedMovementVP() {
3598 if (!m_timed_move_vp_active)
return;
3599 if (m_stvpc++ > m_timedVP_step * 2) {
3606 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3621 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3622 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3624 m_run_lat = new_lat;
3625 m_run_lon = new_lon;
3630void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3632void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3634void ChartCanvas::StartTimedMovementTarget() {}
3636void ChartCanvas::DoTimedMovementTarget() {}
3638void ChartCanvas::StopMovementTarget() {}
3641void ChartCanvas::DoTimedMovement() {
3642 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3646 wxDateTime now = wxDateTime::UNow();
3648 if (m_last_movement_time.IsValid())
3649 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3651 m_last_movement_time = now;
3661 if (dt == 0) dt = 1;
3664 if (m_mustmove < 0) m_mustmove = 0;
3667 if (m_pan_drag.x || m_pan_drag.y) {
3669 m_pan_drag.x = m_pan_drag.y = 0;
3672 if (m_panx || m_pany) {
3673 const double slowpan = .1, maxpan = 2;
3674 if (m_modkeys == wxMOD_ALT)
3675 m_panspeed = slowpan;
3677 m_panspeed += (double)dt / 500;
3678 m_panspeed = wxMin(maxpan, m_panspeed);
3680 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3683 if (m_zoom_factor != 1) {
3684 double alpha = 400, beta = 1.5;
3685 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3687 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3689 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3694 if (zoom_factor > 1) {
3695 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3699 else if (zoom_factor < 1) {
3700 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3705 if (fabs(zoom_factor - 1) > 1e-4) {
3706 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3711 if (m_wheelzoom_stop_oneshot > 0) {
3712 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3713 m_wheelzoom_stop_oneshot = 0;
3718 if (zoom_factor > 1) {
3720 m_wheelzoom_stop_oneshot = 0;
3723 }
else if (zoom_factor < 1) {
3725 m_wheelzoom_stop_oneshot = 0;
3732 if (m_rotation_speed) {
3733 double speed = m_rotation_speed;
3734 if (m_modkeys == wxMOD_ALT) speed /= 10;
3735 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3739void ChartCanvas::SetColorScheme(ColorScheme cs) {
3744 case GLOBAL_COLOR_SCHEME_DAY:
3745 m_pos_image_red = &m_os_image_red_day;
3746 m_pos_image_grey = &m_os_image_grey_day;
3747 m_pos_image_yellow = &m_os_image_yellow_day;
3748 m_pos_image_user = m_pos_image_user_day;
3749 m_pos_image_user_grey = m_pos_image_user_grey_day;
3750 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3751 m_cTideBitmap = m_bmTideDay;
3752 m_cCurrentBitmap = m_bmCurrentDay;
3755 case GLOBAL_COLOR_SCHEME_DUSK:
3756 m_pos_image_red = &m_os_image_red_dusk;
3757 m_pos_image_grey = &m_os_image_grey_dusk;
3758 m_pos_image_yellow = &m_os_image_yellow_dusk;
3759 m_pos_image_user = m_pos_image_user_dusk;
3760 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3761 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3762 m_cTideBitmap = m_bmTideDusk;
3763 m_cCurrentBitmap = m_bmCurrentDusk;
3765 case GLOBAL_COLOR_SCHEME_NIGHT:
3766 m_pos_image_red = &m_os_image_red_night;
3767 m_pos_image_grey = &m_os_image_grey_night;
3768 m_pos_image_yellow = &m_os_image_yellow_night;
3769 m_pos_image_user = m_pos_image_user_night;
3770 m_pos_image_user_grey = m_pos_image_user_grey_night;
3771 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3772 m_cTideBitmap = m_bmTideNight;
3773 m_cCurrentBitmap = m_bmCurrentNight;
3776 m_pos_image_red = &m_os_image_red_day;
3777 m_pos_image_grey = &m_os_image_grey_day;
3778 m_pos_image_yellow = &m_os_image_yellow_day;
3779 m_pos_image_user = m_pos_image_user_day;
3780 m_pos_image_user_grey = m_pos_image_user_grey_day;
3781 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3782 m_cTideBitmap = m_bmTideDay;
3783 m_cCurrentBitmap = m_bmCurrentDay;
3787 CreateDepthUnitEmbossMaps(cs);
3788 CreateOZEmbossMapData(cs);
3791 m_fog_color = wxColor(
3795 case GLOBAL_COLOR_SCHEME_DUSK:
3798 case GLOBAL_COLOR_SCHEME_NIGHT:
3804 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3805 m_fog_color.Blue() * dim);
3809 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3810 SetBackgroundColour( wxColour(0,0,0) );
3812 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3815 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3817 SetBackgroundColour( wxNullColour );
3824 m_Piano->SetColorScheme(cs);
3826 m_Compass->SetColorScheme(cs);
3828 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3830 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3832 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3833 if (m_notification_button) {
3834 m_notification_button->SetColorScheme(cs);
3838 if (g_bopengl && m_glcc) {
3839 m_glcc->SetColorScheme(cs);
3845 m_brepaint_piano =
true;
3852wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3853 wxImage img = Bitmap.ConvertToImage();
3854 int sx = img.GetWidth();
3855 int sy = img.GetHeight();
3857 wxImage new_img(img);
3859 for (
int i = 0; i < sx; i++) {
3860 for (
int j = 0; j < sy; j++) {
3861 if (!img.IsTransparent(i, j)) {
3862 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3863 (
unsigned char)(img.GetGreen(i, j) * factor),
3864 (
unsigned char)(img.GetBlue(i, j) * factor));
3869 wxBitmap ret = wxBitmap(new_img);
3874void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3877 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3879 if (!m_pBrightPopup) {
3882 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3886 m_pBrightPopup->SetSize(x, y);
3887 m_pBrightPopup->Move(120, 120);
3890 int bmpsx = m_pBrightPopup->GetSize().x;
3891 int bmpsy = m_pBrightPopup->GetSize().y;
3893 wxBitmap bmp(bmpsx, bmpsx);
3894 wxMemoryDC mdc(bmp);
3896 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3897 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3898 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3899 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3902 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3904 mdc.SetFont(*pfont);
3907 if (brightness == max)
3909 else if (brightness == min)
3912 val.Printf(
"%3d", brightness);
3914 mdc.DrawText(val, 0, 0);
3916 mdc.SelectObject(wxNullBitmap);
3918 m_pBrightPopup->SetBitmap(bmp);
3919 m_pBrightPopup->Show();
3920 m_pBrightPopup->Refresh();
3923void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3924 m_b_rot_hidef =
true;
3928void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3931 bool b_need_refresh =
false;
3933 wxSize win_size = GetSize() * m_displayScale;
3937 bool showAISRollover =
false;
3939 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3943 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3944 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3947 showAISRollover =
true;
3949 if (NULL == m_pAISRolloverWin) {
3951 m_pAISRolloverWin->IsActive(
false);
3952 b_need_refresh =
true;
3953 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3954 m_AISRollover_MMSI != FoundAIS_MMSI) {
3960 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3961 m_pAISRolloverWin->IsActive(
false);
3962 m_AISRollover_MMSI = 0;
3967 m_AISRollover_MMSI = FoundAIS_MMSI;
3969 if (!m_pAISRolloverWin->IsActive()) {
3970 wxString s = ptarget->GetRolloverString();
3971 m_pAISRolloverWin->SetString(s);
3973 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3974 AIS_ROLLOVER, win_size);
3975 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3976 m_pAISRolloverWin->IsActive(
true);
3977 b_need_refresh =
true;
3981 m_AISRollover_MMSI = 0;
3982 showAISRollover =
false;
3987 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3988 m_pAISRolloverWin->IsActive(
false);
3989 m_AISRollover_MMSI = 0;
3990 b_need_refresh =
true;
3995 bool showRouteRollover =
false;
3997 if (NULL == m_pRolloverRouteSeg) {
4001 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4002 SelectableItemList SelList =
pSelect->FindSelectionList(
4004 auto node = SelList.begin();
4005 while (node != SelList.end()) {
4010 if (pr && pr->IsVisible()) {
4011 m_pRolloverRouteSeg = pFindSel;
4012 showRouteRollover =
true;
4014 if (NULL == m_pRouteRolloverWin) {
4016 m_pRouteRolloverWin->IsActive(
false);
4019 if (!m_pRouteRolloverWin->IsActive()) {
4027 DistanceBearingMercator(
4028 segShow_point_b->m_lat, segShow_point_b->m_lon,
4029 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4031 if (!pr->m_bIsInLayer)
4032 s.Append(_(
"Route") +
": ");
4034 s.Append(_(
"Layer Route: "));
4036 if (pr->m_RouteNameString.IsEmpty())
4037 s.Append(_(
"(unnamed)"));
4039 s.Append(pr->m_RouteNameString);
4044 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4045 << segShow_point_b->GetName() <<
"\n";
4048 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4049 (
int)floor(brg + 0.5), 0x00B0);
4052 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4054 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4056 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4058 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4059 (
int)floor(varBrg + 0.5), 0x00B0);
4067 double shiptoEndLeg = 0.;
4068 bool validActive =
false;
4069 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4072 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4073 auto node = pr->pRoutePointList->begin();
4075 float dist_to_endleg = 0;
4078 for (++node; node != pr->pRoutePointList->end(); ++node) {
4085 if (prp->IsSame(segShow_point_a))
break;
4093 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4096 ->GetCurrentRngToActivePoint();
4105 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4110 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4111 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4113 << wxString(ttg_sec > SECONDS_PER_DAY
4114 ? ttg_span.Format(_(
"%Dd %H:%M"))
4115 : ttg_span.Format(_(
"%H:%M")));
4116 wxDateTime dtnow, eta;
4117 eta = dtnow.SetToCurrent().Add(ttg_span);
4118 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4119 << eta.Format(
" %d %H:%M");
4123 m_pRouteRolloverWin->SetString(s);
4125 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4126 LEG_ROLLOVER, win_size);
4127 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4128 m_pRouteRolloverWin->IsActive(
true);
4129 b_need_refresh =
true;
4130 showRouteRollover =
true;
4139 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4141 m_pRolloverRouteSeg))
4142 showRouteRollover =
false;
4143 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4144 showRouteRollover =
false;
4146 showRouteRollover =
true;
4150 if (m_routeState) showRouteRollover =
false;
4153 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4154 showRouteRollover =
false;
4156 if (m_pRouteRolloverWin &&
4157 !showRouteRollover) {
4158 m_pRouteRolloverWin->IsActive(
false);
4159 m_pRolloverRouteSeg = NULL;
4160 m_pRouteRolloverWin->Destroy();
4161 m_pRouteRolloverWin = NULL;
4162 b_need_refresh =
true;
4163 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4164 m_pRouteRolloverWin->IsActive(
true);
4165 b_need_refresh =
true;
4170 bool showTrackRollover =
false;
4172 if (NULL == m_pRolloverTrackSeg) {
4176 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4177 SelectableItemList SelList =
pSelect->FindSelectionList(
4180 auto node = SelList.begin();
4181 while (node != SelList.end()) {
4186 if (pt && pt->IsVisible()) {
4187 m_pRolloverTrackSeg = pFindSel;
4188 showTrackRollover =
true;
4190 if (NULL == m_pTrackRolloverWin) {
4192 m_pTrackRolloverWin->IsActive(
false);
4195 if (!m_pTrackRolloverWin->IsActive()) {
4203 DistanceBearingMercator(
4204 segShow_point_b->m_lat, segShow_point_b->m_lon,
4205 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4207 if (!pt->m_bIsInLayer)
4208 s.Append(_(
"Track") +
": ");
4210 s.Append(_(
"Layer Track: "));
4212 if (pt->GetName().IsEmpty())
4213 s.Append(_(
"(unnamed)"));
4215 s.Append(pt->GetName());
4216 double tlenght = pt->Length();
4218 if (pt->GetLastPoint()->GetTimeString() &&
4219 pt->GetPoint(0)->GetTimeString()) {
4220 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4221 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4222 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4223 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4224 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4225 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4226 << getUsrSpeedUnit();
4227 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4228 : ttime.Format(
" %H:%M"));
4232 if (g_bShowTrackPointTime &&
4233 strlen(segShow_point_b->GetTimeString())) {
4234 wxString stamp = segShow_point_b->GetTimeString();
4235 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4236 if (timestamp.IsValid()) {
4240 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4242 s <<
"\n" << _(
"Segment Created: ") << stamp;
4247 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4252 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4254 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4256 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4258 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4264 if (segShow_point_a->GetTimeString() &&
4265 segShow_point_b->GetTimeString()) {
4266 wxDateTime apoint = segShow_point_a->GetCreateTime();
4267 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4268 if (apoint.IsValid() && bpoint.IsValid()) {
4269 double segmentSpeed = toUsrSpeed(
4270 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4271 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4272 << getUsrSpeedUnit();
4276 m_pTrackRolloverWin->SetString(s);
4278 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4279 LEG_ROLLOVER, win_size);
4280 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4281 m_pTrackRolloverWin->IsActive(
true);
4282 b_need_refresh =
true;
4283 showTrackRollover =
true;
4292 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4294 m_pRolloverTrackSeg))
4295 showTrackRollover =
false;
4296 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4297 showTrackRollover =
false;
4299 showTrackRollover =
true;
4303 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4304 showTrackRollover =
false;
4307 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4308 showTrackRollover =
false;
4314 if (m_pTrackRolloverWin &&
4315 !showTrackRollover) {
4316 m_pTrackRolloverWin->IsActive(
false);
4317 m_pRolloverTrackSeg = NULL;
4318 m_pTrackRolloverWin->Destroy();
4319 m_pTrackRolloverWin = NULL;
4320 b_need_refresh =
true;
4321 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4322 m_pTrackRolloverWin->IsActive(
true);
4323 b_need_refresh =
true;
4326 if (b_need_refresh) Refresh();
4329void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4330 if ((GetShowENCLights() || m_bsectors_shown) &&
4331 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4332 extendedSectorLegs)) {
4333 if (!m_bsectors_shown) {
4335 m_bsectors_shown =
true;
4338 if (m_bsectors_shown) {
4340 m_bsectors_shown =
false;
4348#if defined(__WXGTK__) || defined(__WXQT__)
4353 double cursor_lat, cursor_lon;
4356 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4357 while (cursor_lon < -180.) cursor_lon += 360.;
4359 while (cursor_lon > 180.) cursor_lon -= 360.;
4361 SetCursorStatus(cursor_lat, cursor_lon);
4367void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4368 if (!top_frame::Get()->GetFrameStatusBar())
return;
4372 s1 += toSDMM(1, cursor_lat);
4374 s1 += toSDMM(2, cursor_lon);
4376 if (STAT_FIELD_CURSOR_LL >= 0)
4377 top_frame::Get()->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4379 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4384 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4385 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4386 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4388 wxString s = st + sm;
4401 if (g_bShowLiveETA) {
4404 float boatSpeedDefault = g_defaultBoatSpeed;
4409 if (!std::isnan(
gSog)) {
4411 if (boatSpeed < 0.5) {
4414 realTimeETA = dist / boatSpeed * 60;
4423 s << minutesToHoursDays(realTimeETA);
4428 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4429 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4431 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4436 top_frame::Get()->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4444wxString minutesToHoursDays(
float timeInMinutes) {
4447 if (timeInMinutes == 0) {
4452 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4453 s << wxString::Format(
"%d", (
int)timeInMinutes);
4458 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4461 hours = (int)timeInMinutes / 60;
4462 min = (int)timeInMinutes % 60;
4465 s << wxString::Format(
"%d", hours);
4468 s << wxString::Format(
"%d", hours);
4470 s << wxString::Format(
"%d", min);
4477 else if (timeInMinutes > 24 * 60) {
4480 days = (int)(timeInMinutes / 60) / 24;
4481 hours = (int)(timeInMinutes / 60) % 24;
4484 s << wxString::Format(
"%d", days);
4487 s << wxString::Format(
"%d", days);
4489 s << wxString::Format(
"%d", hours);
4501void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4509 wxPoint2DDouble *r) {
4514 double rlon, wxPoint2DDouble *r) {
4525 if (!g_bopengl && m_singleChart &&
4526 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4527 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4528 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4529 (m_singleChart->GetChartProjectionType() !=
4530 PROJECTION_TRANSVERSE_MERCATOR) &&
4531 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4532 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4533 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4547 Cur_BSB_Ch->SetVPRasterParms(vp);
4548 double rpixxd, rpixyd;
4549 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4575 if (std::isnan(p.m_x)) {
4576 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4580 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4581 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4583 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4602 if (!g_bopengl && m_singleChart &&
4603 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4604 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4605 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4606 (m_singleChart->GetChartProjectionType() !=
4607 PROJECTION_TRANSVERSE_MERCATOR) &&
4608 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4609 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4610 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4621 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4624 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4629 else if (slon > 180.)
4640 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4646 DoZoomCanvas(factor,
false);
4647 extendedSectorLegs.clear();
4652 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4655 if (StartTimedMovement(stoptimer)) {
4657 m_zoom_factor = factor;
4662 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4664 DoZoomCanvas(factor, can_zoom_to_cursor);
4667 extendedSectorLegs.clear();
4670void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4673 if (!m_pCurrentStack)
return;
4679 if (m_bzooming)
return;
4688 double proposed_scale_onscreen =
4691 bool b_do_zoom =
false;
4700 if (!VPoint.b_quilt) {
4703 if (!m_disable_adjust_on_zoom) {
4704 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4705 if (new_db_index >= 0)
4706 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4710 int current_ref_stack_index = -1;
4711 if (m_pCurrentStack->nEntry) {
4713 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4714 m_pQuilt->SetReferenceChart(trial_index);
4715 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4716 if (new_db_index >= 0)
4717 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4721 if (m_pCurrentStack)
4722 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4733 double min_allowed_scale =
4736 if (proposed_scale_onscreen < min_allowed_scale) {
4741 proposed_scale_onscreen = min_allowed_scale;
4745 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4748 }
else if (factor < 1) {
4753 bool b_smallest =
false;
4755 if (!VPoint.b_quilt) {
4760 LLBBox viewbox = VPoint.GetBBox();
4762 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4763 double max_allowed_scale;
4777 if (proposed_scale_onscreen > max_allowed_scale) {
4779 proposed_scale_onscreen = max_allowed_scale;
4784 if (!m_disable_adjust_on_zoom) {
4786 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4787 if (new_db_index >= 0)
4788 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4790 if (m_pCurrentStack)
4791 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4794 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4796 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4797 proposed_scale_onscreen =
4798 wxMin(proposed_scale_onscreen,
4804 m_absolute_min_scale_ppm)
4805 proposed_scale_onscreen =
4814 bool b_allow_ztc =
true;
4815 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4816 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4818 double brg, distance;
4819 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4822 meters_to_shift = distance * 1852;
4830 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4833 if (m_bFollow) DoCanvasUpdate();
4840void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4842 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4846void ChartCanvas::RotateCanvas(
double dir) {
4850 if (StartTimedMovement()) {
4852 m_rotation_speed = dir * 60;
4855 double speed = dir * 10;
4856 if (m_modkeys == wxMOD_ALT) speed /= 20;
4857 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4861void ChartCanvas::DoRotateCanvas(
double rotation) {
4862 while (rotation < 0) rotation += 2 * PI;
4863 while (rotation > 2 * PI) rotation -= 2 * PI;
4865 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4867 SetVPRotation(rotation);
4868 top_frame::Get()->UpdateRotationState(VPoint.
rotation);
4871void ChartCanvas::DoTiltCanvas(
double tilt) {
4872 while (tilt < 0) tilt = 0;
4873 while (tilt > .95) tilt = .95;
4875 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4881void ChartCanvas::TogglebFollow() {
4888void ChartCanvas::ClearbFollow() {
4891 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4893 UpdateFollowButtonState();
4897 top_frame::Get()->SetChartUpdatePeriod();
4900void ChartCanvas::SetbFollow() {
4903 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4904 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4912 p.m_x += m_OSoffsetx;
4913 p.m_y -= m_OSoffsety;
4922 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4923 UpdateFollowButtonState();
4925 if (!g_bSmoothRecenter) {
4929 top_frame::Get()->SetChartUpdatePeriod();
4932void ChartCanvas::UpdateFollowButtonState() {
4935 m_muiBar->SetFollowButtonState(0);
4938 m_muiBar->SetFollowButtonState(2);
4940 m_muiBar->SetFollowButtonState(1);
4946 androidSetFollowTool(0);
4949 androidSetFollowTool(2);
4951 androidSetFollowTool(1);
4958 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4959 if (pic->m_enabled && pic->m_init_state) {
4960 switch (pic->m_api_version) {
4963 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4974void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4975 if (g_bSmoothRecenter && !m_routeState) {
4976 if (StartSmoothJump(lat, lon, scale_ppm))
4980 double gcDist, gcBearingEnd;
4981 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4983 gcBearingEnd += 180;
4984 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4987 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4988 double new_lat = lat + (lat_offset / (1852 * 60));
4989 double new_lon = lon + (lon_offset / (1852 * 60));
4992 StartSmoothJump(lat, lon, scale_ppm);
4997 if (lon > 180.0) lon -= 360.0;
5003 if (!GetQuiltMode()) {
5005 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
5006 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
5010 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5011 AdjustQuiltRefChart();
5018 UpdateFollowButtonState();
5026bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5031 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5032 double distance_pixels = gcDist *
GetVPScale();
5033 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5039 m_startLat = m_vLat;
5040 m_startLon = m_vLon;
5045 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5046 m_endScale = scale_ppm;
5049 m_animationDuration = 600;
5050 m_animationStart = wxGetLocalTimeMillis();
5057 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5058 m_animationActive =
true;
5063void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5065 wxLongLong now = wxGetLocalTimeMillis();
5066 double elapsed = (now - m_animationStart).ToDouble();
5067 double t = elapsed / m_animationDuration.ToDouble();
5068 if (t > 1.0) t = 1.0;
5071 double e = easeOutCubic(t);
5074 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5075 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5076 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5081 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5087 m_animationActive =
false;
5088 UpdateFollowButtonState();
5097 extendedSectorLegs.clear();
5106 if (iters++ > 5)
return false;
5107 if (!std::isnan(dlat))
break;
5110 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5116 else if (dlat < -90)
5119 if (dlon > 360.) dlon -= 360.;
5120 if (dlon < -360.) dlon += 360.;
5135 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5139 if (VPoint.b_quilt) {
5140 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5141 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5145 double tweak_scale_ppm =
5151 if (new_ref_dbIndex == -1) {
5152#pragma GCC diagnostic push
5153#pragma GCC diagnostic ignored "-Warray-bounds"
5160 int trial_index = -1;
5161 if (m_pCurrentStack->nEntry) {
5163 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5166 if (trial_index < 0) {
5167 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5168 if (full_screen_array.size())
5169 trial_index = full_screen_array[full_screen_array.size() - 1];
5172 if (trial_index >= 0) {
5173 m_pQuilt->SetReferenceChart(trial_index);
5178#pragma GCC diagnostic pop
5185 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5187 double offset_angle = atan2(offy, offx);
5188 double offset_distance = sqrt((offy * offy) + (offx * offx));
5189 double chart_angle = GetVPRotation();
5190 double target_angle = chart_angle - offset_angle;
5191 double d_east_mod = offset_distance * cos(target_angle);
5192 double d_north_mod = offset_distance * sin(target_angle);
5197 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5198 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5200 UpdateFollowButtonState();
5206 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5211bool ChartCanvas::IsOwnshipOnScreen() {
5214 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5215 ((r.y > 0) && r.y < GetCanvasHeight()))
5221void ChartCanvas::ReloadVP(
bool b_adjust) {
5222 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5224 LoadVP(VPoint, b_adjust);
5227void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5229 if (g_bopengl && m_glcc) {
5230 m_glcc->Invalidate();
5231 if (m_glcc->GetSize() != GetSize()) {
5232 m_glcc->SetSize(GetSize());
5237 m_cache_vp.Invalidate();
5238 m_bm_cache_vp.Invalidate();
5241 VPoint.Invalidate();
5243 if (m_pQuilt) m_pQuilt->Invalidate();
5252 vp.m_projection_type, b_adjust);
5255void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5256 m_pQuilt->SetReferenceChart(dbIndex);
5257 VPoint.Invalidate();
5258 m_pQuilt->Invalidate();
5261double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5263 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5270int ChartCanvas::AdjustQuiltRefChart() {
5275 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5277 double min_ref_scale =
5278 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5279 double max_ref_scale =
5280 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5283 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5284 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5285 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5287 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5290 int target_stack_index = wxNOT_FOUND;
5292 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5293 if (index == m_pQuilt->GetRefChartdbIndex()) {
5294 target_stack_index = il;
5299 if (wxNOT_FOUND == target_stack_index)
5300 target_stack_index = 0;
5302 int ref_family = pc->GetChartFamily();
5303 int extended_array_count =
5304 m_pQuilt->GetExtendedStackIndexArray().size();
5305 while ((!brender_ok) &&
5306 ((
int)target_stack_index < (extended_array_count - 1))) {
5307 target_stack_index++;
5309 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5311 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5312 IsChartQuiltableRef(test_db_index)) {
5315 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5317 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5324 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5325 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5326 IsChartQuiltableRef(new_db_index)) {
5327 m_pQuilt->SetReferenceChart(new_db_index);
5330 ret = m_pQuilt->GetRefChartdbIndex();
5332 ret = m_pQuilt->GetRefChartdbIndex();
5335 ret = m_pQuilt->GetRefChartdbIndex();
5344void ChartCanvas::UpdateCanvasOnGroupChange() {
5345 delete m_pCurrentStack;
5357bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5358 double latNE,
double lonNE) {
5360 double latc = (latSW + latNE) / 2.0;
5361 double lonc = (lonSW + lonNE) / 2.0;
5364 double ne_easting, ne_northing;
5365 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5367 double sw_easting, sw_northing;
5368 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5370 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5377 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5380bool ChartCanvas::SetVPProjection(
int projection) {
5386 double prev_true_scale_ppm = m_true_scale_ppm;
5391 m_absolute_min_scale_ppm));
5399bool ChartCanvas::SetVPRotation(
double angle) {
5401 VPoint.
skew, angle);
5404 double skew,
double rotation,
int projection,
5405 bool b_adjust,
bool b_refresh) {
5411 if (VPoint.IsValid()) {
5412 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5413 (fabs(VPoint.
skew - skew) < 1e-9) &&
5414 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5415 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5416 (VPoint.m_projection_type == projection ||
5417 projection == PROJECTION_UNKNOWN))
5420 if (VPoint.m_projection_type != projection)
5421 VPoint.InvalidateTransformCache();
5431 if (projection != PROJECTION_UNKNOWN)
5432 VPoint.SetProjectionType(projection);
5433 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5434 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5437 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5438 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5439 if (VPoint.
clat > 89.5)
5441 else if (VPoint.
clat < -89.5)
5442 VPoint.
clat = -89.5;
5447 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5448 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5460 bool bwasValid = VPoint.IsValid();
5465 m_cache_vp.Invalidate();
5470 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5474 if (top_frame::Get()->GetCanvasIndexUnderMouse() == m_canvasIndex) {
5475 int mouseX = mouse_x;
5476 int mouseY = mouse_y;
5477 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5479 double lat_mouse, lon_mouse;
5487 if (!VPoint.b_quilt && m_singleChart) {
5492 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5496 if ((!m_cache_vp.IsValid()) ||
5501 wxPoint cp_last, cp_this;
5505 if (cp_last != cp_this) {
5511 if (m_pCurrentStack) {
5513 int current_db_index;
5515 m_pCurrentStack->GetCurrentEntrydbIndex();
5517 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5519 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5522 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5526 if (VPoint.b_quilt) {
5530 m_pQuilt->InvalidateAllQuiltPatchs();
5534 if (!m_pCurrentStack)
return false;
5536 int current_db_index;
5538 m_pCurrentStack->GetCurrentEntrydbIndex();
5540 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5541 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5544 int current_ref_stack_index = -1;
5545 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5546 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5547 current_ref_stack_index = i;
5550 if (g_bFullScreenQuilt) {
5551 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5555 bool b_needNewRef =
false;
5558 if ((-1 == current_ref_stack_index) &&
5559 (m_pQuilt->GetRefChartdbIndex() >= 0))
5560 b_needNewRef =
true;
5567 bool renderable =
true;
5569 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5570 if (referenceChart) {
5571 double chartMaxScale = referenceChart->GetNormalScaleMax(
5573 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5575 if (!renderable) b_needNewRef =
true;
5578 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5580 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5581 int target_scale = cte_ref.GetScale();
5582 int target_type = cte_ref.GetChartType();
5583 int candidate_stack_index;
5590 candidate_stack_index = 0;
5591 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5593 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5594 int candidate_scale = cte_candidate.GetScale();
5595 int candidate_type = cte_candidate.GetChartType();
5597 if ((candidate_scale >= target_scale) &&
5598 (candidate_type == target_type)) {
5599 bool renderable =
true;
5601 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5602 if (tentative_referenceChart) {
5603 double chartMaxScale =
5604 tentative_referenceChart->GetNormalScaleMax(
5606 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5609 if (renderable)
break;
5612 candidate_stack_index++;
5617 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5618 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5619 while (candidate_stack_index >= 0) {
5620 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5624 int candidate_scale = cte_candidate.GetScale();
5625 int candidate_type = cte_candidate.GetChartType();
5627 if ((candidate_scale <= target_scale) &&
5628 (candidate_type == target_type))
5631 candidate_stack_index--;
5636 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5637 (candidate_stack_index < 0))
5638 candidate_stack_index = 0;
5640 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5642 m_pQuilt->SetReferenceChart(new_ref_index);
5648 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5653 bool renderable =
true;
5655 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5656 if (referenceChart) {
5657 double chartMaxScale = referenceChart->GetNormalScaleMax(
5659 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5660 proj =
ChartData->GetDBChartProj(ref_db_index);
5662 proj = PROJECTION_MERCATOR;
5664 VPoint.b_MercatorProjectionOverride =
5665 (m_pQuilt->GetnCharts() == 0 || !renderable);
5667 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5669 VPoint.SetProjectionType(proj);
5674 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5679 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5699 m_pQuilt->Invalidate();
5716 if (b_refresh) Refresh(
false);
5723 }
else if (!g_bopengl) {
5724 OcpnProjType projection = PROJECTION_UNKNOWN;
5727 projection = m_singleChart->GetChartProjectionType();
5728 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5729 VPoint.SetProjectionType(projection);
5733 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5734 m_cache_vp.Invalidate();
5738 UpdateCanvasControlBar();
5742 if (VPoint.GetBBox().GetValid()) {
5745 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5754 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5757 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5764 wxPoint2DDouble r, r1;
5766 double delta_check =
5770 double check_point = wxMin(89., VPoint.
clat);
5772 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5775 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5776 VPoint.
clon, 0, &rhumbDist);
5781 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5782 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5784 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5788 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5794 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5796 if (m_true_scale_ppm)
5797 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5802 double round_factor = 1000.;
5806 round_factor = 100.;
5808 round_factor = 1000.;
5811 double retina_coef = 1;
5815 retina_coef = GetContentScaleFactor();
5826 double true_scale_display =
5827 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5832 if (m_displayed_scale_factor > 10.0)
5833 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5834 m_displayed_scale_factor);
5835 else if (m_displayed_scale_factor > 1.0)
5836 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5837 m_displayed_scale_factor);
5838 else if (m_displayed_scale_factor > 0.1) {
5839 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5840 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5841 }
else if (m_displayed_scale_factor > 0.01) {
5842 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5843 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5846 "%s %4.0f (---)", _(
"Scale"),
5847 true_scale_display);
5850 m_scaleValue = true_scale_display;
5852 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5854 if (m_bShowScaleInStatusBar && top_frame::Get()->GetStatusBar() &&
5855 (top_frame::Get()->GetStatusBar()->GetFieldsCount() >
5856 STAT_FIELD_SCALE)) {
5858 bool b_noshow =
false;
5862 wxClientDC dc(top_frame::Get()->GetStatusBar());
5864 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5865 dc.SetFont(*templateFont);
5866 dc.GetTextExtent(text, &w, &h);
5871 top_frame::Get()->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE,
5873 if (w && w > rect.width) {
5874 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5878 dc.GetTextExtent(text, &w, &h);
5880 if (w && w > rect.width) {
5886 if (!b_noshow) top_frame::Get()->SetStatusText(text, STAT_FIELD_SCALE);
5891 m_vLat = VPoint.
clat;
5892 m_vLon = VPoint.
clon;
5906static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5910static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5911 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5913wxColour ChartCanvas::PredColor() {
5916 if (SHIP_NORMAL == m_ownship_state)
5917 return GetGlobalColor(
"URED");
5919 else if (SHIP_LOWACCURACY == m_ownship_state)
5920 return GetGlobalColor(
"YELO1");
5922 return GetGlobalColor(
"NODTA");
5925wxColour ChartCanvas::ShipColor() {
5929 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5931 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5933 return GetGlobalColor(
"URED");
5936void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5937 wxPoint2DDouble lShipMidPoint) {
5938 dc.SetPen(wxPen(PredColor(), 2));
5940 if (SHIP_NORMAL == m_ownship_state)
5941 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5943 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5945 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5946 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5948 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5950 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5951 lShipMidPoint.m_y + 12);
5954void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5955 wxPoint GPSOffsetPixels,
5956 wxPoint2DDouble lGPSPoint) {
5961 float ref_dim = m_display_size_mm / 24;
5962 ref_dim = wxMin(ref_dim, 12);
5963 ref_dim = wxMax(ref_dim, 6);
5966 cPred.Set(g_cog_predictor_color);
5967 if (cPred == wxNullColour) cPred = PredColor();
5974 double nominal_line_width_pix = wxMax(
5976 floor(m_pix_per_mm / 2));
5980 if (nominal_line_width_pix > g_cog_predictor_width)
5981 g_cog_predictor_width = nominal_line_width_pix;
5984 wxPoint lPredPoint, lHeadPoint;
5986 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5987 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5989 double pred_lat, pred_lon;
5990 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5991 &pred_lat, &pred_lon);
6002 float ndelta_pix = 10.;
6003 double hdg_pred_lat, hdg_pred_lon;
6004 bool b_render_hdt =
false;
6005 if (!std::isnan(
gHdt)) {
6007 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
6010 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
6011 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
6012 if (dist > ndelta_pix ) {
6013 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
6014 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6019 wxPoint lShipMidPoint;
6020 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6021 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6022 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6023 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6025 if (lpp >= img_height / 2) {
6026 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6027 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6028 !std::isnan(
gSog)) {
6030 float dash_length = ref_dim;
6031 wxDash dash_long[2];
6033 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6034 g_cog_predictor_width);
6035 dash_long[1] = dash_long[0] / 2.0;
6039 if (dash_length > 250.) {
6040 dash_long[0] = 250. / g_cog_predictor_width;
6041 dash_long[1] = dash_long[0] / 2;
6044 wxPen ppPen2(cPred, g_cog_predictor_width,
6045 (wxPenStyle)g_cog_predictor_style);
6046 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6047 ppPen2.SetDashes(2, dash_long);
6050 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6051 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6053 if (g_cog_predictor_width > 1) {
6054 float line_width = g_cog_predictor_width / 3.;
6056 wxDash dash_long3[2];
6057 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6058 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6060 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6061 (wxPenStyle)g_cog_predictor_style);
6062 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6063 ppPen3.SetDashes(2, dash_long3);
6065 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6066 lGPSPoint.m_y + GPSOffsetPixels.y,
6067 lPredPoint.x + GPSOffsetPixels.x,
6068 lPredPoint.y + GPSOffsetPixels.y);
6071 if (g_cog_predictor_endmarker) {
6073 double png_pred_icon_scale_factor = .4;
6074 if (g_ShipScaleFactorExp > 1.0)
6075 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6076 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6080 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6081 (
float)(lPredPoint.x - lShipMidPoint.x));
6082 cog_rad += (float)PI;
6084 for (
int i = 0; i < 4; i++) {
6086 double pxa = (double)(s_png_pred_icon[j]);
6087 double pya = (double)(s_png_pred_icon[j + 1]);
6089 pya *= png_pred_icon_scale_factor;
6090 pxa *= png_pred_icon_scale_factor;
6092 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6093 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6095 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6096 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6100 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6103 dc.SetBrush(wxBrush(cPred));
6105 dc.StrokePolygon(4, icon);
6112 float hdt_dash_length = ref_dim * 0.4;
6114 cPred.Set(g_ownship_HDTpredictor_color);
6115 if (cPred == wxNullColour) cPred = PredColor();
6117 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6118 : g_cog_predictor_width * 0.8);
6119 wxDash dash_short[2];
6121 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6124 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6127 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6128 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6129 ppPen2.SetDashes(2, dash_short);
6133 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6134 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6136 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6138 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6140 if (g_ownship_HDTpredictor_endmarker) {
6141 double nominal_circle_size_pixels = wxMax(
6142 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6145 if (g_ShipScaleFactorExp > 1.0)
6146 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6148 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6149 lHeadPoint.y + GPSOffsetPixels.y,
6150 nominal_circle_size_pixels / 2);
6155 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6156 double factor = 1.00;
6157 if (g_pNavAidRadarRingsStepUnits == 1)
6159 else if (g_pNavAidRadarRingsStepUnits == 2) {
6160 if (std::isnan(
gSog))
6165 factor *= g_fNavAidRadarRingsStep;
6169 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6172 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6173 pow((
double)(lGPSPoint.m_y - r.y), 2));
6174 int pix_radius = (int)lpp;
6176 wxColor rangeringcolour =
6177 user_colors::GetDimColor(g_colourOwnshipRangeRingsColour);
6179 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6182 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6184 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6185 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6190void ChartCanvas::ResetGlGridFont() { GetglCanvas()->ResetGridFont(); }
6191bool ChartCanvas::CanAccelerateGlPanning() {
6192 return GetglCanvas()->CanAcceleratePanning();
6194void ChartCanvas::SetupGlCompression() { GetglCanvas()->SetupCompression(); }
6197void ChartCanvas::ResetGlGridFont() {}
6198bool ChartCanvas::CanAccelerateGlPanning() {
return false; }
6199void ChartCanvas::SetupGlCompression() {}
6202void ChartCanvas::ComputeShipScaleFactor(
6203 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6204 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6205 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6206 float screenResolution = m_pix_per_mm;
6209 double ship_bow_lat, ship_bow_lon;
6210 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6211 &ship_bow_lat, &ship_bow_lon);
6212 wxPoint lShipBowPoint;
6213 wxPoint2DDouble b_point =
6217 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6218 powf((
float)(b_point.m_y - a_point.m_y), 2));
6221 float shipLength_mm = shipLength_px / screenResolution;
6224 float ownship_min_mm = g_n_ownship_min_mm;
6225 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6228 float hdt_ant = icon_hdt + 180.;
6229 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6230 float dx = g_n_gps_antenna_offset_x / 1852.;
6231 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6239 if (shipLength_mm < ownship_min_mm) {
6240 dy /= shipLength_mm / ownship_min_mm;
6241 dx /= shipLength_mm / ownship_min_mm;
6244 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6246 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6247 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6253 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6254 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6256 float scale_factor = shipLength_px / ownShipLength;
6259 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6262 scale_factor = wxMax(scale_factor, scale_factor_min);
6264 scale_factor_y = scale_factor;
6265 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6266 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6269void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6270 if (!GetVP().IsValid())
return;
6272 wxPoint GPSOffsetPixels(0, 0);
6273 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6276 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6277 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6281 lShipMidPoint = lGPSPoint;
6285 float icon_hdt = pCog;
6286 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6289 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6293 double osd_head_lat, osd_head_lon;
6294 wxPoint osd_head_point;
6296 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6301 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6302 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6303 icon_rad += (float)PI;
6305 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6309 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6313 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6314 if (GetVP().chart_scale >
6317 ShipDrawLargeScale(dc, lShipMidPoint);
6323 if (m_pos_image_user)
6324 pos_image = m_pos_image_user->Copy();
6325 else if (SHIP_NORMAL == m_ownship_state)
6326 pos_image = m_pos_image_red->Copy();
6327 if (SHIP_LOWACCURACY == m_ownship_state)
6328 pos_image = m_pos_image_yellow->Copy();
6329 else if (SHIP_NORMAL != m_ownship_state)
6330 pos_image = m_pos_image_grey->Copy();
6333 if (m_pos_image_user) {
6334 pos_image = m_pos_image_user->Copy();
6336 if (SHIP_LOWACCURACY == m_ownship_state)
6337 pos_image = m_pos_image_user_yellow->Copy();
6338 else if (SHIP_NORMAL != m_ownship_state)
6339 pos_image = m_pos_image_user_grey->Copy();
6342 img_height = pos_image.GetHeight();
6344 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6345 g_OwnShipIconType > 0)
6347 int ownShipWidth = 22;
6348 int ownShipLength = 84;
6349 if (g_OwnShipIconType == 1) {
6350 ownShipWidth = pos_image.GetWidth();
6351 ownShipLength = pos_image.GetHeight();
6354 float scale_factor_x, scale_factor_y;
6355 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6356 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6357 scale_factor_x, scale_factor_y);
6359 if (g_OwnShipIconType == 1) {
6360 pos_image.Rescale(ownShipWidth * scale_factor_x,
6361 ownShipLength * scale_factor_y,
6362 wxIMAGE_QUALITY_HIGH);
6363 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6365 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6368 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6369 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6370 if (rot_image.GetAlpha(ip, jp) > 64)
6371 rot_image.SetAlpha(ip, jp, 255);
6373 wxBitmap os_bm(rot_image);
6375 int w = os_bm.GetWidth();
6376 int h = os_bm.GetHeight();
6379 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6380 lShipMidPoint.m_y - h / 2,
true);
6383 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6384 lShipMidPoint.m_y - h / 2);
6385 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6386 lShipMidPoint.m_y - h / 2 + h);
6389 else if (g_OwnShipIconType == 2) {
6390 wxPoint ownship_icon[10];
6392 for (
int i = 0; i < 10; i++) {
6394 float pxa = (float)(s_ownship_icon[j]);
6395 float pya = (float)(s_ownship_icon[j + 1]);
6396 pya *= scale_factor_y;
6397 pxa *= scale_factor_x;
6399 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6400 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6402 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6403 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6406 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6408 dc.SetBrush(wxBrush(ShipColor()));
6410 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6413 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6415 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6419 img_height = ownShipLength * scale_factor_y;
6423 if (m_pos_image_user) circle_rad = 1;
6425 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6426 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6427 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6430 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6432 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6435 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6436 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6437 if (rot_image.GetAlpha(ip, jp) > 64)
6438 rot_image.SetAlpha(ip, jp, 255);
6440 wxBitmap os_bm(rot_image);
6442 if (g_ShipScaleFactorExp > 1) {
6443 wxImage scaled_image = os_bm.ConvertToImage();
6444 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6446 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6447 scaled_image.GetHeight() * factor,
6448 wxIMAGE_QUALITY_HIGH));
6450 int w = os_bm.GetWidth();
6451 int h = os_bm.GetHeight();
6454 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6455 lShipMidPoint.m_y - h / 2,
true);
6459 if (m_pos_image_user) circle_rad = 1;
6461 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6462 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6463 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6466 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6467 lShipMidPoint.m_y - h / 2);
6468 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6469 lShipMidPoint.m_y - h / 2 + h);
6474 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6487void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6488 float &MinorSpacing) {
6493 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6494 {.000001f, 45.0f, 15.0f},
6495 {.0002f, 30.0f, 10.0f},
6496 {.0003f, 10.0f, 2.0f},
6497 {.0008f, 5.0f, 1.0f},
6498 {.001f, 2.0f, 30.0f / 60.0f},
6499 {.003f, 1.0f, 20.0f / 60.0f},
6500 {.006f, 0.5f, 10.0f / 60.0f},
6501 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6502 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6503 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6504 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6505 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6506 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6507 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6508 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6511 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6512 if (view_scale_ppm < lltab[tabi][0])
break;
6513 MajorSpacing = lltab[tabi][1];
6514 MinorSpacing = lltab[tabi][2];
6528wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6529 int deg = (int)fabs(latlon);
6530 float min = fabs((fabs(latlon) - deg) * 60.0);
6540 }
else if (latlon < 0.0) {
6552 if (spacing >= 1.0) {
6553 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6554 }
else if (spacing >= (1.0 / 60.0)) {
6555 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6557 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6574void ChartCanvas::GridDraw(
ocpnDC &dc) {
6575 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6577 double nlat, elon, slat, wlon;
6580 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6582 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6584 if (!m_pgridFont) SetupGridFont();
6585 dc.SetFont(*m_pgridFont);
6586 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6589 h = m_canvas_height;
6600 dlon = dlon + 360.0;
6603 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6606 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6609 while (lat < nlat) {
6612 CalcGridText(lat, gridlatMajor,
true);
6614 dc.
DrawLine(0, r.y, w, r.y,
false);
6615 dc.DrawText(st, 0, r.y);
6616 lat = lat + gridlatMajor;
6618 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6622 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6625 while (lat < nlat) {
6628 dc.
DrawLine(0, r.y, 10, r.y,
false);
6629 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6630 lat = lat + gridlatMinor;
6634 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6637 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6640 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6642 wxString st = CalcGridText(lon, gridlonMajor,
false);
6644 dc.
DrawLine(r.x, 0, r.x, h,
false);
6645 dc.DrawText(st, r.x, 0);
6646 lon = lon + gridlonMajor;
6651 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6655 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6657 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6660 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6661 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6662 lon = lon + gridlonMinor;
6669void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6671 double blat, blon, tlat, tlon;
6674 int x_origin = m_bDisplayGrid ? 60 : 20;
6675 int y_origin = m_canvas_height - 50;
6681 if (GetVP().chart_scale > 80000)
6685 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6686 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6691 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6692 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6696 double rotation = -VPoint.
rotation;
6698 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6700 int l1 = (y_origin - r.y) / count;
6702 for (
int i = 0; i < count; i++) {
6709 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6712 double blat, blon, tlat, tlon;
6719 int y_origin = m_canvas_height - chartbar_height - 5;
6723 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6730 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6735 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6736 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6740 float places = floor(logdist), rem = logdist - places;
6741 dist = pow(10, places);
6748 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6749 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6750 double rotation = -VPoint.
rotation;
6756 int l1 = r.x - x_origin;
6758 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6763 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6764 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6765 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6767 if (!m_pgridFont) SetupGridFont();
6768 dc.SetFont(*m_pgridFont);
6769 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6771 dc.GetTextExtent(s, &w, &h);
6777 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6781void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6786 double ra_max = 40.;
6788 wxPen pen_save = dc.GetPen();
6790 wxDateTime now = wxDateTime::Now();
6796 x0 = x1 = x + radius;
6801 while (angle < 360.) {
6802 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6805 if (angle > 360.) angle = 360.;
6807 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6815 x1 = (int)(x + cos(angle * PI / 180.) * r);
6816 y1 = (int)(y + sin(angle * PI / 180.) * r);
6826 dc.
DrawLine(x + radius, y, x1, y1);
6828 dc.SetPen(pen_save);
6831static bool bAnchorSoundPlaying =
false;
6833static void onAnchorSoundFinished(
void *ptr) {
6834 o_sound::g_anchorwatch_sound->UnLoad();
6835 bAnchorSoundPlaying =
false;
6838void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6839 using namespace o_sound;
6841 bool play_sound =
false;
6843 if (AnchorAlertOn1) {
6844 wxPoint TargetPoint;
6847 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6848 TargetPoint.y, 100);
6852 AnchorAlertOn1 =
false;
6855 if (AnchorAlertOn2) {
6856 wxPoint TargetPoint;
6859 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6860 TargetPoint.y, 100);
6864 AnchorAlertOn2 =
false;
6867 if (!bAnchorSoundPlaying) {
6868 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6869 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6870 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6871 if (g_anchorwatch_sound->IsOk()) {
6872 bAnchorSoundPlaying =
true;
6873 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6874 g_anchorwatch_sound->Play();
6880void ChartCanvas::UpdateShips() {
6883 wxClientDC dc(
this);
6884 if (!dc.IsOk())
return;
6886 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6887 if (!test_bitmap.IsOk())
return;
6889 wxMemoryDC temp_dc(test_bitmap);
6891 temp_dc.ResetBoundingBox();
6892 temp_dc.DestroyClippingRegion();
6893 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6904 ocpndc.CalcBoundingBox(px.x, px.y);
6909 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6910 temp_dc.MaxY() - temp_dc.MinY());
6912 wxRect own_ship_update_rect = ship_draw_rect;
6914 if (!own_ship_update_rect.IsEmpty()) {
6917 own_ship_update_rect.Union(ship_draw_last_rect);
6918 own_ship_update_rect.Inflate(2);
6921 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6923 ship_draw_last_rect = ship_draw_rect;
6925 temp_dc.SelectObject(wxNullBitmap);
6928void ChartCanvas::UpdateAlerts() {
6933 wxClientDC dc(
this);
6937 dc.GetSize(&sx, &sy);
6940 wxBitmap test_bitmap(sx, sy, -1);
6944 temp_dc.SelectObject(test_bitmap);
6946 temp_dc.ResetBoundingBox();
6947 temp_dc.DestroyClippingRegion();
6948 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6955 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6956 temp_dc.MaxX() - temp_dc.MinX(),
6957 temp_dc.MaxY() - temp_dc.MinY());
6959 if (!alert_rect.IsEmpty())
6960 alert_rect.Inflate(2);
6962 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6965 wxRect alert_update_rect = alert_draw_rect;
6966 alert_update_rect.Union(alert_rect);
6969 RefreshRect(alert_update_rect,
false);
6973 alert_draw_rect = alert_rect;
6975 temp_dc.SelectObject(wxNullBitmap);
6978void ChartCanvas::UpdateAIS() {
6984 wxClientDC dc(
this);
6988 dc.GetSize(&sx, &sy);
6996 if (
g_pAIS->GetTargetList().size() > 10) {
6997 ais_rect = wxRect(0, 0, sx, sy);
7000 wxBitmap test_bitmap(sx, sy, -1);
7004 temp_dc.SelectObject(test_bitmap);
7006 temp_dc.ResetBoundingBox();
7007 temp_dc.DestroyClippingRegion();
7008 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
7012 AISDraw(ocpndc, GetVP(),
this);
7013 AISDrawAreaNotices(ocpndc, GetVP(),
this);
7017 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
7018 temp_dc.MaxY() - temp_dc.MinY());
7020 if (!ais_rect.IsEmpty())
7021 ais_rect.Inflate(2);
7023 temp_dc.SelectObject(wxNullBitmap);
7026 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7029 wxRect ais_update_rect = ais_draw_rect;
7030 ais_update_rect.Union(ais_rect);
7033 RefreshRect(ais_update_rect,
false);
7037 ais_draw_rect = ais_rect;
7040void ChartCanvas::ToggleCPAWarn() {
7041 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7047 g_bTCPA_Max =
false;
7051 if (STAT_FIELD_SCALE >= 4 && top_frame::Get()->GetStatusBar()) {
7052 top_frame::Get()->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7054 if (!g_AisFirstTimeUse) {
7055 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7056 _(
"CPA") +
" " + mess, 4, 4);
7061void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7063void ChartCanvas::OnSize(wxSizeEvent &event) {
7064 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7066 GetClientSize(&m_canvas_width, &m_canvas_height);
7070 m_displayScale = GetContentScaleFactor();
7074 m_canvas_width *= m_displayScale;
7075 m_canvas_height *= m_displayScale;
7088 m_absolute_min_scale_ppm =
7090 (1.2 * WGS84_semimajor_axis_meters * PI);
7093 top_frame::Get()->ProcessCanvasResize();
7103 SetMUIBarPosition();
7104 UpdateFollowButtonState();
7105 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7109 xr_margin = m_canvas_width * 95 / 100;
7110 xl_margin = m_canvas_width * 5 / 100;
7111 yt_margin = m_canvas_height * 5 / 100;
7112 yb_margin = m_canvas_height * 95 / 100;
7115 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7120 m_brepaint_piano =
true;
7123 m_dc_route.SelectObject(wxNullBitmap);
7126 m_dc_route.SelectObject(*proute_bm);
7140 m_glcc->OnSize(event);
7149void ChartCanvas::ProcessNewGUIScale() {
7157void ChartCanvas::CreateMUIBar() {
7158 if (g_useMUI && !m_muiBar) {
7159 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7160 m_muiBar->SetColorScheme(m_cs);
7161 m_muiBarHOSize = m_muiBar->m_size;
7169 SetMUIBarPosition();
7170 UpdateFollowButtonState();
7171 m_muiBar->UpdateDynamicValues();
7172 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7176void ChartCanvas::SetMUIBarPosition() {
7180 int pianoWidth = GetClientSize().x * 0.6f;
7185 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7186 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7188 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7189 m_muiBar->SetColorScheme(m_cs);
7193 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7194 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7196 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7197 m_muiBar->SetColorScheme(m_cs);
7201 m_muiBar->SetBestPosition();
7205void ChartCanvas::DestroyMuiBar() {
7212void ChartCanvas::ShowCompositeInfoWindow(
7213 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7215 if (NULL == m_pCIWin) {
7220 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7223 s = _(
"Composite of ");
7226 s1.Printf(
"%d ", n_charts);
7234 s1.Printf(_(
"Chart scale"));
7237 s2.Printf(
"1:%d\n",
scale);
7241 s1 = _(
"Zoom in for more information");
7245 int char_width = s1.Length();
7246 int char_height = 3;
7248 if (g_bChartBarEx) {
7251 for (
int i : index_vector) {
7253 wxString path = cte.GetFullSystemPath();
7257 char_width = wxMax(char_width, path.Length());
7258 if (j++ >= 9)
break;
7261 s +=
" .\n .\n .\n";
7270 m_pCIWin->SetString(s);
7272 m_pCIWin->FitToChars(char_width, char_height);
7275 p.x = x / GetContentScaleFactor();
7276 if ((p.x + m_pCIWin->GetWinSize().x) >
7277 (m_canvas_width / GetContentScaleFactor()))
7278 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7279 m_pCIWin->GetWinSize().x) /
7282 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7283 4 - m_pCIWin->GetWinSize().y;
7285 m_pCIWin->dbIndex = 0;
7286 m_pCIWin->chart_scale = 0;
7287 m_pCIWin->SetPosition(p);
7288 m_pCIWin->SetBitmap();
7289 m_pCIWin->Refresh();
7293 HideChartInfoWindow();
7297void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7299 if (NULL == m_pCIWin) {
7304 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7313 dbIndex, FULL_INIT);
7315 int char_width, char_height;
7316 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7317 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7319 m_pCIWin->SetString(s);
7320 m_pCIWin->FitToChars(char_width, char_height);
7323 p.x = x / GetContentScaleFactor();
7324 if ((p.x + m_pCIWin->GetWinSize().x) >
7325 (m_canvas_width / GetContentScaleFactor()))
7326 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7327 m_pCIWin->GetWinSize().x) /
7330 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7331 4 - m_pCIWin->GetWinSize().y;
7333 m_pCIWin->dbIndex = dbIndex;
7334 m_pCIWin->SetPosition(p);
7335 m_pCIWin->SetBitmap();
7336 m_pCIWin->Refresh();
7340 HideChartInfoWindow();
7344void ChartCanvas::HideChartInfoWindow() {
7347 m_pCIWin->Destroy();
7351 androidForceFullRepaint();
7356void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7357 wxMouseEvent ev(wxEVT_MOTION);
7360 ev.m_leftDown = mouse_leftisdown;
7362 wxEvtHandler *evthp = GetEventHandler();
7364 ::wxPostEvent(evthp, ev);
7367void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7368 if ((m_panx_target_final - m_panx_target_now) ||
7369 (m_pany_target_final - m_pany_target_now)) {
7370 DoTimedMovementTarget();
7375void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7377bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7379 if (m_disable_edge_pan)
return false;
7382 int pan_margin = m_canvas_width * margin / 100;
7383 int pan_timer_set = 200;
7384 double pan_delta = GetVP().
pix_width * delta / 100;
7388 if (x > m_canvas_width - pan_margin) {
7393 else if (x < pan_margin) {
7398 if (y < pan_margin) {
7403 else if (y > m_canvas_height - pan_margin) {
7412 wxMouseState state = ::wxGetMouseState();
7413#if wxCHECK_VERSION(3, 0, 0)
7414 if (!state.LeftIsDown())
7416 if (!state.LeftDown())
7421 if ((bft) && !pPanTimer->IsRunning()) {
7423 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7429 if ((!bft) && pPanTimer->IsRunning()) {
7439void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7440 bool setBeingEdited) {
7441 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7442 m_pRoutePointEditTarget = NULL;
7443 m_pFoundPoint = NULL;
7446 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7447 SelectableItemList SelList =
pSelect->FindSelectionList(
7457 bool brp_viz =
false;
7458 if (m_pEditRouteArray) {
7459 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7460 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7461 if (pr->IsVisible()) {
7467 brp_viz = frp->IsVisible();
7471 if (m_pEditRouteArray)
7473 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7474 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7477 m_bRouteEditing = setBeingEdited;
7480 frp->m_bRPIsBeingEdited = setBeingEdited;
7481 m_bMarkEditing = setBeingEdited;
7484 m_pRoutePointEditTarget = frp;
7485 m_pFoundPoint = pFind;
7490std::shared_ptr<HostApi121::PiPointContext>
7491ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7505 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7506 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7507 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7508 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7509 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7513 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7516 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7521 int FoundAIS_MMSI = 0;
7523 FoundAIS_MMSI = pFindAIS->GetUserData();
7526 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7527 seltype |= SELTYPE_AISTARGET;
7533 Route *SelectedRoute = NULL;
7539 Route *pSelectedActiveRoute = NULL;
7540 Route *pSelectedVizRoute = NULL;
7543 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7544 SelectableItemList SelList =
7545 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7553 bool brp_viz =
false;
7555 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7557 if (pr->IsVisible()) {
7562 if (!brp_viz && prp->IsShared())
7564 brp_viz = prp->IsVisible();
7567 brp_viz = prp->IsVisible();
7569 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7575 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7578 pSelectedActiveRoute = pr;
7579 pFoundActiveRoutePoint = prp;
7584 if (NULL == pSelectedVizRoute) {
7585 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7587 if (pr->IsVisible()) {
7588 pSelectedVizRoute = pr;
7589 pFoundVizRoutePoint = prp;
7595 delete proute_array;
7600 if (pFoundActiveRoutePoint) {
7601 FoundRoutePoint = pFoundActiveRoutePoint;
7602 SelectedRoute = pSelectedActiveRoute;
7603 }
else if (pFoundVizRoutePoint) {
7604 FoundRoutePoint = pFoundVizRoutePoint;
7605 SelectedRoute = pSelectedVizRoute;
7608 FoundRoutePoint = pFirstVizPoint;
7610 if (SelectedRoute) {
7611 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7612 }
else if (FoundRoutePoint) {
7613 seltype |= SELTYPE_MARKPOINT;
7618 if (m_pFoundRoutePoint) {
7622 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7623 RefreshRect(wp_rect,
true);
7632 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7633 SelectableItemList SelList =
7634 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7636 if (NULL == SelectedRoute)
7641 if (pr->IsVisible()) {
7648 if (SelectedRoute) {
7649 if (NULL == FoundRoutePoint)
7650 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7653 seltype |= SELTYPE_ROUTESEGMENT;
7657 if (pFindTrackSeg) {
7658 m_pSelectedTrack = NULL;
7659 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7660 SelectableItemList SelList =
7661 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7666 if (pt->IsVisible()) {
7667 m_pSelectedTrack = pt;
7671 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7674 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7677 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7678 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7679 rstruct->object_ident =
"";
7681 if (seltype == SELTYPE_AISTARGET) {
7682 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7684 val.Printf(
"%d", FoundAIS_MMSI);
7685 rstruct->object_ident = val.ToStdString();
7686 }
else if (seltype & SELTYPE_MARKPOINT) {
7687 if (FoundRoutePoint) {
7688 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7689 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7691 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7692 if (SelectedRoute) {
7693 rstruct->object_type =
7694 HostApi121::PiContextObjectType::kObjectRoutesegment;
7695 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7697 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7698 if (m_pSelectedTrack) {
7699 rstruct->object_type =
7700 HostApi121::PiContextObjectType::kObjectTracksegment;
7701 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7708void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7709 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7710 singleClickEventIsValid =
false;
7711 m_DoubleClickTimer->Stop();
7716bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7717 if (!m_bChartDragging && !m_bDrawingRoute) {
7722 if (m_Compass && m_Compass->IsShown()) {
7724 bool isInCompass = logicalRect.Contains(event.GetPosition());
7725 if (isInCompass || m_mouseWasInCompass) {
7726 if (m_Compass->MouseEvent(event)) {
7727 cursor_region = CENTER;
7728 if (!g_btouch) SetCanvasCursor(event);
7729 m_mouseWasInCompass = isInCompass;
7733 m_mouseWasInCompass = isInCompass;
7736 if (m_notification_button && m_notification_button->IsShown()) {
7738 bool isinButton = logicalRect.Contains(event.GetPosition());
7740 SetCursor(*pCursorArrow);
7741 if (event.LeftDown()) HandleNotificationMouseClick();
7746 if (MouseEventToolbar(event))
return true;
7748 if (MouseEventChartBar(event))
return true;
7750 if (MouseEventMUIBar(event))
return true;
7752 if (MouseEventIENCBar(event))
return true;
7757void ChartCanvas::HandleNotificationMouseClick() {
7758 if (!m_NotificationsList) {
7762 m_NotificationsList->RecalculateSize();
7763 m_NotificationsList->Hide();
7766 if (m_NotificationsList->IsShown()) {
7767 m_NotificationsList->Hide();
7769 m_NotificationsList->RecalculateSize();
7770 m_NotificationsList->ReloadNotificationList();
7771 m_NotificationsList->Show();
7774bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7775 if (!g_bShowChartBar)
return false;
7777 if (!m_Piano->MouseEvent(event))
return false;
7779 cursor_region = CENTER;
7780 if (!g_btouch) SetCanvasCursor(event);
7784bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7785 if (!IsPrimaryCanvas())
return false;
7794 cursor_region = CENTER;
7795 if (!g_btouch) SetCanvasCursor(event);
7799bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7800 if (!IsPrimaryCanvas())
return false;
7813bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7815 if (!m_muiBar->MouseEvent(event))
return false;
7818 cursor_region = CENTER;
7819 if (!g_btouch) SetCanvasCursor(event);
7831 event.GetPosition(&x, &y);
7833 x *= m_displayScale;
7834 y *= m_displayScale;
7836 m_MouseDragging =
event.Dragging();
7842 if (event.Dragging()) {
7843 if ((x == mouse_x) && (y == mouse_y))
return true;
7849 mouse_leftisdown =
event.LeftDown();
7853 cursor_region = CENTER;
7857 if (m_Compass && m_Compass->IsShown() &&
7858 m_Compass->
GetRect().Contains(event.GetPosition())) {
7859 cursor_region = CENTER;
7860 }
else if (x > xr_margin) {
7861 cursor_region = MID_RIGHT;
7862 }
else if (x < xl_margin) {
7863 cursor_region = MID_LEFT;
7864 }
else if (y > yb_margin - chartbar_height &&
7865 y < m_canvas_height - chartbar_height) {
7866 cursor_region = MID_TOP;
7867 }
else if (y < yt_margin) {
7868 cursor_region = MID_BOT;
7870 cursor_region = CENTER;
7873 if (!g_btouch) SetCanvasCursor(event);
7877 leftIsDown =
event.LeftDown();
7880 if (event.LeftDown()) {
7881 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7884 g_bTempShowMenuBar =
false;
7885 top_frame::Get()->ApplyGlobalSettings(
false);
7893 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7894 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7898 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7899 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7902 event.SetEventObject(
this);
7903 if (SendMouseEventToPlugins(event))
7910 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7911 StartChartDragInertia();
7914 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7915 !singleClickEventIsValid) {
7917 if (m_DoubleClickTimer->IsRunning()) {
7918 m_DoubleClickTimer->Stop();
7923 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7924 singleClickEvent = event;
7925 singleClickEventIsValid =
true;
7934 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7935 if (g_click_stop > 0) {
7943 if (GetUpMode() == COURSE_UP_MODE) {
7944 m_b_rot_hidef =
false;
7945 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7947 pRotDefTimer->Stop();
7950 bool bRoll = !g_btouch;
7955 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7956 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7957 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7958 m_RolloverPopupTimer.Start(
7962 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7966 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7975#if !defined(__WXGTK__) && !defined(__WXQT__)
7983 if ((x >= 0) && (y >= 0))
7988 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7989 wxPoint p = ClientToScreen(wxPoint(x, y));
7995 if (m_routeState >= 2) {
7998 m_bDrawingRoute =
true;
8000 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8005 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
8008 m_bDrawingRoute =
true;
8010 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8023#if defined(__WXMAC__) || defined(__ANDROID__)
8027 wxClientDC cdc(GetParent());
8039 if (m_pSelectedRoute) {
8041 m_pSelectedRoute->DeSelectRoute();
8043 if (g_bopengl && m_glcc) {
8048 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8051 if (m_pFoundRoutePoint) {
8059 if (g_btouch && m_pRoutePointEditTarget) {
8062 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8066 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8067 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8068 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8069 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8070 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8074 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8077 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8083 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8086 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8087 seltype |= SELTYPE_AISTARGET;
8092 m_pFoundRoutePoint = NULL;
8097 Route *pSelectedActiveRoute = NULL;
8098 Route *pSelectedVizRoute = NULL;
8101 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8102 SelectableItemList SelList =
8103 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8111 bool brp_viz =
false;
8113 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8115 if (pr->IsVisible()) {
8120 if (!brp_viz && prp->IsShared())
8122 brp_viz = prp->IsVisible();
8125 brp_viz = prp->IsVisible();
8127 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8132 m_pSelectedRoute = NULL;
8134 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8137 pSelectedActiveRoute = pr;
8138 pFoundActiveRoutePoint = prp;
8143 if (NULL == pSelectedVizRoute) {
8144 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8146 if (pr->IsVisible()) {
8147 pSelectedVizRoute = pr;
8148 pFoundVizRoutePoint = prp;
8154 delete proute_array;
8159 if (pFoundActiveRoutePoint) {
8160 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8161 m_pSelectedRoute = pSelectedActiveRoute;
8162 }
else if (pFoundVizRoutePoint) {
8163 m_pFoundRoutePoint = pFoundVizRoutePoint;
8164 m_pSelectedRoute = pSelectedVizRoute;
8167 m_pFoundRoutePoint = pFirstVizPoint;
8169 if (m_pSelectedRoute) {
8170 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8171 }
else if (m_pFoundRoutePoint) {
8172 seltype |= SELTYPE_MARKPOINT;
8176 if (m_pFoundRoutePoint) {
8180 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8181 RefreshRect(wp_rect,
true);
8189 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8190 SelectableItemList SelList =
8191 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8193 if (NULL == m_pSelectedRoute)
8198 if (pr->IsVisible()) {
8199 m_pSelectedRoute = pr;
8205 if (m_pSelectedRoute) {
8206 if (NULL == m_pFoundRoutePoint)
8207 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8212 if (g_bopengl && m_glcc) {
8217 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8219 seltype |= SELTYPE_ROUTESEGMENT;
8223 if (pFindTrackSeg) {
8224 m_pSelectedTrack = NULL;
8225 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8226 SelectableItemList SelList =
8227 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8232 if (pt->IsVisible()) {
8233 m_pSelectedTrack = pt;
8237 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8243 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8244 seltype |= SELTYPE_CURRENTPOINT;
8247 else if (pFindTide) {
8248 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8249 seltype |= SELTYPE_TIDEPOINT;
8254 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8259IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8269 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8270 SelectableItemList SelList =
8271 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8274 pFind = *SelList.begin();
8275 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8277 auto node = SelList.begin();
8278 if (SelList.size() > 1) {
8279 for (++node; node != SelList.end(); ++node) {
8282 if (pIDX_candidate->
IDX_type ==
'c') {
8283 pIDX_best_candidate = pIDX_candidate;
8288 pFind = *SelList.begin();
8289 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8292 return pIDX_best_candidate;
8294void ChartCanvas::CallPopupMenu(
int x,
int y) {
8298 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8306 if (SELTYPE_CURRENTPOINT == seltype) {
8312 if (SELTYPE_TIDEPOINT == seltype) {
8318 InvokeCanvasMenu(x, y, seltype);
8321 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8325 m_pSelectedRoute = NULL;
8327 if (m_pFoundRoutePoint) {
8328 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8331 m_pFoundRoutePoint = NULL;
8337bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8345 event.GetPosition(&x, &y);
8351 SelectRadius = g_Platform->GetSelectRadiusPix() /
8352 (m_true_scale_ppm * 1852 * 60);
8359 if (event.LeftDClick() && (cursor_region == CENTER)) {
8360 m_DoubleClickTimer->Start();
8361 singleClickEventIsValid =
false;
8367 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8370 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8373 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8374 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8375 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8381 SelectableItemList rpSelList =
8382 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8383 bool b_onRPtarget =
false;
8386 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8387 b_onRPtarget =
true;
8395 std::unique_ptr<HostApi> host_api =
GetHostApi();
8396 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8398 if (m_pRoutePointEditTarget) {
8400 if ((api_121->GetContextMenuMask() &
8401 api_121->kContextMenuDisableWaypoint))
8403 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8409 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8412 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8413 m_pRoutePointEditTarget = NULL;
8414 RefreshRect(wp_rect,
true);
8418 auto node = rpSelList.begin();
8419 if (node != rpSelList.end()) {
8423 wxArrayPtrVoid *proute_array =
8428 bool brp_viz =
false;
8430 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8432 if (pr->IsVisible()) {
8437 delete proute_array;
8441 brp_viz = frp->IsVisible();
8443 brp_viz = frp->IsVisible();
8446 if ((api_121->GetContextMenuMask() &
8447 api_121->kContextMenuDisableWaypoint))
8450 ShowMarkPropertiesDialog(frp);
8459 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8461 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8464 if (pr->IsVisible()) {
8465 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8470 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8472 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8475 if (pt->IsVisible()) {
8476 ShowTrackPropertiesDialog(pt);
8485 if (m_bShowCurrent) {
8487 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8489 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8491 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8492 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8494 if (pic->m_enabled && pic->m_init_state &&
8495 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8498 if (m_pIDXCandidate) {
8499 info.point_type = CURRENT_STATION;
8503 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8504 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8508 if (plugin) plugin->OnTideCurrentClick(info);
8523 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8525 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8527 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8528 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8530 if (pic->m_enabled && pic->m_init_state &&
8531 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8534 if (m_pIDXCandidate) {
8535 info.point_type = TIDE_STATION;
8539 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8540 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8544 if (plugin) plugin->OnTideCurrentClick(info);
8559 ShowObjectQueryWindow(x, y, zlat, zlon);
8564 if (event.LeftDown()) {
8580 bool appending =
false;
8581 bool inserting =
false;
8584 SetCursor(*pCursorPencil);
8588 m_bRouteEditing =
true;
8590 if (m_routeState == 1) {
8591 m_pMouseRoute =
new Route();
8592 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8602 double nearby_radius_meters =
8603 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8606 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8607 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8608 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8609 wxArrayPtrVoid *proute_array =
8614 bool brp_viz =
false;
8616 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8618 if (pr->IsVisible()) {
8623 delete proute_array;
8625 pNearbyPoint->IsShared())
8628 pNearbyPoint->IsVisible();
8630 brp_viz = pNearbyPoint->IsVisible();
8633 wxString msg = _(
"Use nearby waypoint?");
8635 const bool noname(pNearbyPoint->GetName() ==
"");
8638 _(
"Use nearby nameless waypoint and name it M with"
8639 " a unique number?");
8642 m_FinishRouteOnKillFocus =
false;
8644 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8645 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8646 m_FinishRouteOnKillFocus =
true;
8647 if (dlg_return == wxID_YES) {
8649 if (m_pMouseRoute) {
8650 int last_wp_num = m_pMouseRoute->GetnPoints();
8652 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8653 wxString wp_name = wxString::Format(
8654 "M%002i-%s", last_wp_num + 1, guid_short);
8655 pNearbyPoint->SetName(wp_name);
8657 pNearbyPoint->SetName(
"WPXX");
8659 pMousePoint = pNearbyPoint;
8662 if (m_routeState > 1)
8663 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8664 Undo_HasParent, NULL);
8667 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8668 bool procede =
false;
8672 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8678 m_FinishRouteOnKillFocus =
false;
8684 _(
"Insert first part of this route in the new route?");
8685 if (tail->GetIndexOf(pMousePoint) ==
8688 dmsg = _(
"Insert this route in the new route?");
8690 if (tail->GetIndexOf(pMousePoint) > 0) {
8691 dlg_return = OCPNMessageBox(
8692 this, dmsg, _(
"OpenCPN Route Create"),
8693 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8694 m_FinishRouteOnKillFocus =
true;
8696 if (dlg_return == wxID_YES) {
8703 _(
"Append last part of this route to the new route?");
8704 if (tail->GetIndexOf(pMousePoint) == 1)
8706 "Append this route to the new route?");
8711 if (tail->GetLastPoint() != pMousePoint) {
8712 dlg_return = OCPNMessageBox(
8713 this, dmsg, _(
"OpenCPN Route Create"),
8714 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8715 m_FinishRouteOnKillFocus =
true;
8717 if (dlg_return == wxID_YES) {
8728 if (!FindRouteContainingWaypoint(pMousePoint))
8729 pMousePoint->SetShared(
true);
8734 if (NULL == pMousePoint) {
8735 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8737 pMousePoint->SetNameShown(
false);
8741 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8743 if (m_routeState > 1)
8744 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8745 Undo_IsOrphanded, NULL);
8748 if (m_pMouseRoute) {
8749 if (m_routeState == 1) {
8751 m_pMouseRoute->AddPoint(pMousePoint);
8754 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8755 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8756 &rhumbBearing, &rhumbDist);
8757 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8758 rlat, &gcDist, &gcBearing, NULL);
8759 double gcDistNM = gcDist / 1852.0;
8762 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8763 pow(rhumbDist - gcDistNM - 1, 0.5);
8766 msg << _(
"For this leg the Great Circle route is ")
8768 << _(
" shorter than rhumbline.\n\n")
8769 << _(
"Would you like include the Great Circle routing points "
8772 m_FinishRouteOnKillFocus =
false;
8773 m_disable_edge_pan =
true;
8776 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8777 wxYES_NO | wxNO_DEFAULT);
8779 m_disable_edge_pan =
false;
8780 m_FinishRouteOnKillFocus =
true;
8782 if (answer == wxID_YES) {
8784 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8785 wxRealPoint gcCoord;
8787 for (
int i = 1; i <= segmentCount; i++) {
8788 double fraction = (double)i * (1.0 / (
double)segmentCount);
8789 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8790 gcDist * fraction, gcBearing,
8791 &gcCoord.x, &gcCoord.y, NULL);
8793 if (i < segmentCount) {
8794 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8796 gcPoint->SetNameShown(
false);
8798 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8800 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8803 gcPoint = pMousePoint;
8806 m_pMouseRoute->AddPoint(gcPoint);
8807 pSelect->AddSelectableRouteSegment(
8808 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8809 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8810 prevGcPoint = gcPoint;
8813 undo->CancelUndoableAction(
true);
8816 m_pMouseRoute->AddPoint(pMousePoint);
8817 pSelect->AddSelectableRouteSegment(
8818 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8819 pMousePoint, m_pMouseRoute);
8820 undo->AfterUndoableAction(m_pMouseRoute);
8824 m_pMouseRoute->AddPoint(pMousePoint);
8825 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8826 rlon, m_prev_pMousePoint,
8827 pMousePoint, m_pMouseRoute);
8828 undo->AfterUndoableAction(m_pMouseRoute);
8834 m_prev_pMousePoint = pMousePoint;
8842 int connect = tail->GetIndexOf(pMousePoint);
8847 int length = tail->GetnPoints();
8852 start = connect + 1;
8858 m_pMouseRoute->RemovePoint(m_pMouseRoute->GetLastPoint());
8860 for (i = start; i <= stop; i++) {
8861 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8864 m_pMouseRoute->GetnPoints();
8866 top_frame::Get()->RefreshAllCanvas();
8870 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8872 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8873 m_pMouseRoute->FinalizeForRendering();
8875 top_frame::Get()->RefreshAllCanvas();
8879 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8881 SetCursor(*pCursorPencil);
8883 if (!m_pMeasureRoute) {
8884 m_pMeasureRoute =
new Route();
8888 if (m_nMeasureState == 1) {
8895 wxEmptyString, wxEmptyString);
8897 pMousePoint->SetShowWaypointRangeRings(
false);
8899 m_pMeasureRoute->AddPoint(pMousePoint);
8903 m_prev_pMousePoint = pMousePoint;
8907 top_frame::Get()->RefreshAllCanvas();
8912 FindRoutePointsAtCursor(SelectRadius,
true);
8916 m_last_touch_down_pos =
event.GetPosition();
8918 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8926 if (ret)
return true;
8929 if (event.Dragging()) {
8932 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8934 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8936 SelectableItemList SelList =
pSelect->FindSelectionList(
8940 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8945 if (m_pRoutePointEditTarget &&
8946 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8948 SelectableItemList SelList =
pSelect->FindSelectionList(
8952 if (m_pRoutePointEditTarget == frp) {
8953 m_bIsInRadius =
true;
8958 if (!m_dragoffsetSet) {
8960 .PresetDragOffset(
this, mouse_x, mouse_y);
8961 m_dragoffsetSet =
true;
8966 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8967 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8970 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8972 DraggingAllowed =
false;
8974 if (m_pRoutePointEditTarget &&
8975 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8976 DraggingAllowed =
false;
8978 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8980 if (DraggingAllowed) {
8981 if (!undo->InUndoableAction()) {
8982 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8983 Undo_NeedsCopy, m_pFoundPoint);
8989 if (!g_bopengl && m_pEditRouteArray) {
8990 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8991 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8998 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8999 pre_rect.Union(route_rect);
9007 if (CheckEdgePan(x, y,
true, 5, 2))
9015 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9017 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9018 m_pRoutePointEditTarget,
9019 SELTYPE_DRAGHANDLE);
9020 m_pFoundPoint->m_slat =
9021 m_pRoutePointEditTarget->m_lat;
9022 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9024 m_pRoutePointEditTarget->m_lat =
9026 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9027 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9028 m_pFoundPoint->m_slat =
9030 m_pFoundPoint->m_slon = new_cursor_lon;
9046 if (m_pEditRouteArray) {
9047 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9049 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9052 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9053 post_rect.Union(route_rect);
9059 pre_rect.Union(post_rect);
9060 RefreshRect(pre_rect,
false);
9062 top_frame::Get()->RefreshCanvasOther(
this);
9063 m_bRoutePoinDragging =
true;
9068 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9069 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9072 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9074 DraggingAllowed =
false;
9076 if (m_pRoutePointEditTarget &&
9077 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9078 DraggingAllowed =
false;
9080 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9082 if (DraggingAllowed) {
9083 if (!undo->InUndoableAction()) {
9084 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9085 Undo_NeedsCopy, m_pFoundPoint);
9099 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9105 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9106 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9107 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9108 (
int)(lppmax - (pre_rect.height / 2)));
9116 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9119 m_pRoutePointEditTarget,
9120 SELTYPE_DRAGHANDLE);
9121 m_pFoundPoint->m_slat =
9122 m_pRoutePointEditTarget->m_lat;
9123 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9125 m_pRoutePointEditTarget->m_lat =
9128 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9141 if (!g_btouch) InvalidateGL();
9147 .CalculateDCRect(m_dc_route,
this, &post_rect);
9148 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9149 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9150 (
int)(lppmax - (post_rect.height / 2)));
9153 pre_rect.Union(post_rect);
9154 RefreshRect(pre_rect,
false);
9156 top_frame::Get()->RefreshCanvasOther(
this);
9157 m_bRoutePoinDragging =
true;
9159 ret = g_btouch ? m_bRoutePoinDragging :
true;
9162 if (ret)
return true;
9165 if (event.LeftUp()) {
9166 bool b_startedit_route =
false;
9167 m_dragoffsetSet =
false;
9170 m_bChartDragging =
false;
9171 m_bIsInRadius =
false;
9175 if (m_ignore_next_leftup) {
9176 m_ignore_next_leftup =
false;
9181 m_bedge_pan =
false;
9186 bool appending =
false;
9187 bool inserting =
false;
9193 if (m_pRoutePointEditTarget) {
9199 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9200 RefreshRect(wp_rect,
true);
9202 m_pRoutePointEditTarget = NULL;
9204 m_bRouteEditing =
true;
9206 if (m_routeState == 1) {
9207 m_pMouseRoute =
new Route();
9208 m_pMouseRoute->SetHiLite(50);
9212 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9219 double nearby_radius_meters =
9220 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9223 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9224 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9225 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9228 m_FinishRouteOnKillFocus =
9230 dlg_return = OCPNMessageBox(
9231 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9232 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9233 m_FinishRouteOnKillFocus =
true;
9235 dlg_return = wxID_YES;
9237 if (dlg_return == wxID_YES) {
9238 pMousePoint = pNearbyPoint;
9241 if (m_routeState > 1)
9242 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9243 Undo_HasParent, NULL);
9244 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9246 bool procede =
false;
9250 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9256 m_FinishRouteOnKillFocus =
false;
9257 if (m_routeState == 1) {
9261 _(
"Insert first part of this route in the new route?");
9262 if (tail->GetIndexOf(pMousePoint) ==
9265 dmsg = _(
"Insert this route in the new route?");
9267 if (tail->GetIndexOf(pMousePoint) != 1) {
9269 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9270 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9271 m_FinishRouteOnKillFocus =
true;
9273 if (dlg_return == wxID_YES) {
9280 _(
"Append last part of this route to the new route?");
9281 if (tail->GetIndexOf(pMousePoint) == 1)
9283 "Append this route to the new route?");
9287 if (tail->GetLastPoint() != pMousePoint) {
9289 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9290 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9291 m_FinishRouteOnKillFocus =
true;
9293 if (dlg_return == wxID_YES) {
9304 if (!FindRouteContainingWaypoint(pMousePoint))
9305 pMousePoint->SetShared(
true);
9309 if (NULL == pMousePoint) {
9310 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9312 pMousePoint->SetNameShown(
false);
9314 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9316 if (m_routeState > 1)
9317 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9318 Undo_IsOrphanded, NULL);
9321 if (m_routeState == 1) {
9323 m_pMouseRoute->AddPoint(pMousePoint);
9324 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9328 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9329 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9330 &rhumbBearing, &rhumbDist);
9331 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9332 &gcDist, &gcBearing, NULL);
9333 double gcDistNM = gcDist / 1852.0;
9336 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9337 pow(rhumbDist - gcDistNM - 1, 0.5);
9340 msg << _(
"For this leg the Great Circle route is ")
9342 << _(
" shorter than rhumbline.\n\n")
9343 << _(
"Would you like include the Great Circle routing points "
9347 m_FinishRouteOnKillFocus =
false;
9348 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9349 wxYES_NO | wxNO_DEFAULT);
9350 m_FinishRouteOnKillFocus =
true;
9352 int answer = wxID_NO;
9355 if (answer == wxID_YES) {
9357 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9358 wxRealPoint gcCoord;
9360 for (
int i = 1; i <= segmentCount; i++) {
9361 double fraction = (double)i * (1.0 / (
double)segmentCount);
9362 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9363 gcDist * fraction, gcBearing,
9364 &gcCoord.x, &gcCoord.y, NULL);
9366 if (i < segmentCount) {
9367 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9369 gcPoint->SetNameShown(
false);
9370 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9373 gcPoint = pMousePoint;
9376 m_pMouseRoute->AddPoint(gcPoint);
9377 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9379 pSelect->AddSelectableRouteSegment(
9380 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9381 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9382 prevGcPoint = gcPoint;
9385 undo->CancelUndoableAction(
true);
9388 m_pMouseRoute->AddPoint(pMousePoint);
9389 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9390 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9391 rlon, m_prev_pMousePoint,
9392 pMousePoint, m_pMouseRoute);
9393 undo->AfterUndoableAction(m_pMouseRoute);
9397 m_pMouseRoute->AddPoint(pMousePoint);
9398 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9400 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9401 rlon, m_prev_pMousePoint,
9402 pMousePoint, m_pMouseRoute);
9403 undo->AfterUndoableAction(m_pMouseRoute);
9409 m_prev_pMousePoint = pMousePoint;
9416 int connect = tail->GetIndexOf(pMousePoint);
9421 int length = tail->GetnPoints();
9426 start = connect + 1;
9431 m_pMouseRoute->RemovePoint(
9435 for (i = start; i <= stop; i++) {
9436 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9439 m_pMouseRoute->GetnPoints();
9441 top_frame::Get()->RefreshAllCanvas();
9445 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9447 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9448 m_pMouseRoute->FinalizeForRendering();
9453 }
else if (m_bMeasure_Active && m_nMeasureState)
9456 m_bedge_pan =
false;
9460 if (m_ignore_next_leftup) {
9461 m_ignore_next_leftup =
false;
9465 if (m_nMeasureState == 1) {
9466 m_pMeasureRoute =
new Route();
9472 if (m_pMeasureRoute) {
9475 wxEmptyString, wxEmptyString);
9478 m_pMeasureRoute->AddPoint(pMousePoint);
9482 m_prev_pMousePoint = pMousePoint;
9484 m_pMeasureRoute->GetnPoints();
9488 CancelMeasureRoute();
9494 bool bSelectAllowed =
true;
9496 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9498 bSelectAllowed =
false;
9502 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9503 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9504 significant_drag) ||
9505 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9506 significant_drag)) {
9507 bSelectAllowed =
false;
9515 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9517 if (bSelectAllowed) {
9518 bool b_was_editing_mark = m_bMarkEditing;
9519 bool b_was_editing_route = m_bRouteEditing;
9520 FindRoutePointsAtCursor(SelectRadius,
9526 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9527 m_pRoutePointEditTarget = NULL;
9529 if (!b_was_editing_route) {
9530 if (m_pEditRouteArray) {
9531 b_startedit_route =
true;
9535 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9536 m_pTrackRolloverWin->IsActive(
false);
9538 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9539 m_pRouteRolloverWin->IsActive(
false);
9543 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9545 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9553 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9554 pre_rect.Union(route_rect);
9557 RefreshRect(pre_rect,
true);
9560 b_startedit_route =
false;
9564 if (m_pRoutePointEditTarget) {
9565 if (b_was_editing_mark ||
9566 b_was_editing_route) {
9567 if (m_lastRoutePointEditTarget) {
9571 .EnableDragHandle(
false);
9572 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9573 SELTYPE_DRAGHANDLE);
9577 if (m_pRoutePointEditTarget) {
9580 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9581 wxPoint2DDouble dragHandlePoint =
9583 .GetDragHandlePoint(
this);
9585 dragHandlePoint.m_y, dragHandlePoint.m_x,
9586 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9589 if (m_lastRoutePointEditTarget) {
9593 .EnableDragHandle(
false);
9594 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9595 SELTYPE_DRAGHANDLE);
9598 wxArrayPtrVoid *lastEditRouteArray =
9600 m_lastRoutePointEditTarget);
9601 if (lastEditRouteArray) {
9602 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9604 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9609 delete lastEditRouteArray;
9620 if (m_lastRoutePointEditTarget) {
9623 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9624 RefreshRect(wp_rect,
true);
9627 if (m_pRoutePointEditTarget) {
9630 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9631 RefreshRect(wp_rect,
true);
9639 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9640 bool b_start_rollover =
false;
9644 if (pFind) b_start_rollover =
true;
9647 if (!b_start_rollover && !b_startedit_route) {
9648 SelectableItemList SelList =
pSelect->FindSelectionList(
9652 if (pr && pr->IsVisible()) {
9653 b_start_rollover =
true;
9659 if (!b_start_rollover && !b_startedit_route) {
9660 SelectableItemList SelList =
pSelect->FindSelectionList(
9664 if (tr && tr->IsVisible()) {
9665 b_start_rollover =
true;
9671 if (b_start_rollover)
9672 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9676 bool appending =
false;
9677 bool inserting =
false;
9679 if (m_bRouteEditing ) {
9681 if (m_pRoutePointEditTarget) {
9687 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9688 double nearby_radius_meters =
9689 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9690 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9691 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9692 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9694 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9698 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9700 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9704 std::find(list->begin(), list->end(), pNearbyPoint);
9705 if (pos != list->end()) {
9717 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9722 OCPNMessageBox(
this,
9723 _(
"Replace this RoutePoint by the nearby "
9725 _(
"OpenCPN RoutePoint change"),
9726 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9727 if (dlg_return == wxID_YES) {
9732 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9735 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9737 if (tail && current && (tail != current)) {
9739 connect = tail->GetIndexOf(pNearbyPoint);
9740 int index_current_route =
9741 current->GetIndexOf(m_pRoutePointEditTarget);
9742 index_last = current->GetIndexOf(current->GetLastPoint());
9743 dlg_return1 = wxID_NO;
9745 index_current_route) {
9747 if (connect != tail->GetnPoints()) {
9750 _(
"Last part of route to be appended to dragged "
9754 _(
"Full route to be appended to dragged route?");
9756 dlg_return1 = OCPNMessageBox(
9757 this, dmsg, _(
"OpenCPN Route Create"),
9758 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9759 if (dlg_return1 == wxID_YES) {
9763 }
else if (index_current_route ==
9768 _(
"First part of route to be inserted into dragged "
9770 if (connect == tail->GetnPoints())
9772 "Full route to be inserted into dragged route?");
9774 dlg_return1 = OCPNMessageBox(
9775 this, dmsg, _(
"OpenCPN Route Create"),
9776 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9777 if (dlg_return1 == wxID_YES) {
9784 if (m_pRoutePointEditTarget->IsShared()) {
9786 dlg_return = OCPNMessageBox(
9788 _(
"Do you really want to delete and replace this "
9790 "\n" + _(
"which has been created manually?"),
9791 (
"OpenCPN RoutePoint warning"),
9792 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9795 if (dlg_return == wxID_YES) {
9796 pMousePoint = pNearbyPoint;
9798 pMousePoint->SetShared(
true);
9808 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9810 if (m_pEditRouteArray) {
9811 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9813 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9818 auto pos = std::find(list->begin(), list->end(),
9819 m_pRoutePointEditTarget);
9821 pSelect->DeleteAllSelectableRoutePoints(pr);
9822 pSelect->DeleteAllSelectableRouteSegments(pr);
9825 pos = std::find(list->begin(), list->end(),
9826 m_pRoutePointEditTarget);
9829 pSelect->AddAllSelectableRouteSegments(pr);
9830 pSelect->AddAllSelectableRoutePoints(pr);
9832 pr->FinalizeForRendering();
9833 pr->UpdateSegmentDistances();
9834 if (m_bRoutePoinDragging) {
9836 NavObj_dB::GetInstance().UpdateRoute(pr);
9844 if (m_pEditRouteArray) {
9845 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9847 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9866 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9873 delete m_pRoutePointEditTarget;
9874 m_lastRoutePointEditTarget = NULL;
9875 m_pRoutePointEditTarget = NULL;
9876 undo->AfterUndoableAction(pMousePoint);
9877 undo->InvalidateUndo();
9882 else if (m_bMarkEditing) {
9883 if (m_pRoutePointEditTarget)
9884 if (m_bRoutePoinDragging) {
9886 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9890 if (m_pRoutePointEditTarget)
9891 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9893 if (!m_pRoutePointEditTarget) {
9894 delete m_pEditRouteArray;
9895 m_pEditRouteArray = NULL;
9896 m_bRouteEditing =
false;
9898 m_bRoutePoinDragging =
false;
9905 int length = tail->GetnPoints();
9906 for (
int i = connect + 1; i <= length; i++) {
9907 current->AddPointAndSegment(tail->GetPoint(i),
false);
9910 top_frame::Get()->RefreshAllCanvas();
9913 current->FinalizeForRendering();
9919 pSelect->DeleteAllSelectableRoutePoints(current);
9920 pSelect->DeleteAllSelectableRouteSegments(current);
9921 for (
int i = 1; i < connect; i++) {
9922 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9924 pSelect->AddAllSelectableRouteSegments(current);
9925 pSelect->AddAllSelectableRoutePoints(current);
9926 current->FinalizeForRendering();
9933 if (m_pEditRouteArray) {
9934 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9935 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9948 if (m_bRouteEditing) {
9951 bool appending =
false;
9952 bool inserting =
false;
9955 if (m_pRoutePointEditTarget) {
9956 m_pRoutePointEditTarget->
m_bBlink =
false;
9960 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9961 double nearby_radius_meters =
9962 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9963 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9964 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9965 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9967 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9968 bool duplicate =
false;
9970 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9972 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9976 std::find(list->begin(), list->end(), pNearbyPoint);
9977 if (pos != list->end()) {
9989 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9994 OCPNMessageBox(
this,
9995 _(
"Replace this RoutePoint by the nearby "
9997 _(
"OpenCPN RoutePoint change"),
9998 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9999 if (dlg_return == wxID_YES) {
10003 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
10006 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
10008 if (tail && current && (tail != current)) {
10010 connect = tail->GetIndexOf(pNearbyPoint);
10011 int index_current_route =
10012 current->GetIndexOf(m_pRoutePointEditTarget);
10013 index_last = current->GetIndexOf(current->GetLastPoint());
10014 dlg_return1 = wxID_NO;
10016 index_current_route) {
10018 if (connect != tail->GetnPoints()) {
10021 _(
"Last part of route to be appended to dragged "
10025 _(
"Full route to be appended to dragged route?");
10027 dlg_return1 = OCPNMessageBox(
10028 this, dmsg, _(
"OpenCPN Route Create"),
10029 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10030 if (dlg_return1 == wxID_YES) {
10034 }
else if (index_current_route ==
10036 if (connect != 1) {
10039 _(
"First part of route to be inserted into dragged "
10041 if (connect == tail->GetnPoints())
10043 "Full route to be inserted into dragged route?");
10045 dlg_return1 = OCPNMessageBox(
10046 this, dmsg, _(
"OpenCPN Route Create"),
10047 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10048 if (dlg_return1 == wxID_YES) {
10055 if (m_pRoutePointEditTarget->IsShared()) {
10056 dlg_return = wxID_NO;
10057 dlg_return = OCPNMessageBox(
10059 _(
"Do you really want to delete and replace this "
10061 "\n" + _(
"which has been created manually?"),
10062 (
"OpenCPN RoutePoint warning"),
10063 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10066 if (dlg_return == wxID_YES) {
10067 pMousePoint = pNearbyPoint;
10069 pMousePoint->SetShared(
true);
10079 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10081 if (m_pEditRouteArray) {
10082 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10084 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10088 auto pos = std::find(list->begin(), list->end(),
10089 m_pRoutePointEditTarget);
10091 pSelect->DeleteAllSelectableRoutePoints(pr);
10092 pSelect->DeleteAllSelectableRouteSegments(pr);
10095 pos = std::find(list->begin(), list->end(),
10096 m_pRoutePointEditTarget);
10097 if (pos != list->end()) list->erase(pos);
10100 pSelect->AddAllSelectableRouteSegments(pr);
10101 pSelect->AddAllSelectableRoutePoints(pr);
10103 pr->FinalizeForRendering();
10104 pr->UpdateSegmentDistances();
10107 if (m_bRoutePoinDragging) {
10112 NavObj_dB::GetInstance().UpdateRoutePoint(
10113 m_pRoutePointEditTarget);
10115 NavObj_dB::GetInstance().UpdateRoute(pr);
10127 int length = tail->GetnPoints();
10128 for (
int i = connect + 1; i <= length; i++) {
10129 current->AddPointAndSegment(tail->GetPoint(i),
false);
10133 top_frame::Get()->RefreshAllCanvas();
10136 current->FinalizeForRendering();
10142 pSelect->DeleteAllSelectableRoutePoints(current);
10143 pSelect->DeleteAllSelectableRouteSegments(current);
10144 for (
int i = 1; i < connect; i++) {
10145 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10147 pSelect->AddAllSelectableRouteSegments(current);
10148 pSelect->AddAllSelectableRoutePoints(current);
10149 current->FinalizeForRendering();
10156 if (m_pEditRouteArray) {
10157 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10159 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10171 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10178 delete m_pRoutePointEditTarget;
10179 m_lastRoutePointEditTarget = NULL;
10180 undo->AfterUndoableAction(pMousePoint);
10181 undo->InvalidateUndo();
10186 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10189 delete m_pEditRouteArray;
10190 m_pEditRouteArray = NULL;
10194 m_bRouteEditing =
false;
10195 m_pRoutePointEditTarget = NULL;
10201 else if (m_bMarkEditing) {
10202 if (m_pRoutePointEditTarget) {
10203 if (m_bRoutePoinDragging) {
10205 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10207 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10212 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10214 RefreshRect(wp_rect,
true);
10217 m_pRoutePointEditTarget = NULL;
10218 m_bMarkEditing =
false;
10223 else if (leftIsDown) {
10224 leftIsDown =
false;
10228 if (!m_bChartDragging && !m_bMeasure_Active) {
10230 m_bChartDragging =
false;
10234 m_bRoutePoinDragging =
false;
10237 if (ret)
return true;
10240 if (event.RightDown()) {
10251 m_FinishRouteOnKillFocus =
false;
10252 CallPopupMenu(mx, my);
10253 m_FinishRouteOnKillFocus =
true;
10263 if (event.ShiftDown()) {
10267 event.GetPosition(&x, &y);
10269 x *= m_displayScale;
10270 y *= m_displayScale;
10276 int wheel_dir =
event.GetWheelRotation();
10279 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10280 wheel_dir = wheel_dir > 0 ? 1 : -1;
10282 double factor = g_mouse_zoom_sensitivity;
10283 if (wheel_dir < 0) factor = 1 / factor;
10286 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10287 if (wheel_dir == m_last_wheel_dir) {
10288 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10293 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10294 m_wheelstopwatch.Start(0);
10299 m_last_wheel_dir = wheel_dir;
10304 if (event.LeftDown()) {
10310 last_drag.x = x, last_drag.y = y;
10311 panleftIsDown =
true;
10314 if (event.LeftUp()) {
10315 if (panleftIsDown) {
10317 panleftIsDown =
false;
10320 if (!m_bChartDragging && !m_bMeasure_Active) {
10321 switch (cursor_region) {
10343 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10348 m_bChartDragging =
false;
10354 if (event.Dragging() && event.LeftIsDown()) {
10370 if (g_btouch && !m_inPinch) {
10371 struct timespec now;
10372 clock_gettime(CLOCK_MONOTONIC, &now);
10373 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10375 bool trigger_hold =
false;
10376 if (
false == m_bChartDragging) {
10377 if (m_DragTrigger < 0) {
10380 m_DragTriggerStartTime = tnow;
10381 trigger_hold =
true;
10383 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10384 m_DragTrigger = -1;
10389 if (trigger_hold)
return true;
10391 if (
false == m_bChartDragging) {
10394 last_drag.x = x - 1, last_drag.y = y - 1;
10395 m_bChartDragging =
true;
10396 m_chart_drag_total_time = 0;
10397 m_chart_drag_total_x = 0;
10398 m_chart_drag_total_y = 0;
10399 m_inertia_last_drag_x = x;
10400 m_inertia_last_drag_y = y;
10401 m_drag_vec_x.clear();
10402 m_drag_vec_y.clear();
10403 m_drag_vec_t.clear();
10404 m_last_drag_time = tnow;
10408 uint64_t delta_t = tnow - m_last_drag_time;
10409 double delta_tf = delta_t / 1e9;
10411 m_chart_drag_total_time += delta_tf;
10412 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10413 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10415 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10416 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10417 m_drag_vec_t.push_back(delta_tf);
10419 m_inertia_last_drag_x = x;
10420 m_inertia_last_drag_y = y;
10421 m_last_drag_time = tnow;
10423 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10424 m_bChartDragging =
true;
10425 StartTimedMovement();
10426 m_pan_drag.x += last_drag.x - x;
10427 m_pan_drag.y += last_drag.y - y;
10428 last_drag.x = x, last_drag.y = y;
10430 }
else if (!g_btouch) {
10431 if ((last_drag.x != x) || (last_drag.y != y)) {
10432 if (!m_routeState) {
10435 m_bChartDragging =
true;
10436 StartTimedMovement();
10437 m_pan_drag.x += last_drag.x - x;
10438 m_pan_drag.y += last_drag.y - y;
10439 last_drag.x = x, last_drag.y = y;
10446 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10448 m_ignore_next_leftup =
true;
10449 m_DoubleClickTimer->Start();
10450 singleClickEventIsValid =
false;
10458void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10459 if (MouseEventOverlayWindows(event))
return;
10463 bool nm = MouseEventProcessObjects(event);
10467void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10470 wxCursor *ptarget_cursor = pCursorArrow;
10471 if (!pPlugIn_Cursor) {
10472 ptarget_cursor = pCursorArrow;
10473 if ((!m_routeState) &&
10474 (!m_bMeasure_Active) ) {
10475 if (cursor_region == MID_RIGHT) {
10476 ptarget_cursor = pCursorRight;
10477 }
else if (cursor_region == MID_LEFT) {
10478 ptarget_cursor = pCursorLeft;
10479 }
else if (cursor_region == MID_TOP) {
10480 ptarget_cursor = pCursorDown;
10481 }
else if (cursor_region == MID_BOT) {
10482 ptarget_cursor = pCursorUp;
10484 ptarget_cursor = pCursorArrow;
10486 }
else if (m_bMeasure_Active ||
10488 ptarget_cursor = pCursorPencil;
10490 ptarget_cursor = pPlugIn_Cursor;
10493 SetCursor(*ptarget_cursor);
10496void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10497 SetCursor(*pCursorArrow);
10500void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10504 wxArrayString files;
10506 ChartBase *target_chart = GetChartAtCursor();
10507 if (target_chart) {
10508 file.Assign(target_chart->GetFullPath());
10509 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10510 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10513 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10515 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10516 unsigned int im = stackIndexArray.size();
10517 int scale = 2147483647;
10518 if (VPoint.b_quilt && im > 0) {
10519 for (
unsigned int is = 0; is < im; is++) {
10520 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10521 CHART_TYPE_MBTILES) {
10522 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10524 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10525 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10527 .Contains(lat, lon)) {
10528 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10531 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10532 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10540 std::vector<Ais8_001_22 *> area_notices;
10542 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10545 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10546 auto target_data = target.second;
10547 if (!target_data->area_notices.empty()) {
10548 for (
auto &ani : target_data->area_notices) {
10553 for (Ais8_001_22_SubAreaList::iterator sa =
10554 area_notice.sub_areas.begin();
10555 sa != area_notice.sub_areas.end(); ++sa) {
10556 switch (sa->shape) {
10557 case AIS8_001_22_SHAPE_CIRCLE: {
10558 wxPoint target_point;
10560 bbox.Expand(target_point);
10561 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10564 case AIS8_001_22_SHAPE_RECT: {
10565 wxPoint target_point;
10567 bbox.Expand(target_point);
10568 if (sa->e_dim_m > sa->n_dim_m)
10569 bbox.EnLarge(sa->e_dim_m * vp_scale);
10571 bbox.EnLarge(sa->n_dim_m * vp_scale);
10574 case AIS8_001_22_SHAPE_POLYGON:
10575 case AIS8_001_22_SHAPE_POLYLINE: {
10576 for (
int i = 0; i < 4; ++i) {
10577 double lat = sa->latitude;
10578 double lon = sa->longitude;
10579 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10581 wxPoint target_point;
10583 bbox.Expand(target_point);
10587 case AIS8_001_22_SHAPE_SECTOR: {
10588 double lat1 = sa->latitude;
10589 double lon1 = sa->longitude;
10591 wxPoint target_point;
10593 bbox.Expand(target_point);
10594 for (
int i = 0; i < 18; ++i) {
10597 sa->left_bound_deg +
10598 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10599 sa->radius_m / 1852.0, &lat, &lon);
10601 bbox.Expand(target_point);
10603 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10606 bbox.Expand(target_point);
10612 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10613 area_notices.push_back(&area_notice);
10620 if (target_chart || !area_notices.empty() || file.HasName()) {
10622 int sel_rad_pix = 5;
10623 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10628 SetCursor(wxCURSOR_WAIT);
10629 bool lightsVis = m_encShowLights;
10630 if (!lightsVis) SetShowENCLights(
true);
10633 ListOfObjRazRules *rule_list = NULL;
10634 ListOfPI_S57Obj *pi_rule_list = NULL;
10637 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10638 else if (target_plugin_chart)
10639 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10640 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10642 ListOfObjRazRules *overlay_rule_list = NULL;
10643 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10646 if (CHs57_Overlay) {
10647 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10648 zlat, zlon, SelectRadius, &GetVP());
10651 if (!lightsVis) SetShowENCLights(
false);
10654 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10655 wxString face = dFont->GetFaceName();
10659 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10660 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10664 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10672 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10673 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10676 int points = dFont->GetPointSize();
10678 int points = dFont->GetPointSize() + 1;
10682 for (
int i = -2; i < 5; i++) {
10683 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10687 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10689 if (overlay_rule_list && CHs57_Overlay) {
10690 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10691 objText <<
"<hr noshade>";
10694 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10695 an != area_notices.end(); ++an) {
10696 objText <<
"<b>AIS Area Notice:</b> ";
10697 objText << ais8_001_22_notice_names[(*an)->notice_type];
10698 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10699 (*an)->sub_areas.begin();
10700 sa != (*an)->sub_areas.end(); ++sa)
10701 if (!sa->text.empty()) objText << sa->text;
10702 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10703 objText <<
"<hr noshade>";
10707 objText << Chs57->CreateObjDescriptions(rule_list);
10708 else if (target_plugin_chart)
10709 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10712 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10715 wxString AddFiles, filenameOK;
10717 if (!target_plugin_chart) {
10720 AddFiles = wxString::Format(
10721 "<hr noshade><br><b>Additional info files attached to: </b> "
10723 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10725 file.GetFullName());
10727 file.Assign(file.GetPath(),
"");
10728 wxDir dir(file.GetFullPath());
10730 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10732 file.Assign(dir.GetNameWithSep().append(filename));
10733 wxString FormatString =
10734 "<td valign=top><font size=-2><a "
10735 "href=\"%s\">%s</a></font></td>";
10736 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10737 filenameOK = file.GetFullPath();
10739 if (3 * ((
int)filecount / 3) == filecount)
10740 FormatString.Prepend(
"<tr>");
10742 FormatString.Prepend(
10743 "<td>  </td>");
10746 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10747 file.GetFullName());
10750 cont = dir.GetNext(&filename);
10752 objText << AddFiles <<
"</table>";
10754 objText <<
"</font>";
10755 objText <<
"</body></html>";
10757 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10761 if ((!Chs57 && filecount == 1)) {
10763 wxHtmlLinkInfo hli(filenameOK);
10764 wxHtmlLinkEvent hle(1, hli);
10768 if (rule_list) rule_list->Clear();
10771 if (overlay_rule_list) overlay_rule_list->Clear();
10772 delete overlay_rule_list;
10774 if (pi_rule_list) pi_rule_list->Clear();
10775 delete pi_rule_list;
10777 SetCursor(wxCURSOR_ARROW);
10781void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10790 wxSize canvas_size = GetSize();
10797 wxPoint canvas_pos = GetPosition();
10800 bool newFit =
false;
10801 if (canvas_size.x < fitted_size.x) {
10802 fitted_size.x = canvas_size.x - 40;
10803 if (canvas_size.y < fitted_size.y)
10804 fitted_size.y -= 40;
10806 if (canvas_size.y < fitted_size.y) {
10807 fitted_size.y = canvas_size.y - 40;
10808 if (canvas_size.x < fitted_size.x)
10809 fitted_size.x -= 40;
10820 wxString title_base = _(
"Mark Properties");
10822 title_base = _(
"Waypoint Properties");
10827 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10839void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10849 if (g_bresponsive) {
10850 wxSize canvas_size = GetSize();
10851 wxPoint canvas_pos = GetPosition();
10855 if (canvas_size.x < fitted_size.x) {
10856 fitted_size.x = canvas_size.x;
10857 if (canvas_size.y < fitted_size.y)
10858 fitted_size.y -= 20;
10860 if (canvas_size.y < fitted_size.y) {
10861 fitted_size.y = canvas_size.y;
10862 if (canvas_size.x < fitted_size.x)
10863 fitted_size.x -= 20;
10872 wxPoint xxp = ClientToScreen(canvas_pos);
10883void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10895void pupHandler_PasteWaypoint() {
10898 int pasteBuffer = kml.ParsePasteBuffer();
10899 RoutePoint *pasted = kml.GetParsedRoutePoint();
10900 if (!pasted)
return;
10902 double nearby_radius_meters =
10903 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10905 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10906 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10908 int answer = wxID_NO;
10912 "There is an existing waypoint at the same location as the one you are "
10913 "pasting. Would you like to merge the pasted data with it?\n\n");
10914 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10915 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10916 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10919 if (answer == wxID_YES) {
10920 nearPoint->SetName(pasted->GetName());
10926 if (answer == wxID_NO) {
10929 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10932 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10941 top_frame::Get()->InvalidateAllGL();
10942 top_frame::Get()->RefreshAllCanvas(
false);
10945void pupHandler_PasteRoute() {
10948 int pasteBuffer = kml.ParsePasteBuffer();
10949 Route *pasted = kml.GetParsedRoute();
10950 if (!pasted)
return;
10952 double nearby_radius_meters =
10953 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10959 bool mergepoints =
false;
10960 bool createNewRoute =
true;
10961 int existingWaypointCounter = 0;
10963 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10964 curPoint = pasted->GetPoint(i);
10965 nearPoint = pWayPointMan->GetNearbyWaypoint(
10966 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10968 mergepoints =
true;
10969 existingWaypointCounter++;
10977 int answer = wxID_NO;
10981 "There are existing waypoints at the same location as some of the ones "
10982 "you are pasting. Would you like to just merge the pasted data into "
10984 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10985 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10986 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10988 if (answer == wxID_CANCEL) {
10995 if (mergepoints && answer == wxID_YES &&
10996 existingWaypointCounter == pasted->GetnPoints()) {
10999 createNewRoute =
false;
11005 Route *newRoute = 0;
11008 if (createNewRoute) {
11009 newRoute =
new Route();
11013 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11014 curPoint = pasted->GetPoint(i);
11017 newPoint = pWayPointMan->GetNearbyWaypoint(
11018 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11019 newPoint->SetName(curPoint->GetName());
11022 if (createNewRoute) newRoute->AddPoint(newPoint);
11028 newPoint->SetIconName(
"circle");
11031 newPoint->SetShared(
false);
11033 newRoute->AddPoint(newPoint);
11034 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11037 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11040 if (i > 1 && createNewRoute)
11041 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11042 curPoint->m_lat, curPoint->m_lon,
11043 prevPoint, newPoint, newRoute);
11044 prevPoint = newPoint;
11047 if (createNewRoute) {
11050 NavObj_dB::GetInstance().InsertRoute(newRoute);
11060 top_frame::Get()->InvalidateAllGL();
11061 top_frame::Get()->RefreshAllCanvas(
false);
11067void pupHandler_PasteTrack() {
11070 int pasteBuffer = kml.ParsePasteBuffer();
11071 Track *pasted = kml.GetParsedTrack();
11072 if (!pasted)
return;
11080 newTrack->SetName(pasted->GetName());
11082 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11083 curPoint = pasted->GetPoint(i);
11087 wxDateTime now = wxDateTime::Now();
11090 newTrack->AddPoint(newPoint);
11093 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11094 newPoint->m_lat, newPoint->m_lon,
11095 prevPoint, newPoint, newTrack);
11097 prevPoint = newPoint;
11102 NavObj_dB::GetInstance().InsertTrack(newTrack);
11104 top_frame::Get()->InvalidateAllGL();
11105 top_frame::Get()->RefreshAllCanvas(
false);
11108bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11111 v[
"CursorPosition_x"] = x;
11112 v[
"CursorPosition_y"] = y;
11115 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11116 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11117 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11122 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11124 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11127#define SELTYPE_UNKNOWN 0x0001
11128#define SELTYPE_ROUTEPOINT 0x0002
11129#define SELTYPE_ROUTESEGMENT 0x0004
11130#define SELTYPE_TIDEPOINT 0x0008
11131#define SELTYPE_CURRENTPOINT 0x0010
11132#define SELTYPE_ROUTECREATE 0x0020
11133#define SELTYPE_AISTARGET 0x0040
11134#define SELTYPE_MARKPOINT 0x0080
11135#define SELTYPE_TRACKSEGMENT 0x0100
11136#define SELTYPE_DRAGHANDLE 0x0200
11139 if (g_bhide_context_menus)
return true;
11141 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11142 m_pIDXCandidate, m_nmea_log);
11145 wxEVT_COMMAND_MENU_SELECTED,
11146 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11152 if (m_inLongPress) {
11153 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11154 m_inLongPress =
false;
11158 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11161 wxEVT_COMMAND_MENU_SELECTED,
11162 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11164 delete m_canvasMenu;
11165 m_canvasMenu = NULL;
11175void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11178 if (m_canvasMenu) {
11179 m_canvasMenu->PopupMenuHandler(event);
11184void ChartCanvas::StartRoute() {
11186 if (g_brouteCreating)
return;
11190 g_brouteCreating =
true;
11192 m_bDrawingRoute =
false;
11193 SetCursor(*pCursorPencil);
11195 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11197 HideGlobalToolbar();
11200 androidSetRouteAnnunciator(
true);
11204wxString ChartCanvas::FinishRoute() {
11206 m_prev_pMousePoint = NULL;
11207 m_bDrawingRoute =
false;
11209 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11212 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11214 androidSetRouteAnnunciator(
false);
11217 SetCursor(*pCursorArrow);
11219 if (m_pMouseRoute) {
11220 if (m_bAppendingRoute) {
11222 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11224 if (m_pMouseRoute->GetnPoints() > 1) {
11226 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11229 m_pMouseRoute = NULL;
11232 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11244 m_bAppendingRoute =
false;
11245 m_pMouseRoute = NULL;
11247 m_pSelectedRoute = NULL;
11249 undo->InvalidateUndo();
11250 top_frame::Get()->RefreshAllCanvas(
true);
11254 ShowGlobalToolbar();
11256 g_brouteCreating =
false;
11261void ChartCanvas::HideGlobalToolbar() {
11262 if (m_canvasIndex == 0) {
11263 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11267void ChartCanvas::ShowGlobalToolbar() {
11268 if (m_canvasIndex == 0) {
11269 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11273void ChartCanvas::ShowAISTargetList() {
11274 if (NULL == g_pAISTargetList) {
11278 g_pAISTargetList->UpdateAISTargetList();
11281void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11282 if (!m_bShowOutlines)
return;
11286 int nEntry =
ChartData->GetChartTableEntries();
11288 for (
int i = 0; i < nEntry; i++) {
11292 bool b_group_draw =
false;
11293 if (m_groupIndex > 0) {
11294 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11295 int index = pt->GetGroupArray()[ig];
11296 if (m_groupIndex == index) {
11297 b_group_draw =
true;
11302 b_group_draw =
true;
11304 if (b_group_draw) RenderChartOutline(dc, i, vp);
11310 if (VPoint.b_quilt) {
11311 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11312 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11316 }
else if (m_singleChart &&
11317 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11321 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11324 if (zoom_factor > 8.0) {
11325 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11328 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11332 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11336void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11338 if (g_bopengl && m_glcc) {
11340 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11345 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11346 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11349 float plylat, plylon;
11350 float plylat1, plylon1;
11352 int pixx, pixy, pixx1, pixy1;
11355 ChartData->GetDBBoundingBox(dbIndex, box);
11359 if (box.GetLonRange() == 360)
return;
11361 double lon_bias = 0;
11363 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11365 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11367 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11368 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11370 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11371 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11374 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11377 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11378 if (0 == nAuxPlyEntries)
11382 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11383 plylon += lon_bias;
11389 for (
int i = 0; i < nPly - 1; i++) {
11390 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11391 plylon1 += lon_bias;
11397 int pixxs1 = pixx1;
11398 int pixys1 = pixy1;
11400 bool b_skip =
false;
11404 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11405 pow((
double)(pixy1 - pixy), 2)) /
11411 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11416 if (fabs(dist - distgc) > 10000. * 1852.)
11422 ClipResult res = cohen_sutherland_line_clip_i(
11424 if (res != Invisible && !b_skip)
11425 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11433 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11434 plylon1 += lon_bias;
11440 ClipResult res = cohen_sutherland_line_clip_i(
11442 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11449 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11450 for (
int j = 0; j < nAuxPlyEntries; j++) {
11452 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11457 for (
int i = 0; i < nAuxPly - 1; i++) {
11458 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11464 int pixxs1 = pixx1;
11465 int pixys1 = pixy1;
11467 bool b_skip =
false;
11471 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11472 ((pixy1 - pixy) * (pixy1 - pixy))) /
11477 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11482 if (fabs(dist - distgc) > 10000. * 1852.)
11488 ClipResult res = cohen_sutherland_line_clip_i(
11490 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11498 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11503 ClipResult res = cohen_sutherland_line_clip_i(
11505 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11510static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11511 const wxArrayString &legend) {
11512 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11514 int pointsize = dFont->GetPointSize();
11518 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11519 false, dFont->GetFaceName());
11521 dc.SetFont(*psRLI_font);
11528 int hilite_offset = 3;
11530 for (wxString line : legend) {
11533 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11535 dc.GetTextExtent(line, &wl, &hl);
11544 xp = ref_point.x - w;
11546 yp += hilite_offset;
11548 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11550 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11551 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11553 for (wxString line : legend) {
11554 dc.DrawText(line, xp, yp);
11559void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11560 if (!g_bAllowShipToActive)
return;
11566 wxPoint2DDouble pa, pb;
11573 if (rt->
m_width != wxPENSTYLE_INVALID)
11575 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11576 g_shipToActiveStyle, 5)];
11577 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11579 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11582 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11585 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11588 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11589 (
int)pb.m_y, GetVP(),
true);
11593#ifdef USE_ANDROID_GLES2
11594 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11596 if (style != wxPENSTYLE_SOLID) {
11597 if (glChartCanvas::dash_map.find(style) !=
11598 glChartCanvas::dash_map.end()) {
11599 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11603 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11606 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11607 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11613void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11615 if (m_routeState >= 2) route = m_pMouseRoute;
11616 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11617 route = m_pMeasureRoute;
11619 if (!route)
return;
11627 int np = route->GetnPoints();
11629 if (g_btouch && (np > 1)) np--;
11631 render_lat = rp.m_lat;
11632 render_lon = rp.m_lon;
11635 double rhumbBearing, rhumbDist;
11637 &rhumbBearing, &rhumbDist);
11638 double brg = rhumbBearing;
11639 double dist = rhumbDist;
11643 double gcBearing, gcBearing2, gcDist;
11644 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11647 double gcDistm = gcDist / 1852.0;
11650 rhumbBearing = 90.;
11652 wxPoint destPoint, lastPoint;
11655 int milesDiff = rhumbDist - gcDistm;
11656 if (milesDiff > 1) {
11667 for (
int i = 1; i <= milesDiff; i++) {
11668 double p = (double)i * (1.0 / (
double)milesDiff);
11670 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11671 &pLon, &pLat, &gcBearing2);
11673 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11675 lastPoint = destPoint;
11678 if (r_rband.x && r_rband.y) {
11679 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11681 if (m_bMeasure_DistCircle) {
11682 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11683 powf((
float)(r_rband.y - lastPoint.y), 2));
11686 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11687 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11693 wxString routeInfo;
11694 wxArrayString infoArray;
11697 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11703 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11705 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11706 (
int)varBrg, 0x00B0);
11709 infoArray.Add(routeInfo);
11715 routeInfo <<
"Reverse: ";
11717 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11718 (
int)(brg + 180.) % 360, 0x00B0);
11720 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11721 (
int)(varBrg + 180.) % 360, 0x00B0);
11722 infoArray.Add(routeInfo);
11728 s0.Append(_(
"Route") +
": ");
11730 s0.Append(_(
"Layer Route: "));
11733 if (!g_btouch) disp_length += dist;
11739 RouteLegInfo(dc, r_rband, infoArray);
11741 m_brepaint_piano =
true;
11744void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11745 if (!m_bShowVisibleSectors)
return;
11747 if (g_bDeferredInitDone) {
11749 double rhumbBearing, rhumbDist;
11750 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11751 &rhumbBearing, &rhumbDist);
11753 if (rhumbDist > 0.05)
11755 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11756 m_sectorlegsVisible);
11757 m_sector_glat =
gLat;
11758 m_sector_glon =
gLon;
11760 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11764void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11772void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11773 if (!ps52plib)
return;
11775 if (VPoint.b_quilt) {
11776 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11778 if (m_pQuilt->IsQuiltVector()) {
11779 if (ps52plib->GetStateHash() != m_s52StateHash) {
11781 m_s52StateHash = ps52plib->GetStateHash();
11785 if (ps52plib->GetStateHash() != m_s52StateHash) {
11787 m_s52StateHash = ps52plib->GetStateHash();
11792 bool bSendPlibState =
true;
11793 if (VPoint.b_quilt) {
11794 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11797 if (bSendPlibState) {
11799 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11800 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11801 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11802 v[
"OpenCPN Version Date"] = VERSION_DATE;
11803 v[
"OpenCPN Version Full"] = VERSION_FULL;
11806 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11807 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11808 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11809 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11810 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11811 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11812 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11816 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11817 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11821 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11822 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11823 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11824 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11825 ps52plib->m_bShowS57ImportantTextOnly;
11826 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11827 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11828 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11829 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11830 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11833 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11834 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11835 v[
"OpenCPN Scale Factor Exp"] =
11836 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11843 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11844 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11845 g_lastS52PLIBPluginMessage = out;
11852 wxPaintDC dc(
this);
11862 if (!m_b_paint_enable) {
11870 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11872 if (m_glcc && g_bopengl) {
11873 if (!s_in_update) {
11883 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11885 wxRegion ru = GetUpdateRegion();
11887 int rx, ry, rwidth, rheight;
11888 ru.GetBox(rx, ry, rwidth, rheight);
11890#ifdef ocpnUSE_DIBSECTION
11893 wxMemoryDC temp_dc;
11901 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11902 height += m_Piano->GetHeight();
11904 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11908 int thumbx, thumby, thumbsx, thumbsy;
11909 pthumbwin->GetPosition(&thumbx, &thumby);
11910 pthumbwin->GetSize(&thumbsx, &thumbsy);
11911 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11914 rgn_chart.Subtract(rgn_thumbwin);
11915 ru.Subtract(rgn_thumbwin);
11921 wxRegion rgn_blit = ru;
11922 if (g_bShowChartBar) {
11923 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11924 GetClientSize().x, m_Piano->GetHeight());
11927 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11928 if (style->chartStatusWindowTransparent)
11929 m_brepaint_piano =
true;
11931 ru.Subtract(chart_bar_rect);
11935 if (m_Compass && m_Compass->IsShown()) {
11936 wxRect compassRect = m_Compass->
GetRect();
11937 if (ru.Contains(compassRect) != wxOutRegion) {
11938 ru.Subtract(compassRect);
11942 if (m_notification_button) {
11943 wxRect noteRect = m_notification_button->
GetRect();
11944 if (ru.Contains(noteRect) != wxOutRegion) {
11945 ru.Subtract(noteRect);
11950 bool b_newview =
true;
11955 m_cache_vp.IsValid()) {
11961 bool b_rcache_ok =
false;
11962 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11963 b_rcache_ok = !b_newview;
11966 if (VPoint.b_MercatorProjectionOverride)
11967 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11981 if (b_rcache_ok) chart_get_region.Clear();
11984 if (VPoint.b_quilt)
11986 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11988 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11993 AbstractPlatform::ShowBusySpinner();
11997 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11998 (m_working_bm.GetHeight() != svp.
pix_height))
12002 if (fabs(VPoint.
rotation) < 0.01) {
12003 bool b_save =
true;
12008 m_cache_vp.Invalidate();
12022 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12027 int dy = c_new.y - c_old.y;
12028 int dx = c_new.x - c_old.x;
12033 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12037 temp_dc.SelectObject(m_working_bm);
12039 wxMemoryDC cache_dc;
12040 cache_dc.SelectObject(m_cached_chart_bm);
12044 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12047 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12053 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12056 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12064 update_region.Union(
12067 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12072 update_region.Union(
12075 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12079 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12081 cache_dc.SelectObject(wxNullBitmap);
12085 temp_dc.SelectObject(m_cached_chart_bm);
12088 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12092 temp_dc.SelectObject(m_working_bm);
12093 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12098 temp_dc.SelectObject(m_cached_chart_bm);
12103 temp_dc.SelectObject(m_working_bm);
12104 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12117 wxMemoryDC scratch_dc_0;
12118 scratch_dc_0.SelectObject(m_cached_chart_bm);
12121 scratch_dc_0.SelectObject(wxNullBitmap);
12130 temp_dc.SelectObject(m_working_bm);
12133 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12134 chart_get_all_region);
12137 AbstractPlatform::HideBusySpinner();
12143 if (!m_singleChart) {
12144 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12149 if (!chart_get_region.IsEmpty()) {
12150 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12154 if (temp_dc.IsOk()) {
12159 if (!VPoint.b_quilt) {
12162 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12163 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12170 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12171 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12174 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12176 temp_dc.DestroyClippingRegion();
12181 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12183 if (!backgroundRegion.IsEmpty()) {
12189 wxColour water = pWorldBackgroundChart->water;
12190 if (water.IsOk()) {
12191 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12192 temp_dc.SetBrush(wxBrush(water));
12194 while (upd.HaveRects()) {
12195 wxRect rect = upd.GetRect();
12196 temp_dc.DrawRectangle(rect);
12201 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12202 temp_dc.SetDeviceClippingRegion(*clip_region);
12203 delete clip_region;
12207 SetVPRotation(VPoint.
skew);
12216 wxMemoryDC *pChartDC = &temp_dc;
12217 wxMemoryDC rotd_dc;
12219 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12221 if (!b_rcache_ok) {
12223 wxMemoryDC tbase_dc;
12225 tbase_dc.SelectObject(bm_base);
12227 tbase_dc.SelectObject(wxNullBitmap);
12229 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12232 wxImage base_image;
12233 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12241 bool b_rot_ok =
false;
12242 if (base_image.IsOk()) {
12245 m_b_rot_hidef =
false;
12249 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12250 m_b_rot_hidef, &m_roffset);
12255 rot_vp.IsValid() && (ri.IsOk())) {
12262 m_prot_bm =
new wxBitmap(ri);
12265 m_roffset.x += VPoint.rv_rect.x;
12266 m_roffset.y += VPoint.rv_rect.y;
12269 if (m_prot_bm && m_prot_bm->IsOk()) {
12270 rotd_dc.SelectObject(*m_prot_bm);
12271 pChartDC = &rotd_dc;
12273 pChartDC = &temp_dc;
12274 m_roffset = wxPoint(0, 0);
12277 pChartDC = &temp_dc;
12278 m_roffset = wxPoint(0, 0);
12281 wxPoint offset = m_roffset;
12284 m_cache_vp = VPoint;
12287 wxMemoryDC mscratch_dc;
12288 mscratch_dc.SelectObject(*pscratch_bm);
12290 mscratch_dc.ResetBoundingBox();
12291 mscratch_dc.DestroyClippingRegion();
12292 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12295 wxRegionIterator upd(rgn_blit);
12297 wxRect rect = upd.GetRect();
12299 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12300 rect.x - offset.x, rect.y - offset.y);
12306 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12307 if (
this == wxWindow::FindFocus()) {
12310 wxColour colour = GetGlobalColor(
"BLUE4");
12311 mscratch_dc.SetPen(wxPen(colour));
12312 mscratch_dc.SetBrush(wxBrush(colour));
12314 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12315 mscratch_dc.DrawRectangle(activeRect);
12320 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12321 unsigned int im = stackIndexArray.size();
12322 if (VPoint.b_quilt && im > 0) {
12323 std::vector<int> tiles_to_show;
12324 for (
unsigned int is = 0; is < im; is++) {
12326 ChartData->GetChartTableEntry(stackIndexArray[is]);
12327 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12330 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12331 tiles_to_show.push_back(stackIndexArray[is]);
12335 if (tiles_to_show.size())
12336 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12342 ocpnDC scratch_dc(mscratch_dc);
12343 RenderAlertMessage(mscratch_dc, GetVP());
12349#ifdef ocpnUSE_DIBSECTION
12354 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12355 q_dc.SelectObject(qbm);
12358 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12361 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12362 q_dc.SetBrush(qbr);
12363 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12366 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12369 q_dc.SelectObject(wxNullBitmap);
12378 if( VPoint.b_quilt ) {
12379 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12380 ChartBase *chart = m_pQuilt->GetRefChart();
12381 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12386 ChPI->ClearPLIBTextList();
12389 ps52plib->ClearTextList();
12393 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12395 wxColor maskBackground = wxColour(1,0,0);
12396 t_dc.SelectObject( qbm );
12397 t_dc.SetBackground(wxBrush(maskBackground));
12401 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12404 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12405 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12408 wxRegionIterator upd_final( ru );
12409 while( upd_final ) {
12410 wxRect rect = upd_final.GetRect();
12411 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12415 t_dc.SelectObject( wxNullBitmap );
12421 if (VPoint.b_quilt) {
12422 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12423 ChartBase *chart = m_pQuilt->GetRefChart();
12424 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12428 ChPI->ClearPLIBTextList();
12430 if (ps52plib) ps52plib->ClearTextList();
12435 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12437 if (g_bShowChartBar && m_Piano) {
12438 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12439 GetVP().pix_width, m_Piano->GetHeight());
12442 if (!style->chartStatusWindowTransparent)
12443 chart_all_text_region.Subtract(chart_bar_rect);
12446 if (m_Compass && m_Compass->IsShown()) {
12447 wxRect compassRect = m_Compass->
GetRect();
12448 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12449 chart_all_text_region.Subtract(compassRect);
12453 mscratch_dc.DestroyClippingRegion();
12455 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12456 chart_all_text_region);
12462 ocpnDC scratch_dc(mscratch_dc);
12463 DrawOverlayObjects(scratch_dc, ru);
12466 wxRegionIterator upd_final(rgn_blit);
12467 while (upd_final) {
12468 wxRect rect = upd_final.GetRect();
12469 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12476 temp_dc.SelectObject(wxNullBitmap);
12478 mscratch_dc.SelectObject(wxNullBitmap);
12480 dc.DestroyClippingRegion();
12485void ChartCanvas::PaintCleanup() {
12487 if (m_inPinch)
return;
12498 m_bTCupdate =
false;
12502 WarpPointer(warp_x, warp_y);
12509 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12510 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12514wxColour GetErrorGraphicColor(
double val)
12533 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12534 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12535 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12536 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12537 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12538 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12539 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12540 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12541 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12542 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12543 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12544 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12545 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12546 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12547 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12548 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12549 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12550 else if( val >= 48) c.Set(
"#410000");
12555void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12558 gr_image.InitAlpha();
12560 double maxval = -10000;
12561 double minval = 10000;
12578 maxval = wxMax(maxval, (glat - rlat));
12579 minval = wxMin(minval, (glat - rlat));
12596 double f = ((glat - rlat)-minval)/(maxval - minval);
12598 double dy = (f * 40);
12600 wxColour c = GetErrorGraphicColor(dy);
12601 unsigned char r = c.Red();
12602 unsigned char g = c.Green();
12603 unsigned char b = c.Blue();
12605 gr_image.SetRGB(j, i, r,g,b);
12606 if((glat - rlat )!= 0)
12607 gr_image.SetAlpha(j, i, 128);
12609 gr_image.SetAlpha(j, i, 255);
12616 wxBitmap *pbm =
new wxBitmap(gr_image);
12617 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12618 pbm->SetMask(gr_mask);
12620 pmdc->DrawBitmap(*pbm, 0,0);
12628void ChartCanvas::CancelMouseRoute() {
12630 m_pMouseRoute = NULL;
12631 m_bDrawingRoute =
false;
12634int ChartCanvas::GetNextContextMenuId() {
12635 return CanvasMenuHandler::GetNextContextMenuId();
12638bool ChartCanvas::SetCursor(
const wxCursor &c) {
12640 if (g_bopengl && m_glcc)
12641 return m_glcc->SetCursor(c);
12644 return wxWindow::SetCursor(c);
12647void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12648 if (g_bquiting)
return;
12658 if (!m_RolloverPopupTimer.IsRunning() &&
12659 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12660 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12661 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12662 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12665 if (m_glcc && g_bopengl) {
12668 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12670 m_glcc->Refresh(eraseBackground,
12687 if (m_pCIWin && m_pCIWin->IsShown()) {
12689 m_pCIWin->Refresh(
false);
12697 wxWindow::Refresh(eraseBackground, rect);
12700void ChartCanvas::Update() {
12701 if (m_glcc && g_bopengl) {
12706 wxWindow::Update();
12710 if (!pemboss)
return;
12711 int x = pemboss->x, y = pemboss->y;
12712 const double factor = 200;
12714 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12715 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12716 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12719 wxMemoryDC snip_dc;
12720 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12721 snip_dc.SelectObject(snip_bmp);
12723 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12724 snip_dc.SelectObject(wxNullBitmap);
12726 wxImage snip_img = snip_bmp.ConvertToImage();
12729 unsigned char *pdata = snip_img.GetData();
12731 for (
int y = 0; y < pemboss->height; y++) {
12732 int map_index = (y * pemboss->width);
12733 for (
int x = 0; x < pemboss->width; x++) {
12734 double val = (pemboss->pmap[map_index] * factor) / 256.;
12736 int nred = (int)((*pdata) + val);
12737 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12738 *pdata++ = (
unsigned char)nred;
12740 int ngreen = (int)((*pdata) + val);
12741 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12742 *pdata++ = (
unsigned char)ngreen;
12744 int nblue = (int)((*pdata) + val);
12745 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12746 *pdata++ = (
unsigned char)nblue;
12754 wxBitmap emb_bmp(snip_img);
12757 wxMemoryDC result_dc;
12758 result_dc.SelectObject(emb_bmp);
12761 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12763 result_dc.SelectObject(wxNullBitmap);
12769 if (GetQuiltMode()) {
12771 int refIndex = GetQuiltRefChartdbIndex();
12772 if (refIndex >= 0) {
12774 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12775 if (current_type == CHART_TYPE_MBTILES) {
12776 ChartBase *pChart = m_pQuilt->GetRefChart();
12779 zoom_factor = ptc->GetZoomFactor();
12784 if (zoom_factor <= 3.9)
return NULL;
12786 if (m_singleChart) {
12787 if (zoom_factor <= 3.9)
return NULL;
12792 if (m_pEM_OverZoom) {
12793 m_pEM_OverZoom->x = 4;
12794 m_pEM_OverZoom->y = 0;
12796 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12797 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12800 return m_pEM_OverZoom;
12803void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12816 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12817 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12821 AISDrawAreaNotices(dc, GetVP(),
this);
12823 wxDC *pdc = dc.GetDC();
12825 pdc->DestroyClippingRegion();
12826 wxDCClipper(*pdc, ru);
12829 if (m_bShowNavobjects) {
12830 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12831 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12832 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12833 DrawAnchorWatchPoints(dc);
12835 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12836 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12839 AISDraw(dc, GetVP(),
this);
12843 RenderVisibleSectorLights(dc);
12845 RenderAllChartOutlines(dc, GetVP());
12846 RenderRouteLegs(dc);
12847 RenderShipToActive(dc,
false);
12849 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12851 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12855 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12856 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12859 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12864 RebuildTideSelectList(GetVP().GetBBox());
12865 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12868 if (m_bShowCurrent) {
12869 RebuildCurrentSelectList(GetVP().GetBBox());
12870 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12873 if (!g_PrintingInProgress) {
12874 if (IsPrimaryCanvas()) {
12878 if (IsPrimaryCanvas()) {
12882 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12884 if (m_pTrackRolloverWin) {
12885 m_pTrackRolloverWin->Draw(dc);
12886 m_brepaint_piano =
true;
12889 if (m_pRouteRolloverWin) {
12890 m_pRouteRolloverWin->Draw(dc);
12891 m_brepaint_piano =
true;
12894 if (m_pAISRolloverWin) {
12895 m_pAISRolloverWin->Draw(dc);
12896 m_brepaint_piano =
true;
12898 if (m_brepaint_piano && g_bShowChartBar) {
12899 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12902 if (m_Compass) m_Compass->Paint(dc);
12904 if (!g_CanvasHideNotificationIcon) {
12905 if (IsPrimaryCanvas()) {
12906 auto ¬eman = NotificationManager::GetInstance();
12907 if (noteman.GetNotificationCount()) {
12908 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12909 if (m_notification_button->UpdateStatus()) Refresh();
12910 m_notification_button->Show(
true);
12911 m_notification_button->Paint(dc);
12913 m_notification_button->Show(
false);
12919 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12925 if (!m_bShowDepthUnits)
return NULL;
12927 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12929 if (GetQuiltMode()) {
12930 wxString s = m_pQuilt->GetQuiltDepthUnit();
12933 depth_unit_type = DEPTH_UNIT_FEET;
12934 else if (s.StartsWith(
"FATHOMS"))
12935 depth_unit_type = DEPTH_UNIT_FATHOMS;
12936 else if (s.StartsWith(
"METERS"))
12937 depth_unit_type = DEPTH_UNIT_METERS;
12938 else if (s.StartsWith(
"METRES"))
12939 depth_unit_type = DEPTH_UNIT_METERS;
12940 else if (s.StartsWith(
"METRIC"))
12941 depth_unit_type = DEPTH_UNIT_METERS;
12942 else if (s.StartsWith(
"METER"))
12943 depth_unit_type = DEPTH_UNIT_METERS;
12946 if (m_singleChart) {
12947 depth_unit_type = m_singleChart->GetDepthUnitType();
12948 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12949 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12954 switch (depth_unit_type) {
12955 case DEPTH_UNIT_FEET:
12958 case DEPTH_UNIT_METERS:
12959 ped = m_pEM_Meters;
12961 case DEPTH_UNIT_FATHOMS:
12962 ped = m_pEM_Fathoms;
12968 ped->x = (GetVP().
pix_width - ped->width);
12970 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12971 wxRect r = m_Compass->
GetRect();
12972 ped->y = r.y + r.height;
12979void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12982 if (style->embossFont == wxEmptyString) {
12983 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12985 font.SetPointSize(60);
12986 font.SetWeight(wxFONTWEIGHT_BOLD);
12988 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12989 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12991 int emboss_width = 500;
12992 int emboss_height = 200;
12996 delete m_pEM_Meters;
12997 delete m_pEM_Fathoms;
13001 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
13003 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
13005 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
13008#define OVERZOOM_TEXT _("OverZoom")
13010void ChartCanvas::SetOverzoomFont() {
13015 if (style->embossFont == wxEmptyString) {
13016 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13018 font.SetPointSize(40);
13019 font.SetWeight(wxFONTWEIGHT_BOLD);
13021 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13022 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13024 wxClientDC dc(
this);
13026 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13028 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13029 font.SetPointSize(font.GetPointSize() - 1);
13031 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13033 m_overzoomFont = font;
13034 m_overzoomTextWidth = w;
13035 m_overzoomTextHeight = h;
13038void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13039 delete m_pEM_OverZoom;
13041 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13043 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13044 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13047emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13048 int height,
const wxString &str,
13053 wxBitmap bmp(width, height, -1);
13056 wxMemoryDC temp_dc;
13057 temp_dc.SelectObject(bmp);
13060 temp_dc.SetBackground(*wxWHITE_BRUSH);
13061 temp_dc.SetTextBackground(*wxWHITE);
13062 temp_dc.SetTextForeground(*wxBLACK);
13066 temp_dc.SetFont(font);
13069 temp_dc.GetTextExtent(str, &str_w, &str_h);
13071 temp_dc.DrawText(str, 1, 1);
13074 temp_dc.SelectObject(wxNullBitmap);
13077 wxImage img = bmp.ConvertToImage();
13079 int image_width = str_w * 105 / 100;
13080 int image_height = str_h * 105 / 100;
13081 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13082 wxMin(image_height, img.GetHeight()));
13083 wxImage imgs = img.GetSubImage(r);
13087 case GLOBAL_COLOR_SCHEME_DAY:
13091 case GLOBAL_COLOR_SCHEME_DUSK:
13094 case GLOBAL_COLOR_SCHEME_NIGHT:
13101 const int w = imgs.GetWidth();
13102 const int h = imgs.GetHeight();
13103 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13108 for (
int y = 1; y < h - 1; y++) {
13109 for (
int x = 1; x < w - 1; x++) {
13111 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13112 val = (int)(val * val_factor);
13113 index = (y * w) + x;
13126void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13127 Track *active_track = NULL;
13130 active_track = pTrackDraw;
13134 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13137 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13140void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13141 Track *active_track = NULL;
13144 active_track = pTrackDraw;
13148 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13151void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13152 Route *active_route = NULL;
13154 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13155 active_route = pRouteDraw;
13160 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13165 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13168void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13169 Route *active_route = NULL;
13172 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13173 active_route = pRouteDraw;
13177 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13180void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13181 if (!pWayPointMan)
return;
13183 auto node = pWayPointMan->GetWaypointList()->begin();
13185 while (node != pWayPointMan->GetWaypointList()->end()) {
13194 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13198 if (pWP->GetShowWaypointRangeRings() &&
13199 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13200 double factor = 1.00;
13201 if (pWP->GetWaypointRangeRingsStepUnits() ==
13203 factor = 1 / 1.852;
13205 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13206 pWP->GetWaypointRangeRingsStep() / 60.;
13210 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13211 pWP->m_lat + radius, pWP->m_lon + radius);
13212 if (!BltBBox.IntersectOut(radar_box)) {
13223void ChartCanvas::DrawBlinkObjects() {
13225 wxRect update_rect;
13227 if (!pWayPointMan)
return;
13229 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13236 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13239void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13244 wxPoint lAnchorPoint1, lAnchorPoint2;
13258 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13259 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13261 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13262 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13263 dc.SetBrush(*ppBrush);
13267 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13272 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13277 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13282 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13287double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13290 wxPoint lAnchorPoint;
13293 double tlat1, tlon1;
13295 if (pAnchorWatchPoint) {
13296 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13298 dabs = fabs(d1 / 1852.);
13299 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13304 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13305 pow((
double)(lAnchorPoint.y - r1.y), 2));
13308 if (d1 < 0) lpp = -lpp;
13316void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13319 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13321 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13327 if ((type ==
't') || (type ==
'T')) {
13328 if (BBox.Contains(lat, lon)) {
13330 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13336void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13339 wxDateTime this_now = gTimeSource;
13340 bool cur_time = !gTimeSource.IsValid();
13341 if (cur_time) this_now = wxDateTime::Now();
13342 time_t t_this_now = this_now.GetTicks();
13344 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13346 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13347 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13348 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13349 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13351 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13352 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13353 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13354 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13355 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13356 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13358 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13359 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13360 int font_size = wxMax(10, dFont->GetPointSize());
13363 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13364 false, dFont->GetFaceName());
13366 dc.SetPen(*pblack_pen);
13367 dc.SetBrush(*pgreen_brush);
13371 case GLOBAL_COLOR_SCHEME_DAY:
13374 case GLOBAL_COLOR_SCHEME_DUSK:
13377 case GLOBAL_COLOR_SCHEME_NIGHT:
13378 bm = m_bmTideNight;
13385 int bmw = bm.GetWidth();
13386 int bmh = bm.GetHeight();
13388 float scale_factor = 1.0;
13392 float icon_pixelRefDim = 45;
13397 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13399 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13401 scale_factor *= pix_factor;
13408 scale_factor *= user_scale_factor;
13409 scale_factor *= GetContentScaleFactor();
13412 double marge = 0.05;
13413 std::vector<LLBBox> drawn_boxes;
13414 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13418 if ((type ==
't') || (type ==
'T'))
13423 if (BBox.ContainsMarge(lat, lon, marge)) {
13425 if (GetVP().chart_scale < 500000) {
13426 bool bdrawn =
false;
13427 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13428 if (drawn_boxes[i].Contains(lat, lon)) {
13433 if (bdrawn)
continue;
13436 this_box.Set(lat, lon, lat, lon);
13437 this_box.EnLarge(.005);
13438 drawn_boxes.push_back(this_box);
13444 if (GetVP().chart_scale > 500000) {
13445 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13449 dc.SetFont(*plabelFont);
13461 if (
ptcmgr->GetTideFlowSens(
13462 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13466 ptcmgr->GetHightOrLowTide(
13467 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13468 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13480 if (tctime > t_this_now)
13481 ptcmgr->GetHightOrLowTide(
13482 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13483 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13487 ptcmgr->GetHightOrLowTide(
13488 t_this_now, FORWARD_TEN_MINUTES_STEP,
13489 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13503 int width = (int)(12 * scale_factor + 0.5);
13504 int height = (int)(45 * scale_factor + 0.5);
13505 int linew = wxMax(1, (
int)(scale_factor));
13506 int xDraw = r.x - (width / 2);
13507 int yDraw = r.y - (height / 2);
13510 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13511 int hs = (httime > lttime) ? -4 : 4;
13512 hs *= (int)(scale_factor + 0.5);
13513 if (ts > 0.995 || ts < 0.005) hs = 0;
13514 int ht_y = (int)(height * ts);
13517 pblack_pen->SetWidth(linew);
13518 dc.SetPen(*pblack_pen);
13519 dc.SetBrush(*pyelo_brush);
13520 dc.DrawRectangle(xDraw, yDraw, width, height);
13524 dc.SetPen(*pblue_pen);
13525 dc.SetBrush(*pblue_brush);
13526 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13527 (width - (4 * linew)), height - ht_y);
13533 arrow[0].x = xDraw + 2 * linew;
13534 arrow[1].x = xDraw + width / 2;
13535 arrow[2].x = xDraw + width - 2 * linew;
13536 pyelo_pen->SetWidth(linew);
13537 pblue_pen->SetWidth(linew);
13538 if (ts > 0.35 || ts < 0.15)
13540 hl = (int)(height * 0.25) + yDraw;
13542 arrow[1].y = hl + hs;
13545 dc.SetPen(*pyelo_pen);
13547 dc.SetPen(*pblue_pen);
13548 dc.DrawLines(3, arrow);
13550 if (ts > 0.60 || ts < 0.40)
13552 hl = (int)(height * 0.5) + yDraw;
13554 arrow[1].y = hl + hs;
13557 dc.SetPen(*pyelo_pen);
13559 dc.SetPen(*pblue_pen);
13560 dc.DrawLines(3, arrow);
13562 if (ts < 0.65 || ts > 0.85)
13564 hl = (int)(height * 0.75) + yDraw;
13566 arrow[1].y = hl + hs;
13569 dc.SetPen(*pyelo_pen);
13571 dc.SetPen(*pblue_pen);
13572 dc.DrawLines(3, arrow);
13576 s.Printf(
"%3.1f", nowlev);
13578 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13580 dc.GetTextExtent(s, &wx1, NULL);
13582 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13597void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13600 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13602 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13608 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13609 if ((BBox.Contains(lat, lon))) {
13611 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13617void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13620 float tcvalue, dir;
13624 double lon_last = 0.;
13625 double lat_last = 0.;
13627 double marge = 0.2;
13628 bool cur_time = !gTimeSource.IsValid();
13630 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13631 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13633 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13635 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13636 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13637 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13638 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13639 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13640 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13641 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13642 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13644 double skew_angle = GetVPRotation();
13646 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13647 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13648 int font_size = wxMax(10, dFont->GetPointSize());
13651 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13652 false, dFont->GetFaceName());
13654 float scale_factor = 1.0;
13660 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13662 float nominal_icon_size_pixels = 15;
13663 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13665 scale_factor *= pix_factor;
13672 scale_factor *= user_scale_factor;
13674 scale_factor *= GetContentScaleFactor();
13677 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13683 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13684 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13689 int dd = (int)(5.0 * scale_factor + 0.5);
13700 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13701 dc.SetPen(*pblack_pen);
13702 dc.SetBrush(*porange_brush);
13703 dc.DrawPolygon(4, d);
13706 dc.SetBrush(*pblack_brush);
13707 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13711 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13725 double a1 = fabs(tcvalue) * 10.;
13727 a1 = wxMax(1.0, a1);
13728 double a2 = log10(a1);
13730 float cscale = scale_factor * a2 * 0.3;
13732 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13733 dc.SetPen(*porange_pen);
13734 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13738 if (bDrawCurrentValues) {
13739 dc.SetFont(*pTCFont);
13740 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13741 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13767 if (!pvIDX)
return;
13772 if (pCwin && pCwin->IsShown()) {
13780 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13795 pCwin =
new TCWin(
this, x, y, pvIDX);
13813#define NUM_CURRENT_ARROW_POINTS 9
13814static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13815 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13816 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13817 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13819void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13821 if (
scale > 1e-2) {
13822 float sin_rot = sin(rot_angle * PI / 180.);
13823 float cos_rot = cos(rot_angle * PI / 180.);
13827 float xt = CurrentArrowArray[0].x;
13828 float yt = CurrentArrowArray[0].y;
13830 float xp = (xt * cos_rot) - (yt * sin_rot);
13831 float yp = (xt * sin_rot) + (yt * cos_rot);
13832 int x1 = (int)(xp *
scale);
13833 int y1 = (int)(yp *
scale);
13836 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13837 xt = CurrentArrowArray[ip].x;
13838 yt = CurrentArrowArray[ip].y;
13840 float xp = (xt * cos_rot) - (yt * sin_rot);
13841 float yp = (xt * sin_rot) + (yt * cos_rot);
13842 int x2 = (int)(xp *
scale);
13843 int y2 = (int)(yp *
scale);
13845 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13853wxString ChartCanvas::FindValidUploadPort() {
13856 if (!g_uploadConnection.IsEmpty() &&
13857 g_uploadConnection.StartsWith(
"Serial")) {
13858 port = g_uploadConnection;
13864 for (
auto *cp : TheConnectionParams()) {
13865 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13866 port <<
"Serial:" << cp->Port;
13872void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13875 if (NULL == g_pais_query_dialog_active) {
13876 int pos_x = g_ais_query_dialog_x;
13877 int pos_y = g_ais_query_dialog_y;
13879 if (g_pais_query_dialog_active) {
13880 g_pais_query_dialog_active->Destroy();
13886 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13887 wxPoint(pos_x, pos_y));
13889 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13890 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13891 g_pais_query_dialog_active->SetMMSI(mmsi);
13892 g_pais_query_dialog_active->UpdateText();
13893 wxSize sz = g_pais_query_dialog_active->GetSize();
13895 bool b_reset_pos =
false;
13900 RECT frame_title_rect;
13901 frame_title_rect.left = pos_x;
13902 frame_title_rect.top = pos_y;
13903 frame_title_rect.right = pos_x + sz.x;
13904 frame_title_rect.bottom = pos_y + 30;
13906 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13907 b_reset_pos =
true;
13912 wxRect window_title_rect;
13913 window_title_rect.x = pos_x;
13914 window_title_rect.y = pos_y;
13915 window_title_rect.width = sz.x;
13916 window_title_rect.height = 30;
13918 wxRect ClientRect = wxGetClientDisplayRect();
13919 ClientRect.Deflate(
13921 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13925 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13928 g_pais_query_dialog_active->SetMMSI(mmsi);
13929 g_pais_query_dialog_active->UpdateText();
13932 g_pais_query_dialog_active->Show();
13935void ChartCanvas::ToggleCanvasQuiltMode() {
13936 bool cur_mode = GetQuiltMode();
13938 if (!GetQuiltMode())
13939 SetQuiltMode(
true);
13940 else if (GetQuiltMode()) {
13941 SetQuiltMode(
false);
13942 g_sticky_chart = GetQuiltReferenceChartIndex();
13945 if (cur_mode != GetQuiltMode()) {
13946 SetupCanvasQuiltMode();
13955 if (ps52plib) ps52plib->GenerateStateHash();
13957 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13958 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13961void ChartCanvas::DoCanvasStackDelta(
int direction) {
13962 if (!GetQuiltMode()) {
13963 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13964 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13965 if ((current_stack_index + direction) < 0)
return;
13967 if (m_bpersistent_quilt ) {
13969 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13971 if (IsChartQuiltableRef(new_dbIndex)) {
13972 ToggleCanvasQuiltMode();
13973 SelectQuiltRefdbChart(new_dbIndex);
13974 m_bpersistent_quilt =
false;
13977 SelectChartFromStack(current_stack_index + direction);
13980 std::vector<int> piano_chart_index_array =
13981 GetQuiltExtendedStackdbIndexArray();
13982 int refdb = GetQuiltRefChartdbIndex();
13985 int current_index = -1;
13986 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13987 if (refdb == piano_chart_index_array[i]) {
13992 if (current_index == -1)
return;
13995 int target_family = ctet.GetChartFamily();
13997 int new_index = -1;
13998 int check_index = current_index + direction;
13999 bool found =
false;
14000 int check_dbIndex = -1;
14001 int new_dbIndex = -1;
14005 (
unsigned int)check_index < piano_chart_index_array.size() &&
14006 (check_index >= 0)) {
14007 check_dbIndex = piano_chart_index_array[check_index];
14009 if (target_family == cte.GetChartFamily()) {
14011 new_index = check_index;
14012 new_dbIndex = check_dbIndex;
14016 check_index += direction;
14019 if (!found)
return;
14021 if (!IsChartQuiltableRef(new_dbIndex)) {
14022 ToggleCanvasQuiltMode();
14023 SelectdbChart(new_dbIndex);
14024 m_bpersistent_quilt =
true;
14026 SelectQuiltRefChart(new_index);
14031 top_frame::Get()->UpdateGlobalMenuItems();
14032 SetQuiltChartHiLiteIndex(-1);
14043void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14046 switch (event.GetId()) {
14058 DoCanvasStackDelta(1);
14063 DoCanvasStackDelta(-1);
14073 ShowCurrents(!GetbShowCurrent());
14080 ShowTides(!GetbShowTide());
14087 if (0 == m_routeState) {
14094 androidSetRouteAnnunciator(m_routeState == 1);
14100 SetAISCanvasDisplayStyle(-1);
14112void ChartCanvas::SetShowAIS(
bool show) {
14114 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14115 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14118void ChartCanvas::SetAttenAIS(
bool show) {
14119 m_bShowAISScaled = show;
14120 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14121 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14124void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14127 bool bShowAIS_Array[3] = {
true,
true,
false};
14128 bool bShowScaled_Array[3] = {
false,
true,
true};
14129 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14130 _(
"Attenuate less critical AIS targets"),
14131 _(
"Hide AIS Targets")};
14132 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14134 int AIS_Toolbar_Switch = 0;
14135 if (StyleIndx == -1) {
14137 for (
int i = 1; i < ArraySize; i++) {
14138 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14139 (bShowScaled_Array[i] == m_bShowAISScaled))
14140 AIS_Toolbar_Switch = i;
14142 AIS_Toolbar_Switch++;
14143 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14144 AIS_Toolbar_Switch++;
14147 AIS_Toolbar_Switch = StyleIndx;
14150 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14152 int AIS_Toolbar_Switch_Next =
14153 AIS_Toolbar_Switch + 1;
14154 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14155 AIS_Toolbar_Switch_Next++;
14156 if (AIS_Toolbar_Switch_Next >= ArraySize)
14157 AIS_Toolbar_Switch_Next = 0;
14160 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14161 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14164void ChartCanvas::TouchAISToolActive() {}
14166void ChartCanvas::UpdateAISTBTool() {}
14174void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14176 bool b_update =
false;
14177 int cc1_edge_comp = 2;
14178 wxRect rect = m_Compass->
GetRect();
14179 wxSize parent_size = GetSize();
14181 parent_size *= m_displayScale;
14185 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14186 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14187 wxRect compass_rect(compass_pt, rect.GetSize());
14189 m_Compass->Move(compass_pt);
14191 if (m_Compass && m_Compass->IsShown())
14192 m_Compass->UpdateStatus(b_force_new | b_update);
14194 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14195 scaler = wxMax(scaler, 1.0);
14196 wxPoint note_point = wxPoint(
14197 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14198 if (m_notification_button) {
14199 m_notification_button->Move(note_point);
14200 m_notification_button->UpdateStatus();
14203 if (b_force_new | b_update) Refresh();
14206void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14207 ChartTypeEnum New_Type,
14208 ChartFamilyEnum New_Family) {
14209 if (!GetpCurrentStack())
return;
14212 if (index < GetpCurrentStack()->nEntry) {
14215 pTentative_Chart =
ChartData->OpenStackChartConditional(
14216 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14218 if (pTentative_Chart) {
14219 if (m_singleChart) m_singleChart->Deactivate();
14221 m_singleChart = pTentative_Chart;
14222 m_singleChart->Activate();
14224 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14225 GetpCurrentStack(), m_singleChart->GetFullPath());
14238 double best_scale_ppm = GetBestVPScale(m_singleChart);
14239 double rotation = GetVPRotation();
14240 double oldskew = GetVPSkew();
14241 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14243 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14244 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14245 if (fabs(newskew) > 0.0001) rotation = newskew;
14248 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14250 UpdateGPSCompassStatusBox(
true);
14254 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14255 if (idx < 0)
return;
14257 std::vector<int> piano_active_chart_index_array;
14258 piano_active_chart_index_array.push_back(
14259 GetpCurrentStack()->GetCurrentEntrydbIndex());
14260 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14263void ChartCanvas::SelectdbChart(
int dbindex) {
14264 if (!GetpCurrentStack())
return;
14267 if (dbindex >= 0) {
14270 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14272 if (pTentative_Chart) {
14273 if (m_singleChart) m_singleChart->Deactivate();
14275 m_singleChart = pTentative_Chart;
14276 m_singleChart->Activate();
14278 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14279 GetpCurrentStack(), m_singleChart->GetFullPath());
14292 double best_scale_ppm = GetBestVPScale(m_singleChart);
14296 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14306void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14309 if (!GetQuiltMode()) {
14310 if (GetpCurrentStack()) {
14311 int stack_index = -1;
14312 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14313 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14314 if (check_dbIndex < 0)
continue;
14316 ChartData->GetChartTableEntry(check_dbIndex);
14317 if (type == cte.GetChartType()) {
14320 }
else if (family == cte.GetChartFamily()) {
14326 if (stack_index >= 0) {
14327 SelectChartFromStack(stack_index);
14331 int sel_dbIndex = -1;
14332 std::vector<int> piano_chart_index_array =
14333 GetQuiltExtendedStackdbIndexArray();
14334 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14335 int check_dbIndex = piano_chart_index_array[i];
14337 if (type == cte.GetChartType()) {
14338 if (IsChartQuiltableRef(check_dbIndex)) {
14339 sel_dbIndex = check_dbIndex;
14342 }
else if (family == cte.GetChartFamily()) {
14343 if (IsChartQuiltableRef(check_dbIndex)) {
14344 sel_dbIndex = check_dbIndex;
14350 if (sel_dbIndex >= 0) {
14351 SelectQuiltRefdbChart(sel_dbIndex,
false);
14353 AdjustQuiltRefChart();
14360 SetQuiltChartHiLiteIndex(-1);
14365bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14366 return std::find(m_tile_yesshow_index_array.begin(),
14367 m_tile_yesshow_index_array.end(),
14368 index) != m_tile_yesshow_index_array.end();
14371bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14372 return std::find(m_tile_noshow_index_array.begin(),
14373 m_tile_noshow_index_array.end(),
14374 index) != m_tile_noshow_index_array.end();
14377void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14378 if (std::find(m_tile_noshow_index_array.begin(),
14379 m_tile_noshow_index_array.end(),
14380 index) == m_tile_noshow_index_array.end()) {
14381 m_tile_noshow_index_array.push_back(index);
14391void ChartCanvas::HandlePianoClick(
14392 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14395 if (!m_pCurrentStack)
return;
14411 double distance = 25000;
14412 int closest_index = -1;
14413 for (
int chart_index : selected_dbIndex_array) {
14415 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14416 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14419 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14420 if (test_distance < distance) {
14421 distance = test_distance;
14422 closest_index = chart_index;
14426 int selected_dbIndex = selected_dbIndex_array[0];
14427 if (closest_index >= 0) selected_dbIndex = closest_index;
14429 if (!GetQuiltMode()) {
14430 if (m_bpersistent_quilt ) {
14431 if (IsChartQuiltableRef(selected_dbIndex)) {
14432 ToggleCanvasQuiltMode();
14433 SelectQuiltRefdbChart(selected_dbIndex);
14434 m_bpersistent_quilt =
false;
14436 SelectChartFromStack(selected_index);
14439 SelectChartFromStack(selected_index);
14440 g_sticky_chart = selected_dbIndex;
14444 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14448 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14449 bool bfound =
false;
14450 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14451 if (m_tile_noshow_index_array[i] ==
14452 selected_dbIndex) {
14453 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14460 m_tile_noshow_index_array.push_back(selected_dbIndex);
14464 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14465 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14469 if (IsChartQuiltableRef(selected_dbIndex)) {
14475 bool set_scale =
false;
14476 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14477 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14483 SelectQuiltRefdbChart(selected_dbIndex,
true);
14485 SelectQuiltRefdbChart(selected_dbIndex,
false);
14490 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14492 double proposed_scale_onscreen =
14495 if (g_bPreserveScaleOnX) {
14496 proposed_scale_onscreen =
14497 wxMin(proposed_scale_onscreen,
14499 GetCanvasWidth()));
14501 proposed_scale_onscreen =
14502 wxMin(proposed_scale_onscreen,
14504 GetCanvasWidth()));
14506 proposed_scale_onscreen =
14507 wxMax(proposed_scale_onscreen,
14516 ToggleCanvasQuiltMode();
14517 SelectdbChart(selected_dbIndex);
14518 m_bpersistent_quilt =
true;
14523 SetQuiltChartHiLiteIndex(-1);
14525 top_frame::Get()->UpdateGlobalMenuItems();
14526 HideChartInfoWindow();
14531void ChartCanvas::HandlePianoRClick(
14532 int x,
int y,
int selected_index,
14533 const std::vector<int> &selected_dbIndex_array) {
14536 if (!GetpCurrentStack())
return;
14538 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14539 UpdateCanvasControlBar();
14541 SetQuiltChartHiLiteIndex(-1);
14544void ChartCanvas::HandlePianoRollover(
14545 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14546 int n_charts,
int scale) {
14549 if (!GetpCurrentStack())
return;
14554 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14556 if (!GetQuiltMode()) {
14557 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14560 std::vector<int> piano_chart_index_array;
14561 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14562 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14563 if ((GetpCurrentStack()->nEntry > 1) ||
14564 (piano_chart_index_array.size() >= 1)) {
14565 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14567 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14569 }
else if (GetpCurrentStack()->nEntry == 1) {
14571 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14572 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14573 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14575 }
else if ((-1 == selected_index) &&
14576 (0 == selected_dbIndex_array.size())) {
14577 ShowChartInfoWindow(key_location.x, -1);
14581 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14583 if ((GetpCurrentStack()->nEntry > 1) ||
14584 (piano_chart_index_array.size() >= 1)) {
14586 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14587 selected_dbIndex_array);
14588 else if (n_charts == 1)
14589 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14591 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14598void ChartCanvas::ClearPianoRollover() {
14599 ClearQuiltChartHiLiteIndexArray();
14600 ShowChartInfoWindow(0, -1);
14601 std::vector<int> vec;
14602 ShowCompositeInfoWindow(0, 0, 0, vec);
14606void ChartCanvas::UpdateCanvasControlBar() {
14607 if (m_pianoFrozen)
return;
14609 if (!GetpCurrentStack())
return;
14611 if (!g_bShowChartBar)
return;
14614 int sel_family = -1;
14616 std::vector<int> piano_chart_index_array;
14617 std::vector<int> empty_piano_chart_index_array;
14619 wxString old_hash = m_Piano->GetStoredHash();
14621 if (GetQuiltMode()) {
14622 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14623 GetQuiltFullScreendbIndexArray());
14625 std::vector<int> piano_active_chart_index_array =
14626 GetQuiltCandidatedbIndexArray();
14627 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14629 std::vector<int> piano_eclipsed_chart_index_array =
14630 GetQuiltEclipsedStackdbIndexArray();
14631 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14633 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14634 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14636 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14637 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14639 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14640 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14643 if (m_singleChart) {
14644 sel_type = m_singleChart->GetChartType();
14645 sel_family = m_singleChart->GetChartFamily();
14650 std::vector<int> piano_skew_chart_index_array;
14651 std::vector<int> piano_tmerc_chart_index_array;
14652 std::vector<int> piano_poly_chart_index_array;
14654 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14656 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14657 double skew_norm = ctei.GetChartSkew();
14658 if (skew_norm > 180.) skew_norm -= 360.;
14660 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14661 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14664 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14665 if (fabs(skew_norm) > 1.)
14666 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14668 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14669 }
else if (fabs(skew_norm) > 1.)
14670 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14672 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14673 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14674 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14676 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14677 if (new_hash != old_hash) {
14678 m_Piano->FormatKeys();
14679 HideChartInfoWindow();
14680 m_Piano->ResetRollover();
14681 SetQuiltChartHiLiteIndex(-1);
14682 m_brepaint_piano =
true;
14688 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14690 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14691 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14692 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14693 if (e == CHART_FAMILY_RASTER) mask |= 1;
14694 if (e == CHART_FAMILY_VECTOR) {
14695 if (t == CHART_TYPE_CM93COMP)
14702 wxString s_indicated;
14703 if (sel_type == CHART_TYPE_CM93COMP)
14704 s_indicated =
"cm93";
14706 if (sel_family == CHART_FAMILY_RASTER)
14707 s_indicated =
"raster";
14708 else if (sel_family == CHART_FAMILY_VECTOR)
14709 s_indicated =
"vector";
14712 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14715void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14717void ChartCanvas::PianoPopupMenu(
14718 int x,
int y,
int selected_index,
14719 const std::vector<int> &selected_dbIndex_array) {
14720 if (!GetpCurrentStack())
return;
14723 if (!GetQuiltMode())
return;
14725 m_piano_ctx_menu =
new wxMenu();
14727 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14737 menu_selected_dbIndex = selected_dbIndex_array[0];
14738 menu_selected_index = selected_index;
14741 bool b_is_in_noshow =
false;
14742 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14743 if (m_quilt_noshow_index_array[i] ==
14744 menu_selected_dbIndex)
14746 b_is_in_noshow =
true;
14751 if (b_is_in_noshow) {
14752 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14753 _(
"Show This Chart"));
14754 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14755 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14756 }
else if (GetpCurrentStack()->nEntry > 1) {
14757 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14758 _(
"Hide This Chart"));
14759 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14760 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14764 wxPoint pos = wxPoint(x, y - 30);
14767 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14768 PopupMenu(m_piano_ctx_menu, pos);
14770 delete m_piano_ctx_menu;
14771 m_piano_ctx_menu = NULL;
14773 HideChartInfoWindow();
14774 m_Piano->ResetRollover();
14776 SetQuiltChartHiLiteIndex(-1);
14777 ClearQuiltChartHiLiteIndexArray();
14782void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14783 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14784 if (m_quilt_noshow_index_array[i] ==
14785 menu_selected_dbIndex)
14787 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14793void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14794 if (!GetpCurrentStack())
return;
14797 RemoveChartFromQuilt(menu_selected_dbIndex);
14801 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14802 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14804 int i = menu_selected_index + 1;
14805 bool b_success =
false;
14806 while (i < GetpCurrentStack()->nEntry - 1) {
14807 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14808 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14809 SelectQuiltRefChart(i);
14819 i = menu_selected_index - 1;
14821 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14822 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14823 SelectQuiltRefChart(i);
14833void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14835 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14836 if (m_quilt_noshow_index_array[i] ==
14839 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14844 m_quilt_noshow_index_array.push_back(dbIndex);
14847bool ChartCanvas::UpdateS52State() {
14848 bool retval =
false;
14851 ps52plib->SetShowS57Text(m_encShowText);
14852 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14853 ps52plib->m_bShowSoundg = m_encShowDepth;
14854 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14855 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14858 if (!m_encShowLights)
14859 ps52plib->AddObjNoshow(
"LIGHTS");
14861 ps52plib->RemoveObjNoshow(
"LIGHTS");
14862 ps52plib->SetLightsOff(!m_encShowLights);
14863 ps52plib->m_bExtendLightSectors =
true;
14866 ps52plib->SetAnchorOn(m_encShowAnchor);
14867 ps52plib->SetQualityOfData(m_encShowDataQual);
14873void ChartCanvas::SetShowENCDataQual(
bool show) {
14874 m_encShowDataQual = show;
14875 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14876 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14878 m_s52StateHash = 0;
14881void ChartCanvas::SetShowENCText(
bool show) {
14882 m_encShowText = show;
14883 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14884 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14886 m_s52StateHash = 0;
14889void ChartCanvas::SetENCDisplayCategory(
int category) {
14890 m_encDisplayCategory = category;
14891 m_s52StateHash = 0;
14894void ChartCanvas::SetShowENCDepth(
bool show) {
14895 m_encShowDepth = show;
14896 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14897 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14899 m_s52StateHash = 0;
14902void ChartCanvas::SetShowENCLightDesc(
bool show) {
14903 m_encShowLightDesc = show;
14904 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14905 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14907 m_s52StateHash = 0;
14910void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14911 m_encShowBuoyLabels = show;
14912 m_s52StateHash = 0;
14915void ChartCanvas::SetShowENCLights(
bool show) {
14916 m_encShowLights = show;
14917 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14918 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14920 m_s52StateHash = 0;
14923void ChartCanvas::SetShowENCAnchor(
bool show) {
14924 m_encShowAnchor = show;
14925 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14926 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14928 m_s52StateHash = 0;
14931wxRect ChartCanvas::GetMUIBarRect() {
14934 rv = m_muiBar->GetRect();
14940void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14941 if (!GetAlertString().IsEmpty()) {
14942 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14943 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14945 dc.SetFont(*pfont);
14946 dc.SetPen(*wxTRANSPARENT_PEN);
14948 dc.SetBrush(wxColour(243, 229, 47));
14950 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14954 wxRect sbr = GetScaleBarRect();
14955 int xp = sbr.x + sbr.width + 10;
14956 int yp = (sbr.y + sbr.height) - h;
14958 int wdraw = w + 10;
14959 dc.DrawRectangle(xp, yp, wdraw, h);
14960 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14961 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14971#define BRIGHT_XCALIB
14972#define __OPCPN_USEICC__
14975#ifdef __OPCPN_USEICC__
14976int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14977 double co_green,
double co_blue);
14979wxString temp_file_name;
14983class ocpnCurtain:
public wxDialog
14985 DECLARE_CLASS( ocpnCurtain )
14986 DECLARE_EVENT_TABLE()
14989 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14991 bool ProcessEvent(wxEvent& event);
14995IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14997BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
15000ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
15002 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
15005ocpnCurtain::~ocpnCurtain()
15009bool ocpnCurtain::ProcessEvent(wxEvent& event)
15011 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
15012 return GetParent()->GetEventHandler()->ProcessEvent(event);
15017#include <windows.h>
15020typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15021typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15022SetDeviceGammaRamp_ptr_type
15023 g_pSetDeviceGammaRamp;
15024GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15026WORD *g_pSavedGammaMap;
15030int InitScreenBrightness() {
15033 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15037 if (NULL == hGDI32DLL) {
15038 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15040 if (NULL != hGDI32DLL) {
15042 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15043 hGDI32DLL,
"SetDeviceGammaRamp");
15044 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15045 hGDI32DLL,
"GetDeviceGammaRamp");
15048 if ((NULL == g_pSetDeviceGammaRamp) ||
15049 (NULL == g_pGetDeviceGammaRamp)) {
15050 FreeLibrary(hGDI32DLL);
15059 if (!g_pSavedGammaMap) {
15060 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15063 bbr = g_pGetDeviceGammaRamp(
15064 hDC, g_pSavedGammaMap);
15065 ReleaseDC(NULL, hDC);
15070 wxRegKey *pRegKey =
new wxRegKey(
15071 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15072 "NT\\CurrentVersion\\ICM");
15073 if (!pRegKey->Exists()) pRegKey->Create();
15074 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15076 g_brightness_init =
true;
15082 if (NULL == g_pcurtain) {
15083 if (top_frame::Get()->CanSetTransparent()) {
15085 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15086 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15087 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15088 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15095 g_pcurtain->Hide();
15097 HWND hWnd = GetHwndOf(g_pcurtain);
15098 SetWindowLong(hWnd, GWL_EXSTYLE,
15099 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15100 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15101 g_pcurtain->SetTransparent(0);
15103 g_pcurtain->Maximize();
15104 g_pcurtain->Show();
15107 g_pcurtain->Enable();
15108 g_pcurtain->Disable();
15110 top_frame::Get()->Disable();
15111 top_frame::Get()->Enable();
15115 g_brightness_init =
true;
15121 wxString cmd(
"xcalib -version");
15123 wxArrayString output;
15124 long r = wxExecute(cmd, output);
15127 " External application \"xcalib\" not found. Screen brightness "
15130 g_brightness_init =
true;
15135int RestoreScreenBrightness() {
15138 if (g_pSavedGammaMap) {
15139 HDC hDC = GetDC(NULL);
15140 g_pSetDeviceGammaRamp(hDC,
15142 ReleaseDC(NULL, hDC);
15144 free(g_pSavedGammaMap);
15145 g_pSavedGammaMap = NULL;
15149 g_pcurtain->Close();
15150 g_pcurtain->Destroy();
15154 g_brightness_init =
false;
15159#ifdef BRIGHT_XCALIB
15160 if (g_brightness_init) {
15162 cmd =
"xcalib -clear";
15163 wxExecute(cmd, wxEXEC_ASYNC);
15164 g_brightness_init =
false;
15174int SetScreenBrightness(
int brightness) {
15181 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15183 g_pcurtain->Close();
15184 g_pcurtain->Destroy();
15188 InitScreenBrightness();
15190 if (NULL == hGDI32DLL) {
15192 wchar_t wdll_name[80];
15193 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15194 LPCWSTR cstr = wdll_name;
15196 hGDI32DLL = LoadLibrary(cstr);
15198 if (NULL != hGDI32DLL) {
15200 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15201 hGDI32DLL,
"SetDeviceGammaRamp");
15202 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15203 hGDI32DLL,
"GetDeviceGammaRamp");
15206 if ((NULL == g_pSetDeviceGammaRamp) ||
15207 (NULL == g_pGetDeviceGammaRamp)) {
15208 FreeLibrary(hGDI32DLL);
15215 HDC hDC = GetDC(NULL);
15226 int increment = brightness * 256 / 100;
15229 WORD GammaTable[3][256];
15232 for (
int i = 0; i < 256; i++) {
15233 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15234 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15235 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15237 table_val += increment;
15239 if (table_val > 65535) table_val = 65535;
15242 g_pSetDeviceGammaRamp(hDC, GammaTable);
15243 ReleaseDC(NULL, hDC);
15250 if (g_pSavedGammaMap) {
15251 HDC hDC = GetDC(NULL);
15252 g_pSetDeviceGammaRamp(hDC,
15254 ReleaseDC(NULL, hDC);
15257 if (brightness < 100) {
15258 if (NULL == g_pcurtain) InitScreenBrightness();
15261 int sbrite = wxMax(1, brightness);
15262 sbrite = wxMin(100, sbrite);
15264 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15268 g_pcurtain->Close();
15269 g_pcurtain->Destroy();
15279#ifdef BRIGHT_XCALIB
15281 if (!g_brightness_init) {
15282 last_brightness = 100;
15283 g_brightness_init =
true;
15284 temp_file_name = wxFileName::CreateTempFileName(
"");
15285 InitScreenBrightness();
15288#ifdef __OPCPN_USEICC__
15291 if (!CreateSimpleICCProfileFile(
15292 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15293 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15294 wxString cmd(
"xcalib ");
15295 cmd += temp_file_name;
15297 wxExecute(cmd, wxEXEC_ASYNC);
15306 if (brightness > last_brightness) {
15308 cmd =
"xcalib -clear";
15309 wxExecute(cmd, wxEXEC_ASYNC);
15311 ::wxMilliSleep(10);
15313 int brite_adj = wxMax(1, brightness);
15314 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15315 wxExecute(cmd, wxEXEC_ASYNC);
15317 int brite_adj = wxMax(1, brightness);
15318 int factor = (brite_adj * 100) / last_brightness;
15319 factor = wxMax(1, factor);
15321 cmd.Printf(
"xcalib -co %2d -a", factor);
15322 wxExecute(cmd, wxEXEC_ASYNC);
15327 last_brightness = brightness;
15334#ifdef __OPCPN_USEICC__
15336#define MLUT_TAG 0x6d4c5554L
15337#define VCGT_TAG 0x76636774L
15339int GetIntEndian(
unsigned char *s) {
15344 p = (
unsigned char *)&ret;
15347 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15349 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15354unsigned short GetShortEndian(
unsigned char *s) {
15355 unsigned short ret;
15359 p = (
unsigned char *)&ret;
15362 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15364 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15370int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15371 double co_green,
double co_blue) {
15375 fp = fopen(file_name,
"wb");
15376 if (!fp)
return -1;
15382 for (
int i = 0; i < 128; i++) header[i] = 0;
15384 fwrite(header, 128, 1, fp);
15388 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15389 fwrite(&numTags, 1, 4, fp);
15391 int tagName0 = VCGT_TAG;
15392 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15393 fwrite(&tagName, 1, 4, fp);
15395 int tagOffset0 = 128 + 4 *
sizeof(int);
15396 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15397 fwrite(&tagOffset, 1, 4, fp);
15400 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15401 fwrite(&tagSize, 1, 4, fp);
15403 fwrite(&tagName, 1, 4, fp);
15405 fwrite(&tagName, 1, 4, fp);
15410 int gammatype0 = 0;
15411 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15412 fwrite(&gammatype, 1, 4, fp);
15414 int numChannels0 = 3;
15415 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15416 fwrite(&numChannels, 1, 2, fp);
15418 int numEntries0 = 256;
15419 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15420 fwrite(&numEntries, 1, 2, fp);
15422 int entrySize0 = 1;
15423 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15424 fwrite(&entrySize, 1, 2, fp);
15426 unsigned char ramp[256];
15429 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15430 fwrite(ramp, 256, 1, fp);
15433 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15434 fwrite(ramp, 256, 1, fp);
15437 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15438 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.