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) != 1) {
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);
8755 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8756 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8757 &rhumbBearing, &rhumbDist);
8758 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8759 rlat, &gcDist, &gcBearing, NULL);
8760 double gcDistNM = gcDist / 1852.0;
8763 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8764 pow(rhumbDist - gcDistNM - 1, 0.5);
8767 msg << _(
"For this leg the Great Circle route is ")
8769 << _(
" shorter than rhumbline.\n\n")
8770 << _(
"Would you like include the Great Circle routing points "
8773 m_FinishRouteOnKillFocus =
false;
8774 m_disable_edge_pan =
true;
8777 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8778 wxYES_NO | wxNO_DEFAULT);
8780 m_disable_edge_pan =
false;
8781 m_FinishRouteOnKillFocus =
true;
8783 if (answer == wxID_YES) {
8785 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8786 wxRealPoint gcCoord;
8788 for (
int i = 1; i <= segmentCount; i++) {
8789 double fraction = (double)i * (1.0 / (
double)segmentCount);
8790 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8791 gcDist * fraction, gcBearing,
8792 &gcCoord.x, &gcCoord.y, NULL);
8794 if (i < segmentCount) {
8795 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8797 gcPoint->SetNameShown(
false);
8799 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8801 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8804 gcPoint = pMousePoint;
8807 m_pMouseRoute->AddPoint(gcPoint);
8808 pSelect->AddSelectableRouteSegment(
8809 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8810 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8811 prevGcPoint = gcPoint;
8814 undo->CancelUndoableAction(
true);
8817 m_pMouseRoute->AddPoint(pMousePoint);
8818 pSelect->AddSelectableRouteSegment(
8819 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8820 pMousePoint, m_pMouseRoute);
8821 undo->AfterUndoableAction(m_pMouseRoute);
8825 m_pMouseRoute->AddPoint(pMousePoint);
8826 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8827 rlon, m_prev_pMousePoint,
8828 pMousePoint, m_pMouseRoute);
8829 undo->AfterUndoableAction(m_pMouseRoute);
8835 m_prev_pMousePoint = pMousePoint;
8843 int connect = tail->GetIndexOf(pMousePoint);
8848 int length = tail->GetnPoints();
8853 start = connect + 1;
8858 m_pMouseRoute->RemovePoint(
8862 for (i = start; i <= stop; i++) {
8863 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8866 m_pMouseRoute->GetnPoints();
8868 top_frame::Get()->RefreshAllCanvas();
8872 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8874 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8875 m_pMouseRoute->FinalizeForRendering();
8877 top_frame::Get()->RefreshAllCanvas();
8881 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8883 SetCursor(*pCursorPencil);
8885 if (!m_pMeasureRoute) {
8886 m_pMeasureRoute =
new Route();
8890 if (m_nMeasureState == 1) {
8897 wxEmptyString, wxEmptyString);
8899 pMousePoint->SetShowWaypointRangeRings(
false);
8901 m_pMeasureRoute->AddPoint(pMousePoint);
8905 m_prev_pMousePoint = pMousePoint;
8909 top_frame::Get()->RefreshAllCanvas();
8914 FindRoutePointsAtCursor(SelectRadius,
true);
8918 m_last_touch_down_pos =
event.GetPosition();
8920 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8928 if (ret)
return true;
8931 if (event.Dragging()) {
8934 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8936 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8938 SelectableItemList SelList =
pSelect->FindSelectionList(
8942 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8947 if (m_pRoutePointEditTarget &&
8948 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8950 SelectableItemList SelList =
pSelect->FindSelectionList(
8954 if (m_pRoutePointEditTarget == frp) {
8955 m_bIsInRadius =
true;
8960 if (!m_dragoffsetSet) {
8962 .PresetDragOffset(
this, mouse_x, mouse_y);
8963 m_dragoffsetSet =
true;
8968 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8969 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8972 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8974 DraggingAllowed =
false;
8976 if (m_pRoutePointEditTarget &&
8977 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8978 DraggingAllowed =
false;
8980 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8982 if (DraggingAllowed) {
8983 if (!undo->InUndoableAction()) {
8984 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8985 Undo_NeedsCopy, m_pFoundPoint);
8991 if (!g_bopengl && m_pEditRouteArray) {
8992 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8993 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9000 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9001 pre_rect.Union(route_rect);
9009 if (CheckEdgePan(x, y,
true, 5, 2))
9017 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9019 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9020 m_pRoutePointEditTarget,
9021 SELTYPE_DRAGHANDLE);
9022 m_pFoundPoint->m_slat =
9023 m_pRoutePointEditTarget->m_lat;
9024 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9026 m_pRoutePointEditTarget->m_lat =
9028 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9029 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9030 m_pFoundPoint->m_slat =
9032 m_pFoundPoint->m_slon = new_cursor_lon;
9048 if (m_pEditRouteArray) {
9049 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9051 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9054 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9055 post_rect.Union(route_rect);
9061 pre_rect.Union(post_rect);
9062 RefreshRect(pre_rect,
false);
9064 top_frame::Get()->RefreshCanvasOther(
this);
9065 m_bRoutePoinDragging =
true;
9070 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9071 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9074 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9076 DraggingAllowed =
false;
9078 if (m_pRoutePointEditTarget &&
9079 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9080 DraggingAllowed =
false;
9082 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9084 if (DraggingAllowed) {
9085 if (!undo->InUndoableAction()) {
9086 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9087 Undo_NeedsCopy, m_pFoundPoint);
9101 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9107 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9108 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9109 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9110 (
int)(lppmax - (pre_rect.height / 2)));
9118 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9121 m_pRoutePointEditTarget,
9122 SELTYPE_DRAGHANDLE);
9123 m_pFoundPoint->m_slat =
9124 m_pRoutePointEditTarget->m_lat;
9125 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9127 m_pRoutePointEditTarget->m_lat =
9130 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9143 if (!g_btouch) InvalidateGL();
9149 .CalculateDCRect(m_dc_route,
this, &post_rect);
9150 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9151 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9152 (
int)(lppmax - (post_rect.height / 2)));
9155 pre_rect.Union(post_rect);
9156 RefreshRect(pre_rect,
false);
9158 top_frame::Get()->RefreshCanvasOther(
this);
9159 m_bRoutePoinDragging =
true;
9161 ret = g_btouch ? m_bRoutePoinDragging :
true;
9164 if (ret)
return true;
9167 if (event.LeftUp()) {
9168 bool b_startedit_route =
false;
9169 m_dragoffsetSet =
false;
9172 m_bChartDragging =
false;
9173 m_bIsInRadius =
false;
9177 if (m_ignore_next_leftup) {
9178 m_ignore_next_leftup =
false;
9183 m_bedge_pan =
false;
9188 bool appending =
false;
9189 bool inserting =
false;
9195 if (m_pRoutePointEditTarget) {
9201 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9202 RefreshRect(wp_rect,
true);
9204 m_pRoutePointEditTarget = NULL;
9206 m_bRouteEditing =
true;
9208 if (m_routeState == 1) {
9209 m_pMouseRoute =
new Route();
9210 m_pMouseRoute->SetHiLite(50);
9214 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9221 double nearby_radius_meters =
9222 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9225 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9226 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9227 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9230 m_FinishRouteOnKillFocus =
9232 dlg_return = OCPNMessageBox(
9233 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9234 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9235 m_FinishRouteOnKillFocus =
true;
9237 dlg_return = wxID_YES;
9239 if (dlg_return == wxID_YES) {
9240 pMousePoint = pNearbyPoint;
9243 if (m_routeState > 1)
9244 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9245 Undo_HasParent, NULL);
9246 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9248 bool procede =
false;
9252 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9258 m_FinishRouteOnKillFocus =
false;
9259 if (m_routeState == 1) {
9263 _(
"Insert first part of this route in the new route?");
9264 if (tail->GetIndexOf(pMousePoint) ==
9267 dmsg = _(
"Insert this route in the new route?");
9269 if (tail->GetIndexOf(pMousePoint) != 1) {
9271 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9272 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9273 m_FinishRouteOnKillFocus =
true;
9275 if (dlg_return == wxID_YES) {
9282 _(
"Append last part of this route to the new route?");
9283 if (tail->GetIndexOf(pMousePoint) == 1)
9285 "Append this route to the new route?");
9289 if (tail->GetLastPoint() != pMousePoint) {
9291 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9292 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9293 m_FinishRouteOnKillFocus =
true;
9295 if (dlg_return == wxID_YES) {
9306 if (!FindRouteContainingWaypoint(pMousePoint))
9307 pMousePoint->SetShared(
true);
9311 if (NULL == pMousePoint) {
9312 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9314 pMousePoint->SetNameShown(
false);
9316 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9318 if (m_routeState > 1)
9319 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9320 Undo_IsOrphanded, NULL);
9323 if (m_routeState == 1) {
9325 m_pMouseRoute->AddPoint(pMousePoint);
9326 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9330 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9331 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9332 &rhumbBearing, &rhumbDist);
9333 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9334 &gcDist, &gcBearing, NULL);
9335 double gcDistNM = gcDist / 1852.0;
9338 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9339 pow(rhumbDist - gcDistNM - 1, 0.5);
9342 msg << _(
"For this leg the Great Circle route is ")
9344 << _(
" shorter than rhumbline.\n\n")
9345 << _(
"Would you like include the Great Circle routing points "
9349 m_FinishRouteOnKillFocus =
false;
9350 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9351 wxYES_NO | wxNO_DEFAULT);
9352 m_FinishRouteOnKillFocus =
true;
9354 int answer = wxID_NO;
9357 if (answer == wxID_YES) {
9359 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9360 wxRealPoint gcCoord;
9362 for (
int i = 1; i <= segmentCount; i++) {
9363 double fraction = (double)i * (1.0 / (
double)segmentCount);
9364 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9365 gcDist * fraction, gcBearing,
9366 &gcCoord.x, &gcCoord.y, NULL);
9368 if (i < segmentCount) {
9369 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9371 gcPoint->SetNameShown(
false);
9372 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9375 gcPoint = pMousePoint;
9378 m_pMouseRoute->AddPoint(gcPoint);
9379 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9381 pSelect->AddSelectableRouteSegment(
9382 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9383 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9384 prevGcPoint = gcPoint;
9387 undo->CancelUndoableAction(
true);
9390 m_pMouseRoute->AddPoint(pMousePoint);
9391 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9392 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9393 rlon, m_prev_pMousePoint,
9394 pMousePoint, m_pMouseRoute);
9395 undo->AfterUndoableAction(m_pMouseRoute);
9399 m_pMouseRoute->AddPoint(pMousePoint);
9400 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9402 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9403 rlon, m_prev_pMousePoint,
9404 pMousePoint, m_pMouseRoute);
9405 undo->AfterUndoableAction(m_pMouseRoute);
9411 m_prev_pMousePoint = pMousePoint;
9418 int connect = tail->GetIndexOf(pMousePoint);
9423 int length = tail->GetnPoints();
9428 start = connect + 1;
9433 m_pMouseRoute->RemovePoint(
9437 for (i = start; i <= stop; i++) {
9438 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9441 m_pMouseRoute->GetnPoints();
9443 top_frame::Get()->RefreshAllCanvas();
9447 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9449 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9450 m_pMouseRoute->FinalizeForRendering();
9455 }
else if (m_bMeasure_Active && m_nMeasureState)
9458 m_bedge_pan =
false;
9462 if (m_ignore_next_leftup) {
9463 m_ignore_next_leftup =
false;
9467 if (m_nMeasureState == 1) {
9468 m_pMeasureRoute =
new Route();
9474 if (m_pMeasureRoute) {
9477 wxEmptyString, wxEmptyString);
9480 m_pMeasureRoute->AddPoint(pMousePoint);
9484 m_prev_pMousePoint = pMousePoint;
9486 m_pMeasureRoute->GetnPoints();
9490 CancelMeasureRoute();
9496 bool bSelectAllowed =
true;
9498 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9500 bSelectAllowed =
false;
9504 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9505 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9506 significant_drag) ||
9507 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9508 significant_drag)) {
9509 bSelectAllowed =
false;
9517 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9519 if (bSelectAllowed) {
9520 bool b_was_editing_mark = m_bMarkEditing;
9521 bool b_was_editing_route = m_bRouteEditing;
9522 FindRoutePointsAtCursor(SelectRadius,
9528 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9529 m_pRoutePointEditTarget = NULL;
9531 if (!b_was_editing_route) {
9532 if (m_pEditRouteArray) {
9533 b_startedit_route =
true;
9537 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9538 m_pTrackRolloverWin->IsActive(
false);
9540 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9541 m_pRouteRolloverWin->IsActive(
false);
9545 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9547 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9555 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9556 pre_rect.Union(route_rect);
9559 RefreshRect(pre_rect,
true);
9562 b_startedit_route =
false;
9566 if (m_pRoutePointEditTarget) {
9567 if (b_was_editing_mark ||
9568 b_was_editing_route) {
9569 if (m_lastRoutePointEditTarget) {
9573 .EnableDragHandle(
false);
9574 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9575 SELTYPE_DRAGHANDLE);
9579 if (m_pRoutePointEditTarget) {
9582 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9583 wxPoint2DDouble dragHandlePoint =
9585 .GetDragHandlePoint(
this);
9587 dragHandlePoint.m_y, dragHandlePoint.m_x,
9588 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9591 if (m_lastRoutePointEditTarget) {
9595 .EnableDragHandle(
false);
9596 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9597 SELTYPE_DRAGHANDLE);
9600 wxArrayPtrVoid *lastEditRouteArray =
9602 m_lastRoutePointEditTarget);
9603 if (lastEditRouteArray) {
9604 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9606 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9611 delete lastEditRouteArray;
9622 if (m_lastRoutePointEditTarget) {
9625 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9626 RefreshRect(wp_rect,
true);
9629 if (m_pRoutePointEditTarget) {
9632 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9633 RefreshRect(wp_rect,
true);
9641 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9642 bool b_start_rollover =
false;
9646 if (pFind) b_start_rollover =
true;
9649 if (!b_start_rollover && !b_startedit_route) {
9650 SelectableItemList SelList =
pSelect->FindSelectionList(
9654 if (pr && pr->IsVisible()) {
9655 b_start_rollover =
true;
9661 if (!b_start_rollover && !b_startedit_route) {
9662 SelectableItemList SelList =
pSelect->FindSelectionList(
9666 if (tr && tr->IsVisible()) {
9667 b_start_rollover =
true;
9673 if (b_start_rollover)
9674 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9678 bool appending =
false;
9679 bool inserting =
false;
9681 if (m_bRouteEditing ) {
9683 if (m_pRoutePointEditTarget) {
9689 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9690 double nearby_radius_meters =
9691 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9692 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9693 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9694 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9696 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9700 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9702 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9706 std::find(list->begin(), list->end(), pNearbyPoint);
9707 if (pos != list->end()) {
9719 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9724 OCPNMessageBox(
this,
9725 _(
"Replace this RoutePoint by the nearby "
9727 _(
"OpenCPN RoutePoint change"),
9728 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9729 if (dlg_return == wxID_YES) {
9734 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9737 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9739 if (tail && current && (tail != current)) {
9741 connect = tail->GetIndexOf(pNearbyPoint);
9742 int index_current_route =
9743 current->GetIndexOf(m_pRoutePointEditTarget);
9744 index_last = current->GetIndexOf(current->GetLastPoint());
9745 dlg_return1 = wxID_NO;
9747 index_current_route) {
9749 if (connect != tail->GetnPoints()) {
9752 _(
"Last part of route to be appended to dragged "
9756 _(
"Full route to be appended to dragged route?");
9758 dlg_return1 = OCPNMessageBox(
9759 this, dmsg, _(
"OpenCPN Route Create"),
9760 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9761 if (dlg_return1 == wxID_YES) {
9765 }
else if (index_current_route ==
9770 _(
"First part of route to be inserted into dragged "
9772 if (connect == tail->GetnPoints())
9774 "Full route to be inserted into dragged route?");
9776 dlg_return1 = OCPNMessageBox(
9777 this, dmsg, _(
"OpenCPN Route Create"),
9778 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9779 if (dlg_return1 == wxID_YES) {
9786 if (m_pRoutePointEditTarget->IsShared()) {
9788 dlg_return = OCPNMessageBox(
9790 _(
"Do you really want to delete and replace this "
9792 "\n" + _(
"which has been created manually?"),
9793 (
"OpenCPN RoutePoint warning"),
9794 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9797 if (dlg_return == wxID_YES) {
9798 pMousePoint = pNearbyPoint;
9800 pMousePoint->SetShared(
true);
9810 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9812 if (m_pEditRouteArray) {
9813 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9815 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9820 auto pos = std::find(list->begin(), list->end(),
9821 m_pRoutePointEditTarget);
9823 pSelect->DeleteAllSelectableRoutePoints(pr);
9824 pSelect->DeleteAllSelectableRouteSegments(pr);
9827 pos = std::find(list->begin(), list->end(),
9828 m_pRoutePointEditTarget);
9831 pSelect->AddAllSelectableRouteSegments(pr);
9832 pSelect->AddAllSelectableRoutePoints(pr);
9834 pr->FinalizeForRendering();
9835 pr->UpdateSegmentDistances();
9836 if (m_bRoutePoinDragging) {
9838 NavObj_dB::GetInstance().UpdateRoute(pr);
9846 if (m_pEditRouteArray) {
9847 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9849 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9868 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9875 delete m_pRoutePointEditTarget;
9876 m_lastRoutePointEditTarget = NULL;
9877 m_pRoutePointEditTarget = NULL;
9878 undo->AfterUndoableAction(pMousePoint);
9879 undo->InvalidateUndo();
9884 else if (m_bMarkEditing) {
9885 if (m_pRoutePointEditTarget)
9886 if (m_bRoutePoinDragging) {
9888 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9892 if (m_pRoutePointEditTarget)
9893 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9895 if (!m_pRoutePointEditTarget) {
9896 delete m_pEditRouteArray;
9897 m_pEditRouteArray = NULL;
9898 m_bRouteEditing =
false;
9900 m_bRoutePoinDragging =
false;
9907 int length = tail->GetnPoints();
9908 for (
int i = connect + 1; i <= length; i++) {
9909 current->AddPointAndSegment(tail->GetPoint(i),
false);
9912 top_frame::Get()->RefreshAllCanvas();
9915 current->FinalizeForRendering();
9921 pSelect->DeleteAllSelectableRoutePoints(current);
9922 pSelect->DeleteAllSelectableRouteSegments(current);
9923 for (
int i = 1; i < connect; i++) {
9924 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9926 pSelect->AddAllSelectableRouteSegments(current);
9927 pSelect->AddAllSelectableRoutePoints(current);
9928 current->FinalizeForRendering();
9935 if (m_pEditRouteArray) {
9936 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9937 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9950 if (m_bRouteEditing) {
9953 bool appending =
false;
9954 bool inserting =
false;
9957 if (m_pRoutePointEditTarget) {
9958 m_pRoutePointEditTarget->
m_bBlink =
false;
9962 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9963 double nearby_radius_meters =
9964 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9965 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9966 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9967 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9969 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9970 bool duplicate =
false;
9972 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9974 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9978 std::find(list->begin(), list->end(), pNearbyPoint);
9979 if (pos != list->end()) {
9991 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9996 OCPNMessageBox(
this,
9997 _(
"Replace this RoutePoint by the nearby "
9999 _(
"OpenCPN RoutePoint change"),
10000 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10001 if (dlg_return == wxID_YES) {
10005 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
10008 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
10010 if (tail && current && (tail != current)) {
10012 connect = tail->GetIndexOf(pNearbyPoint);
10013 int index_current_route =
10014 current->GetIndexOf(m_pRoutePointEditTarget);
10015 index_last = current->GetIndexOf(current->GetLastPoint());
10016 dlg_return1 = wxID_NO;
10018 index_current_route) {
10020 if (connect != tail->GetnPoints()) {
10023 _(
"Last part of route to be appended to dragged "
10027 _(
"Full route to be appended to dragged route?");
10029 dlg_return1 = OCPNMessageBox(
10030 this, dmsg, _(
"OpenCPN Route Create"),
10031 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10032 if (dlg_return1 == wxID_YES) {
10036 }
else if (index_current_route ==
10038 if (connect != 1) {
10041 _(
"First part of route to be inserted into dragged "
10043 if (connect == tail->GetnPoints())
10045 "Full route to be inserted into dragged route?");
10047 dlg_return1 = OCPNMessageBox(
10048 this, dmsg, _(
"OpenCPN Route Create"),
10049 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10050 if (dlg_return1 == wxID_YES) {
10057 if (m_pRoutePointEditTarget->IsShared()) {
10058 dlg_return = wxID_NO;
10059 dlg_return = OCPNMessageBox(
10061 _(
"Do you really want to delete and replace this "
10063 "\n" + _(
"which has been created manually?"),
10064 (
"OpenCPN RoutePoint warning"),
10065 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10068 if (dlg_return == wxID_YES) {
10069 pMousePoint = pNearbyPoint;
10071 pMousePoint->SetShared(
true);
10081 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10083 if (m_pEditRouteArray) {
10084 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10086 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10090 auto pos = std::find(list->begin(), list->end(),
10091 m_pRoutePointEditTarget);
10093 pSelect->DeleteAllSelectableRoutePoints(pr);
10094 pSelect->DeleteAllSelectableRouteSegments(pr);
10097 pos = std::find(list->begin(), list->end(),
10098 m_pRoutePointEditTarget);
10099 if (pos != list->end()) list->erase(pos);
10102 pSelect->AddAllSelectableRouteSegments(pr);
10103 pSelect->AddAllSelectableRoutePoints(pr);
10105 pr->FinalizeForRendering();
10106 pr->UpdateSegmentDistances();
10109 if (m_bRoutePoinDragging) {
10114 NavObj_dB::GetInstance().UpdateRoutePoint(
10115 m_pRoutePointEditTarget);
10117 NavObj_dB::GetInstance().UpdateRoute(pr);
10129 int length = tail->GetnPoints();
10130 for (
int i = connect + 1; i <= length; i++) {
10131 current->AddPointAndSegment(tail->GetPoint(i),
false);
10135 top_frame::Get()->RefreshAllCanvas();
10138 current->FinalizeForRendering();
10144 pSelect->DeleteAllSelectableRoutePoints(current);
10145 pSelect->DeleteAllSelectableRouteSegments(current);
10146 for (
int i = 1; i < connect; i++) {
10147 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10149 pSelect->AddAllSelectableRouteSegments(current);
10150 pSelect->AddAllSelectableRoutePoints(current);
10151 current->FinalizeForRendering();
10158 if (m_pEditRouteArray) {
10159 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10161 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10173 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10180 delete m_pRoutePointEditTarget;
10181 m_lastRoutePointEditTarget = NULL;
10182 undo->AfterUndoableAction(pMousePoint);
10183 undo->InvalidateUndo();
10188 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10191 delete m_pEditRouteArray;
10192 m_pEditRouteArray = NULL;
10196 m_bRouteEditing =
false;
10197 m_pRoutePointEditTarget = NULL;
10203 else if (m_bMarkEditing) {
10204 if (m_pRoutePointEditTarget) {
10205 if (m_bRoutePoinDragging) {
10207 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10209 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10214 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10216 RefreshRect(wp_rect,
true);
10219 m_pRoutePointEditTarget = NULL;
10220 m_bMarkEditing =
false;
10225 else if (leftIsDown) {
10226 leftIsDown =
false;
10230 if (!m_bChartDragging && !m_bMeasure_Active) {
10232 m_bChartDragging =
false;
10236 m_bRoutePoinDragging =
false;
10239 if (ret)
return true;
10242 if (event.RightDown()) {
10253 m_FinishRouteOnKillFocus =
false;
10254 CallPopupMenu(mx, my);
10255 m_FinishRouteOnKillFocus =
true;
10265 if (event.ShiftDown()) {
10269 event.GetPosition(&x, &y);
10271 x *= m_displayScale;
10272 y *= m_displayScale;
10278 int wheel_dir =
event.GetWheelRotation();
10281 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10282 wheel_dir = wheel_dir > 0 ? 1 : -1;
10284 double factor = g_mouse_zoom_sensitivity;
10285 if (wheel_dir < 0) factor = 1 / factor;
10288 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10289 if (wheel_dir == m_last_wheel_dir) {
10290 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10295 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10296 m_wheelstopwatch.Start(0);
10301 m_last_wheel_dir = wheel_dir;
10306 if (event.LeftDown()) {
10312 last_drag.x = x, last_drag.y = y;
10313 panleftIsDown =
true;
10316 if (event.LeftUp()) {
10317 if (panleftIsDown) {
10319 panleftIsDown =
false;
10322 if (!m_bChartDragging && !m_bMeasure_Active) {
10323 switch (cursor_region) {
10345 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10350 m_bChartDragging =
false;
10356 if (event.Dragging() && event.LeftIsDown()) {
10372 if (g_btouch && !m_inPinch) {
10373 struct timespec now;
10374 clock_gettime(CLOCK_MONOTONIC, &now);
10375 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10377 bool trigger_hold =
false;
10378 if (
false == m_bChartDragging) {
10379 if (m_DragTrigger < 0) {
10382 m_DragTriggerStartTime = tnow;
10383 trigger_hold =
true;
10385 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10386 m_DragTrigger = -1;
10391 if (trigger_hold)
return true;
10393 if (
false == m_bChartDragging) {
10396 last_drag.x = x - 1, last_drag.y = y - 1;
10397 m_bChartDragging =
true;
10398 m_chart_drag_total_time = 0;
10399 m_chart_drag_total_x = 0;
10400 m_chart_drag_total_y = 0;
10401 m_inertia_last_drag_x = x;
10402 m_inertia_last_drag_y = y;
10403 m_drag_vec_x.clear();
10404 m_drag_vec_y.clear();
10405 m_drag_vec_t.clear();
10406 m_last_drag_time = tnow;
10410 uint64_t delta_t = tnow - m_last_drag_time;
10411 double delta_tf = delta_t / 1e9;
10413 m_chart_drag_total_time += delta_tf;
10414 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10415 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10417 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10418 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10419 m_drag_vec_t.push_back(delta_tf);
10421 m_inertia_last_drag_x = x;
10422 m_inertia_last_drag_y = y;
10423 m_last_drag_time = tnow;
10425 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10426 m_bChartDragging =
true;
10427 StartTimedMovement();
10428 m_pan_drag.x += last_drag.x - x;
10429 m_pan_drag.y += last_drag.y - y;
10430 last_drag.x = x, last_drag.y = y;
10432 }
else if (!g_btouch) {
10433 if ((last_drag.x != x) || (last_drag.y != y)) {
10434 if (!m_routeState) {
10437 m_bChartDragging =
true;
10438 StartTimedMovement();
10439 m_pan_drag.x += last_drag.x - x;
10440 m_pan_drag.y += last_drag.y - y;
10441 last_drag.x = x, last_drag.y = y;
10448 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10450 m_ignore_next_leftup =
true;
10451 m_DoubleClickTimer->Start();
10452 singleClickEventIsValid =
false;
10460void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10461 if (MouseEventOverlayWindows(event))
return;
10465 bool nm = MouseEventProcessObjects(event);
10469void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10472 wxCursor *ptarget_cursor = pCursorArrow;
10473 if (!pPlugIn_Cursor) {
10474 ptarget_cursor = pCursorArrow;
10475 if ((!m_routeState) &&
10476 (!m_bMeasure_Active) ) {
10477 if (cursor_region == MID_RIGHT) {
10478 ptarget_cursor = pCursorRight;
10479 }
else if (cursor_region == MID_LEFT) {
10480 ptarget_cursor = pCursorLeft;
10481 }
else if (cursor_region == MID_TOP) {
10482 ptarget_cursor = pCursorDown;
10483 }
else if (cursor_region == MID_BOT) {
10484 ptarget_cursor = pCursorUp;
10486 ptarget_cursor = pCursorArrow;
10488 }
else if (m_bMeasure_Active ||
10490 ptarget_cursor = pCursorPencil;
10492 ptarget_cursor = pPlugIn_Cursor;
10495 SetCursor(*ptarget_cursor);
10498void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10499 SetCursor(*pCursorArrow);
10502void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10506 wxArrayString files;
10508 ChartBase *target_chart = GetChartAtCursor();
10509 if (target_chart) {
10510 file.Assign(target_chart->GetFullPath());
10511 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10512 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10515 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10517 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10518 unsigned int im = stackIndexArray.size();
10519 int scale = 2147483647;
10520 if (VPoint.b_quilt && im > 0) {
10521 for (
unsigned int is = 0; is < im; is++) {
10522 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10523 CHART_TYPE_MBTILES) {
10524 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10526 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10527 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10529 .Contains(lat, lon)) {
10530 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10533 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10534 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10542 std::vector<Ais8_001_22 *> area_notices;
10544 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10547 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10548 auto target_data = target.second;
10549 if (!target_data->area_notices.empty()) {
10550 for (
auto &ani : target_data->area_notices) {
10555 for (Ais8_001_22_SubAreaList::iterator sa =
10556 area_notice.sub_areas.begin();
10557 sa != area_notice.sub_areas.end(); ++sa) {
10558 switch (sa->shape) {
10559 case AIS8_001_22_SHAPE_CIRCLE: {
10560 wxPoint target_point;
10562 bbox.Expand(target_point);
10563 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10566 case AIS8_001_22_SHAPE_RECT: {
10567 wxPoint target_point;
10569 bbox.Expand(target_point);
10570 if (sa->e_dim_m > sa->n_dim_m)
10571 bbox.EnLarge(sa->e_dim_m * vp_scale);
10573 bbox.EnLarge(sa->n_dim_m * vp_scale);
10576 case AIS8_001_22_SHAPE_POLYGON:
10577 case AIS8_001_22_SHAPE_POLYLINE: {
10578 for (
int i = 0; i < 4; ++i) {
10579 double lat = sa->latitude;
10580 double lon = sa->longitude;
10581 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10583 wxPoint target_point;
10585 bbox.Expand(target_point);
10589 case AIS8_001_22_SHAPE_SECTOR: {
10590 double lat1 = sa->latitude;
10591 double lon1 = sa->longitude;
10593 wxPoint target_point;
10595 bbox.Expand(target_point);
10596 for (
int i = 0; i < 18; ++i) {
10599 sa->left_bound_deg +
10600 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10601 sa->radius_m / 1852.0, &lat, &lon);
10603 bbox.Expand(target_point);
10605 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10608 bbox.Expand(target_point);
10614 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10615 area_notices.push_back(&area_notice);
10622 if (target_chart || !area_notices.empty() || file.HasName()) {
10624 int sel_rad_pix = 5;
10625 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10630 SetCursor(wxCURSOR_WAIT);
10631 bool lightsVis = m_encShowLights;
10632 if (!lightsVis) SetShowENCLights(
true);
10635 ListOfObjRazRules *rule_list = NULL;
10636 ListOfPI_S57Obj *pi_rule_list = NULL;
10639 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10640 else if (target_plugin_chart)
10641 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10642 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10644 ListOfObjRazRules *overlay_rule_list = NULL;
10645 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10648 if (CHs57_Overlay) {
10649 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10650 zlat, zlon, SelectRadius, &GetVP());
10653 if (!lightsVis) SetShowENCLights(
false);
10656 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10657 wxString face = dFont->GetFaceName();
10661 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10662 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10666 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10674 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10675 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10678 int points = dFont->GetPointSize();
10680 int points = dFont->GetPointSize() + 1;
10684 for (
int i = -2; i < 5; i++) {
10685 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10689 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10691 if (overlay_rule_list && CHs57_Overlay) {
10692 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10693 objText <<
"<hr noshade>";
10696 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10697 an != area_notices.end(); ++an) {
10698 objText <<
"<b>AIS Area Notice:</b> ";
10699 objText << ais8_001_22_notice_names[(*an)->notice_type];
10700 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10701 (*an)->sub_areas.begin();
10702 sa != (*an)->sub_areas.end(); ++sa)
10703 if (!sa->text.empty()) objText << sa->text;
10704 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10705 objText <<
"<hr noshade>";
10709 objText << Chs57->CreateObjDescriptions(rule_list);
10710 else if (target_plugin_chart)
10711 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10714 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10717 wxString AddFiles, filenameOK;
10719 if (!target_plugin_chart) {
10722 AddFiles = wxString::Format(
10723 "<hr noshade><br><b>Additional info files attached to: </b> "
10725 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10727 file.GetFullName());
10729 file.Assign(file.GetPath(),
"");
10730 wxDir dir(file.GetFullPath());
10732 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10734 file.Assign(dir.GetNameWithSep().append(filename));
10735 wxString FormatString =
10736 "<td valign=top><font size=-2><a "
10737 "href=\"%s\">%s</a></font></td>";
10738 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10739 filenameOK = file.GetFullPath();
10741 if (3 * ((
int)filecount / 3) == filecount)
10742 FormatString.Prepend(
"<tr>");
10744 FormatString.Prepend(
10745 "<td>  </td>");
10748 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10749 file.GetFullName());
10752 cont = dir.GetNext(&filename);
10754 objText << AddFiles <<
"</table>";
10756 objText <<
"</font>";
10757 objText <<
"</body></html>";
10759 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10763 if ((!Chs57 && filecount == 1)) {
10765 wxHtmlLinkInfo hli(filenameOK);
10766 wxHtmlLinkEvent hle(1, hli);
10770 if (rule_list) rule_list->Clear();
10773 if (overlay_rule_list) overlay_rule_list->Clear();
10774 delete overlay_rule_list;
10776 if (pi_rule_list) pi_rule_list->Clear();
10777 delete pi_rule_list;
10779 SetCursor(wxCURSOR_ARROW);
10783void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10792 wxSize canvas_size = GetSize();
10799 wxPoint canvas_pos = GetPosition();
10802 bool newFit =
false;
10803 if (canvas_size.x < fitted_size.x) {
10804 fitted_size.x = canvas_size.x - 40;
10805 if (canvas_size.y < fitted_size.y)
10806 fitted_size.y -= 40;
10808 if (canvas_size.y < fitted_size.y) {
10809 fitted_size.y = canvas_size.y - 40;
10810 if (canvas_size.x < fitted_size.x)
10811 fitted_size.x -= 40;
10822 wxString title_base = _(
"Mark Properties");
10824 title_base = _(
"Waypoint Properties");
10829 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10841void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10851 if (g_bresponsive) {
10852 wxSize canvas_size = GetSize();
10853 wxPoint canvas_pos = GetPosition();
10857 if (canvas_size.x < fitted_size.x) {
10858 fitted_size.x = canvas_size.x;
10859 if (canvas_size.y < fitted_size.y)
10860 fitted_size.y -= 20;
10862 if (canvas_size.y < fitted_size.y) {
10863 fitted_size.y = canvas_size.y;
10864 if (canvas_size.x < fitted_size.x)
10865 fitted_size.x -= 20;
10874 wxPoint xxp = ClientToScreen(canvas_pos);
10885void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10897void pupHandler_PasteWaypoint() {
10900 int pasteBuffer = kml.ParsePasteBuffer();
10901 RoutePoint *pasted = kml.GetParsedRoutePoint();
10902 if (!pasted)
return;
10904 double nearby_radius_meters =
10905 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10907 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10908 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10910 int answer = wxID_NO;
10914 "There is an existing waypoint at the same location as the one you are "
10915 "pasting. Would you like to merge the pasted data with it?\n\n");
10916 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10917 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10918 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10921 if (answer == wxID_YES) {
10922 nearPoint->SetName(pasted->GetName());
10928 if (answer == wxID_NO) {
10931 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10934 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10943 top_frame::Get()->InvalidateAllGL();
10944 top_frame::Get()->RefreshAllCanvas(
false);
10947void pupHandler_PasteRoute() {
10950 int pasteBuffer = kml.ParsePasteBuffer();
10951 Route *pasted = kml.GetParsedRoute();
10952 if (!pasted)
return;
10954 double nearby_radius_meters =
10955 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10961 bool mergepoints =
false;
10962 bool createNewRoute =
true;
10963 int existingWaypointCounter = 0;
10965 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10966 curPoint = pasted->GetPoint(i);
10967 nearPoint = pWayPointMan->GetNearbyWaypoint(
10968 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10970 mergepoints =
true;
10971 existingWaypointCounter++;
10979 int answer = wxID_NO;
10983 "There are existing waypoints at the same location as some of the ones "
10984 "you are pasting. Would you like to just merge the pasted data into "
10986 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10987 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10988 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10990 if (answer == wxID_CANCEL) {
10997 if (mergepoints && answer == wxID_YES &&
10998 existingWaypointCounter == pasted->GetnPoints()) {
11001 createNewRoute =
false;
11007 Route *newRoute = 0;
11010 if (createNewRoute) {
11011 newRoute =
new Route();
11015 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11016 curPoint = pasted->GetPoint(i);
11019 newPoint = pWayPointMan->GetNearbyWaypoint(
11020 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11021 newPoint->SetName(curPoint->GetName());
11024 if (createNewRoute) newRoute->AddPoint(newPoint);
11030 newPoint->SetIconName(
"circle");
11033 newPoint->SetShared(
false);
11035 newRoute->AddPoint(newPoint);
11036 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11039 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11042 if (i > 1 && createNewRoute)
11043 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11044 curPoint->m_lat, curPoint->m_lon,
11045 prevPoint, newPoint, newRoute);
11046 prevPoint = newPoint;
11049 if (createNewRoute) {
11052 NavObj_dB::GetInstance().InsertRoute(newRoute);
11062 top_frame::Get()->InvalidateAllGL();
11063 top_frame::Get()->RefreshAllCanvas(
false);
11069void pupHandler_PasteTrack() {
11072 int pasteBuffer = kml.ParsePasteBuffer();
11073 Track *pasted = kml.GetParsedTrack();
11074 if (!pasted)
return;
11082 newTrack->SetName(pasted->GetName());
11084 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11085 curPoint = pasted->GetPoint(i);
11089 wxDateTime now = wxDateTime::Now();
11092 newTrack->AddPoint(newPoint);
11095 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11096 newPoint->m_lat, newPoint->m_lon,
11097 prevPoint, newPoint, newTrack);
11099 prevPoint = newPoint;
11104 NavObj_dB::GetInstance().InsertTrack(newTrack);
11106 top_frame::Get()->InvalidateAllGL();
11107 top_frame::Get()->RefreshAllCanvas(
false);
11110bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11113 v[
"CursorPosition_x"] = x;
11114 v[
"CursorPosition_y"] = y;
11117 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11118 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11119 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11124 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11126 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11129#define SELTYPE_UNKNOWN 0x0001
11130#define SELTYPE_ROUTEPOINT 0x0002
11131#define SELTYPE_ROUTESEGMENT 0x0004
11132#define SELTYPE_TIDEPOINT 0x0008
11133#define SELTYPE_CURRENTPOINT 0x0010
11134#define SELTYPE_ROUTECREATE 0x0020
11135#define SELTYPE_AISTARGET 0x0040
11136#define SELTYPE_MARKPOINT 0x0080
11137#define SELTYPE_TRACKSEGMENT 0x0100
11138#define SELTYPE_DRAGHANDLE 0x0200
11141 if (g_bhide_context_menus)
return true;
11143 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11144 m_pIDXCandidate, m_nmea_log);
11147 wxEVT_COMMAND_MENU_SELECTED,
11148 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11154 if (m_inLongPress) {
11155 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11156 m_inLongPress =
false;
11160 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11163 wxEVT_COMMAND_MENU_SELECTED,
11164 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11166 delete m_canvasMenu;
11167 m_canvasMenu = NULL;
11177void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11180 if (m_canvasMenu) {
11181 m_canvasMenu->PopupMenuHandler(event);
11186void ChartCanvas::StartRoute() {
11188 if (g_brouteCreating)
return;
11192 g_brouteCreating =
true;
11194 m_bDrawingRoute =
false;
11195 SetCursor(*pCursorPencil);
11197 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11199 HideGlobalToolbar();
11202 androidSetRouteAnnunciator(
true);
11206wxString ChartCanvas::FinishRoute() {
11208 m_prev_pMousePoint = NULL;
11209 m_bDrawingRoute =
false;
11211 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11214 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11216 androidSetRouteAnnunciator(
false);
11219 SetCursor(*pCursorArrow);
11221 if (m_pMouseRoute) {
11222 if (m_bAppendingRoute) {
11224 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11226 if (m_pMouseRoute->GetnPoints() > 1) {
11228 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11231 m_pMouseRoute = NULL;
11234 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11246 m_bAppendingRoute =
false;
11247 m_pMouseRoute = NULL;
11249 m_pSelectedRoute = NULL;
11251 undo->InvalidateUndo();
11252 top_frame::Get()->RefreshAllCanvas(
true);
11256 ShowGlobalToolbar();
11258 g_brouteCreating =
false;
11263void ChartCanvas::HideGlobalToolbar() {
11264 if (m_canvasIndex == 0) {
11265 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11269void ChartCanvas::ShowGlobalToolbar() {
11270 if (m_canvasIndex == 0) {
11271 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11275void ChartCanvas::ShowAISTargetList() {
11276 if (NULL == g_pAISTargetList) {
11280 g_pAISTargetList->UpdateAISTargetList();
11283void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11284 if (!m_bShowOutlines)
return;
11288 int nEntry =
ChartData->GetChartTableEntries();
11290 for (
int i = 0; i < nEntry; i++) {
11294 bool b_group_draw =
false;
11295 if (m_groupIndex > 0) {
11296 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11297 int index = pt->GetGroupArray()[ig];
11298 if (m_groupIndex == index) {
11299 b_group_draw =
true;
11304 b_group_draw =
true;
11306 if (b_group_draw) RenderChartOutline(dc, i, vp);
11312 if (VPoint.b_quilt) {
11313 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11314 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11318 }
else if (m_singleChart &&
11319 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11323 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11326 if (zoom_factor > 8.0) {
11327 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11330 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11334 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11338void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11340 if (g_bopengl && m_glcc) {
11342 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11347 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11348 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11351 float plylat, plylon;
11352 float plylat1, plylon1;
11354 int pixx, pixy, pixx1, pixy1;
11357 ChartData->GetDBBoundingBox(dbIndex, box);
11361 if (box.GetLonRange() == 360)
return;
11363 double lon_bias = 0;
11365 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11367 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11369 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11370 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11372 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11373 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11376 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11379 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11380 if (0 == nAuxPlyEntries)
11384 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11385 plylon += lon_bias;
11391 for (
int i = 0; i < nPly - 1; i++) {
11392 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11393 plylon1 += lon_bias;
11399 int pixxs1 = pixx1;
11400 int pixys1 = pixy1;
11402 bool b_skip =
false;
11406 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11407 pow((
double)(pixy1 - pixy), 2)) /
11413 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11418 if (fabs(dist - distgc) > 10000. * 1852.)
11424 ClipResult res = cohen_sutherland_line_clip_i(
11426 if (res != Invisible && !b_skip)
11427 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11435 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11436 plylon1 += lon_bias;
11442 ClipResult res = cohen_sutherland_line_clip_i(
11444 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11451 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11452 for (
int j = 0; j < nAuxPlyEntries; j++) {
11454 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11459 for (
int i = 0; i < nAuxPly - 1; i++) {
11460 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11466 int pixxs1 = pixx1;
11467 int pixys1 = pixy1;
11469 bool b_skip =
false;
11473 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11474 ((pixy1 - pixy) * (pixy1 - pixy))) /
11479 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11484 if (fabs(dist - distgc) > 10000. * 1852.)
11490 ClipResult res = cohen_sutherland_line_clip_i(
11492 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11500 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11505 ClipResult res = cohen_sutherland_line_clip_i(
11507 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11512static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11513 const wxArrayString &legend) {
11514 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11516 int pointsize = dFont->GetPointSize();
11520 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11521 false, dFont->GetFaceName());
11523 dc.SetFont(*psRLI_font);
11530 int hilite_offset = 3;
11532 for (wxString line : legend) {
11535 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11537 dc.GetTextExtent(line, &wl, &hl);
11546 xp = ref_point.x - w;
11548 yp += hilite_offset;
11550 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11552 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11553 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11555 for (wxString line : legend) {
11556 dc.DrawText(line, xp, yp);
11561void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11562 if (!g_bAllowShipToActive)
return;
11568 wxPoint2DDouble pa, pb;
11575 if (rt->
m_width != wxPENSTYLE_INVALID)
11577 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11578 g_shipToActiveStyle, 5)];
11579 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11581 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11584 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11587 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11590 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11591 (
int)pb.m_y, GetVP(),
true);
11595#ifdef USE_ANDROID_GLES2
11596 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11598 if (style != wxPENSTYLE_SOLID) {
11599 if (glChartCanvas::dash_map.find(style) !=
11600 glChartCanvas::dash_map.end()) {
11601 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11605 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11608 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11609 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11615void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11617 if (m_routeState >= 2) route = m_pMouseRoute;
11618 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11619 route = m_pMeasureRoute;
11621 if (!route)
return;
11629 int np = route->GetnPoints();
11631 if (g_btouch && (np > 1)) np--;
11633 render_lat = rp.m_lat;
11634 render_lon = rp.m_lon;
11637 double rhumbBearing, rhumbDist;
11639 &rhumbBearing, &rhumbDist);
11640 double brg = rhumbBearing;
11641 double dist = rhumbDist;
11645 double gcBearing, gcBearing2, gcDist;
11646 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11649 double gcDistm = gcDist / 1852.0;
11652 rhumbBearing = 90.;
11654 wxPoint destPoint, lastPoint;
11657 int milesDiff = rhumbDist - gcDistm;
11658 if (milesDiff > 1) {
11669 for (
int i = 1; i <= milesDiff; i++) {
11670 double p = (double)i * (1.0 / (
double)milesDiff);
11672 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11673 &pLon, &pLat, &gcBearing2);
11675 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11677 lastPoint = destPoint;
11680 if (r_rband.x && r_rband.y) {
11681 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11683 if (m_bMeasure_DistCircle) {
11684 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11685 powf((
float)(r_rband.y - lastPoint.y), 2));
11688 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11689 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11695 wxString routeInfo;
11696 wxArrayString infoArray;
11699 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11705 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11707 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11708 (
int)varBrg, 0x00B0);
11711 infoArray.Add(routeInfo);
11717 routeInfo <<
"Reverse: ";
11719 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11720 (
int)(brg + 180.) % 360, 0x00B0);
11722 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11723 (
int)(varBrg + 180.) % 360, 0x00B0);
11724 infoArray.Add(routeInfo);
11730 s0.Append(_(
"Route") +
": ");
11732 s0.Append(_(
"Layer Route: "));
11735 if (!g_btouch) disp_length += dist;
11741 RouteLegInfo(dc, r_rband, infoArray);
11743 m_brepaint_piano =
true;
11746void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11747 if (!m_bShowVisibleSectors)
return;
11749 if (g_bDeferredInitDone) {
11751 double rhumbBearing, rhumbDist;
11752 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11753 &rhumbBearing, &rhumbDist);
11755 if (rhumbDist > 0.05)
11757 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11758 m_sectorlegsVisible);
11759 m_sector_glat =
gLat;
11760 m_sector_glon =
gLon;
11762 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11766void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11774void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11775 if (!ps52plib)
return;
11777 if (VPoint.b_quilt) {
11778 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11780 if (m_pQuilt->IsQuiltVector()) {
11781 if (ps52plib->GetStateHash() != m_s52StateHash) {
11783 m_s52StateHash = ps52plib->GetStateHash();
11787 if (ps52plib->GetStateHash() != m_s52StateHash) {
11789 m_s52StateHash = ps52plib->GetStateHash();
11794 bool bSendPlibState =
true;
11795 if (VPoint.b_quilt) {
11796 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11799 if (bSendPlibState) {
11801 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11802 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11803 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11804 v[
"OpenCPN Version Date"] = VERSION_DATE;
11805 v[
"OpenCPN Version Full"] = VERSION_FULL;
11808 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11809 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11810 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11811 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11812 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11813 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11814 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11818 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11819 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11823 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11824 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11825 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11826 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11827 ps52plib->m_bShowS57ImportantTextOnly;
11828 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11829 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11830 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11831 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11832 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11835 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11836 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11837 v[
"OpenCPN Scale Factor Exp"] =
11838 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11845 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11846 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11847 g_lastS52PLIBPluginMessage = out;
11854 wxPaintDC dc(
this);
11864 if (!m_b_paint_enable) {
11872 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11874 if (m_glcc && g_bopengl) {
11875 if (!s_in_update) {
11885 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11887 wxRegion ru = GetUpdateRegion();
11889 int rx, ry, rwidth, rheight;
11890 ru.GetBox(rx, ry, rwidth, rheight);
11892#ifdef ocpnUSE_DIBSECTION
11895 wxMemoryDC temp_dc;
11903 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11904 height += m_Piano->GetHeight();
11906 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11910 int thumbx, thumby, thumbsx, thumbsy;
11911 pthumbwin->GetPosition(&thumbx, &thumby);
11912 pthumbwin->GetSize(&thumbsx, &thumbsy);
11913 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11916 rgn_chart.Subtract(rgn_thumbwin);
11917 ru.Subtract(rgn_thumbwin);
11923 wxRegion rgn_blit = ru;
11924 if (g_bShowChartBar) {
11925 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11926 GetClientSize().x, m_Piano->GetHeight());
11929 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11930 if (style->chartStatusWindowTransparent)
11931 m_brepaint_piano =
true;
11933 ru.Subtract(chart_bar_rect);
11937 if (m_Compass && m_Compass->IsShown()) {
11938 wxRect compassRect = m_Compass->
GetRect();
11939 if (ru.Contains(compassRect) != wxOutRegion) {
11940 ru.Subtract(compassRect);
11944 if (m_notification_button) {
11945 wxRect noteRect = m_notification_button->
GetRect();
11946 if (ru.Contains(noteRect) != wxOutRegion) {
11947 ru.Subtract(noteRect);
11952 bool b_newview =
true;
11957 m_cache_vp.IsValid()) {
11963 bool b_rcache_ok =
false;
11964 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11965 b_rcache_ok = !b_newview;
11968 if (VPoint.b_MercatorProjectionOverride)
11969 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11983 if (b_rcache_ok) chart_get_region.Clear();
11986 if (VPoint.b_quilt)
11988 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11990 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11995 AbstractPlatform::ShowBusySpinner();
11999 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
12000 (m_working_bm.GetHeight() != svp.
pix_height))
12004 if (fabs(VPoint.
rotation) < 0.01) {
12005 bool b_save =
true;
12010 m_cache_vp.Invalidate();
12024 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12029 int dy = c_new.y - c_old.y;
12030 int dx = c_new.x - c_old.x;
12035 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12039 temp_dc.SelectObject(m_working_bm);
12041 wxMemoryDC cache_dc;
12042 cache_dc.SelectObject(m_cached_chart_bm);
12046 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12049 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12055 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12058 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12066 update_region.Union(
12069 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12074 update_region.Union(
12077 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12081 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12083 cache_dc.SelectObject(wxNullBitmap);
12087 temp_dc.SelectObject(m_cached_chart_bm);
12090 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12094 temp_dc.SelectObject(m_working_bm);
12095 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12100 temp_dc.SelectObject(m_cached_chart_bm);
12105 temp_dc.SelectObject(m_working_bm);
12106 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12119 wxMemoryDC scratch_dc_0;
12120 scratch_dc_0.SelectObject(m_cached_chart_bm);
12123 scratch_dc_0.SelectObject(wxNullBitmap);
12132 temp_dc.SelectObject(m_working_bm);
12135 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12136 chart_get_all_region);
12139 AbstractPlatform::HideBusySpinner();
12145 if (!m_singleChart) {
12146 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12151 if (!chart_get_region.IsEmpty()) {
12152 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12156 if (temp_dc.IsOk()) {
12161 if (!VPoint.b_quilt) {
12164 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12165 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12172 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12173 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12176 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12178 temp_dc.DestroyClippingRegion();
12183 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12185 if (!backgroundRegion.IsEmpty()) {
12191 wxColour water = pWorldBackgroundChart->water;
12192 if (water.IsOk()) {
12193 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12194 temp_dc.SetBrush(wxBrush(water));
12196 while (upd.HaveRects()) {
12197 wxRect rect = upd.GetRect();
12198 temp_dc.DrawRectangle(rect);
12203 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12204 temp_dc.SetDeviceClippingRegion(*clip_region);
12205 delete clip_region;
12209 SetVPRotation(VPoint.
skew);
12218 wxMemoryDC *pChartDC = &temp_dc;
12219 wxMemoryDC rotd_dc;
12221 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12223 if (!b_rcache_ok) {
12225 wxMemoryDC tbase_dc;
12227 tbase_dc.SelectObject(bm_base);
12229 tbase_dc.SelectObject(wxNullBitmap);
12231 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12234 wxImage base_image;
12235 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12243 bool b_rot_ok =
false;
12244 if (base_image.IsOk()) {
12247 m_b_rot_hidef =
false;
12251 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12252 m_b_rot_hidef, &m_roffset);
12257 rot_vp.IsValid() && (ri.IsOk())) {
12264 m_prot_bm =
new wxBitmap(ri);
12267 m_roffset.x += VPoint.rv_rect.x;
12268 m_roffset.y += VPoint.rv_rect.y;
12271 if (m_prot_bm && m_prot_bm->IsOk()) {
12272 rotd_dc.SelectObject(*m_prot_bm);
12273 pChartDC = &rotd_dc;
12275 pChartDC = &temp_dc;
12276 m_roffset = wxPoint(0, 0);
12279 pChartDC = &temp_dc;
12280 m_roffset = wxPoint(0, 0);
12283 wxPoint offset = m_roffset;
12286 m_cache_vp = VPoint;
12289 wxMemoryDC mscratch_dc;
12290 mscratch_dc.SelectObject(*pscratch_bm);
12292 mscratch_dc.ResetBoundingBox();
12293 mscratch_dc.DestroyClippingRegion();
12294 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12297 wxRegionIterator upd(rgn_blit);
12299 wxRect rect = upd.GetRect();
12301 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12302 rect.x - offset.x, rect.y - offset.y);
12308 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12309 if (
this == wxWindow::FindFocus()) {
12312 wxColour colour = GetGlobalColor(
"BLUE4");
12313 mscratch_dc.SetPen(wxPen(colour));
12314 mscratch_dc.SetBrush(wxBrush(colour));
12316 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12317 mscratch_dc.DrawRectangle(activeRect);
12322 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12323 unsigned int im = stackIndexArray.size();
12324 if (VPoint.b_quilt && im > 0) {
12325 std::vector<int> tiles_to_show;
12326 for (
unsigned int is = 0; is < im; is++) {
12328 ChartData->GetChartTableEntry(stackIndexArray[is]);
12329 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12332 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12333 tiles_to_show.push_back(stackIndexArray[is]);
12337 if (tiles_to_show.size())
12338 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12344 ocpnDC scratch_dc(mscratch_dc);
12345 RenderAlertMessage(mscratch_dc, GetVP());
12351#ifdef ocpnUSE_DIBSECTION
12356 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12357 q_dc.SelectObject(qbm);
12360 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12363 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12364 q_dc.SetBrush(qbr);
12365 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12368 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12371 q_dc.SelectObject(wxNullBitmap);
12380 if( VPoint.b_quilt ) {
12381 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12382 ChartBase *chart = m_pQuilt->GetRefChart();
12383 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12388 ChPI->ClearPLIBTextList();
12391 ps52plib->ClearTextList();
12395 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12397 wxColor maskBackground = wxColour(1,0,0);
12398 t_dc.SelectObject( qbm );
12399 t_dc.SetBackground(wxBrush(maskBackground));
12403 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12406 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12407 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12410 wxRegionIterator upd_final( ru );
12411 while( upd_final ) {
12412 wxRect rect = upd_final.GetRect();
12413 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12417 t_dc.SelectObject( wxNullBitmap );
12423 if (VPoint.b_quilt) {
12424 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12425 ChartBase *chart = m_pQuilt->GetRefChart();
12426 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12430 ChPI->ClearPLIBTextList();
12432 if (ps52plib) ps52plib->ClearTextList();
12437 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12439 if (g_bShowChartBar && m_Piano) {
12440 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12441 GetVP().pix_width, m_Piano->GetHeight());
12444 if (!style->chartStatusWindowTransparent)
12445 chart_all_text_region.Subtract(chart_bar_rect);
12448 if (m_Compass && m_Compass->IsShown()) {
12449 wxRect compassRect = m_Compass->
GetRect();
12450 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12451 chart_all_text_region.Subtract(compassRect);
12455 mscratch_dc.DestroyClippingRegion();
12457 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12458 chart_all_text_region);
12464 ocpnDC scratch_dc(mscratch_dc);
12465 DrawOverlayObjects(scratch_dc, ru);
12468 wxRegionIterator upd_final(rgn_blit);
12469 while (upd_final) {
12470 wxRect rect = upd_final.GetRect();
12471 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12478 temp_dc.SelectObject(wxNullBitmap);
12480 mscratch_dc.SelectObject(wxNullBitmap);
12482 dc.DestroyClippingRegion();
12487void ChartCanvas::PaintCleanup() {
12489 if (m_inPinch)
return;
12500 m_bTCupdate =
false;
12504 WarpPointer(warp_x, warp_y);
12511 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12512 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12516wxColour GetErrorGraphicColor(
double val)
12535 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12536 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12537 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12538 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12539 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12540 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12541 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12542 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12543 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12544 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12545 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12546 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12547 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12548 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12549 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12550 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12551 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12552 else if( val >= 48) c.Set(
"#410000");
12557void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12560 gr_image.InitAlpha();
12562 double maxval = -10000;
12563 double minval = 10000;
12580 maxval = wxMax(maxval, (glat - rlat));
12581 minval = wxMin(minval, (glat - rlat));
12598 double f = ((glat - rlat)-minval)/(maxval - minval);
12600 double dy = (f * 40);
12602 wxColour c = GetErrorGraphicColor(dy);
12603 unsigned char r = c.Red();
12604 unsigned char g = c.Green();
12605 unsigned char b = c.Blue();
12607 gr_image.SetRGB(j, i, r,g,b);
12608 if((glat - rlat )!= 0)
12609 gr_image.SetAlpha(j, i, 128);
12611 gr_image.SetAlpha(j, i, 255);
12618 wxBitmap *pbm =
new wxBitmap(gr_image);
12619 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12620 pbm->SetMask(gr_mask);
12622 pmdc->DrawBitmap(*pbm, 0,0);
12630void ChartCanvas::CancelMouseRoute() {
12632 m_pMouseRoute = NULL;
12633 m_bDrawingRoute =
false;
12636int ChartCanvas::GetNextContextMenuId() {
12637 return CanvasMenuHandler::GetNextContextMenuId();
12640bool ChartCanvas::SetCursor(
const wxCursor &c) {
12642 if (g_bopengl && m_glcc)
12643 return m_glcc->SetCursor(c);
12646 return wxWindow::SetCursor(c);
12649void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12650 if (g_bquiting)
return;
12660 if (!m_RolloverPopupTimer.IsRunning() &&
12661 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12662 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12663 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12664 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12667 if (m_glcc && g_bopengl) {
12670 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12672 m_glcc->Refresh(eraseBackground,
12689 if (m_pCIWin && m_pCIWin->IsShown()) {
12691 m_pCIWin->Refresh(
false);
12699 wxWindow::Refresh(eraseBackground, rect);
12702void ChartCanvas::Update() {
12703 if (m_glcc && g_bopengl) {
12708 wxWindow::Update();
12712 if (!pemboss)
return;
12713 int x = pemboss->x, y = pemboss->y;
12714 const double factor = 200;
12716 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12717 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12718 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12721 wxMemoryDC snip_dc;
12722 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12723 snip_dc.SelectObject(snip_bmp);
12725 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12726 snip_dc.SelectObject(wxNullBitmap);
12728 wxImage snip_img = snip_bmp.ConvertToImage();
12731 unsigned char *pdata = snip_img.GetData();
12733 for (
int y = 0; y < pemboss->height; y++) {
12734 int map_index = (y * pemboss->width);
12735 for (
int x = 0; x < pemboss->width; x++) {
12736 double val = (pemboss->pmap[map_index] * factor) / 256.;
12738 int nred = (int)((*pdata) + val);
12739 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12740 *pdata++ = (
unsigned char)nred;
12742 int ngreen = (int)((*pdata) + val);
12743 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12744 *pdata++ = (
unsigned char)ngreen;
12746 int nblue = (int)((*pdata) + val);
12747 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12748 *pdata++ = (
unsigned char)nblue;
12756 wxBitmap emb_bmp(snip_img);
12759 wxMemoryDC result_dc;
12760 result_dc.SelectObject(emb_bmp);
12763 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12765 result_dc.SelectObject(wxNullBitmap);
12771 if (GetQuiltMode()) {
12773 int refIndex = GetQuiltRefChartdbIndex();
12774 if (refIndex >= 0) {
12776 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12777 if (current_type == CHART_TYPE_MBTILES) {
12778 ChartBase *pChart = m_pQuilt->GetRefChart();
12781 zoom_factor = ptc->GetZoomFactor();
12786 if (zoom_factor <= 3.9)
return NULL;
12788 if (m_singleChart) {
12789 if (zoom_factor <= 3.9)
return NULL;
12794 if (m_pEM_OverZoom) {
12795 m_pEM_OverZoom->x = 4;
12796 m_pEM_OverZoom->y = 0;
12798 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12799 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12802 return m_pEM_OverZoom;
12805void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12818 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12819 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12823 AISDrawAreaNotices(dc, GetVP(),
this);
12825 wxDC *pdc = dc.GetDC();
12827 pdc->DestroyClippingRegion();
12828 wxDCClipper(*pdc, ru);
12831 if (m_bShowNavobjects) {
12832 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12833 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12834 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12835 DrawAnchorWatchPoints(dc);
12837 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12838 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12841 AISDraw(dc, GetVP(),
this);
12845 RenderVisibleSectorLights(dc);
12847 RenderAllChartOutlines(dc, GetVP());
12848 RenderRouteLegs(dc);
12849 RenderShipToActive(dc,
false);
12851 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12853 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12857 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12858 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12861 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12866 RebuildTideSelectList(GetVP().GetBBox());
12867 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12870 if (m_bShowCurrent) {
12871 RebuildCurrentSelectList(GetVP().GetBBox());
12872 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12875 if (!g_PrintingInProgress) {
12876 if (IsPrimaryCanvas()) {
12880 if (IsPrimaryCanvas()) {
12884 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12886 if (m_pTrackRolloverWin) {
12887 m_pTrackRolloverWin->Draw(dc);
12888 m_brepaint_piano =
true;
12891 if (m_pRouteRolloverWin) {
12892 m_pRouteRolloverWin->Draw(dc);
12893 m_brepaint_piano =
true;
12896 if (m_pAISRolloverWin) {
12897 m_pAISRolloverWin->Draw(dc);
12898 m_brepaint_piano =
true;
12900 if (m_brepaint_piano && g_bShowChartBar) {
12901 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12904 if (m_Compass) m_Compass->Paint(dc);
12906 if (!g_CanvasHideNotificationIcon) {
12907 if (IsPrimaryCanvas()) {
12908 auto ¬eman = NotificationManager::GetInstance();
12909 if (noteman.GetNotificationCount()) {
12910 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12911 if (m_notification_button->UpdateStatus()) Refresh();
12912 m_notification_button->Show(
true);
12913 m_notification_button->Paint(dc);
12915 m_notification_button->Show(
false);
12921 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12927 if (!m_bShowDepthUnits)
return NULL;
12929 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12931 if (GetQuiltMode()) {
12932 wxString s = m_pQuilt->GetQuiltDepthUnit();
12935 depth_unit_type = DEPTH_UNIT_FEET;
12936 else if (s.StartsWith(
"FATHOMS"))
12937 depth_unit_type = DEPTH_UNIT_FATHOMS;
12938 else if (s.StartsWith(
"METERS"))
12939 depth_unit_type = DEPTH_UNIT_METERS;
12940 else if (s.StartsWith(
"METRES"))
12941 depth_unit_type = DEPTH_UNIT_METERS;
12942 else if (s.StartsWith(
"METRIC"))
12943 depth_unit_type = DEPTH_UNIT_METERS;
12944 else if (s.StartsWith(
"METER"))
12945 depth_unit_type = DEPTH_UNIT_METERS;
12948 if (m_singleChart) {
12949 depth_unit_type = m_singleChart->GetDepthUnitType();
12950 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12951 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12956 switch (depth_unit_type) {
12957 case DEPTH_UNIT_FEET:
12960 case DEPTH_UNIT_METERS:
12961 ped = m_pEM_Meters;
12963 case DEPTH_UNIT_FATHOMS:
12964 ped = m_pEM_Fathoms;
12970 ped->x = (GetVP().
pix_width - ped->width);
12972 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12973 wxRect r = m_Compass->
GetRect();
12974 ped->y = r.y + r.height;
12981void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12984 if (style->embossFont == wxEmptyString) {
12985 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12987 font.SetPointSize(60);
12988 font.SetWeight(wxFONTWEIGHT_BOLD);
12990 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12991 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12993 int emboss_width = 500;
12994 int emboss_height = 200;
12998 delete m_pEM_Meters;
12999 delete m_pEM_Fathoms;
13003 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
13005 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
13007 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
13010#define OVERZOOM_TEXT _("OverZoom")
13012void ChartCanvas::SetOverzoomFont() {
13017 if (style->embossFont == wxEmptyString) {
13018 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13020 font.SetPointSize(40);
13021 font.SetWeight(wxFONTWEIGHT_BOLD);
13023 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13024 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13026 wxClientDC dc(
this);
13028 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13030 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13031 font.SetPointSize(font.GetPointSize() - 1);
13033 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13035 m_overzoomFont = font;
13036 m_overzoomTextWidth = w;
13037 m_overzoomTextHeight = h;
13040void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13041 delete m_pEM_OverZoom;
13043 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13045 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13046 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13049emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13050 int height,
const wxString &str,
13055 wxBitmap bmp(width, height, -1);
13058 wxMemoryDC temp_dc;
13059 temp_dc.SelectObject(bmp);
13062 temp_dc.SetBackground(*wxWHITE_BRUSH);
13063 temp_dc.SetTextBackground(*wxWHITE);
13064 temp_dc.SetTextForeground(*wxBLACK);
13068 temp_dc.SetFont(font);
13071 temp_dc.GetTextExtent(str, &str_w, &str_h);
13073 temp_dc.DrawText(str, 1, 1);
13076 temp_dc.SelectObject(wxNullBitmap);
13079 wxImage img = bmp.ConvertToImage();
13081 int image_width = str_w * 105 / 100;
13082 int image_height = str_h * 105 / 100;
13083 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13084 wxMin(image_height, img.GetHeight()));
13085 wxImage imgs = img.GetSubImage(r);
13089 case GLOBAL_COLOR_SCHEME_DAY:
13093 case GLOBAL_COLOR_SCHEME_DUSK:
13096 case GLOBAL_COLOR_SCHEME_NIGHT:
13103 const int w = imgs.GetWidth();
13104 const int h = imgs.GetHeight();
13105 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13110 for (
int y = 1; y < h - 1; y++) {
13111 for (
int x = 1; x < w - 1; x++) {
13113 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13114 val = (int)(val * val_factor);
13115 index = (y * w) + x;
13128void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13129 Track *active_track = NULL;
13132 active_track = pTrackDraw;
13136 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13139 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13142void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13143 Track *active_track = NULL;
13146 active_track = pTrackDraw;
13150 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13153void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13154 Route *active_route = NULL;
13156 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13157 active_route = pRouteDraw;
13162 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13167 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13170void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13171 Route *active_route = NULL;
13174 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13175 active_route = pRouteDraw;
13179 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13182void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13183 if (!pWayPointMan)
return;
13185 auto node = pWayPointMan->GetWaypointList()->begin();
13187 while (node != pWayPointMan->GetWaypointList()->end()) {
13196 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13200 if (pWP->GetShowWaypointRangeRings() &&
13201 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13202 double factor = 1.00;
13203 if (pWP->GetWaypointRangeRingsStepUnits() ==
13205 factor = 1 / 1.852;
13207 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13208 pWP->GetWaypointRangeRingsStep() / 60.;
13212 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13213 pWP->m_lat + radius, pWP->m_lon + radius);
13214 if (!BltBBox.IntersectOut(radar_box)) {
13225void ChartCanvas::DrawBlinkObjects() {
13227 wxRect update_rect;
13229 if (!pWayPointMan)
return;
13231 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13238 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13241void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13246 wxPoint lAnchorPoint1, lAnchorPoint2;
13260 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13261 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13263 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13264 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13265 dc.SetBrush(*ppBrush);
13269 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13274 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13279 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13284 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13289double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13292 wxPoint lAnchorPoint;
13295 double tlat1, tlon1;
13297 if (pAnchorWatchPoint) {
13298 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13300 dabs = fabs(d1 / 1852.);
13301 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13306 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13307 pow((
double)(lAnchorPoint.y - r1.y), 2));
13310 if (d1 < 0) lpp = -lpp;
13318void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13321 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13323 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13329 if ((type ==
't') || (type ==
'T')) {
13330 if (BBox.Contains(lat, lon)) {
13332 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13338void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13341 wxDateTime this_now = gTimeSource;
13342 bool cur_time = !gTimeSource.IsValid();
13343 if (cur_time) this_now = wxDateTime::Now();
13344 time_t t_this_now = this_now.GetTicks();
13346 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13348 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13349 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13350 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13351 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13353 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13354 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13355 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13356 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13357 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13358 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13360 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13361 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13362 int font_size = wxMax(10, dFont->GetPointSize());
13365 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13366 false, dFont->GetFaceName());
13368 dc.SetPen(*pblack_pen);
13369 dc.SetBrush(*pgreen_brush);
13373 case GLOBAL_COLOR_SCHEME_DAY:
13376 case GLOBAL_COLOR_SCHEME_DUSK:
13379 case GLOBAL_COLOR_SCHEME_NIGHT:
13380 bm = m_bmTideNight;
13387 int bmw = bm.GetWidth();
13388 int bmh = bm.GetHeight();
13390 float scale_factor = 1.0;
13394 float icon_pixelRefDim = 45;
13399 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13401 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13403 scale_factor *= pix_factor;
13410 scale_factor *= user_scale_factor;
13411 scale_factor *= GetContentScaleFactor();
13414 double marge = 0.05;
13415 std::vector<LLBBox> drawn_boxes;
13416 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13420 if ((type ==
't') || (type ==
'T'))
13425 if (BBox.ContainsMarge(lat, lon, marge)) {
13427 if (GetVP().chart_scale < 500000) {
13428 bool bdrawn =
false;
13429 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13430 if (drawn_boxes[i].Contains(lat, lon)) {
13435 if (bdrawn)
continue;
13438 this_box.Set(lat, lon, lat, lon);
13439 this_box.EnLarge(.005);
13440 drawn_boxes.push_back(this_box);
13446 if (GetVP().chart_scale > 500000) {
13447 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13451 dc.SetFont(*plabelFont);
13463 if (
ptcmgr->GetTideFlowSens(
13464 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13468 ptcmgr->GetHightOrLowTide(
13469 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13470 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13482 if (tctime > t_this_now)
13483 ptcmgr->GetHightOrLowTide(
13484 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13485 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13489 ptcmgr->GetHightOrLowTide(
13490 t_this_now, FORWARD_TEN_MINUTES_STEP,
13491 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13505 int width = (int)(12 * scale_factor + 0.5);
13506 int height = (int)(45 * scale_factor + 0.5);
13507 int linew = wxMax(1, (
int)(scale_factor));
13508 int xDraw = r.x - (width / 2);
13509 int yDraw = r.y - (height / 2);
13512 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13513 int hs = (httime > lttime) ? -4 : 4;
13514 hs *= (int)(scale_factor + 0.5);
13515 if (ts > 0.995 || ts < 0.005) hs = 0;
13516 int ht_y = (int)(height * ts);
13519 pblack_pen->SetWidth(linew);
13520 dc.SetPen(*pblack_pen);
13521 dc.SetBrush(*pyelo_brush);
13522 dc.DrawRectangle(xDraw, yDraw, width, height);
13526 dc.SetPen(*pblue_pen);
13527 dc.SetBrush(*pblue_brush);
13528 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13529 (width - (4 * linew)), height - ht_y);
13535 arrow[0].x = xDraw + 2 * linew;
13536 arrow[1].x = xDraw + width / 2;
13537 arrow[2].x = xDraw + width - 2 * linew;
13538 pyelo_pen->SetWidth(linew);
13539 pblue_pen->SetWidth(linew);
13540 if (ts > 0.35 || ts < 0.15)
13542 hl = (int)(height * 0.25) + yDraw;
13544 arrow[1].y = hl + hs;
13547 dc.SetPen(*pyelo_pen);
13549 dc.SetPen(*pblue_pen);
13550 dc.DrawLines(3, arrow);
13552 if (ts > 0.60 || ts < 0.40)
13554 hl = (int)(height * 0.5) + yDraw;
13556 arrow[1].y = hl + hs;
13559 dc.SetPen(*pyelo_pen);
13561 dc.SetPen(*pblue_pen);
13562 dc.DrawLines(3, arrow);
13564 if (ts < 0.65 || ts > 0.85)
13566 hl = (int)(height * 0.75) + yDraw;
13568 arrow[1].y = hl + hs;
13571 dc.SetPen(*pyelo_pen);
13573 dc.SetPen(*pblue_pen);
13574 dc.DrawLines(3, arrow);
13578 s.Printf(
"%3.1f", nowlev);
13580 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13582 dc.GetTextExtent(s, &wx1, NULL);
13584 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13599void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13602 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13604 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13610 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13611 if ((BBox.Contains(lat, lon))) {
13613 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13619void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13622 float tcvalue, dir;
13626 double lon_last = 0.;
13627 double lat_last = 0.;
13629 double marge = 0.2;
13630 bool cur_time = !gTimeSource.IsValid();
13632 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13633 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13635 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13637 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13638 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13639 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13640 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13641 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13642 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13643 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13644 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13646 double skew_angle = GetVPRotation();
13648 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13649 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13650 int font_size = wxMax(10, dFont->GetPointSize());
13653 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13654 false, dFont->GetFaceName());
13656 float scale_factor = 1.0;
13662 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13664 float nominal_icon_size_pixels = 15;
13665 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13667 scale_factor *= pix_factor;
13674 scale_factor *= user_scale_factor;
13676 scale_factor *= GetContentScaleFactor();
13679 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13685 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13686 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13691 int dd = (int)(5.0 * scale_factor + 0.5);
13702 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13703 dc.SetPen(*pblack_pen);
13704 dc.SetBrush(*porange_brush);
13705 dc.DrawPolygon(4, d);
13708 dc.SetBrush(*pblack_brush);
13709 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13713 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13727 double a1 = fabs(tcvalue) * 10.;
13729 a1 = wxMax(1.0, a1);
13730 double a2 = log10(a1);
13732 float cscale = scale_factor * a2 * 0.3;
13734 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13735 dc.SetPen(*porange_pen);
13736 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13740 if (bDrawCurrentValues) {
13741 dc.SetFont(*pTCFont);
13742 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13743 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13769 if (!pvIDX)
return;
13774 if (pCwin && pCwin->IsShown()) {
13782 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13797 pCwin =
new TCWin(
this, x, y, pvIDX);
13815#define NUM_CURRENT_ARROW_POINTS 9
13816static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13817 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13818 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13819 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13821void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13823 if (
scale > 1e-2) {
13824 float sin_rot = sin(rot_angle * PI / 180.);
13825 float cos_rot = cos(rot_angle * PI / 180.);
13829 float xt = CurrentArrowArray[0].x;
13830 float yt = CurrentArrowArray[0].y;
13832 float xp = (xt * cos_rot) - (yt * sin_rot);
13833 float yp = (xt * sin_rot) + (yt * cos_rot);
13834 int x1 = (int)(xp *
scale);
13835 int y1 = (int)(yp *
scale);
13838 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13839 xt = CurrentArrowArray[ip].x;
13840 yt = CurrentArrowArray[ip].y;
13842 float xp = (xt * cos_rot) - (yt * sin_rot);
13843 float yp = (xt * sin_rot) + (yt * cos_rot);
13844 int x2 = (int)(xp *
scale);
13845 int y2 = (int)(yp *
scale);
13847 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13855wxString ChartCanvas::FindValidUploadPort() {
13858 if (!g_uploadConnection.IsEmpty() &&
13859 g_uploadConnection.StartsWith(
"Serial")) {
13860 port = g_uploadConnection;
13866 for (
auto *cp : TheConnectionParams()) {
13867 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13868 port <<
"Serial:" << cp->Port;
13874void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13877 if (NULL == g_pais_query_dialog_active) {
13878 int pos_x = g_ais_query_dialog_x;
13879 int pos_y = g_ais_query_dialog_y;
13881 if (g_pais_query_dialog_active) {
13882 g_pais_query_dialog_active->Destroy();
13888 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13889 wxPoint(pos_x, pos_y));
13891 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13892 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13893 g_pais_query_dialog_active->SetMMSI(mmsi);
13894 g_pais_query_dialog_active->UpdateText();
13895 wxSize sz = g_pais_query_dialog_active->GetSize();
13897 bool b_reset_pos =
false;
13902 RECT frame_title_rect;
13903 frame_title_rect.left = pos_x;
13904 frame_title_rect.top = pos_y;
13905 frame_title_rect.right = pos_x + sz.x;
13906 frame_title_rect.bottom = pos_y + 30;
13908 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13909 b_reset_pos =
true;
13914 wxRect window_title_rect;
13915 window_title_rect.x = pos_x;
13916 window_title_rect.y = pos_y;
13917 window_title_rect.width = sz.x;
13918 window_title_rect.height = 30;
13920 wxRect ClientRect = wxGetClientDisplayRect();
13921 ClientRect.Deflate(
13923 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13927 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13930 g_pais_query_dialog_active->SetMMSI(mmsi);
13931 g_pais_query_dialog_active->UpdateText();
13934 g_pais_query_dialog_active->Show();
13937void ChartCanvas::ToggleCanvasQuiltMode() {
13938 bool cur_mode = GetQuiltMode();
13940 if (!GetQuiltMode())
13941 SetQuiltMode(
true);
13942 else if (GetQuiltMode()) {
13943 SetQuiltMode(
false);
13944 g_sticky_chart = GetQuiltReferenceChartIndex();
13947 if (cur_mode != GetQuiltMode()) {
13948 SetupCanvasQuiltMode();
13957 if (ps52plib) ps52plib->GenerateStateHash();
13959 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13960 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13963void ChartCanvas::DoCanvasStackDelta(
int direction) {
13964 if (!GetQuiltMode()) {
13965 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13966 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13967 if ((current_stack_index + direction) < 0)
return;
13969 if (m_bpersistent_quilt ) {
13971 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13973 if (IsChartQuiltableRef(new_dbIndex)) {
13974 ToggleCanvasQuiltMode();
13975 SelectQuiltRefdbChart(new_dbIndex);
13976 m_bpersistent_quilt =
false;
13979 SelectChartFromStack(current_stack_index + direction);
13982 std::vector<int> piano_chart_index_array =
13983 GetQuiltExtendedStackdbIndexArray();
13984 int refdb = GetQuiltRefChartdbIndex();
13987 int current_index = -1;
13988 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13989 if (refdb == piano_chart_index_array[i]) {
13994 if (current_index == -1)
return;
13997 int target_family = ctet.GetChartFamily();
13999 int new_index = -1;
14000 int check_index = current_index + direction;
14001 bool found =
false;
14002 int check_dbIndex = -1;
14003 int new_dbIndex = -1;
14007 (
unsigned int)check_index < piano_chart_index_array.size() &&
14008 (check_index >= 0)) {
14009 check_dbIndex = piano_chart_index_array[check_index];
14011 if (target_family == cte.GetChartFamily()) {
14013 new_index = check_index;
14014 new_dbIndex = check_dbIndex;
14018 check_index += direction;
14021 if (!found)
return;
14023 if (!IsChartQuiltableRef(new_dbIndex)) {
14024 ToggleCanvasQuiltMode();
14025 SelectdbChart(new_dbIndex);
14026 m_bpersistent_quilt =
true;
14028 SelectQuiltRefChart(new_index);
14033 top_frame::Get()->UpdateGlobalMenuItems();
14034 SetQuiltChartHiLiteIndex(-1);
14045void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14048 switch (event.GetId()) {
14060 DoCanvasStackDelta(1);
14065 DoCanvasStackDelta(-1);
14075 ShowCurrents(!GetbShowCurrent());
14082 ShowTides(!GetbShowTide());
14089 if (0 == m_routeState) {
14096 androidSetRouteAnnunciator(m_routeState == 1);
14102 SetAISCanvasDisplayStyle(-1);
14114void ChartCanvas::SetShowAIS(
bool show) {
14116 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14117 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14120void ChartCanvas::SetAttenAIS(
bool show) {
14121 m_bShowAISScaled = show;
14122 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14123 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14126void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14129 bool bShowAIS_Array[3] = {
true,
true,
false};
14130 bool bShowScaled_Array[3] = {
false,
true,
true};
14131 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14132 _(
"Attenuate less critical AIS targets"),
14133 _(
"Hide AIS Targets")};
14134 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14136 int AIS_Toolbar_Switch = 0;
14137 if (StyleIndx == -1) {
14139 for (
int i = 1; i < ArraySize; i++) {
14140 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14141 (bShowScaled_Array[i] == m_bShowAISScaled))
14142 AIS_Toolbar_Switch = i;
14144 AIS_Toolbar_Switch++;
14145 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14146 AIS_Toolbar_Switch++;
14149 AIS_Toolbar_Switch = StyleIndx;
14152 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14154 int AIS_Toolbar_Switch_Next =
14155 AIS_Toolbar_Switch + 1;
14156 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14157 AIS_Toolbar_Switch_Next++;
14158 if (AIS_Toolbar_Switch_Next >= ArraySize)
14159 AIS_Toolbar_Switch_Next = 0;
14162 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14163 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14166void ChartCanvas::TouchAISToolActive() {}
14168void ChartCanvas::UpdateAISTBTool() {}
14176void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14178 bool b_update =
false;
14179 int cc1_edge_comp = 2;
14180 wxRect rect = m_Compass->
GetRect();
14181 wxSize parent_size = GetSize();
14183 parent_size *= m_displayScale;
14187 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14188 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14189 wxRect compass_rect(compass_pt, rect.GetSize());
14191 m_Compass->Move(compass_pt);
14193 if (m_Compass && m_Compass->IsShown())
14194 m_Compass->UpdateStatus(b_force_new | b_update);
14196 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14197 scaler = wxMax(scaler, 1.0);
14198 wxPoint note_point = wxPoint(
14199 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14200 if (m_notification_button) {
14201 m_notification_button->Move(note_point);
14202 m_notification_button->UpdateStatus();
14205 if (b_force_new | b_update) Refresh();
14208void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14209 ChartTypeEnum New_Type,
14210 ChartFamilyEnum New_Family) {
14211 if (!GetpCurrentStack())
return;
14214 if (index < GetpCurrentStack()->nEntry) {
14217 pTentative_Chart =
ChartData->OpenStackChartConditional(
14218 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14220 if (pTentative_Chart) {
14221 if (m_singleChart) m_singleChart->Deactivate();
14223 m_singleChart = pTentative_Chart;
14224 m_singleChart->Activate();
14226 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14227 GetpCurrentStack(), m_singleChart->GetFullPath());
14240 double best_scale_ppm = GetBestVPScale(m_singleChart);
14241 double rotation = GetVPRotation();
14242 double oldskew = GetVPSkew();
14243 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14245 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14246 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14247 if (fabs(newskew) > 0.0001) rotation = newskew;
14250 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14252 UpdateGPSCompassStatusBox(
true);
14256 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14257 if (idx < 0)
return;
14259 std::vector<int> piano_active_chart_index_array;
14260 piano_active_chart_index_array.push_back(
14261 GetpCurrentStack()->GetCurrentEntrydbIndex());
14262 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14265void ChartCanvas::SelectdbChart(
int dbindex) {
14266 if (!GetpCurrentStack())
return;
14269 if (dbindex >= 0) {
14272 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14274 if (pTentative_Chart) {
14275 if (m_singleChart) m_singleChart->Deactivate();
14277 m_singleChart = pTentative_Chart;
14278 m_singleChart->Activate();
14280 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14281 GetpCurrentStack(), m_singleChart->GetFullPath());
14294 double best_scale_ppm = GetBestVPScale(m_singleChart);
14298 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14308void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14311 if (!GetQuiltMode()) {
14312 if (GetpCurrentStack()) {
14313 int stack_index = -1;
14314 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14315 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14316 if (check_dbIndex < 0)
continue;
14318 ChartData->GetChartTableEntry(check_dbIndex);
14319 if (type == cte.GetChartType()) {
14322 }
else if (family == cte.GetChartFamily()) {
14328 if (stack_index >= 0) {
14329 SelectChartFromStack(stack_index);
14333 int sel_dbIndex = -1;
14334 std::vector<int> piano_chart_index_array =
14335 GetQuiltExtendedStackdbIndexArray();
14336 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14337 int check_dbIndex = piano_chart_index_array[i];
14339 if (type == cte.GetChartType()) {
14340 if (IsChartQuiltableRef(check_dbIndex)) {
14341 sel_dbIndex = check_dbIndex;
14344 }
else if (family == cte.GetChartFamily()) {
14345 if (IsChartQuiltableRef(check_dbIndex)) {
14346 sel_dbIndex = check_dbIndex;
14352 if (sel_dbIndex >= 0) {
14353 SelectQuiltRefdbChart(sel_dbIndex,
false);
14355 AdjustQuiltRefChart();
14362 SetQuiltChartHiLiteIndex(-1);
14367bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14368 return std::find(m_tile_yesshow_index_array.begin(),
14369 m_tile_yesshow_index_array.end(),
14370 index) != m_tile_yesshow_index_array.end();
14373bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14374 return std::find(m_tile_noshow_index_array.begin(),
14375 m_tile_noshow_index_array.end(),
14376 index) != m_tile_noshow_index_array.end();
14379void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14380 if (std::find(m_tile_noshow_index_array.begin(),
14381 m_tile_noshow_index_array.end(),
14382 index) == m_tile_noshow_index_array.end()) {
14383 m_tile_noshow_index_array.push_back(index);
14393void ChartCanvas::HandlePianoClick(
14394 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14397 if (!m_pCurrentStack)
return;
14413 double distance = 25000;
14414 int closest_index = -1;
14415 for (
int chart_index : selected_dbIndex_array) {
14417 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14418 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14421 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14422 if (test_distance < distance) {
14423 distance = test_distance;
14424 closest_index = chart_index;
14428 int selected_dbIndex = selected_dbIndex_array[0];
14429 if (closest_index >= 0) selected_dbIndex = closest_index;
14431 if (!GetQuiltMode()) {
14432 if (m_bpersistent_quilt ) {
14433 if (IsChartQuiltableRef(selected_dbIndex)) {
14434 ToggleCanvasQuiltMode();
14435 SelectQuiltRefdbChart(selected_dbIndex);
14436 m_bpersistent_quilt =
false;
14438 SelectChartFromStack(selected_index);
14441 SelectChartFromStack(selected_index);
14442 g_sticky_chart = selected_dbIndex;
14446 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14450 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14451 bool bfound =
false;
14452 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14453 if (m_tile_noshow_index_array[i] ==
14454 selected_dbIndex) {
14455 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14462 m_tile_noshow_index_array.push_back(selected_dbIndex);
14466 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14467 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14471 if (IsChartQuiltableRef(selected_dbIndex)) {
14477 bool set_scale =
false;
14478 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14479 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14485 SelectQuiltRefdbChart(selected_dbIndex,
true);
14487 SelectQuiltRefdbChart(selected_dbIndex,
false);
14492 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14494 double proposed_scale_onscreen =
14497 if (g_bPreserveScaleOnX) {
14498 proposed_scale_onscreen =
14499 wxMin(proposed_scale_onscreen,
14501 GetCanvasWidth()));
14503 proposed_scale_onscreen =
14504 wxMin(proposed_scale_onscreen,
14506 GetCanvasWidth()));
14508 proposed_scale_onscreen =
14509 wxMax(proposed_scale_onscreen,
14518 ToggleCanvasQuiltMode();
14519 SelectdbChart(selected_dbIndex);
14520 m_bpersistent_quilt =
true;
14525 SetQuiltChartHiLiteIndex(-1);
14527 top_frame::Get()->UpdateGlobalMenuItems();
14528 HideChartInfoWindow();
14533void ChartCanvas::HandlePianoRClick(
14534 int x,
int y,
int selected_index,
14535 const std::vector<int> &selected_dbIndex_array) {
14538 if (!GetpCurrentStack())
return;
14540 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14541 UpdateCanvasControlBar();
14543 SetQuiltChartHiLiteIndex(-1);
14546void ChartCanvas::HandlePianoRollover(
14547 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14548 int n_charts,
int scale) {
14551 if (!GetpCurrentStack())
return;
14556 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14558 if (!GetQuiltMode()) {
14559 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14562 std::vector<int> piano_chart_index_array;
14563 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14564 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14565 if ((GetpCurrentStack()->nEntry > 1) ||
14566 (piano_chart_index_array.size() >= 1)) {
14567 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14569 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14571 }
else if (GetpCurrentStack()->nEntry == 1) {
14573 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14574 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14575 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14577 }
else if ((-1 == selected_index) &&
14578 (0 == selected_dbIndex_array.size())) {
14579 ShowChartInfoWindow(key_location.x, -1);
14583 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14585 if ((GetpCurrentStack()->nEntry > 1) ||
14586 (piano_chart_index_array.size() >= 1)) {
14588 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14589 selected_dbIndex_array);
14590 else if (n_charts == 1)
14591 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14593 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14600void ChartCanvas::ClearPianoRollover() {
14601 ClearQuiltChartHiLiteIndexArray();
14602 ShowChartInfoWindow(0, -1);
14603 std::vector<int> vec;
14604 ShowCompositeInfoWindow(0, 0, 0, vec);
14608void ChartCanvas::UpdateCanvasControlBar() {
14609 if (m_pianoFrozen)
return;
14611 if (!GetpCurrentStack())
return;
14613 if (!g_bShowChartBar)
return;
14616 int sel_family = -1;
14618 std::vector<int> piano_chart_index_array;
14619 std::vector<int> empty_piano_chart_index_array;
14621 wxString old_hash = m_Piano->GetStoredHash();
14623 if (GetQuiltMode()) {
14624 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14625 GetQuiltFullScreendbIndexArray());
14627 std::vector<int> piano_active_chart_index_array =
14628 GetQuiltCandidatedbIndexArray();
14629 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14631 std::vector<int> piano_eclipsed_chart_index_array =
14632 GetQuiltEclipsedStackdbIndexArray();
14633 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14635 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14636 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14638 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14639 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14641 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14642 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14645 if (m_singleChart) {
14646 sel_type = m_singleChart->GetChartType();
14647 sel_family = m_singleChart->GetChartFamily();
14652 std::vector<int> piano_skew_chart_index_array;
14653 std::vector<int> piano_tmerc_chart_index_array;
14654 std::vector<int> piano_poly_chart_index_array;
14656 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14658 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14659 double skew_norm = ctei.GetChartSkew();
14660 if (skew_norm > 180.) skew_norm -= 360.;
14662 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14663 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14666 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14667 if (fabs(skew_norm) > 1.)
14668 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14670 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14671 }
else if (fabs(skew_norm) > 1.)
14672 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14674 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14675 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14676 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14678 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14679 if (new_hash != old_hash) {
14680 m_Piano->FormatKeys();
14681 HideChartInfoWindow();
14682 m_Piano->ResetRollover();
14683 SetQuiltChartHiLiteIndex(-1);
14684 m_brepaint_piano =
true;
14690 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14692 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14693 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14694 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14695 if (e == CHART_FAMILY_RASTER) mask |= 1;
14696 if (e == CHART_FAMILY_VECTOR) {
14697 if (t == CHART_TYPE_CM93COMP)
14704 wxString s_indicated;
14705 if (sel_type == CHART_TYPE_CM93COMP)
14706 s_indicated =
"cm93";
14708 if (sel_family == CHART_FAMILY_RASTER)
14709 s_indicated =
"raster";
14710 else if (sel_family == CHART_FAMILY_VECTOR)
14711 s_indicated =
"vector";
14714 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14717void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14719void ChartCanvas::PianoPopupMenu(
14720 int x,
int y,
int selected_index,
14721 const std::vector<int> &selected_dbIndex_array) {
14722 if (!GetpCurrentStack())
return;
14725 if (!GetQuiltMode())
return;
14727 m_piano_ctx_menu =
new wxMenu();
14729 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14739 menu_selected_dbIndex = selected_dbIndex_array[0];
14740 menu_selected_index = selected_index;
14743 bool b_is_in_noshow =
false;
14744 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14745 if (m_quilt_noshow_index_array[i] ==
14746 menu_selected_dbIndex)
14748 b_is_in_noshow =
true;
14753 if (b_is_in_noshow) {
14754 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14755 _(
"Show This Chart"));
14756 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14757 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14758 }
else if (GetpCurrentStack()->nEntry > 1) {
14759 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14760 _(
"Hide This Chart"));
14761 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14762 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14766 wxPoint pos = wxPoint(x, y - 30);
14769 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14770 PopupMenu(m_piano_ctx_menu, pos);
14772 delete m_piano_ctx_menu;
14773 m_piano_ctx_menu = NULL;
14775 HideChartInfoWindow();
14776 m_Piano->ResetRollover();
14778 SetQuiltChartHiLiteIndex(-1);
14779 ClearQuiltChartHiLiteIndexArray();
14784void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14785 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14786 if (m_quilt_noshow_index_array[i] ==
14787 menu_selected_dbIndex)
14789 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14795void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14796 if (!GetpCurrentStack())
return;
14799 RemoveChartFromQuilt(menu_selected_dbIndex);
14803 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14804 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14806 int i = menu_selected_index + 1;
14807 bool b_success =
false;
14808 while (i < GetpCurrentStack()->nEntry - 1) {
14809 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14810 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14811 SelectQuiltRefChart(i);
14821 i = menu_selected_index - 1;
14823 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14824 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14825 SelectQuiltRefChart(i);
14835void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14837 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14838 if (m_quilt_noshow_index_array[i] ==
14841 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14846 m_quilt_noshow_index_array.push_back(dbIndex);
14849bool ChartCanvas::UpdateS52State() {
14850 bool retval =
false;
14853 ps52plib->SetShowS57Text(m_encShowText);
14854 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14855 ps52plib->m_bShowSoundg = m_encShowDepth;
14856 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14857 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14860 if (!m_encShowLights)
14861 ps52plib->AddObjNoshow(
"LIGHTS");
14863 ps52plib->RemoveObjNoshow(
"LIGHTS");
14864 ps52plib->SetLightsOff(!m_encShowLights);
14865 ps52plib->m_bExtendLightSectors =
true;
14868 ps52plib->SetAnchorOn(m_encShowAnchor);
14869 ps52plib->SetQualityOfData(m_encShowDataQual);
14875void ChartCanvas::SetShowENCDataQual(
bool show) {
14876 m_encShowDataQual = show;
14877 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14878 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14880 m_s52StateHash = 0;
14883void ChartCanvas::SetShowENCText(
bool show) {
14884 m_encShowText = show;
14885 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14886 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14888 m_s52StateHash = 0;
14891void ChartCanvas::SetENCDisplayCategory(
int category) {
14892 m_encDisplayCategory = category;
14893 m_s52StateHash = 0;
14896void ChartCanvas::SetShowENCDepth(
bool show) {
14897 m_encShowDepth = show;
14898 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14899 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14901 m_s52StateHash = 0;
14904void ChartCanvas::SetShowENCLightDesc(
bool show) {
14905 m_encShowLightDesc = show;
14906 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14907 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14909 m_s52StateHash = 0;
14912void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14913 m_encShowBuoyLabels = show;
14914 m_s52StateHash = 0;
14917void ChartCanvas::SetShowENCLights(
bool show) {
14918 m_encShowLights = show;
14919 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14920 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14922 m_s52StateHash = 0;
14925void ChartCanvas::SetShowENCAnchor(
bool show) {
14926 m_encShowAnchor = show;
14927 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14928 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14930 m_s52StateHash = 0;
14933wxRect ChartCanvas::GetMUIBarRect() {
14936 rv = m_muiBar->GetRect();
14942void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14943 if (!GetAlertString().IsEmpty()) {
14944 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14945 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14947 dc.SetFont(*pfont);
14948 dc.SetPen(*wxTRANSPARENT_PEN);
14950 dc.SetBrush(wxColour(243, 229, 47));
14952 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14956 wxRect sbr = GetScaleBarRect();
14957 int xp = sbr.x + sbr.width + 10;
14958 int yp = (sbr.y + sbr.height) - h;
14960 int wdraw = w + 10;
14961 dc.DrawRectangle(xp, yp, wdraw, h);
14962 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14963 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14973#define BRIGHT_XCALIB
14974#define __OPCPN_USEICC__
14977#ifdef __OPCPN_USEICC__
14978int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14979 double co_green,
double co_blue);
14981wxString temp_file_name;
14985class ocpnCurtain:
public wxDialog
14987 DECLARE_CLASS( ocpnCurtain )
14988 DECLARE_EVENT_TABLE()
14991 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14993 bool ProcessEvent(wxEvent& event);
14997IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14999BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
15002ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
15004 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
15007ocpnCurtain::~ocpnCurtain()
15011bool ocpnCurtain::ProcessEvent(wxEvent& event)
15013 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
15014 return GetParent()->GetEventHandler()->ProcessEvent(event);
15019#include <windows.h>
15022typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15023typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15024SetDeviceGammaRamp_ptr_type
15025 g_pSetDeviceGammaRamp;
15026GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15028WORD *g_pSavedGammaMap;
15032int InitScreenBrightness() {
15035 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15039 if (NULL == hGDI32DLL) {
15040 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15042 if (NULL != hGDI32DLL) {
15044 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15045 hGDI32DLL,
"SetDeviceGammaRamp");
15046 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15047 hGDI32DLL,
"GetDeviceGammaRamp");
15050 if ((NULL == g_pSetDeviceGammaRamp) ||
15051 (NULL == g_pGetDeviceGammaRamp)) {
15052 FreeLibrary(hGDI32DLL);
15061 if (!g_pSavedGammaMap) {
15062 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15065 bbr = g_pGetDeviceGammaRamp(
15066 hDC, g_pSavedGammaMap);
15067 ReleaseDC(NULL, hDC);
15072 wxRegKey *pRegKey =
new wxRegKey(
15073 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15074 "NT\\CurrentVersion\\ICM");
15075 if (!pRegKey->Exists()) pRegKey->Create();
15076 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15078 g_brightness_init =
true;
15084 if (NULL == g_pcurtain) {
15085 if (top_frame::Get()->CanSetTransparent()) {
15087 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15088 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15089 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15090 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15097 g_pcurtain->Hide();
15099 HWND hWnd = GetHwndOf(g_pcurtain);
15100 SetWindowLong(hWnd, GWL_EXSTYLE,
15101 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15102 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15103 g_pcurtain->SetTransparent(0);
15105 g_pcurtain->Maximize();
15106 g_pcurtain->Show();
15109 g_pcurtain->Enable();
15110 g_pcurtain->Disable();
15112 top_frame::Get()->Disable();
15113 top_frame::Get()->Enable();
15117 g_brightness_init =
true;
15123 wxString cmd(
"xcalib -version");
15125 wxArrayString output;
15126 long r = wxExecute(cmd, output);
15129 " External application \"xcalib\" not found. Screen brightness "
15132 g_brightness_init =
true;
15137int RestoreScreenBrightness() {
15140 if (g_pSavedGammaMap) {
15141 HDC hDC = GetDC(NULL);
15142 g_pSetDeviceGammaRamp(hDC,
15144 ReleaseDC(NULL, hDC);
15146 free(g_pSavedGammaMap);
15147 g_pSavedGammaMap = NULL;
15151 g_pcurtain->Close();
15152 g_pcurtain->Destroy();
15156 g_brightness_init =
false;
15161#ifdef BRIGHT_XCALIB
15162 if (g_brightness_init) {
15164 cmd =
"xcalib -clear";
15165 wxExecute(cmd, wxEXEC_ASYNC);
15166 g_brightness_init =
false;
15176int SetScreenBrightness(
int brightness) {
15183 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15185 g_pcurtain->Close();
15186 g_pcurtain->Destroy();
15190 InitScreenBrightness();
15192 if (NULL == hGDI32DLL) {
15194 wchar_t wdll_name[80];
15195 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15196 LPCWSTR cstr = wdll_name;
15198 hGDI32DLL = LoadLibrary(cstr);
15200 if (NULL != hGDI32DLL) {
15202 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15203 hGDI32DLL,
"SetDeviceGammaRamp");
15204 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15205 hGDI32DLL,
"GetDeviceGammaRamp");
15208 if ((NULL == g_pSetDeviceGammaRamp) ||
15209 (NULL == g_pGetDeviceGammaRamp)) {
15210 FreeLibrary(hGDI32DLL);
15217 HDC hDC = GetDC(NULL);
15228 int increment = brightness * 256 / 100;
15231 WORD GammaTable[3][256];
15234 for (
int i = 0; i < 256; i++) {
15235 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15236 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15237 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15239 table_val += increment;
15241 if (table_val > 65535) table_val = 65535;
15244 g_pSetDeviceGammaRamp(hDC, GammaTable);
15245 ReleaseDC(NULL, hDC);
15252 if (g_pSavedGammaMap) {
15253 HDC hDC = GetDC(NULL);
15254 g_pSetDeviceGammaRamp(hDC,
15256 ReleaseDC(NULL, hDC);
15259 if (brightness < 100) {
15260 if (NULL == g_pcurtain) InitScreenBrightness();
15263 int sbrite = wxMax(1, brightness);
15264 sbrite = wxMin(100, sbrite);
15266 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15270 g_pcurtain->Close();
15271 g_pcurtain->Destroy();
15281#ifdef BRIGHT_XCALIB
15283 if (!g_brightness_init) {
15284 last_brightness = 100;
15285 g_brightness_init =
true;
15286 temp_file_name = wxFileName::CreateTempFileName(
"");
15287 InitScreenBrightness();
15290#ifdef __OPCPN_USEICC__
15293 if (!CreateSimpleICCProfileFile(
15294 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15295 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15296 wxString cmd(
"xcalib ");
15297 cmd += temp_file_name;
15299 wxExecute(cmd, wxEXEC_ASYNC);
15308 if (brightness > last_brightness) {
15310 cmd =
"xcalib -clear";
15311 wxExecute(cmd, wxEXEC_ASYNC);
15313 ::wxMilliSleep(10);
15315 int brite_adj = wxMax(1, brightness);
15316 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15317 wxExecute(cmd, wxEXEC_ASYNC);
15319 int brite_adj = wxMax(1, brightness);
15320 int factor = (brite_adj * 100) / last_brightness;
15321 factor = wxMax(1, factor);
15323 cmd.Printf(
"xcalib -co %2d -a", factor);
15324 wxExecute(cmd, wxEXEC_ASYNC);
15329 last_brightness = brightness;
15336#ifdef __OPCPN_USEICC__
15338#define MLUT_TAG 0x6d4c5554L
15339#define VCGT_TAG 0x76636774L
15341int GetIntEndian(
unsigned char *s) {
15346 p = (
unsigned char *)&ret;
15349 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15351 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15356unsigned short GetShortEndian(
unsigned char *s) {
15357 unsigned short ret;
15361 p = (
unsigned char *)&ret;
15364 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15366 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15372int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15373 double co_green,
double co_blue) {
15377 fp = fopen(file_name,
"wb");
15378 if (!fp)
return -1;
15384 for (
int i = 0; i < 128; i++) header[i] = 0;
15386 fwrite(header, 128, 1, fp);
15390 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15391 fwrite(&numTags, 1, 4, fp);
15393 int tagName0 = VCGT_TAG;
15394 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15395 fwrite(&tagName, 1, 4, fp);
15397 int tagOffset0 = 128 + 4 *
sizeof(int);
15398 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15399 fwrite(&tagOffset, 1, 4, fp);
15402 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15403 fwrite(&tagSize, 1, 4, fp);
15405 fwrite(&tagName, 1, 4, fp);
15407 fwrite(&tagName, 1, 4, fp);
15412 int gammatype0 = 0;
15413 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15414 fwrite(&gammatype, 1, 4, fp);
15416 int numChannels0 = 3;
15417 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15418 fwrite(&numChannels, 1, 2, fp);
15420 int numEntries0 = 256;
15421 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15422 fwrite(&numEntries, 1, 2, fp);
15424 int entrySize0 = 1;
15425 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15426 fwrite(&entrySize, 1, 2, fp);
15428 unsigned char ramp[256];
15431 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15432 fwrite(ramp, 256, 1, fp);
15435 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15436 fwrite(ramp, 256, 1, fp);
15439 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15440 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.