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;
480 m_canvas_scale_factor = 1.;
482 m_canvas_width = 1000;
484 m_overzoomTextWidth = 0;
485 m_overzoomTextHeight = 0;
494 m_pEM_Fathoms = NULL;
496 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
498 m_pEM_OverZoom = NULL;
500 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
508 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
511 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
514 double factor_dusk = 0.5;
515 double factor_night = 0.25;
518 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
520 int rimg_width = m_os_image_red_day.GetWidth();
521 int rimg_height = m_os_image_red_day.GetHeight();
523 m_os_image_red_dusk = m_os_image_red_day.Copy();
524 m_os_image_red_night = m_os_image_red_day.Copy();
526 for (
int iy = 0; iy < rimg_height; iy++) {
527 for (
int ix = 0; ix < rimg_width; ix++) {
528 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
529 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
530 m_os_image_red_day.GetGreen(ix, iy),
531 m_os_image_red_day.GetBlue(ix, iy));
532 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
533 hsv.value = hsv.value * factor_dusk;
534 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
535 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
537 hsv = wxImage::RGBtoHSV(rgb);
538 hsv.value = hsv.value * factor_night;
539 nrgb = wxImage::HSVtoRGB(hsv);
540 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
546 m_os_image_grey_day =
547 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
549 int gimg_width = m_os_image_grey_day.GetWidth();
550 int gimg_height = m_os_image_grey_day.GetHeight();
552 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
553 m_os_image_grey_night = m_os_image_grey_day.Copy();
555 for (
int iy = 0; iy < gimg_height; iy++) {
556 for (
int ix = 0; ix < gimg_width; ix++) {
557 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
558 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
559 m_os_image_grey_day.GetGreen(ix, iy),
560 m_os_image_grey_day.GetBlue(ix, iy));
561 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
562 hsv.value = hsv.value * factor_dusk;
563 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
564 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
566 hsv = wxImage::RGBtoHSV(rgb);
567 hsv.value = hsv.value * factor_night;
568 nrgb = wxImage::HSVtoRGB(hsv);
569 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
575 m_os_image_yellow_day = m_os_image_red_day.Copy();
577 gimg_width = m_os_image_yellow_day.GetWidth();
578 gimg_height = m_os_image_yellow_day.GetHeight();
580 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
581 m_os_image_yellow_night = m_os_image_red_day.Copy();
583 for (
int iy = 0; iy < gimg_height; iy++) {
584 for (
int ix = 0; ix < gimg_width; ix++) {
585 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
586 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
587 m_os_image_yellow_day.GetGreen(ix, iy),
588 m_os_image_yellow_day.GetBlue(ix, iy));
589 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
590 hsv.hue += 60. / 360.;
591 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
592 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
594 hsv = wxImage::RGBtoHSV(rgb);
595 hsv.value = hsv.value * factor_dusk;
596 hsv.hue += 60. / 360.;
597 nrgb = wxImage::HSVtoRGB(hsv);
598 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
600 hsv = wxImage::RGBtoHSV(rgb);
601 hsv.hue += 60. / 360.;
602 hsv.value = hsv.value * factor_night;
603 nrgb = wxImage::HSVtoRGB(hsv);
604 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
610 m_pos_image_red = &m_os_image_red_day;
611 m_pos_image_yellow = &m_os_image_yellow_day;
612 m_pos_image_grey = &m_os_image_grey_day;
616 m_pBrightPopup = NULL;
619 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
624 m_Piano =
new Piano(
this);
626 m_bShowCompassWin =
false;
628 m_Compass->SetScaleFactor(g_compass_scalefactor);
629 m_Compass->Show(
false);
631 if (IsPrimaryCanvas() && !g_disableNotifications) {
633 m_notification_button->SetScaleFactor(g_compass_scalefactor);
634 m_notification_button->Show(
true);
637 m_pianoFrozen =
false;
639 SetMinSize(wxSize(200, 200));
641 m_displayScale = 1.0;
642#if defined(__WXOSX__) || defined(__WXGTK3__)
644 m_displayScale = GetContentScaleFactor();
646 VPoint.SetPixelScale(m_displayScale);
648#ifdef HAVE_WX_GESTURE_EVENTS
651 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
652 wxLogError(
"Failed to enable touch events");
657 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
658 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
660 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
661 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
663 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
664 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
666 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
667 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
672 auto ¬eman = NotificationManager::GetInstance();
674 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
675 evt_notificationlist_change_listener.Listen(
676 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
677 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
678 if (m_NotificationsList && m_NotificationsList->IsShown()) {
679 m_NotificationsList->ReloadNotificationList();
685ChartCanvas::~ChartCanvas() {
686 delete pThumbDIBShow;
694 delete pCursorPencil;
698 delete pMovementTimer;
699 delete pMovementStopTimer;
700 delete pCurTrackTimer;
702 delete m_DoubleClickTimer;
704 delete m_pTrackRolloverWin;
705 delete m_pRouteRolloverWin;
706 delete m_pAISRolloverWin;
707 delete m_pBrightPopup;
713 m_dc_route.SelectObject(wxNullBitmap);
716 delete pWorldBackgroundChart;
717 delete pss_overlay_bmp;
721 delete m_pEM_Fathoms;
723 delete m_pEM_OverZoom;
728 delete m_pos_image_user_day;
729 delete m_pos_image_user_dusk;
730 delete m_pos_image_user_night;
731 delete m_pos_image_user_grey_day;
732 delete m_pos_image_user_grey_dusk;
733 delete m_pos_image_user_grey_night;
734 delete m_pos_image_user_yellow_day;
735 delete m_pos_image_user_yellow_dusk;
736 delete m_pos_image_user_yellow_night;
740 if (!g_bdisable_opengl) {
743#if wxCHECK_VERSION(2, 9, 0)
744 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
751 MUIBar *muiBar = m_muiBar;
755 delete m_pCurrentStack;
758 delete m_notification_button;
761void ChartCanvas::SetupGridFont() {
762 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
764 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
766 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
767 FALSE, wxString(
"Arial"));
770void ChartCanvas::RebuildCursors() {
776 delete pCursorPencil;
780 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
785 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
786 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
787 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
788 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
789 wxImage ICursorPencil =
790 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
791 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
793#if !defined(__WXMSW__) && !defined(__WXQT__)
794 ICursorLeft.ConvertAlphaToMask(128);
795 ICursorRight.ConvertAlphaToMask(128);
796 ICursorUp.ConvertAlphaToMask(128);
797 ICursorDown.ConvertAlphaToMask(128);
798 ICursorPencil.ConvertAlphaToMask(10);
799 ICursorCross.ConvertAlphaToMask(10);
802 if (ICursorLeft.Ok()) {
803 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
804 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
805 pCursorLeft =
new wxCursor(ICursorLeft);
807 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
809 if (ICursorRight.Ok()) {
810 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
811 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
812 pCursorRight =
new wxCursor(ICursorRight);
814 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
816 if (ICursorUp.Ok()) {
817 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
818 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
819 pCursorUp =
new wxCursor(ICursorUp);
821 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
823 if (ICursorDown.Ok()) {
824 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
825 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
826 pCursorDown =
new wxCursor(ICursorDown);
828 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
830 if (ICursorPencil.Ok()) {
831 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
832 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
833 pCursorPencil =
new wxCursor(ICursorPencil);
835 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
837 if (ICursorCross.Ok()) {
838 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
839 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
840 pCursorCross =
new wxCursor(ICursorCross);
842 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
844 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
845 pPlugIn_Cursor = NULL;
848void ChartCanvas::CanvasApplyLocale() {
849 CreateDepthUnitEmbossMaps(m_cs);
850 CreateOZEmbossMapData(m_cs);
853void ChartCanvas::SetupGlCanvas() {
856 if (!g_bdisable_opengl) {
858 wxLogMessage(
"Creating glChartCanvas");
863 if (IsPrimaryCanvas()) {
870 wxGLContext *pctx =
new wxGLContext(m_glcc);
871 m_glcc->SetContext(pctx);
875 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
877 m_glcc->SetContext(g_pGLcontext);
887 if (!g_bdisable_opengl) {
890 wxLogMessage(
"Creating glChartCanvas");
894 if (IsPrimaryCanvas()) {
895 qDebug() <<
"Creating Primary glChartCanvas";
903 wxGLContext *pctx =
new wxGLContext(m_glcc);
904 m_glcc->SetContext(pctx);
906 m_glcc->m_pParentCanvas =
this;
909 qDebug() <<
"Creating Secondary glChartCanvas";
916 top_frame::Get()->GetWxGlCanvas());
919 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
920 m_glcc->SetContext(pwxctx);
921 m_glcc->m_pParentCanvas =
this;
929void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
930 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
945 if (m_routeState && m_FinishRouteOnKillFocus)
946 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
948 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
952void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
953 m_routeFinishTimer.Stop();
957 top_frame::Get()->UpdateGlobalMenuItems(
this);
959 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
962void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
963 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
966#ifdef HAVE_WX_GESTURE_EVENTS
967void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
974 m_popupWanted =
true;
976 m_inLongPress = !g_bhide_context_menus;
979 m_menuPos =
event.GetPosition();
980 wxMouseEvent ev(wxEVT_LEFT_UP);
981 ev.m_x = m_menuPos.x;
982 ev.m_y = m_menuPos.y;
983 wxPostEvent(
this, ev);
987 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
988 ev_right_click.m_x = m_menuPos.x;
989 ev_right_click.m_y = m_menuPos.y;
990 MouseEvent(ev_right_click);
995void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
999void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1001void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1003void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1005 long dt = m_sw_left_up.Time() - m_sw_up_time;
1006 m_sw_up_time = m_sw_left_up.Time();
1017 wxPoint pos =
event.GetPosition();
1021 if (!m_popupWanted) {
1022 wxMouseEvent ev(wxEVT_LEFT_UP);
1029 m_popupWanted =
false;
1031 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1038void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1043 long dt = m_sw_left_down.Time() - m_sw_down_time;
1044 m_sw_down_time = m_sw_left_down.Time();
1068 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1070 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1071 m_lastTapPos.y - max_double_click_distance,
1072 max_double_click_distance * 2, max_double_click_distance * 2);
1075 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1081 m_lastTapPos =
event.GetPosition();
1082 m_tap_timer.StartOnce(
1086 if (m_tap_count == 2) {
1090 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1103void ChartCanvas::OnMotion(wxMouseEvent &event) {
1108 event.m_leftDown = m_leftdown;
1112void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1114 if (event.IsGestureEnd())
return;
1116 double factor =
event.GetZoomFactor();
1118 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1123 double wanted_factor = m_oldVPSScale / current_vps * factor;
1128 if (event.IsGestureStart()) {
1129 m_zoomStartPoint =
event.GetPosition();
1131 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1133 m_zoomStartPoint =
event.GetPosition();
1137void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1139void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1140 DoRotateCanvas(0.0);
1144void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1149void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1150 m_FinishRouteOnKillFocus =
false;
1151 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1152 m_FinishRouteOnKillFocus =
true;
1155void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1160 m_restore_dbindex = pcc->DBindex;
1162 if (pcc->GroupID < 0) pcc->GroupID = 0;
1167 m_groupIndex = pcc->GroupID;
1169 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1181 SetbEnableBasemapTile((pcc->bEnableBasemapTile));
1185 m_encDisplayCategory = pcc->nENCDisplayCategory;
1186 m_encShowDepth = pcc->bShowENCDepths;
1187 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1188 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1189 m_encShowLights = pcc->bShowENCLights;
1190 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1191 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1192 m_encShowDataQual = pcc->bShowENCDataQuality;
1196 m_upMode = NORTH_UP_MODE;
1198 m_upMode = COURSE_UP_MODE;
1200 m_upMode = HEAD_UP_MODE;
1204 m_singleChart = NULL;
1207void ChartCanvas::ApplyGlobalSettings() {
1210 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1211 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1213 if (m_notification_button) m_notification_button->UpdateStatus();
1216void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1217 bool groupOK = CheckGroup(m_groupIndex);
1220 SetGroupIndex(m_groupIndex,
true);
1224void ChartCanvas::SetShowGPS(
bool bshow) {
1225 if (m_bShowGPS != bshow) {
1228 m_Compass->SetScaleFactor(g_compass_scalefactor);
1229 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1234void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1235 m_bShowCompassWin = bshow;
1237 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1238 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1242int ChartCanvas::GetPianoHeight() {
1244 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1249void ChartCanvas::ConfigureChartBar() {
1252 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1253 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1255 if (GetQuiltMode()) {
1256 m_Piano->SetRoundedRectangles(
true);
1258 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1259 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1260 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1263void ChartCanvas::ShowTides(
bool bShow) {
1264 top_frame::Get()->LoadHarmonics();
1267 SetbShowTide(bShow);
1269 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1271 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1272 SetbShowTide(
false);
1273 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1276 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1277 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1288void ChartCanvas::ShowCurrents(
bool bShow) {
1289 top_frame::Get()->LoadHarmonics();
1292 SetbShowCurrent(bShow);
1293 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1295 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1296 SetbShowCurrent(
false);
1297 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1300 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1301 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1318void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1320void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1323 int new_index = index;
1326 bool bgroup_override =
false;
1327 int old_group_index = new_index;
1329 if (!CheckGroup(new_index)) {
1331 bgroup_override =
true;
1334 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1338 int current_chart_native_scale = GetCanvasChartNativeScale();
1341 m_groupIndex = new_index;
1347 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1351 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1355 g_sticky_chart = -1;
1359 UpdateCanvasOnGroupChange();
1362 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1364 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1367 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1368 double best_scale = GetBestStartScale(dbi_hint, vp);
1372 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1376 canvasChartsRefresh(dbi_hint);
1378 UpdateCanvasControlBar();
1380 if (!autoSwitch && bgroup_override) {
1382 wxString msg(_(
"Group \""));
1385 msg += pGroup->m_group_name;
1387 msg += _(
"\" is empty.");
1389 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1396 if (bgroup_override) {
1397 wxString msg(_(
"Group \""));
1400 msg += pGroup->m_group_name;
1402 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1404 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1408bool ChartCanvas::CheckGroup(
int igroup) {
1411 if (igroup == 0)
return true;
1418 if (pGroup->m_element_array.empty())
1422 for (
const auto &elem : pGroup->m_element_array) {
1423 for (
unsigned int ic = 0;
1424 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1425 auto &cte =
ChartData->GetChartTableEntry(ic);
1426 wxString chart_full_path(cte.GetpFullPath(), wxConvUTF8);
1428 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1433 for (
const auto &elem : pGroup->m_element_array) {
1434 const wxString &element_root = elem.m_element_name;
1435 wxString test_string =
"GSHH";
1436 if (element_root.Upper().Contains(test_string))
return true;
1442void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1445 AbstractPlatform::ShowBusySpinner();
1449 SetQuiltRefChart(-1);
1451 m_singleChart = NULL;
1457 if (!m_pCurrentStack) {
1459 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1462 if (-1 != dbi_hint) {
1463 if (GetQuiltMode()) {
1464 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1465 SetQuiltRefChart(dbi_hint);
1469 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1471 if (pTentative_Chart) {
1474 if (m_singleChart) m_singleChart->Deactivate();
1476 m_singleChart = pTentative_Chart;
1477 m_singleChart->Activate();
1479 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1480 GetpCurrentStack(), m_singleChart->GetFullPath());
1488 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1489 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1490 SetQuiltRefChart(selected_index);
1494 SetupCanvasQuiltMode();
1495 if (!GetQuiltMode() && m_singleChart == 0) {
1497 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1498 m_singleChart = pDummyChart;
1504 UpdateCanvasControlBar();
1505 UpdateGPSCompassStatusBox(
true);
1507 SetCursor(wxCURSOR_ARROW);
1509 AbstractPlatform::HideBusySpinner();
1512bool ChartCanvas::DoCanvasUpdate() {
1514 double vpLat, vpLon;
1515 bool blong_jump =
false;
1516 meters_to_shift = 0;
1519 bool bNewChart =
false;
1520 bool bNewView =
false;
1521 bool bCanvasChartAutoOpen =
true;
1523 bool bNewPiano =
false;
1524 bool bOpenSpecified;
1530 if (!GetVP().IsValid())
return false;
1531 if (bDBUpdateInProgress)
return false;
1536 if (m_chart_drag_inertia_active)
return false;
1537 if (m_animationActive)
return false;
1563 double dx = m_OSoffsetx;
1564 double dy = m_OSoffsety;
1568 if (GetUpMode() == NORTH_UP_MODE) {
1569 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1571 double offset_angle = atan2(d_north, d_east);
1572 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1573 double chart_angle = GetVPRotation();
1574 double target_angle = chart_angle + offset_angle;
1575 double d_east_mod = offset_distance * cos(target_angle);
1576 double d_north_mod = offset_distance * sin(target_angle);
1577 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1581 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1582 double cog_to_use =
gCog;
1584 (fabs(
gCog - gCog_gt) > 20)) {
1585 cog_to_use = gCog_gt;
1588 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1590 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1592 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1593 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1595 double pixel_delta_tent =
1596 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1598 double pixel_delta = 0;
1603 if (!std::isnan(
gSog)) {
1607 pixel_delta = pixel_delta_tent;
1610 meters_to_shift = 0;
1612 if (!std::isnan(
gCog)) {
1613 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1614 dir_to_shift = cog_to_use;
1615 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1621 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1635 if (GetQuiltMode()) {
1636 int current_db_index = -1;
1637 if (m_pCurrentStack)
1640 ->GetCurrentEntrydbIndex();
1648 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1650 if (m_pCurrentStack->nEntry) {
1651 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1653 SelectQuiltRefdbChart(new_dbIndex,
true);
1654 m_bautofind =
false;
1658 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1659 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1664 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1670 double proposed_scale_onscreen =
1673 int initial_db_index = m_restore_dbindex;
1674 if (initial_db_index < 0) {
1675 if (m_pCurrentStack->nEntry) {
1677 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1682 if (m_pCurrentStack->nEntry) {
1683 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1688 if (!IsChartQuiltableRef(initial_db_index)) {
1692 int stack_index = 0;
1694 if (stack_index >= 0) {
1695 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1696 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1697 if (IsChartQuiltableRef(test_db_index) &&
1699 ChartData->GetDBChartType(initial_db_index))) {
1700 initial_db_index = test_db_index;
1710 SetQuiltRefChart(initial_db_index);
1711 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1719 0, GetVPRotation());
1724 bool super_jump =
false;
1726 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1727 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1728 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1735 pLast_Ch = m_singleChart;
1736 ChartTypeEnum new_open_type;
1737 ChartFamilyEnum new_open_family;
1739 new_open_type = pLast_Ch->GetChartType();
1740 new_open_family = pLast_Ch->GetChartFamily();
1742 new_open_type = CHART_TYPE_KAP;
1743 new_open_family = CHART_FAMILY_RASTER;
1746 bOpenSpecified = m_bFirstAuto;
1749 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1752 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1754 if (NULL == pDummyChart) {
1760 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1762 m_singleChart = pDummyChart;
1767 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1769 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1772 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1773 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1780 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1786 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1791 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1794 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1799 if (NULL != m_singleChart)
1800 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1801 m_singleChart->GetFullPath());
1804 m_pCurrentStack->CurrentStackEntry = tEntry;
1814 if (bCanvasChartAutoOpen) {
1815 bool search_direction =
1817 int start_index = 0;
1821 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1822 (LastStack.nEntry == 0)) {
1823 search_direction =
true;
1824 start_index = m_pCurrentStack->nEntry - 1;
1828 if (bOpenSpecified) {
1829 if (m_restore_dbindex >= 0) {
1831 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
1832 std::vector<int> one_array;
1833 one_array.push_back(m_restore_dbindex);
1834 m_Piano->SetActiveKeyArray(one_array);
1835 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
1836 m_restore_dbindex = -1;
1840 search_direction =
false;
1841 start_index = m_restore_dbindex;
1842 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1845 new_open_type = CHART_TYPE_DONTCARE;
1850 pProposed =
ChartData->OpenStackChartConditional(
1851 m_pCurrentStack, start_index, search_direction, new_open_type,
1855 if (NULL == pProposed)
1856 pProposed =
ChartData->OpenStackChartConditional(
1857 m_pCurrentStack, start_index, search_direction,
1858 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1860 if (NULL == pProposed)
1861 pProposed =
ChartData->OpenStackChartConditional(
1862 m_pCurrentStack, start_index, search_direction,
1863 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1874 if (NULL == pProposed) {
1875 if (NULL == pDummyChart) {
1881 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1883 pProposed = pDummyChart;
1887 if (m_singleChart) m_singleChart->Deactivate();
1888 m_singleChart = pProposed;
1890 if (m_singleChart) {
1891 m_singleChart->Activate();
1892 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1893 m_pCurrentStack, m_singleChart->GetFullPath());
1898 if (NULL != m_singleChart) {
1902 double proposed_scale_onscreen;
1905 double new_scale_ppm =
1906 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1914 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1915 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1916 double equivalent_vp_scale =
1918 double new_scale_ppm =
1919 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1924 proposed_scale_onscreen =
1925 wxMin(proposed_scale_onscreen,
1928 proposed_scale_onscreen =
1929 wxMax(proposed_scale_onscreen,
1937 m_singleChart->GetChartSkew() * PI / 180.,
1945 if ((m_bFollow) && m_singleChart)
1947 m_singleChart->GetChartSkew() * PI / 180.,
1956 m_bFirstAuto =
false;
1960 if (bNewChart && !bNewView) Refresh(
false);
1965 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1968 return bNewChart | bNewView;
1971void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1972 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1974 SetQuiltRefChart(db_index);
1979 double best_scale_ppm = GetBestVPScale(pc);
1983 SetQuiltRefChart(-1);
1985 SetQuiltRefChart(-1);
1988void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1989 std::vector<int> piano_chart_index_array =
1990 GetQuiltExtendedStackdbIndexArray();
1991 int current_db_index = piano_chart_index_array[selected_index];
1993 SelectQuiltRefdbChart(current_db_index);
1996double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2000 if ((g_bPreserveScaleOnX) ||
2001 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2007 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2008 double equivalent_vp_scale =
2010 double new_scale_ppm =
2011 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2018 double max_underzoom_multiplier = 2.0;
2019 if (GetVP().b_quilt) {
2020 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2021 pchart->GetChartType(),
2022 pchart->GetChartFamily());
2023 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2026 proposed_scale_onscreen = wxMin(
2027 proposed_scale_onscreen,
2029 max_underzoom_multiplier);
2032 proposed_scale_onscreen =
2033 wxMax(proposed_scale_onscreen,
2041void ChartCanvas::SetupCanvasQuiltMode() {
2046 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2050 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2051 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2052 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2053 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2055 m_Piano->SetRoundedRectangles(
true);
2058 int target_new_dbindex = -1;
2059 if (m_pCurrentStack) {
2060 target_new_dbindex =
2061 GetQuiltReferenceChartIndex();
2063 if (-1 != target_new_dbindex) {
2064 if (!IsChartQuiltableRef(target_new_dbindex)) {
2065 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2066 int type =
ChartData->GetDBChartType(target_new_dbindex);
2069 int stack_index = m_pCurrentStack->CurrentStackEntry;
2071 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2072 (stack_index >= 0)) {
2073 int proj_tent =
ChartData->GetDBChartProj(
2074 m_pCurrentStack->GetDBIndex(stack_index));
2075 int type_tent =
ChartData->GetDBChartType(
2076 m_pCurrentStack->GetDBIndex(stack_index));
2078 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2079 if ((proj == proj_tent) && (type_tent == type)) {
2080 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2090 if (IsChartQuiltableRef(target_new_dbindex))
2091 SelectQuiltRefdbChart(target_new_dbindex,
2094 int stack_index = m_pCurrentStack->CurrentStackEntry;
2095 SelectQuiltRefdbChart(m_pCurrentStack->GetDBIndex(stack_index),
false);
2098 m_singleChart = NULL;
2101 AdjustQuiltRefChart();
2109 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2113 std::vector<int> empty_array;
2114 m_Piano->SetActiveKeyArray(empty_array);
2115 m_Piano->SetNoshowIndexArray(empty_array);
2116 m_Piano->SetEclipsedIndexArray(empty_array);
2119 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2120 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2121 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2122 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2124 m_Piano->SetRoundedRectangles(
false);
2130 if (!GetQuiltMode()) {
2135 if (m_bFollow ==
true) {
2143 if (!m_singleChart) {
2145 if (GetQuiltReferenceChartIndex() >= 0) {
2146 m_singleChart =
ChartData->OpenChartFromDB(
2147 GetQuiltReferenceChartIndex(), FULL_INIT);
2150 else if (m_restore_dbindex >= 0) {
2152 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
2158 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2166 int cur_max_scale = (int)1e8;
2168 ChartBase *pChart = GetFirstQuiltChart();
2172 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2174 if (pChart->GetNativeScale() < cur_max_scale) {
2175 Candidate_Chart = pChart;
2176 cur_max_scale = pChart->GetNativeScale();
2179 pChart = GetNextQuiltChart();
2182 m_singleChart = Candidate_Chart;
2186 if (NULL == m_singleChart) {
2187 m_singleChart =
ChartData->OpenStackChartConditional(
2188 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2189 CHART_FAMILY_DONTCARE);
2195 InvalidateAllQuiltPatchs();
2197 if (m_singleChart) {
2198 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2199 std::vector<int> one_array;
2200 one_array.push_back(dbi);
2201 m_Piano->SetActiveKeyArray(one_array);
2204 if (m_singleChart) {
2205 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2210 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2214bool ChartCanvas::IsTempMenuBarEnabled() {
2217 wxGetOsVersion(&major);
2225double ChartCanvas::GetCanvasRangeMeters() {
2227 GetSize(&width, &height);
2228 int minDimension = wxMin(width, height);
2231 range *= cos(GetVP().clat * PI / 180.);
2235void ChartCanvas::SetCanvasRangeMeters(
double range) {
2237 GetSize(&width, &height);
2238 int minDimension = wxMin(width, height);
2240 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2244bool ChartCanvas::SetUserOwnship() {
2248 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2249 double factor_dusk = 0.5;
2250 double factor_night = 0.25;
2252 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2253 m_pos_image_user_day =
new wxImage;
2254 *m_pos_image_user_day = pbmp->ConvertToImage();
2255 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2257 int gimg_width = m_pos_image_user_day->GetWidth();
2258 int gimg_height = m_pos_image_user_day->GetHeight();
2261 m_pos_image_user_dusk =
new wxImage;
2262 m_pos_image_user_night =
new wxImage;
2264 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2265 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2267 for (
int iy = 0; iy < gimg_height; iy++) {
2268 for (
int ix = 0; ix < gimg_width; ix++) {
2269 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2270 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2271 m_pos_image_user_day->GetGreen(ix, iy),
2272 m_pos_image_user_day->GetBlue(ix, iy));
2273 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2274 hsv.value = hsv.value * factor_dusk;
2275 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2276 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2279 hsv = wxImage::RGBtoHSV(rgb);
2280 hsv.value = hsv.value * factor_night;
2281 nrgb = wxImage::HSVtoRGB(hsv);
2282 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2289 m_pos_image_user_grey_day =
new wxImage;
2290 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2292 m_pos_image_user_grey_dusk =
new wxImage;
2293 m_pos_image_user_grey_night =
new wxImage;
2295 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2296 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2298 for (
int iy = 0; iy < gimg_height; iy++) {
2299 for (
int ix = 0; ix < gimg_width; ix++) {
2300 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2301 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2302 m_pos_image_user_grey_day->GetGreen(ix, iy),
2303 m_pos_image_user_grey_day->GetBlue(ix, iy));
2304 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2305 hsv.value = hsv.value * factor_dusk;
2306 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2307 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2310 hsv = wxImage::RGBtoHSV(rgb);
2311 hsv.value = hsv.value * factor_night;
2312 nrgb = wxImage::HSVtoRGB(hsv);
2313 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2320 m_pos_image_user_yellow_day =
new wxImage;
2321 m_pos_image_user_yellow_dusk =
new wxImage;
2322 m_pos_image_user_yellow_night =
new wxImage;
2324 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2325 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2326 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2328 for (
int iy = 0; iy < gimg_height; iy++) {
2329 for (
int ix = 0; ix < gimg_width; ix++) {
2330 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2331 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2332 m_pos_image_user_grey_day->GetGreen(ix, iy),
2333 m_pos_image_user_grey_day->GetBlue(ix, iy));
2337 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2338 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2339 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2341 hsv = wxImage::RGBtoHSV(rgb);
2342 hsv.value = hsv.value * factor_dusk;
2343 nrgb = wxImage::HSVtoRGB(hsv);
2344 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2346 hsv = wxImage::RGBtoHSV(rgb);
2347 hsv.value = hsv.value * factor_night;
2348 nrgb = wxImage::HSVtoRGB(hsv);
2349 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2361 m_display_size_mm = size;
2368 double horizontal = sd.x;
2372 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2373 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2377 ps52plib->SetPPMM(m_pix_per_mm);
2382 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2384 m_display_size_mm, sd.x, sd.y);
2390 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2393 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2396void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2398 wxString msg(event.m_string.c_str(), wxConvUTF8);
2400 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2401 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2404 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2406 compress_msg_array.RemoveAt(event.thread);
2407 compress_msg_array.Insert( msg, event.thread);
2410 compress_msg_array.Add(msg);
2413 wxString combined_msg;
2414 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2415 combined_msg += compress_msg_array[i];
2416 combined_msg +=
"\n";
2420 pprog->Update(pprog_count, combined_msg, &skip );
2421 pprog->SetSize(pprog_size);
2426void ChartCanvas::InvalidateGL() {
2427 if (!m_glcc)
return;
2429 if (g_bopengl) m_glcc->Invalidate();
2431 if (m_Compass) m_Compass->UpdateStatus(
true);
2434int ChartCanvas::GetCanvasChartNativeScale() {
2436 if (!VPoint.b_quilt) {
2437 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2439 ret = (int)m_pQuilt->GetRefNativeScale();
2444ChartBase *ChartCanvas::GetChartAtCursor() {
2446 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2447 target_chart = m_singleChart;
2448 else if (VPoint.b_quilt)
2449 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2451 target_chart = NULL;
2452 return target_chart;
2455ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2459 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2461 target_chart = NULL;
2462 return target_chart;
2465int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2466 int new_dbIndex = -1;
2467 if (!VPoint.b_quilt) {
2468 if (m_pCurrentStack) {
2469 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2470 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2472 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2483 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2486 for (
unsigned int is = 0; is < im; is++) {
2488 m_pQuilt->GetExtendedStackIndexArray()[is]);
2489 if ((m.Scale_ge(
scale)) &&
2490 (m_pQuilt->GetRefFamily() == m.GetChartFamily())) {
2491 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2498 if (new_dbIndex < 0) {
2499 for (
unsigned int is = 0; is < im; is++) {
2501 m_pQuilt->GetExtendedStackIndexArray()[is]);
2502 if (m.Scale_ge(
scale)) {
2503 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2514void ChartCanvas::EnablePaint(
bool b_enable) {
2515 m_b_paint_enable = b_enable;
2517 if (m_glcc) m_glcc->EnablePaint(b_enable);
2521bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2523void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2525std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2526 return m_pQuilt->GetQuiltIndexArray();
2530void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2531 VPoint.b_quilt = b_quilt;
2532 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2535bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2537int ChartCanvas::GetQuiltReferenceChartIndex() {
2538 return m_pQuilt->GetRefChartdbIndex();
2541void ChartCanvas::InvalidateAllQuiltPatchs() {
2542 m_pQuilt->InvalidateAllQuiltPatchs();
2545ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2546 return m_pQuilt->GetLargestScaleChart();
2549ChartBase *ChartCanvas::GetFirstQuiltChart() {
2550 return m_pQuilt->GetFirstChart();
2553ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2555int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2557void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2558 m_pQuilt->SetHiliteIndex(dbIndex);
2561void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2562 m_pQuilt->SetHiliteIndexArray(hilite_array);
2565void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2566 m_pQuilt->ClearHiliteIndexArray();
2569std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2571 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2574int ChartCanvas::GetQuiltRefChartdbIndex() {
2575 return m_pQuilt->GetRefChartdbIndex();
2578std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2579 return m_pQuilt->GetExtendedStackIndexArray();
2582std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2583 return m_pQuilt->GetFullscreenIndexArray();
2586std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2587 return m_pQuilt->GetEclipsedStackIndexArray();
2590void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2592double ChartCanvas::GetQuiltMaxErrorFactor() {
2593 return m_pQuilt->GetMaxErrorFactor();
2596bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2597 return m_pQuilt->IsChartQuiltableRef(db_index);
2601 double chartMaxScale =
2603 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2606void ChartCanvas::StartMeasureRoute() {
2607 if (!m_routeState) {
2608 if (m_bMeasure_Active) {
2610 m_pMeasureRoute = NULL;
2613 m_bMeasure_Active =
true;
2614 m_nMeasureState = 1;
2615 m_bDrawingRoute =
false;
2617 SetCursor(*pCursorPencil);
2622void ChartCanvas::CancelMeasureRoute() {
2623 m_bMeasure_Active =
false;
2624 m_nMeasureState = 0;
2625 m_bDrawingRoute =
false;
2627 if (m_pMeasureRoute &&
g_pRouteMan->IsRouteInList(m_pMeasureRoute)) {
2629 }
else if (m_pMeasureRoute) {
2630 wxLogMessage(
"CancelMeasureRoute: stale route %p", m_pMeasureRoute);
2633 m_pMeasureRoute = NULL;
2635 SetCursor(*pCursorArrow);
2638ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2640void ChartCanvas::SetVP(
ViewPort &vp) {
2651void ChartCanvas::TriggerDeferredFocus() {
2654 m_deferredFocusTimer.Start(20,
true);
2656#if defined(__WXGTK__) || defined(__WXOSX__)
2657 top_frame::Get()->Raise();
2667void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2672void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2673 if (SendKeyEventToPlugins(event))
2677 int key_char =
event.GetKeyCode();
2680 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2686 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2691 if (g_benable_rotate) {
2712void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2713 if (SendKeyEventToPlugins(event))
2717 bool b_handled =
false;
2719 m_modkeys =
event.GetModifiers();
2721 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2723#ifdef OCPN_ALT_MENUBAR
2729 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2731 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2732 if (!g_bTempShowMenuBar) {
2733 g_bTempShowMenuBar =
true;
2734 top_frame::Get()->ApplyGlobalSettings(
false);
2736 m_bMayToggleMenuBar =
false;
2742 if (event.GetKeyCode() != WXK_ALT) {
2743 m_bMayToggleMenuBar =
false;
2750 switch (event.GetKeyCode()) {
2757 event.GetPosition(&x, &y);
2758 m_FinishRouteOnKillFocus =
false;
2759 CallPopupMenu(x, y);
2760 m_FinishRouteOnKillFocus =
true;
2764 m_modkeys |= wxMOD_ALT;
2768 m_modkeys |= wxMOD_CONTROL;
2773 case WXK_RAW_CONTROL:
2774 m_modkeys |= wxMOD_RAW_CONTROL;
2779 if (m_modkeys == wxMOD_CONTROL)
2780 top_frame::Get()->DoStackDown(
this);
2782 StartTimedMovement();
2792 StartTimedMovement();
2800 if (m_modkeys == wxMOD_CONTROL)
2801 top_frame::Get()->DoStackUp(
this);
2803 StartTimedMovement();
2813 StartTimedMovement();
2821 if (event.ShiftDown()) {
2823 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2825 std::shared_ptr<HostApi> host_api;
2827 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2830 api_121->SelectChartFamily(m_canvasIndex,
2837 if (event.ShiftDown()) {
2839 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2841 std::shared_ptr<HostApi> host_api;
2843 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2846 api_121->SelectChartFamily(m_canvasIndex,
2849 SetShowENCText(!GetShowENCText());
2856 if (!m_bMeasure_Active) {
2857 if (event.ShiftDown())
2858 m_bMeasure_DistCircle =
true;
2860 m_bMeasure_DistCircle =
false;
2862 StartMeasureRoute();
2864 CancelMeasureRoute();
2866 SetCursor(*pCursorArrow);
2876 top_frame::Get()->ToggleColorScheme();
2877 top_frame::Get()->Raise();
2878 TriggerDeferredFocus();
2882 int mod = m_modkeys & wxMOD_SHIFT;
2883 if (mod != m_brightmod) {
2885 m_bbrightdir = !m_bbrightdir;
2888 if (!m_bbrightdir) {
2889 g_nbrightness -= 10;
2890 if (g_nbrightness <= MIN_BRIGHT) {
2891 g_nbrightness = MIN_BRIGHT;
2892 m_bbrightdir =
true;
2895 g_nbrightness += 10;
2896 if (g_nbrightness >= MAX_BRIGHT) {
2897 g_nbrightness = MAX_BRIGHT;
2898 m_bbrightdir =
false;
2902 SetScreenBrightness(g_nbrightness);
2903 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2906 top_frame::Get()->Raise();
2912 top_frame::Get()->DoStackDown(
this);
2916 top_frame::Get()->DoStackUp(
this);
2921 ToggleCanvasQuiltMode();
2927 top_frame::Get()->ToggleFullScreen();
2932 if (m_modkeys == wxMOD_ALT) {
2935 ToggleChartOutlines();
2941 top_frame::Get()->ActivateMOB();
2945 case WXK_NUMPAD_ADD:
2950 case WXK_NUMPAD_SUBTRACT:
2951 case WXK_PAGEDOWN: {
2952 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2957 if (m_bMeasure_Active) {
2958 if (m_nMeasureState > 2) {
2959 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2961 m_pMeasureRoute->GetnPoints();
2963 top_frame::Get()->RefreshAllCanvas();
2965 CancelMeasureRoute();
2966 StartMeasureRoute();
2974 if (event.GetKeyCode() < 128)
2976 int key_char =
event.GetKeyCode();
2980 if (!g_b_assume_azerty) {
2982 if (g_benable_rotate) {
3014 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3021 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3022 m_modkeys & wxMOD_RAW_CONTROL) {
3023 top_frame::Get()->ToggleFullScreen();
3028 if (event.ControlDown()) key_char -= 64;
3030 if (key_char >=
'0' && key_char <=
'9')
3031 SetGroupIndex(key_char -
'0');
3036 SetShowENCAnchor(!GetShowENCAnchor());
3042 top_frame::Get()->ToggleColorScheme();
3047 event.GetPosition(&x, &y);
3048 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3049 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3052 if (VPoint.b_quilt) {
3054 if (m_pQuilt->GetChartAtPix(
3059 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3061 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3066 if (m_singleChart) {
3067 ChartType = m_singleChart->GetChartType();
3068 ChartFam = m_singleChart->GetChartFamily();
3072 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3073 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3075 this, -1, ChartType, ChartFam,
3076 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3077 wxDefaultSize, wxSIMPLE_BORDER,
"");
3090 m_nmea_log->Raise();
3094 SetShowENCLights(!GetShowENCLights());
3100 if (event.ShiftDown())
3101 m_bMeasure_DistCircle =
true;
3103 m_bMeasure_DistCircle =
false;
3105 StartMeasureRoute();
3109 if (g_bInlandEcdis && ps52plib) {
3110 SetENCDisplayCategory((_DisCat)STANDARD);
3115 ToggleChartOutlines();
3119 ToggleCanvasQuiltMode();
3123 top_frame::Get()->ToggleTestPause();
3126 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3127 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3128 g_iNavAidRadarRingsNumberVisible = 1;
3129 else if (!g_bNavAidRadarRingsShown &&
3130 g_iNavAidRadarRingsNumberVisible == 1)
3131 g_iNavAidRadarRingsNumberVisible = 0;
3134 SetShowENCDepth(!m_encShowDepth);
3139 SetShowENCText(!GetShowENCText());
3144 SetShowENCDataQual(!GetShowENCDataQual());
3149 m_bShowNavobjects = !m_bShowNavobjects;
3164 if (g_bShowMenuBar ==
false) top_frame::Get()->ToggleChartBar(
this);
3169 if (event.ControlDown()) top_frame::Get()->DropMarker(
false);
3176 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3177 if ((indexActive + 1) <= r->GetnPoints()) {
3188 if (!g_bShowMenuBar) top_frame::Get()->DropMarker(
true);
3194 if (g_bSpaceDropMark) top_frame::Get()->DropMarker(
true);
3200 if (m_modkeys == wxMOD_CONTROL) top_frame::Get()->ActivateMOB();
3207 top_frame::Get()->DoSettings();
3211 parent_frame->Close();
3227 if (undo->AnythingToRedo()) {
3228 undo->RedoNextAction();
3235 if (event.ShiftDown()) {
3236 if (undo->AnythingToRedo()) {
3237 undo->RedoNextAction();
3242 if (undo->AnythingToUndo()) {
3243 undo->UndoLastAction();
3252 if (m_bMeasure_Active) {
3253 CancelMeasureRoute();
3255 SetCursor(*pCursorArrow);
3258 top_frame::Get()->RefreshAllCanvas();
3272 switch (gamma_state) {
3292 SetScreenBrightness(g_nbrightness);
3297 if (event.ControlDown()) {
3298 m_bShowCompassWin = !m_bShowCompassWin;
3299 SetShowGPSCompassWindow(m_bShowCompassWin);
3316void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3317 if (SendKeyEventToPlugins(event))
3321 switch (event.GetKeyCode()) {
3323 top_frame::Get()->SwitchKBFocus(
this);
3329 if (!m_pany) m_panspeed = 0;
3335 if (!m_panx) m_panspeed = 0;
3338 case WXK_NUMPAD_ADD:
3339 case WXK_NUMPAD_SUBTRACT:
3348 m_modkeys &= ~wxMOD_ALT;
3349#ifdef OCPN_ALT_MENUBAR
3354 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3355 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3356 top_frame::Get()->ApplyGlobalSettings(
false);
3358 m_bMayToggleMenuBar =
true;
3364 m_modkeys &= ~wxMOD_CONTROL;
3368 if (event.GetKeyCode() < 128)
3370 int key_char =
event.GetKeyCode();
3374 if (!g_b_assume_azerty) {
3389 m_rotation_speed = 0;
3407void ChartCanvas::ToggleChartOutlines() {
3408 m_bShowOutlines = !m_bShowOutlines;
3414 if (g_bopengl) InvalidateGL();
3418void ChartCanvas::ToggleLookahead() {
3419 m_bLookAhead = !m_bLookAhead;
3424void ChartCanvas::SetUpMode(
int mode) {
3427 if (mode != NORTH_UP_MODE) {
3430 if (!std::isnan(
gCog)) stuff =
gCog;
3433 auto cog_table = top_frame::Get()->GetCOGTable();
3434 for (
int i = 0; i <
g_COGAvgSec; i++) cog_table[i] = stuff;
3437 top_frame::Get()->StartCogTimer();
3439 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3440 SetVPRotation(GetVPSkew());
3445 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3446 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3448 UpdateGPSCompassStatusBox(
true);
3449 top_frame::Get()->DoChartUpdate();
3452bool ChartCanvas::DoCanvasCOGSet() {
3453 if (GetUpMode() == NORTH_UP_MODE)
return false;
3455 if (g_btenhertz) cog_use =
gCog;
3457 double rotation = 0;
3458 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3459 rotation = -
gHdt * PI / 180.;
3460 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3461 rotation = -cog_use * PI / 180.;
3463 SetVPRotation(rotation);
3467double easeOutCubic(
double t) {
3469 return 1.0 - pow(1.0 - t, 3.0);
3472void ChartCanvas::StartChartDragInertia() {
3473 m_bChartDragging =
false;
3476 m_chart_drag_inertia_time = 750;
3477 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3482 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3486 size_t length = m_drag_vec_t.size();
3487 for (
size_t i = 0; i < n_vel; i++) {
3488 xacc += m_drag_vec_x.at(length - 1 - i);
3489 yacc += m_drag_vec_y.at(length - 1 - i);
3490 tacc += m_drag_vec_t.at(length - 1 - i);
3493 if (tacc == 0)
return;
3495 double drag_velocity_x = xacc / tacc;
3496 double drag_velocity_y = yacc / tacc;
3502 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3504 m_chart_drag_velocity_x = drag_velocity_x;
3505 m_chart_drag_velocity_y = drag_velocity_y;
3507 m_chart_drag_inertia_active =
true;
3509 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3512void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3513 if (!m_chart_drag_inertia_active)
return;
3515 wxLongLong now = wxGetLocalTimeMillis();
3516 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3517 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3518 if (t > 1.0) t = 1.0;
3519 double e = 1.0 - easeOutCubic(t);
3522 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3524 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3526 m_last_elapsed = elapsed;
3530 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3531 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3532 double inertia_lat, inertia_lon;
3534 double prev_clat = VPoint.
clat;
3537 if (fabs(VPoint.
clat - prev_clat) < 1e-9 && fabs(dy) > 1) {
3538 m_chart_drag_inertia_timer.Stop();
3539 m_chart_drag_inertia_active =
false;
3544 if (!IsOwnshipOnScreen()) {
3546 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3547 UpdateFollowButtonState();
3558 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3559 m_chart_drag_inertia_timer.Stop();
3562 m_target_lat = GetVP().
clat;
3563 m_target_lon = GetVP().
clon;
3564 m_pan_drag.x = m_pan_drag.y = 0;
3565 m_panx = m_pany = 0;
3566 m_chart_drag_inertia_active =
false;
3570 int target_redraw_interval = 40;
3571 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3575void ChartCanvas::StopMovement() {
3576 m_panx = m_pany = 0;
3579 m_rotation_speed = 0;
3582#if !defined(__WXGTK__) && !defined(__WXQT__)
3584 top_frame::Get()->Raise();
3593bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3595 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3597 if (!pMovementTimer->IsRunning()) {
3598 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3601 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3606 m_last_movement_time = wxDateTime::UNow();
3610void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3613 m_target_lat = target_lat;
3614 m_target_lon = target_lon;
3617 m_start_lat = GetVP().
clat;
3618 m_start_lon = GetVP().
clon;
3620 m_VPMovementTimer.Start(1,
true);
3621 m_timed_move_vp_active =
true;
3623 m_timedVP_step = nstep;
3626void ChartCanvas::DoTimedMovementVP() {
3627 if (!m_timed_move_vp_active)
return;
3628 if (m_stvpc++ > m_timedVP_step * 2) {
3635 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3650 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3651 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3653 m_run_lat = new_lat;
3654 m_run_lon = new_lon;
3659void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3661void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3663void ChartCanvas::StartTimedMovementTarget() {}
3665void ChartCanvas::DoTimedMovementTarget() {}
3667void ChartCanvas::StopMovementTarget() {}
3670void ChartCanvas::DoTimedMovement() {
3671 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3675 wxDateTime now = wxDateTime::UNow();
3677 if (m_last_movement_time.IsValid())
3678 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3680 m_last_movement_time = now;
3690 if (dt == 0) dt = 1;
3693 if (m_mustmove < 0) m_mustmove = 0;
3696 if (m_pan_drag.x || m_pan_drag.y) {
3698 m_pan_drag.x = m_pan_drag.y = 0;
3701 if (m_panx || m_pany) {
3702 const double slowpan = .1, maxpan = 2;
3703 if (m_modkeys == wxMOD_ALT)
3704 m_panspeed = slowpan;
3706 m_panspeed += (double)dt / 500;
3707 m_panspeed = wxMin(maxpan, m_panspeed);
3709 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3712 if (m_zoom_factor != 1) {
3713 double alpha = 400, beta = 1.5;
3714 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3716 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3718 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3723 if (zoom_factor > 1) {
3724 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3728 else if (zoom_factor < 1) {
3729 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3733 if ((
GetVPScale()) < (m_absolute_min_scale_ppm * 1.00001))
3738 if (fabs(zoom_factor - 1) > 1e-4) {
3739 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3744 if (m_wheelzoom_stop_oneshot > 0) {
3745 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3746 m_wheelzoom_stop_oneshot = 0;
3751 if (zoom_factor > 1) {
3753 m_wheelzoom_stop_oneshot = 0;
3756 }
else if (zoom_factor < 1) {
3758 m_wheelzoom_stop_oneshot = 0;
3765 if (m_rotation_speed) {
3766 double speed = m_rotation_speed;
3767 if (m_modkeys == wxMOD_ALT) speed /= 10;
3768 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3772void ChartCanvas::SetColorScheme(ColorScheme cs) {
3777 case GLOBAL_COLOR_SCHEME_DAY:
3778 m_pos_image_red = &m_os_image_red_day;
3779 m_pos_image_grey = &m_os_image_grey_day;
3780 m_pos_image_yellow = &m_os_image_yellow_day;
3781 m_pos_image_user = m_pos_image_user_day;
3782 m_pos_image_user_grey = m_pos_image_user_grey_day;
3783 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3784 m_cTideBitmap = m_bmTideDay;
3785 m_cCurrentBitmap = m_bmCurrentDay;
3788 case GLOBAL_COLOR_SCHEME_DUSK:
3789 m_pos_image_red = &m_os_image_red_dusk;
3790 m_pos_image_grey = &m_os_image_grey_dusk;
3791 m_pos_image_yellow = &m_os_image_yellow_dusk;
3792 m_pos_image_user = m_pos_image_user_dusk;
3793 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3794 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3795 m_cTideBitmap = m_bmTideDusk;
3796 m_cCurrentBitmap = m_bmCurrentDusk;
3798 case GLOBAL_COLOR_SCHEME_NIGHT:
3799 m_pos_image_red = &m_os_image_red_night;
3800 m_pos_image_grey = &m_os_image_grey_night;
3801 m_pos_image_yellow = &m_os_image_yellow_night;
3802 m_pos_image_user = m_pos_image_user_night;
3803 m_pos_image_user_grey = m_pos_image_user_grey_night;
3804 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3805 m_cTideBitmap = m_bmTideNight;
3806 m_cCurrentBitmap = m_bmCurrentNight;
3809 m_pos_image_red = &m_os_image_red_day;
3810 m_pos_image_grey = &m_os_image_grey_day;
3811 m_pos_image_yellow = &m_os_image_yellow_day;
3812 m_pos_image_user = m_pos_image_user_day;
3813 m_pos_image_user_grey = m_pos_image_user_grey_day;
3814 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3815 m_cTideBitmap = m_bmTideDay;
3816 m_cCurrentBitmap = m_bmCurrentDay;
3820 CreateDepthUnitEmbossMaps(cs);
3821 CreateOZEmbossMapData(cs);
3824 m_fog_color = wxColor(
3828 case GLOBAL_COLOR_SCHEME_DUSK:
3831 case GLOBAL_COLOR_SCHEME_NIGHT:
3837 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3838 m_fog_color.Blue() * dim);
3842 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3843 SetBackgroundColour( wxColour(0,0,0) );
3845 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3848 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3850 SetBackgroundColour( wxNullColour );
3857 m_Piano->SetColorScheme(cs);
3859 m_Compass->SetColorScheme(cs);
3861 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3863 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3865 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3866 if (m_notification_button) {
3867 m_notification_button->SetColorScheme(cs);
3871 if (g_bopengl && m_glcc) {
3872 m_glcc->SetColorScheme(cs);
3878 m_brepaint_piano =
true;
3885wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3886 wxImage img = Bitmap.ConvertToImage();
3887 int sx = img.GetWidth();
3888 int sy = img.GetHeight();
3890 wxImage new_img(img);
3892 for (
int i = 0; i < sx; i++) {
3893 for (
int j = 0; j < sy; j++) {
3894 if (!img.IsTransparent(i, j)) {
3895 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3896 (
unsigned char)(img.GetGreen(i, j) * factor),
3897 (
unsigned char)(img.GetBlue(i, j) * factor));
3902 wxBitmap ret = wxBitmap(new_img);
3907void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3910 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3912 if (!m_pBrightPopup) {
3915 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3919 m_pBrightPopup->SetSize(x, y);
3920 m_pBrightPopup->Move(120, 120);
3923 int bmpsx = m_pBrightPopup->GetSize().x;
3924 int bmpsy = m_pBrightPopup->GetSize().y;
3926 wxBitmap bmp(bmpsx, bmpsx);
3927 wxMemoryDC mdc(bmp);
3929 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3930 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3931 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3932 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3935 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3937 mdc.SetFont(*pfont);
3940 if (brightness == max)
3942 else if (brightness == min)
3945 val.Printf(
"%3d", brightness);
3947 mdc.DrawText(val, 0, 0);
3949 mdc.SelectObject(wxNullBitmap);
3951 m_pBrightPopup->SetBitmap(bmp);
3952 m_pBrightPopup->Show();
3953 m_pBrightPopup->Refresh();
3956void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3957 m_b_rot_hidef =
true;
3961void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3964 bool b_need_refresh =
false;
3966 wxSize win_size = GetSize() * m_displayScale;
3970 bool showAISRollover =
false;
3972 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3976 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3977 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3980 showAISRollover =
true;
3982 if (NULL == m_pAISRolloverWin) {
3984 m_pAISRolloverWin->IsActive(
false);
3985 b_need_refresh =
true;
3986 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3987 m_AISRollover_MMSI != FoundAIS_MMSI) {
3993 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3994 m_pAISRolloverWin->IsActive(
false);
3995 m_AISRollover_MMSI = 0;
4000 m_AISRollover_MMSI = FoundAIS_MMSI;
4002 if (!m_pAISRolloverWin->IsActive()) {
4003 wxString s = ptarget->GetRolloverString();
4004 m_pAISRolloverWin->SetString(s);
4006 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4007 AIS_ROLLOVER, win_size);
4008 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
4009 m_pAISRolloverWin->IsActive(
true);
4010 b_need_refresh =
true;
4014 m_AISRollover_MMSI = 0;
4015 showAISRollover =
false;
4020 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
4021 m_pAISRolloverWin->IsActive(
false);
4022 m_AISRollover_MMSI = 0;
4023 b_need_refresh =
true;
4028 bool showRouteRollover =
false;
4030 if (NULL == m_pRolloverRouteSeg) {
4034 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4035 SelectableItemList SelList =
pSelect->FindSelectionList(
4037 auto node = SelList.begin();
4038 while (node != SelList.end()) {
4043 if (pr && pr->IsVisible()) {
4044 m_pRolloverRouteSeg = pFindSel;
4045 showRouteRollover =
true;
4047 if (NULL == m_pRouteRolloverWin) {
4049 m_pRouteRolloverWin->IsActive(
false);
4052 if (!m_pRouteRolloverWin->IsActive()) {
4060 int ia = pr->GetIndexOf(segShow_point_a);
4061 int ib = pr->GetIndexOf(segShow_point_b);
4062 if (ia < 0 || ib < 0) {
4063 wxLogMessage(
"Ignoring stale route segment selection.");
4068 DistanceBearingMercator(
4069 segShow_point_b->m_lat, segShow_point_b->m_lon,
4070 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4072 if (!pr->m_bIsInLayer)
4073 s.Append(_(
"Route") +
": ");
4075 s.Append(_(
"Layer Route: "));
4077 if (pr->m_RouteNameString.IsEmpty())
4078 s.Append(_(
"(unnamed)"));
4080 s.Append(pr->m_RouteNameString);
4085 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4086 << segShow_point_b->GetName() <<
"\n";
4089 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4090 (
int)floor(brg + 0.5), 0x00B0);
4093 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4095 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4097 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4099 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4100 (
int)floor(varBrg + 0.5), 0x00B0);
4108 double shiptoEndLeg = 0.;
4109 bool validActive =
false;
4110 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4113 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4114 auto node = pr->pRoutePointList->begin();
4116 float dist_to_endleg = 0;
4119 for (++node; node != pr->pRoutePointList->end(); ++node) {
4126 if (prp->IsSame(segShow_point_a))
break;
4134 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4137 ->GetCurrentRngToActivePoint();
4146 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4151 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4152 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4154 << wxString(ttg_sec > SECONDS_PER_DAY
4155 ? ttg_span.Format(_(
"%Dd %H:%M"))
4156 : ttg_span.Format(_(
"%H:%M")));
4157 wxDateTime dtnow, eta;
4158 eta = dtnow.SetToCurrent().Add(ttg_span);
4159 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4160 << eta.Format(
" %d %H:%M");
4164 m_pRouteRolloverWin->SetString(s);
4166 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4167 LEG_ROLLOVER, win_size);
4168 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4169 m_pRouteRolloverWin->IsActive(
true);
4170 b_need_refresh =
true;
4171 showRouteRollover =
true;
4180 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4182 m_pRolloverRouteSeg))
4183 showRouteRollover =
false;
4184 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4185 showRouteRollover =
false;
4187 showRouteRollover =
true;
4191 if (m_routeState) showRouteRollover =
false;
4194 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4195 showRouteRollover =
false;
4197 if (m_pRouteRolloverWin &&
4198 !showRouteRollover) {
4199 m_pRouteRolloverWin->IsActive(
false);
4200 m_pRolloverRouteSeg = NULL;
4201 m_pRouteRolloverWin->Destroy();
4202 m_pRouteRolloverWin = NULL;
4203 b_need_refresh =
true;
4204 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4205 m_pRouteRolloverWin->IsActive(
true);
4206 b_need_refresh =
true;
4211 bool showTrackRollover =
false;
4213 if (NULL == m_pRolloverTrackSeg) {
4217 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4218 SelectableItemList SelList =
pSelect->FindSelectionList(
4221 auto node = SelList.begin();
4222 while (node != SelList.end()) {
4227 if (pt && pt->IsVisible()) {
4228 m_pRolloverTrackSeg = pFindSel;
4229 showTrackRollover =
true;
4231 if (NULL == m_pTrackRolloverWin) {
4233 m_pTrackRolloverWin->IsActive(
false);
4236 if (!m_pTrackRolloverWin->IsActive()) {
4244 DistanceBearingMercator(
4245 segShow_point_b->m_lat, segShow_point_b->m_lon,
4246 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4248 if (!pt->m_bIsInLayer)
4249 s.Append(_(
"Track") +
": ");
4251 s.Append(_(
"Layer Track: "));
4253 if (pt->GetName().IsEmpty())
4254 s.Append(_(
"(unnamed)"));
4256 s.Append(pt->GetName());
4257 double tlenght = pt->Length();
4259 if (pt->GetLastPoint()->GetTimeString() &&
4260 pt->GetPoint(0)->GetTimeString()) {
4261 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4262 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4263 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4264 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4265 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4266 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4267 << getUsrSpeedUnit();
4268 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4269 : ttime.Format(
" %H:%M"));
4273 if (g_bShowTrackPointTime &&
4274 strlen(segShow_point_b->GetTimeString())) {
4275 wxString stamp = segShow_point_b->GetTimeString();
4276 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4277 if (timestamp.IsValid()) {
4281 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4283 s <<
"\n" << _(
"Segment Created: ") << stamp;
4288 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4293 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4295 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4297 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4299 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4305 if (segShow_point_a->GetTimeString() &&
4306 segShow_point_b->GetTimeString()) {
4307 wxDateTime apoint = segShow_point_a->GetCreateTime();
4308 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4309 if (apoint.IsValid() && bpoint.IsValid()) {
4310 double segmentSpeed = toUsrSpeed(
4311 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4312 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4313 << getUsrSpeedUnit();
4317 m_pTrackRolloverWin->SetString(s);
4319 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4320 LEG_ROLLOVER, win_size);
4321 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4322 m_pTrackRolloverWin->IsActive(
true);
4323 b_need_refresh =
true;
4324 showTrackRollover =
true;
4333 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4335 m_pRolloverTrackSeg))
4336 showTrackRollover =
false;
4337 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4338 showTrackRollover =
false;
4340 showTrackRollover =
true;
4344 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4345 showTrackRollover =
false;
4348 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4349 showTrackRollover =
false;
4355 if (m_pTrackRolloverWin &&
4356 !showTrackRollover) {
4357 m_pTrackRolloverWin->IsActive(
false);
4358 m_pRolloverTrackSeg = NULL;
4359 m_pTrackRolloverWin->Destroy();
4360 m_pTrackRolloverWin = NULL;
4361 b_need_refresh =
true;
4362 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4363 m_pTrackRolloverWin->IsActive(
true);
4364 b_need_refresh =
true;
4367 if (b_need_refresh) Refresh();
4370void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4371 if ((GetShowENCLights() || m_bsectors_shown) &&
4372 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4373 extendedSectorLegs)) {
4374 if (!m_bsectors_shown) {
4376 m_bsectors_shown =
true;
4379 if (m_bsectors_shown) {
4381 m_bsectors_shown =
false;
4389#if defined(__WXGTK__) || defined(__WXQT__)
4394 double cursor_lat, cursor_lon;
4397 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4398 while (cursor_lon < -180.) cursor_lon += 360.;
4400 while (cursor_lon > 180.) cursor_lon -= 360.;
4402 SetCursorStatus(cursor_lat, cursor_lon);
4408void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4409 if (!top_frame::Get()->GetFrameStatusBar())
return;
4413 s1 += toSDMM(1, cursor_lat);
4415 s1 += toSDMM(2, cursor_lon);
4417 if (STAT_FIELD_CURSOR_LL >= 0)
4418 top_frame::Get()->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4420 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4425 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4426 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4427 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4429 wxString s = st + sm;
4442 if (g_bShowLiveETA) {
4445 float boatSpeedDefault = g_defaultBoatSpeed;
4450 if (!std::isnan(
gSog)) {
4452 if (boatSpeed < 0.5) {
4455 realTimeETA = dist / boatSpeed * 60;
4464 s << minutesToHoursDays(realTimeETA);
4469 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4470 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4472 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4477 top_frame::Get()->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4485wxString minutesToHoursDays(
float timeInMinutes) {
4488 if (timeInMinutes == 0) {
4493 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4494 s << wxString::Format(
"%d", (
int)timeInMinutes);
4499 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4502 hours = (int)timeInMinutes / 60;
4503 min = (int)timeInMinutes % 60;
4506 s << wxString::Format(
"%d", hours);
4509 s << wxString::Format(
"%d", hours);
4511 s << wxString::Format(
"%d", min);
4518 else if (timeInMinutes > 24 * 60) {
4521 days = (int)(timeInMinutes / 60) / 24;
4522 hours = (int)(timeInMinutes / 60) % 24;
4525 s << wxString::Format(
"%d", days);
4528 s << wxString::Format(
"%d", days);
4530 s << wxString::Format(
"%d", hours);
4542void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4550 wxPoint2DDouble *r) {
4555 double rlon, wxPoint2DDouble *r) {
4566 if (!g_bopengl && m_singleChart &&
4567 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4568 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4569 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4570 (m_singleChart->GetChartProjectionType() !=
4571 PROJECTION_TRANSVERSE_MERCATOR) &&
4572 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4573 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4574 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4588 Cur_BSB_Ch->SetVPRasterParms(vp);
4589 double rpixxd, rpixyd;
4590 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4616 if (std::isnan(p.m_x)) {
4617 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4621 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4622 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4624 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4643 if (!g_bopengl && m_singleChart &&
4644 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4645 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4646 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4647 (m_singleChart->GetChartProjectionType() !=
4648 PROJECTION_TRANSVERSE_MERCATOR) &&
4649 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4650 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4651 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4662 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4665 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4670 else if (slon > 180.)
4681 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4687 DoZoomCanvas(factor,
false);
4688 extendedSectorLegs.clear();
4693 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4696 if (StartTimedMovement(stoptimer)) {
4698 m_zoom_factor = factor;
4703 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4705 DoZoomCanvas(factor, can_zoom_to_cursor);
4708 extendedSectorLegs.clear();
4711void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4714 if (!m_pCurrentStack)
return;
4720 if (m_bzooming)
return;
4729 double proposed_scale_onscreen =
4732 bool b_do_zoom =
false;
4741 if (!VPoint.b_quilt) {
4744 if (!m_disable_adjust_on_zoom) {
4745 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4746 if (new_db_index >= 0)
4747 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4751 int current_ref_stack_index = -1;
4752 if (m_pCurrentStack->nEntry) {
4754 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4755 m_pQuilt->SetReferenceChart(trial_index);
4756 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4757 if (new_db_index >= 0)
4758 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4762 if (m_pCurrentStack)
4763 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4774 double min_allowed_scale =
4777 if (proposed_scale_onscreen < min_allowed_scale) {
4782 proposed_scale_onscreen = min_allowed_scale;
4786 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4789 }
else if (factor < 1) {
4794 bool b_smallest =
false;
4796 if (!VPoint.b_quilt) {
4801 LLBBox viewbox = VPoint.GetBBox();
4803 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4804 double max_allowed_scale;
4818 if (proposed_scale_onscreen > max_allowed_scale) {
4820 proposed_scale_onscreen = max_allowed_scale;
4825 if (!m_disable_adjust_on_zoom) {
4827 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4828 if (new_db_index >= 0)
4829 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4831 if (m_pCurrentStack)
4832 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4835 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4837 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4838 proposed_scale_onscreen =
4839 wxMin(proposed_scale_onscreen,
4845 m_absolute_min_scale_ppm)
4846 proposed_scale_onscreen =
4855 bool b_allow_ztc =
true;
4856 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4857 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4859 double brg, distance;
4860 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4863 meters_to_shift = distance * 1852;
4871 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4874 if (m_bFollow) DoCanvasUpdate();
4881void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4883 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4887void ChartCanvas::RotateCanvas(
double dir) {
4891 if (StartTimedMovement()) {
4893 m_rotation_speed = dir * 60;
4896 double speed = dir * 10;
4897 if (m_modkeys == wxMOD_ALT) speed /= 20;
4898 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4902void ChartCanvas::DoRotateCanvas(
double rotation) {
4903 while (rotation < 0) rotation += 2 * PI;
4904 while (rotation > 2 * PI) rotation -= 2 * PI;
4906 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4908 SetVPRotation(rotation);
4909 top_frame::Get()->UpdateRotationState(VPoint.
rotation);
4912void ChartCanvas::DoTiltCanvas(
double tilt) {
4913 while (tilt < 0) tilt = 0;
4914 while (tilt > .95) tilt = .95;
4916 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4922void ChartCanvas::TogglebFollow() {
4929void ChartCanvas::ClearbFollow() {
4932 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4934 UpdateFollowButtonState();
4938 top_frame::Get()->SetChartUpdatePeriod();
4941void ChartCanvas::SetbFollow() {
4944 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4945 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4953 p.m_x += m_OSoffsetx;
4954 p.m_y -= m_OSoffsety;
4963 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4964 UpdateFollowButtonState();
4966 if (!g_bSmoothRecenter) {
4970 top_frame::Get()->SetChartUpdatePeriod();
4973void ChartCanvas::UpdateFollowButtonState() {
4976 m_muiBar->SetFollowButtonState(0);
4979 m_muiBar->SetFollowButtonState(2);
4981 m_muiBar->SetFollowButtonState(1);
4987 androidSetFollowTool(0);
4990 androidSetFollowTool(2);
4992 androidSetFollowTool(1);
4999 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
5000 if (pic->m_enabled && pic->m_init_state) {
5001 switch (pic->m_api_version) {
5004 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
5015void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
5016 if (g_bSmoothRecenter && !m_routeState) {
5017 if (StartSmoothJump(lat, lon, scale_ppm))
5021 double gcDist, gcBearingEnd;
5022 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
5024 gcBearingEnd += 180;
5025 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
5028 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
5029 double new_lat = lat + (lat_offset / (1852 * 60));
5030 double new_lon = lon + (lon_offset / (1852 * 60));
5033 StartSmoothJump(lat, lon, scale_ppm);
5038 if (lon > 180.0) lon -= 360.0;
5044 if (!GetQuiltMode()) {
5046 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
5047 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
5051 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5052 AdjustQuiltRefChart();
5059 UpdateFollowButtonState();
5067bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5072 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5073 double distance_pixels = gcDist *
GetVPScale();
5074 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5080 m_startLat = m_vLat;
5081 m_startLon = m_vLon;
5086 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5087 m_endScale = scale_ppm;
5090 m_animationDuration = 600;
5091 m_animationStart = wxGetLocalTimeMillis();
5098 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5099 m_animationActive =
true;
5104void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5106 wxLongLong now = wxGetLocalTimeMillis();
5107 double elapsed = (now - m_animationStart).ToDouble();
5108 double t = elapsed / m_animationDuration.ToDouble();
5109 if (t > 1.0) t = 1.0;
5112 double e = easeOutCubic(t);
5115 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5116 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5117 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5122 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5128 m_animationActive =
false;
5129 UpdateFollowButtonState();
5138 extendedSectorLegs.clear();
5147 if (iters++ > 5)
return false;
5148 if (!std::isnan(dlat))
break;
5151 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5154 if (dlon > 360.) dlon -= 360.;
5155 if (dlon < -360.) dlon += 360.;
5170 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5174 if (VPoint.b_quilt) {
5175 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5176 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5180 double tweak_scale_ppm =
5190 if (new_ref_dbIndex == -1) {
5191#pragma GCC diagnostic push
5192#pragma GCC diagnostic ignored "-Warray-bounds"
5199 int trial_index = -1;
5200 if (m_pCurrentStack->nEntry) {
5201 trial_index = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5204 if (trial_index < 0) {
5205 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5206 if (full_screen_array.size())
5207 trial_index = full_screen_array[full_screen_array.size() - 1];
5210 if (trial_index >= 0) {
5211 m_pQuilt->SetReferenceChart(trial_index);
5216#pragma GCC diagnostic pop
5224 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5226 double offset_angle = atan2(offy, offx);
5227 double offset_distance = sqrt((offy * offy) + (offx * offx));
5228 double chart_angle = GetVPRotation();
5229 double target_angle = chart_angle - offset_angle;
5230 double d_east_mod = offset_distance * cos(target_angle);
5231 double d_north_mod = offset_distance * sin(target_angle);
5236 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5237 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5239 UpdateFollowButtonState();
5245 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5250bool ChartCanvas::IsOwnshipOnScreen() {
5253 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5254 ((r.y > 0) && r.y < GetCanvasHeight()))
5260void ChartCanvas::ReloadVP(
bool b_adjust) {
5261 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5263 LoadVP(VPoint, b_adjust);
5266void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5268 if (g_bopengl && m_glcc) {
5269 m_glcc->Invalidate();
5270 if (m_glcc->GetSize() != GetSize()) {
5271 m_glcc->SetSize(GetSize());
5276 m_cache_vp.Invalidate();
5277 m_bm_cache_vp.Invalidate();
5280 VPoint.Invalidate();
5282 if (m_pQuilt) m_pQuilt->Invalidate();
5291 vp.m_projection_type, b_adjust);
5294void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5295 m_pQuilt->SetReferenceChart(dbIndex);
5296 VPoint.Invalidate();
5297 m_pQuilt->Invalidate();
5300double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5302 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5309int ChartCanvas::AdjustQuiltRefChart() {
5314 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5316 double min_ref_scale =
5317 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5318 double max_ref_scale =
5319 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5322 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5323 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5324 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5326 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5329 int target_stack_index = wxNOT_FOUND;
5331 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5332 if (index == m_pQuilt->GetRefChartdbIndex()) {
5333 target_stack_index = il;
5338 if (wxNOT_FOUND == target_stack_index)
5339 target_stack_index = 0;
5341 int ref_family = pc->GetChartFamily();
5342 int extended_array_count =
5343 m_pQuilt->GetExtendedStackIndexArray().size();
5344 while ((!brender_ok) &&
5345 ((
int)target_stack_index < (extended_array_count - 1))) {
5346 target_stack_index++;
5348 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5350 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5351 IsChartQuiltableRef(test_db_index)) {
5354 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5356 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5363 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5364 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5365 IsChartQuiltableRef(new_db_index)) {
5366 m_pQuilt->SetReferenceChart(new_db_index);
5369 ret = m_pQuilt->GetRefChartdbIndex();
5371 ret = m_pQuilt->GetRefChartdbIndex();
5374 ret = m_pQuilt->GetRefChartdbIndex();
5383void ChartCanvas::UpdateCanvasOnGroupChange() {
5384 delete m_pCurrentStack;
5396bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5397 double latNE,
double lonNE) {
5399 double latc = (latSW + latNE) / 2.0;
5400 double lonc = (lonSW + lonNE) / 2.0;
5403 double ne_easting, ne_northing;
5404 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5406 double sw_easting, sw_northing;
5407 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5409 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5416 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5419bool ChartCanvas::SetVPProjection(
int projection) {
5425 double prev_true_scale_ppm = m_true_scale_ppm;
5430 m_absolute_min_scale_ppm));
5438bool ChartCanvas::SetVPRotation(
double angle) {
5440 VPoint.
skew, angle);
5443 double skew,
double rotation,
int projection,
5444 bool b_adjust,
bool b_refresh) {
5450 if (VPoint.IsValid()) {
5451 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5452 (fabs(VPoint.
skew - skew) < 1e-9) &&
5453 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5454 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5455 (VPoint.m_projection_type == projection ||
5456 projection == PROJECTION_UNKNOWN))
5459 if (VPoint.m_projection_type != projection)
5460 VPoint.InvalidateTransformCache();
5470 if (projection != PROJECTION_UNKNOWN)
5471 VPoint.SetProjectionType(projection);
5472 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5473 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5478 static const double MAX_LAT = 85.0;
5480 if (VPoint.
pix_height > 0 && scale_ppm > 0) {
5481 double edge_lat, edge_lon;
5483 for (
int i = 0; i < 3; i++) {
5486 if (!std::isnan(edge_lat) && edge_lat > MAX_LAT) {
5487 VPoint.
clat -= (edge_lat - MAX_LAT);
5493 for (
int i = 0; i < 3; i++) {
5497 if (!std::isnan(edge_lat) && edge_lat < -MAX_LAT) {
5498 VPoint.
clat -= (edge_lat + MAX_LAT);
5506 if (VPoint.
clat > MAX_LAT)
5507 VPoint.
clat = MAX_LAT;
5508 else if (VPoint.
clat < -MAX_LAT)
5509 VPoint.
clat = -MAX_LAT;
5513 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5514 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5526 bool bwasValid = VPoint.IsValid();
5531 m_cache_vp.Invalidate();
5536 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5540 if (top_frame::Get()->GetCanvasIndexUnderMouse() == m_canvasIndex) {
5541 int mouseX = mouse_x;
5542 int mouseY = mouse_y;
5543 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5545 double lat_mouse, lon_mouse;
5553 if (!VPoint.b_quilt && m_singleChart) {
5558 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5562 if ((!m_cache_vp.IsValid()) ||
5567 wxPoint cp_last, cp_this;
5571 if (cp_last != cp_this) {
5577 if (m_pCurrentStack) {
5579 int current_db_index;
5581 m_pCurrentStack->GetCurrentEntrydbIndex();
5583 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5585 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5588 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5592 if (VPoint.b_quilt) {
5596 m_pQuilt->InvalidateAllQuiltPatchs();
5600 if (!m_pCurrentStack)
return false;
5602 int current_db_index;
5604 m_pCurrentStack->GetCurrentEntrydbIndex();
5606 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5607 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5610 int current_ref_stack_index = -1;
5611 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5612 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5613 current_ref_stack_index = i;
5616 if (g_bFullScreenQuilt) {
5617 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5621 bool b_needNewRef =
false;
5624 if ((-1 == current_ref_stack_index) &&
5625 (m_pQuilt->GetRefChartdbIndex() >= 0))
5626 b_needNewRef =
true;
5633 bool renderable =
true;
5635 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5636 if (referenceChart) {
5637 double chartMaxScale = referenceChart->GetNormalScaleMax(
5639 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5641 if (!renderable) b_needNewRef =
true;
5644 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5646 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5647 int target_scale = cte_ref.GetScale();
5648 int target_type = cte_ref.GetChartType();
5649 int candidate_stack_index;
5656 candidate_stack_index = 0;
5657 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5659 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5660 int candidate_scale = cte_candidate.GetScale();
5661 int candidate_type = cte_candidate.GetChartType();
5663 if ((candidate_scale >= target_scale) &&
5664 (candidate_type == target_type)) {
5665 bool renderable =
true;
5667 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5668 if (tentative_referenceChart) {
5669 double chartMaxScale =
5670 tentative_referenceChart->GetNormalScaleMax(
5672 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5675 if (renderable)
break;
5678 candidate_stack_index++;
5683 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5684 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5685 while (candidate_stack_index >= 0) {
5686 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5690 int candidate_scale = cte_candidate.GetScale();
5691 int candidate_type = cte_candidate.GetChartType();
5693 if ((candidate_scale <= target_scale) &&
5694 (candidate_type == target_type))
5697 candidate_stack_index--;
5702 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5703 (candidate_stack_index < 0))
5704 candidate_stack_index = 0;
5706 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5708 m_pQuilt->SetReferenceChart(new_ref_index);
5714 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5719 bool renderable =
true;
5721 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5722 if (referenceChart) {
5723 double chartMaxScale = referenceChart->GetNormalScaleMax(
5725 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5726 proj =
ChartData->GetDBChartProj(ref_db_index);
5728 proj = PROJECTION_MERCATOR;
5730 VPoint.b_MercatorProjectionOverride =
5731 (m_pQuilt->GetnCharts() == 0 || !renderable);
5733 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5735 VPoint.SetProjectionType(proj);
5740 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5745 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5765 m_pQuilt->Invalidate();
5782 if (b_refresh) Refresh(
false);
5789 }
else if (!g_bopengl) {
5790 OcpnProjType projection = PROJECTION_UNKNOWN;
5793 projection = m_singleChart->GetChartProjectionType();
5794 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5795 VPoint.SetProjectionType(projection);
5799 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5800 m_cache_vp.Invalidate();
5804 UpdateCanvasControlBar();
5808 if (VPoint.GetBBox().GetValid()) {
5811 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5820 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5823 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5830 wxPoint2DDouble r, r1;
5832 double delta_check =
5836 double check_point = wxMin(89., VPoint.
clat);
5838 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5841 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5842 VPoint.
clon, 0, &rhumbDist);
5847 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5848 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5850 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5854 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5860 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5862 if (m_true_scale_ppm)
5863 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5868 double round_factor = 1000.;
5872 round_factor = 100.;
5874 round_factor = 1000.;
5877 double retina_coef = 1;
5881 retina_coef = GetContentScaleFactor();
5892 double true_scale_display =
5893 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5898 if (m_displayed_scale_factor > 10.0)
5899 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5900 m_displayed_scale_factor);
5901 else if (m_displayed_scale_factor > 1.0)
5902 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5903 m_displayed_scale_factor);
5904 else if (m_displayed_scale_factor > 0.1) {
5905 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5906 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5907 }
else if (m_displayed_scale_factor > 0.01) {
5908 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5909 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5912 "%s %4.0f (---)", _(
"Scale"),
5913 true_scale_display);
5916 m_scaleValue = true_scale_display;
5918 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5920 if (m_bShowScaleInStatusBar && top_frame::Get()->GetStatusBar() &&
5921 (top_frame::Get()->GetStatusBar()->GetFieldsCount() >
5922 STAT_FIELD_SCALE)) {
5924 bool b_noshow =
false;
5928 wxClientDC dc(top_frame::Get()->GetStatusBar());
5930 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5931 dc.SetFont(*templateFont);
5932 dc.GetTextExtent(text, &w, &h);
5937 top_frame::Get()->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE,
5939 if (w && w > rect.width) {
5940 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5944 dc.GetTextExtent(text, &w, &h);
5946 if (w && w > rect.width) {
5952 if (!b_noshow) top_frame::Get()->SetStatusText(text, STAT_FIELD_SCALE);
5957 m_vLat = VPoint.
clat;
5958 m_vLon = VPoint.
clon;
5972static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5976static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5977 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5979wxColour ChartCanvas::PredColor() {
5982 if (SHIP_NORMAL == m_ownship_state)
5983 return GetGlobalColor(
"URED");
5985 else if (SHIP_LOWACCURACY == m_ownship_state)
5986 return GetGlobalColor(
"YELO1");
5988 return GetGlobalColor(
"NODTA");
5991wxColour ChartCanvas::ShipColor() {
5995 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5997 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5999 return GetGlobalColor(
"URED");
6002void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
6003 wxPoint2DDouble lShipMidPoint) {
6004 dc.SetPen(wxPen(PredColor(), 2));
6006 if (SHIP_NORMAL == m_ownship_state)
6007 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
6009 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
6011 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
6012 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
6014 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
6016 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
6017 lShipMidPoint.m_y + 12);
6020void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
6021 wxPoint GPSOffsetPixels,
6022 wxPoint2DDouble lGPSPoint) {
6027 float ref_dim = m_display_size_mm / 24;
6028 ref_dim = wxMin(ref_dim, 12);
6029 ref_dim = wxMax(ref_dim, 6);
6032 cPred.Set(g_cog_predictor_color);
6033 if (cPred == wxNullColour) cPred = PredColor();
6040 double nominal_line_width_pix = wxMax(
6042 floor(m_pix_per_mm / 2));
6046 if (nominal_line_width_pix > g_cog_predictor_width)
6047 g_cog_predictor_width = nominal_line_width_pix;
6050 wxPoint lPredPoint, lHeadPoint;
6052 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6053 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6055 double pred_lat, pred_lon;
6056 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
6057 &pred_lat, &pred_lon);
6068 float ndelta_pix = 10.;
6069 double hdg_pred_lat, hdg_pred_lon;
6070 bool b_render_hdt =
false;
6071 if (!std::isnan(
gHdt)) {
6073 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
6076 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
6077 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
6078 if (dist > ndelta_pix ) {
6079 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
6080 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6085 wxPoint lShipMidPoint;
6086 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6087 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6088 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6089 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6091 if (lpp >= img_height / 2) {
6092 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6093 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6094 !std::isnan(
gSog)) {
6096 float dash_length = ref_dim;
6097 wxDash dash_long[2];
6099 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6100 g_cog_predictor_width);
6101 dash_long[1] = dash_long[0] / 2.0;
6105 if (dash_length > 250.) {
6106 dash_long[0] = 250. / g_cog_predictor_width;
6107 dash_long[1] = dash_long[0] / 2;
6110 wxPen ppPen2(cPred, g_cog_predictor_width,
6111 (wxPenStyle)g_cog_predictor_style);
6112 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6113 ppPen2.SetDashes(2, dash_long);
6116 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6117 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6119 if (g_cog_predictor_width > 1) {
6120 float line_width = g_cog_predictor_width / 3.;
6122 wxDash dash_long3[2];
6123 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6124 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6126 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6127 (wxPenStyle)g_cog_predictor_style);
6128 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6129 ppPen3.SetDashes(2, dash_long3);
6131 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6132 lGPSPoint.m_y + GPSOffsetPixels.y,
6133 lPredPoint.x + GPSOffsetPixels.x,
6134 lPredPoint.y + GPSOffsetPixels.y);
6137 if (g_cog_predictor_endmarker) {
6139 double png_pred_icon_scale_factor = .4;
6140 if (g_ShipScaleFactorExp > 1.0)
6141 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6142 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6146 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6147 (
float)(lPredPoint.x - lShipMidPoint.x));
6148 cog_rad += (float)PI;
6150 for (
int i = 0; i < 4; i++) {
6152 double pxa = (double)(s_png_pred_icon[j]);
6153 double pya = (double)(s_png_pred_icon[j + 1]);
6155 pya *= png_pred_icon_scale_factor;
6156 pxa *= png_pred_icon_scale_factor;
6158 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6159 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6161 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6162 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6166 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6169 dc.SetBrush(wxBrush(cPred));
6171 dc.StrokePolygon(4, icon);
6178 float hdt_dash_length = ref_dim * 0.4;
6180 cPred.Set(g_ownship_HDTpredictor_color);
6181 if (cPred == wxNullColour) cPred = PredColor();
6183 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6184 : g_cog_predictor_width * 0.8);
6185 wxDash dash_short[2];
6187 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6190 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6193 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6194 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6195 ppPen2.SetDashes(2, dash_short);
6199 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6200 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6202 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6204 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6206 if (g_ownship_HDTpredictor_endmarker) {
6207 double nominal_circle_size_pixels = wxMax(
6208 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6211 if (g_ShipScaleFactorExp > 1.0)
6212 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6214 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6215 lHeadPoint.y + GPSOffsetPixels.y,
6216 nominal_circle_size_pixels / 2);
6221 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6222 double factor = 1.00;
6223 if (g_pNavAidRadarRingsStepUnits == 1)
6225 else if (g_pNavAidRadarRingsStepUnits == 2) {
6226 if (std::isnan(
gSog))
6231 factor *= g_fNavAidRadarRingsStep;
6235 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6238 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6239 pow((
double)(lGPSPoint.m_y - r.y), 2));
6240 int pix_radius = (int)lpp;
6242 wxColor rangeringcolour =
6243 user_colors::GetDimColor(g_colourOwnshipRangeRingsColour);
6245 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6248 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6250 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6251 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6256void ChartCanvas::ResetGlGridFont() { GetglCanvas()->ResetGridFont(); }
6257bool ChartCanvas::CanAccelerateGlPanning() {
6258 return GetglCanvas()->CanAcceleratePanning();
6260void ChartCanvas::SetupGlCompression() { GetglCanvas()->SetupCompression(); }
6263void ChartCanvas::ResetGlGridFont() {}
6264bool ChartCanvas::CanAccelerateGlPanning() {
return false; }
6265void ChartCanvas::SetupGlCompression() {}
6268void ChartCanvas::ComputeShipScaleFactor(
6269 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6270 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6271 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6272 float screenResolution = m_pix_per_mm;
6275 double ship_bow_lat, ship_bow_lon;
6276 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6277 &ship_bow_lat, &ship_bow_lon);
6278 wxPoint lShipBowPoint;
6279 wxPoint2DDouble b_point =
6283 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6284 powf((
float)(b_point.m_y - a_point.m_y), 2));
6287 float shipLength_mm = shipLength_px / screenResolution;
6290 float ownship_min_mm = g_n_ownship_min_mm;
6291 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6294 float hdt_ant = icon_hdt + 180.;
6295 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6296 float dx = g_n_gps_antenna_offset_x / 1852.;
6297 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6305 if (shipLength_mm < ownship_min_mm) {
6306 dy /= shipLength_mm / ownship_min_mm;
6307 dx /= shipLength_mm / ownship_min_mm;
6310 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6312 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6313 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6319 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6320 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6322 float scale_factor = shipLength_px / ownShipLength;
6325 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6328 scale_factor = wxMax(scale_factor, scale_factor_min);
6330 scale_factor_y = scale_factor;
6331 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6332 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6335void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6336 if (!GetVP().IsValid())
return;
6338 wxPoint GPSOffsetPixels(0, 0);
6339 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6342 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6343 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6347 lShipMidPoint = lGPSPoint;
6351 float icon_hdt = pCog;
6352 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6355 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6359 double osd_head_lat, osd_head_lon;
6360 wxPoint osd_head_point;
6362 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6367 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6368 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6369 icon_rad += (float)PI;
6371 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6375 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6379 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6380 if (GetVP().chart_scale >
6383 ShipDrawLargeScale(dc, lShipMidPoint);
6389 if (m_pos_image_user)
6390 pos_image = m_pos_image_user->Copy();
6391 else if (SHIP_NORMAL == m_ownship_state)
6392 pos_image = m_pos_image_red->Copy();
6393 if (SHIP_LOWACCURACY == m_ownship_state)
6394 pos_image = m_pos_image_yellow->Copy();
6395 else if (SHIP_NORMAL != m_ownship_state)
6396 pos_image = m_pos_image_grey->Copy();
6399 if (m_pos_image_user) {
6400 pos_image = m_pos_image_user->Copy();
6402 if (SHIP_LOWACCURACY == m_ownship_state)
6403 pos_image = m_pos_image_user_yellow->Copy();
6404 else if (SHIP_NORMAL != m_ownship_state)
6405 pos_image = m_pos_image_user_grey->Copy();
6408 img_height = pos_image.GetHeight();
6410 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6411 g_OwnShipIconType > 0)
6413 int ownShipWidth = 22;
6414 int ownShipLength = 84;
6415 if (g_OwnShipIconType == 1) {
6416 ownShipWidth = pos_image.GetWidth();
6417 ownShipLength = pos_image.GetHeight();
6420 float scale_factor_x, scale_factor_y;
6421 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6422 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6423 scale_factor_x, scale_factor_y);
6425 if (g_OwnShipIconType == 1) {
6426 pos_image.Rescale(ownShipWidth * scale_factor_x,
6427 ownShipLength * scale_factor_y,
6428 wxIMAGE_QUALITY_HIGH);
6429 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6431 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6434 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6435 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6436 if (rot_image.GetAlpha(ip, jp) > 64)
6437 rot_image.SetAlpha(ip, jp, 255);
6439 wxBitmap os_bm(rot_image);
6441 int w = os_bm.GetWidth();
6442 int h = os_bm.GetHeight();
6445 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6446 lShipMidPoint.m_y - h / 2,
true);
6449 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6450 lShipMidPoint.m_y - h / 2);
6451 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6452 lShipMidPoint.m_y - h / 2 + h);
6455 else if (g_OwnShipIconType == 2) {
6456 wxPoint ownship_icon[10];
6458 for (
int i = 0; i < 10; i++) {
6460 float pxa = (float)(s_ownship_icon[j]);
6461 float pya = (float)(s_ownship_icon[j + 1]);
6462 pya *= scale_factor_y;
6463 pxa *= scale_factor_x;
6465 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6466 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6468 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6469 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6472 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6474 dc.SetBrush(wxBrush(ShipColor()));
6476 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6479 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6481 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6485 img_height = ownShipLength * scale_factor_y;
6489 if (m_pos_image_user) circle_rad = 1;
6491 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6492 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6493 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6496 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6498 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6501 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6502 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6503 if (rot_image.GetAlpha(ip, jp) > 64)
6504 rot_image.SetAlpha(ip, jp, 255);
6506 wxBitmap os_bm(rot_image);
6508 if (g_ShipScaleFactorExp > 1) {
6509 wxImage scaled_image = os_bm.ConvertToImage();
6510 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6512 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6513 scaled_image.GetHeight() * factor,
6514 wxIMAGE_QUALITY_HIGH));
6516 int w = os_bm.GetWidth();
6517 int h = os_bm.GetHeight();
6520 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6521 lShipMidPoint.m_y - h / 2,
true);
6525 if (m_pos_image_user) circle_rad = 1;
6527 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6528 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6529 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6532 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6533 lShipMidPoint.m_y - h / 2);
6534 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6535 lShipMidPoint.m_y - h / 2 + h);
6540 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6553void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6554 float &MinorSpacing) {
6559 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6560 {.000001f, 45.0f, 15.0f},
6561 {.0002f, 30.0f, 10.0f},
6562 {.0003f, 10.0f, 2.0f},
6563 {.0008f, 5.0f, 1.0f},
6564 {.001f, 2.0f, 30.0f / 60.0f},
6565 {.003f, 1.0f, 20.0f / 60.0f},
6566 {.006f, 0.5f, 10.0f / 60.0f},
6567 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6568 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6569 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6570 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6571 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6572 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6573 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6574 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6577 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6578 if (view_scale_ppm < lltab[tabi][0])
break;
6579 MajorSpacing = lltab[tabi][1];
6580 MinorSpacing = lltab[tabi][2];
6594wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6595 int deg = (int)fabs(latlon);
6596 float min = fabs((fabs(latlon) - deg) * 60.0);
6606 }
else if (latlon < 0.0) {
6618 if (spacing >= 1.0) {
6619 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6620 }
else if (spacing >= (1.0 / 60.0)) {
6621 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6623 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6640void ChartCanvas::GridDraw(
ocpnDC &dc) {
6641 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6643 double nlat, elon, slat, wlon;
6646 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6648 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6650 if (!m_pgridFont) SetupGridFont();
6651 dc.SetFont(*m_pgridFont);
6652 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6655 h = m_canvas_height;
6666 dlon = dlon + 360.0;
6669 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6672 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6675 while (lat < nlat) {
6678 CalcGridText(lat, gridlatMajor,
true);
6680 dc.
DrawLine(0, r.y, w, r.y,
false);
6681 dc.DrawText(st, 0, r.y);
6682 lat = lat + gridlatMajor;
6684 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6688 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6691 while (lat < nlat) {
6694 dc.
DrawLine(0, r.y, 10, r.y,
false);
6695 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6696 lat = lat + gridlatMinor;
6700 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6703 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6706 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6708 wxString st = CalcGridText(lon, gridlonMajor,
false);
6710 dc.
DrawLine(r.x, 0, r.x, h,
false);
6711 dc.DrawText(st, r.x, 0);
6712 lon = lon + gridlonMajor;
6717 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6721 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6723 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6726 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6727 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6728 lon = lon + gridlonMinor;
6735void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6737 double blat, blon, tlat, tlon;
6740 int x_origin = m_bDisplayGrid ? 60 : 20;
6741 int y_origin = m_canvas_height - 50;
6747 if (GetVP().chart_scale > 80000)
6751 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6752 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6757 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6758 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6762 double rotation = -VPoint.
rotation;
6764 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6766 int l1 = (y_origin - r.y) / count;
6768 for (
int i = 0; i < count; i++) {
6775 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6778 double blat, blon, tlat, tlon;
6785 int y_origin = m_canvas_height - chartbar_height - 5;
6789 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6796 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6801 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6802 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6806 float places = floor(logdist), rem = logdist - places;
6807 dist = pow(10, places);
6814 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6815 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6816 double rotation = -VPoint.
rotation;
6822 int l1 = r.x - x_origin;
6824 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6829 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6830 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6831 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6833 if (!m_pgridFont) SetupGridFont();
6834 dc.SetFont(*m_pgridFont);
6835 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6837 dc.GetTextExtent(s, &w, &h);
6843 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6847void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6852 double ra_max = 40.;
6854 wxPen pen_save = dc.GetPen();
6856 wxDateTime now = wxDateTime::Now();
6862 x0 = x1 = x + radius;
6867 while (angle < 360.) {
6868 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6871 if (angle > 360.) angle = 360.;
6873 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6881 x1 = (int)(x + cos(angle * PI / 180.) * r);
6882 y1 = (int)(y + sin(angle * PI / 180.) * r);
6892 dc.
DrawLine(x + radius, y, x1, y1);
6894 dc.SetPen(pen_save);
6897static bool bAnchorSoundPlaying =
false;
6899static void onAnchorSoundFinished(
void *ptr) {
6900 o_sound::g_anchorwatch_sound->UnLoad();
6901 bAnchorSoundPlaying =
false;
6904void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6905 using namespace o_sound;
6907 bool play_sound =
false;
6909 if (AnchorAlertOn1) {
6910 wxPoint TargetPoint;
6913 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6914 TargetPoint.y, 100);
6918 AnchorAlertOn1 =
false;
6921 if (AnchorAlertOn2) {
6922 wxPoint TargetPoint;
6925 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6926 TargetPoint.y, 100);
6930 AnchorAlertOn2 =
false;
6933 if (!bAnchorSoundPlaying) {
6934 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6935 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6936 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6937 if (g_anchorwatch_sound->IsOk()) {
6938 bAnchorSoundPlaying =
true;
6939 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6940 g_anchorwatch_sound->Play();
6946void ChartCanvas::UpdateShips() {
6949 wxClientDC dc(
this);
6952 if (!dc.IsOk() || dc.GetSize().x < 1 || dc.GetSize().y < 1)
return;
6954 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6955 if (!test_bitmap.IsOk())
return;
6957 wxMemoryDC temp_dc(test_bitmap);
6959 temp_dc.ResetBoundingBox();
6960 temp_dc.DestroyClippingRegion();
6961 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6972 ocpndc.CalcBoundingBox(px.x, px.y);
6977 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6978 temp_dc.MaxY() - temp_dc.MinY());
6980 wxRect own_ship_update_rect = ship_draw_rect;
6982 if (!own_ship_update_rect.IsEmpty()) {
6985 own_ship_update_rect.Union(ship_draw_last_rect);
6986 own_ship_update_rect.Inflate(2);
6989 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6991 ship_draw_last_rect = ship_draw_rect;
6993 temp_dc.SelectObject(wxNullBitmap);
6996void ChartCanvas::UpdateAlerts() {
7001 wxClientDC dc(
this);
7005 dc.GetSize(&sx, &sy);
7008 wxBitmap test_bitmap(sx, sy, -1);
7012 temp_dc.SelectObject(test_bitmap);
7014 temp_dc.ResetBoundingBox();
7015 temp_dc.DestroyClippingRegion();
7016 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
7023 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
7024 temp_dc.MaxX() - temp_dc.MinX(),
7025 temp_dc.MaxY() - temp_dc.MinY());
7027 if (!alert_rect.IsEmpty())
7028 alert_rect.Inflate(2);
7030 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
7033 wxRect alert_update_rect = alert_draw_rect;
7034 alert_update_rect.Union(alert_rect);
7037 RefreshRect(alert_update_rect,
false);
7041 alert_draw_rect = alert_rect;
7043 temp_dc.SelectObject(wxNullBitmap);
7046void ChartCanvas::UpdateAIS() {
7052 wxClientDC dc(
this);
7056 dc.GetSize(&sx, &sy);
7064 if (
g_pAIS->GetTargetList().size() > 10) {
7065 ais_rect = wxRect(0, 0, sx, sy);
7068 wxBitmap test_bitmap(sx, sy, -1);
7072 temp_dc.SelectObject(test_bitmap);
7074 temp_dc.ResetBoundingBox();
7075 temp_dc.DestroyClippingRegion();
7076 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
7080 AISDraw(ocpndc, GetVP(),
this);
7081 AISDrawAreaNotices(ocpndc, GetVP(),
this);
7085 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
7086 temp_dc.MaxY() - temp_dc.MinY());
7088 if (!ais_rect.IsEmpty())
7089 ais_rect.Inflate(2);
7091 temp_dc.SelectObject(wxNullBitmap);
7094 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7097 wxRect ais_update_rect = ais_draw_rect;
7098 ais_update_rect.Union(ais_rect);
7101 RefreshRect(ais_update_rect,
false);
7105 ais_draw_rect = ais_rect;
7108void ChartCanvas::ToggleCPAWarn() {
7109 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7115 g_bTCPA_Max =
false;
7119 if (STAT_FIELD_SCALE >= 4 && top_frame::Get()->GetStatusBar()) {
7120 top_frame::Get()->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7122 if (!g_AisFirstTimeUse) {
7123 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7124 _(
"CPA") +
" " + mess, 4, 4);
7129void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7131void ChartCanvas::OnSize(wxSizeEvent &event) {
7132 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7134 GetClientSize(&m_canvas_width, &m_canvas_height);
7138 m_displayScale = GetContentScaleFactor();
7142 m_canvas_width *= m_displayScale;
7143 m_canvas_height *= m_displayScale;
7156 m_absolute_min_scale_ppm =
7158 (1.2 * WGS84_semimajor_axis_meters * PI);
7161 top_frame::Get()->ProcessCanvasResize();
7171 SetMUIBarPosition();
7172 UpdateFollowButtonState();
7173 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7177 xr_margin = m_canvas_width * 95 / 100;
7178 xl_margin = m_canvas_width * 5 / 100;
7179 yt_margin = m_canvas_height * 5 / 100;
7180 yb_margin = m_canvas_height * 95 / 100;
7183 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7188 m_brepaint_piano =
true;
7191 m_dc_route.SelectObject(wxNullBitmap);
7194 m_dc_route.SelectObject(*proute_bm);
7208 m_glcc->OnSize(event);
7217void ChartCanvas::ProcessNewGUIScale() {
7225void ChartCanvas::CreateMUIBar() {
7226 if (g_useMUI && !m_muiBar) {
7227 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7228 m_muiBar->SetColorScheme(m_cs);
7229 m_muiBarHOSize = m_muiBar->m_size;
7237 SetMUIBarPosition();
7238 UpdateFollowButtonState();
7239 m_muiBar->UpdateDynamicValues();
7240 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7244void ChartCanvas::SetMUIBarPosition() {
7248 int pianoWidth = GetClientSize().x * 0.6f;
7253 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7254 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7256 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7257 m_muiBar->SetColorScheme(m_cs);
7261 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7262 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7264 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7265 m_muiBar->SetColorScheme(m_cs);
7269 m_muiBar->SetBestPosition();
7273void ChartCanvas::DestroyMuiBar() {
7280void ChartCanvas::ShowCompositeInfoWindow(
7281 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7283 if (NULL == m_pCIWin) {
7288 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7291 s = _(
"Composite of ");
7294 s1.Printf(
"%d ", n_charts);
7302 s1.Printf(_(
"Chart scale"));
7305 s2.Printf(
"1:%d\n",
scale);
7309 s1 = _(
"Zoom in for more information");
7313 int char_width = s1.Length();
7314 int char_height = 3;
7316 if (g_bChartBarEx) {
7319 for (
int i : index_vector) {
7321 wxString path = cte.GetFullSystemPath();
7325 char_width = wxMax(char_width, path.Length());
7326 if (j++ >= 9)
break;
7329 s +=
" .\n .\n .\n";
7338 m_pCIWin->SetString(s);
7340 m_pCIWin->FitToChars(char_width, char_height);
7343 p.x = x / GetContentScaleFactor();
7344 if ((p.x + m_pCIWin->GetWinSize().x) >
7345 (m_canvas_width / GetContentScaleFactor()))
7346 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7347 m_pCIWin->GetWinSize().x) /
7350 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7351 4 - m_pCIWin->GetWinSize().y;
7353 m_pCIWin->dbIndex = 0;
7354 m_pCIWin->chart_scale = 0;
7355 m_pCIWin->SetPosition(p);
7356 m_pCIWin->SetBitmap();
7357 m_pCIWin->Refresh();
7361 HideChartInfoWindow();
7365void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7367 if (NULL == m_pCIWin) {
7372 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7381 dbIndex, FULL_INIT);
7383 int char_width, char_height;
7384 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7385 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7387 m_pCIWin->SetString(s);
7388 m_pCIWin->FitToChars(char_width, char_height);
7391 p.x = x / GetContentScaleFactor();
7392 if ((p.x + m_pCIWin->GetWinSize().x) >
7393 (m_canvas_width / GetContentScaleFactor()))
7394 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7395 m_pCIWin->GetWinSize().x) /
7398 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7399 4 - m_pCIWin->GetWinSize().y;
7401 m_pCIWin->dbIndex = dbIndex;
7402 m_pCIWin->SetPosition(p);
7403 m_pCIWin->SetBitmap();
7404 m_pCIWin->Refresh();
7408 HideChartInfoWindow();
7412void ChartCanvas::HideChartInfoWindow() {
7415 m_pCIWin->Destroy();
7419 androidForceFullRepaint();
7424void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7425 wxMouseEvent ev(wxEVT_MOTION);
7428 ev.m_leftDown = mouse_leftisdown;
7430 wxEvtHandler *evthp = GetEventHandler();
7432 ::wxPostEvent(evthp, ev);
7435void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7436 if ((m_panx_target_final - m_panx_target_now) ||
7437 (m_pany_target_final - m_pany_target_now)) {
7438 DoTimedMovementTarget();
7443void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7445bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7447 if (m_disable_edge_pan)
return false;
7450 int pan_margin = m_canvas_width * margin / 100;
7451 int pan_timer_set = 200;
7452 double pan_delta = GetVP().
pix_width * delta / 100;
7456 if (x > m_canvas_width - pan_margin) {
7461 else if (x < pan_margin) {
7466 if (y < pan_margin) {
7471 else if (y > m_canvas_height - pan_margin) {
7480 wxMouseState state = ::wxGetMouseState();
7481#if wxCHECK_VERSION(3, 0, 0)
7482 if (!state.LeftIsDown())
7484 if (!state.LeftDown())
7489 if ((bft) && !pPanTimer->IsRunning()) {
7491 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7497 if ((!bft) && pPanTimer->IsRunning()) {
7507void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7508 bool setBeingEdited) {
7509 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7510 m_pRoutePointEditTarget = NULL;
7511 m_pFoundPoint = NULL;
7514 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7515 SelectableItemList SelList =
pSelect->FindSelectionList(
7525 bool brp_viz =
false;
7526 if (m_pEditRouteArray) {
7527 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7528 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7529 if (pr->IsVisible()) {
7535 brp_viz = frp->IsVisible();
7539 if (m_pEditRouteArray)
7541 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7542 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7545 m_bRouteEditing = setBeingEdited;
7548 frp->m_bRPIsBeingEdited = setBeingEdited;
7549 m_bMarkEditing = setBeingEdited;
7552 m_pRoutePointEditTarget = frp;
7553 m_pFoundPoint = pFind;
7558std::shared_ptr<HostApi121::PiPointContext>
7559ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7573 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7575 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7576 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7577 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7578 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7582 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7585 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7590 int FoundAIS_MMSI = 0;
7592 FoundAIS_MMSI = pFindAIS->GetUserData();
7595 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7596 seltype |= SELTYPE_AISTARGET;
7602 Route *SelectedRoute = NULL;
7608 Route *pSelectedActiveRoute = NULL;
7609 Route *pSelectedVizRoute = NULL;
7612 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7613 SelectableItemList SelList =
7614 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7622 bool brp_viz =
false;
7624 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7626 if (pr->IsVisible()) {
7631 if (!brp_viz && prp->IsShared())
7633 brp_viz = prp->IsVisible();
7636 brp_viz = prp->IsVisible();
7638 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7644 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7647 pSelectedActiveRoute = pr;
7648 pFoundActiveRoutePoint = prp;
7653 if (NULL == pSelectedVizRoute) {
7654 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7656 if (pr->IsVisible()) {
7657 pSelectedVizRoute = pr;
7658 pFoundVizRoutePoint = prp;
7664 delete proute_array;
7669 if (pFoundActiveRoutePoint) {
7670 FoundRoutePoint = pFoundActiveRoutePoint;
7671 SelectedRoute = pSelectedActiveRoute;
7672 }
else if (pFoundVizRoutePoint) {
7673 FoundRoutePoint = pFoundVizRoutePoint;
7674 SelectedRoute = pSelectedVizRoute;
7677 FoundRoutePoint = pFirstVizPoint;
7679 if (SelectedRoute) {
7680 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7681 }
else if (FoundRoutePoint) {
7682 seltype |= SELTYPE_MARKPOINT;
7687 if (m_pFoundRoutePoint) {
7691 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7692 RefreshRect(wp_rect,
true);
7701 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7702 SelectableItemList SelList =
7703 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7705 if (NULL == SelectedRoute)
7710 if (pr->IsVisible()) {
7717 if (SelectedRoute) {
7718 if (NULL == FoundRoutePoint)
7719 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7722 seltype |= SELTYPE_ROUTESEGMENT;
7726 if (pFindTrackSeg) {
7727 m_pSelectedTrack = NULL;
7728 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7729 SelectableItemList SelList =
7730 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7735 if (pt->IsVisible()) {
7736 m_pSelectedTrack = pt;
7740 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7743 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7746 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7747 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7748 rstruct->object_ident =
"";
7750 if (seltype == SELTYPE_AISTARGET) {
7751 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7753 val.Printf(
"%d", FoundAIS_MMSI);
7754 rstruct->object_ident = val.ToStdString();
7755 }
else if (seltype & SELTYPE_MARKPOINT) {
7756 if (FoundRoutePoint) {
7757 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7758 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7760 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7761 if (SelectedRoute) {
7762 rstruct->object_type =
7763 HostApi121::PiContextObjectType::kObjectRoutesegment;
7764 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7766 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7767 if (m_pSelectedTrack) {
7768 rstruct->object_type =
7769 HostApi121::PiContextObjectType::kObjectTracksegment;
7770 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7777void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7778 if (singleClickEventIsValid) {
7779 const bool wasReplaying = m_isReplayingClickEvent;
7780 m_isReplayingClickEvent =
true;
7781 MouseEvent(singleClickEvent);
7782 m_isReplayingClickEvent = wasReplaying;
7785 singleClickEventIsValid =
false;
7786 m_DoubleClickTimer->Stop();
7791bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7792 if (!m_bChartDragging && !m_bDrawingRoute) {
7797 if (m_Compass && m_Compass->IsShown()) {
7799 bool isInCompass = logicalRect.Contains(event.GetPosition());
7800 if (isInCompass || m_mouseWasInCompass) {
7801 if (m_Compass->MouseEvent(event)) {
7802 cursor_region = CENTER;
7803 if (!g_btouch) SetCanvasCursor(event);
7804 m_mouseWasInCompass = isInCompass;
7808 m_mouseWasInCompass = isInCompass;
7811 if (m_notification_button && m_notification_button->IsShown()) {
7813 bool isinButton = logicalRect.Contains(event.GetPosition());
7815 SetCursor(*pCursorArrow);
7816 if (event.LeftDown()) HandleNotificationMouseClick();
7821 if (MouseEventToolbar(event))
return true;
7823 if (MouseEventChartBar(event))
return true;
7825 if (MouseEventMUIBar(event))
return true;
7827 if (MouseEventIENCBar(event))
return true;
7832void ChartCanvas::HandleNotificationMouseClick() {
7833 if (!m_NotificationsList) {
7837 m_NotificationsList->RecalculateSize();
7838 m_NotificationsList->Hide();
7841 if (m_NotificationsList->IsShown()) {
7842 m_NotificationsList->Hide();
7844 m_NotificationsList->RecalculateSize();
7845 m_NotificationsList->ReloadNotificationList();
7846 m_NotificationsList->Show();
7849bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7850 if (!g_bShowChartBar)
return false;
7852 if (!m_Piano->MouseEvent(event))
return false;
7854 cursor_region = CENTER;
7855 if (!g_btouch) SetCanvasCursor(event);
7859bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7860 if (!IsPrimaryCanvas())
return false;
7869 cursor_region = CENTER;
7870 if (!g_btouch) SetCanvasCursor(event);
7874bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7875 if (!IsPrimaryCanvas())
return false;
7888bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7890 if (!m_muiBar->MouseEvent(event))
return false;
7893 cursor_region = CENTER;
7894 if (!g_btouch) SetCanvasCursor(event);
7906 event.GetPosition(&x, &y);
7908 x *= m_displayScale;
7909 y *= m_displayScale;
7911 m_MouseDragging =
event.Dragging();
7917 if (event.Dragging()) {
7918 if ((x == mouse_x) && (y == mouse_y))
return true;
7924 mouse_leftisdown =
event.LeftDown();
7928 cursor_region = CENTER;
7932 if (m_Compass && m_Compass->IsShown() &&
7933 m_Compass->
GetRect().Contains(event.GetPosition())) {
7934 cursor_region = CENTER;
7935 }
else if (x > xr_margin) {
7936 cursor_region = MID_RIGHT;
7937 }
else if (x < xl_margin) {
7938 cursor_region = MID_LEFT;
7939 }
else if (y > yb_margin - chartbar_height &&
7940 y < m_canvas_height - chartbar_height) {
7941 cursor_region = MID_TOP;
7942 }
else if (y < yt_margin) {
7943 cursor_region = MID_BOT;
7945 cursor_region = CENTER;
7948 if (!g_btouch) SetCanvasCursor(event);
7952 leftIsDown =
event.LeftDown();
7955 if (event.LeftDown()) {
7956 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7959 g_bTempShowMenuBar =
false;
7960 top_frame::Get()->ApplyGlobalSettings(
false);
7968 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7969 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7974 if (!m_isReplayingClickEvent) {
7975 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7976 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7980 event.SetEventObject(
this);
7981 if (SendMouseEventToPlugins(event))
7988 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7989 StartChartDragInertia();
7992 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7993 !singleClickEventIsValid) {
7995 if (m_DoubleClickTimer->IsRunning()) {
7996 m_DoubleClickTimer->Stop();
8001 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
8002 singleClickEvent = event;
8003 singleClickEventIsValid =
true;
8012 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
8013 if (g_click_stop > 0) {
8021 if (GetUpMode() == COURSE_UP_MODE) {
8022 m_b_rot_hidef =
false;
8023 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
8025 pRotDefTimer->Stop();
8028 bool bRoll = !g_btouch;
8033 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
8034 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
8035 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
8036 m_RolloverPopupTimer.Start(
8040 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
8044 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
8053#if !defined(__WXGTK__) && !defined(__WXQT__)
8061 if ((x >= 0) && (y >= 0))
8066 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
8067 wxPoint p = ClientToScreen(wxPoint(x, y));
8073 if (m_routeState >= 2) {
8076 m_bDrawingRoute =
true;
8078 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8083 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
8086 m_bDrawingRoute =
true;
8088 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8101#if defined(__WXMAC__) || defined(__ANDROID__)
8105 wxClientDC cdc(GetParent());
8117 if (m_pSelectedRoute) {
8119 m_pSelectedRoute->DeSelectRoute();
8121 if (g_bopengl && m_glcc) {
8126 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8129 if (m_pFoundRoutePoint) {
8137 if (g_btouch && m_pRoutePointEditTarget) {
8140 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8144 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8145 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8146 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8147 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8148 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8152 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8155 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8161 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8164 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8165 seltype |= SELTYPE_AISTARGET;
8170 m_pFoundRoutePoint = NULL;
8175 Route *pSelectedActiveRoute = NULL;
8176 Route *pSelectedVizRoute = NULL;
8179 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8180 SelectableItemList SelList =
8181 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8189 bool brp_viz =
false;
8191 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8193 if (pr->IsVisible()) {
8198 if (!brp_viz && prp->IsShared())
8200 brp_viz = prp->IsVisible();
8203 brp_viz = prp->IsVisible();
8205 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8210 m_pSelectedRoute = NULL;
8212 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8215 pSelectedActiveRoute = pr;
8216 pFoundActiveRoutePoint = prp;
8221 if (NULL == pSelectedVizRoute) {
8222 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8224 if (pr->IsVisible()) {
8225 pSelectedVizRoute = pr;
8226 pFoundVizRoutePoint = prp;
8232 delete proute_array;
8237 if (pFoundActiveRoutePoint) {
8238 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8239 m_pSelectedRoute = pSelectedActiveRoute;
8240 }
else if (pFoundVizRoutePoint) {
8241 m_pFoundRoutePoint = pFoundVizRoutePoint;
8242 m_pSelectedRoute = pSelectedVizRoute;
8245 m_pFoundRoutePoint = pFirstVizPoint;
8247 if (m_pSelectedRoute) {
8248 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8249 }
else if (m_pFoundRoutePoint) {
8250 seltype |= SELTYPE_MARKPOINT;
8254 if (m_pFoundRoutePoint) {
8258 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8259 RefreshRect(wp_rect,
true);
8267 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8268 SelectableItemList SelList =
8269 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8271 if (NULL == m_pSelectedRoute)
8276 if (pr->IsVisible()) {
8277 m_pSelectedRoute = pr;
8283 if (m_pSelectedRoute) {
8284 if (NULL == m_pFoundRoutePoint)
8285 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8290 if (g_bopengl && m_glcc) {
8295 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8297 seltype |= SELTYPE_ROUTESEGMENT;
8301 if (pFindTrackSeg) {
8302 m_pSelectedTrack = NULL;
8303 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8304 SelectableItemList SelList =
8305 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8310 if (pt->IsVisible()) {
8311 m_pSelectedTrack = pt;
8315 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8321 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8322 seltype |= SELTYPE_CURRENTPOINT;
8325 else if (pFindTide) {
8326 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8327 seltype |= SELTYPE_TIDEPOINT;
8332 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8337IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8347 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8348 SelectableItemList SelList =
8349 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8352 pFind = *SelList.begin();
8353 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8355 auto node = SelList.begin();
8356 if (SelList.size() > 1) {
8357 for (++node; node != SelList.end(); ++node) {
8360 if (pIDX_candidate->
IDX_type ==
'c') {
8361 pIDX_best_candidate = pIDX_candidate;
8366 pFind = *SelList.begin();
8367 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8370 return pIDX_best_candidate;
8372void ChartCanvas::CallPopupMenu(
int x,
int y) {
8376 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8384 if (SELTYPE_CURRENTPOINT == seltype) {
8390 if (SELTYPE_TIDEPOINT == seltype) {
8396 InvokeCanvasMenu(x, y, seltype);
8399 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8403 m_pSelectedRoute = NULL;
8405 if (m_pFoundRoutePoint) {
8406 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8409 m_pFoundRoutePoint = NULL;
8418 if (m_pRoutePointEditTarget &&
8419 !
pSelect->IsSelectableRoutePointValid(m_pRoutePointEditTarget)) {
8420 m_pRoutePointEditTarget = NULL;
8421 m_lastRoutePointEditTarget = NULL;
8422 m_pFoundPoint = NULL;
8423 m_bRouteEditing =
false;
8424 m_bMarkEditing =
false;
8431bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8439 event.GetPosition(&x, &y);
8445 SelectRadius = g_Platform->GetSelectRadiusPix() /
8446 (m_true_scale_ppm * 1852 * 60);
8453 if (event.LeftDClick() && (cursor_region == CENTER)) {
8454 m_DoubleClickTimer->Start();
8455 singleClickEventIsValid =
false;
8461 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8464 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8467 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8468 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8469 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8475 SelectableItemList rpSelList =
8476 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8477 bool b_onRPtarget =
false;
8480 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8481 b_onRPtarget =
true;
8489 std::unique_ptr<HostApi> host_api =
GetHostApi();
8490 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8492 if (m_pRoutePointEditTarget) {
8494 if ((api_121->GetContextMenuMask() &
8495 api_121->kContextMenuDisableWaypoint))
8497 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8503 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8506 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8507 m_pRoutePointEditTarget = NULL;
8508 RefreshRect(wp_rect,
true);
8512 auto node = rpSelList.begin();
8513 if (node != rpSelList.end()) {
8517 wxArrayPtrVoid *proute_array =
8522 bool brp_viz =
false;
8524 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8526 if (pr->IsVisible()) {
8531 delete proute_array;
8535 brp_viz = frp->IsVisible();
8537 brp_viz = frp->IsVisible();
8540 if ((api_121->GetContextMenuMask() &
8541 api_121->kContextMenuDisableWaypoint))
8544 ShowMarkPropertiesDialog(frp);
8553 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8555 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8558 if (pr->IsVisible()) {
8559 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8564 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8566 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8569 if (pt->IsVisible()) {
8570 ShowTrackPropertiesDialog(pt);
8579 if (m_bShowCurrent) {
8581 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8583 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8585 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8586 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8588 if (pic->m_enabled && pic->m_init_state &&
8589 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8592 if (m_pIDXCandidate) {
8593 info.point_type = CURRENT_STATION;
8597 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8598 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8602 if (plugin) plugin->OnTideCurrentClick(info);
8617 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8619 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8621 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8622 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8624 if (pic->m_enabled && pic->m_init_state &&
8625 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8628 if (m_pIDXCandidate) {
8629 info.point_type = TIDE_STATION;
8633 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8634 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8638 if (plugin) plugin->OnTideCurrentClick(info);
8653 ShowObjectQueryWindow(x, y, zlat, zlon);
8658 if (event.LeftDown()) {
8674 bool appending =
false;
8675 bool inserting =
false;
8678 SetCursor(*pCursorPencil);
8682 m_bRouteEditing =
true;
8684 if (m_routeState == 1) {
8685 m_pMouseRoute =
new Route();
8686 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8696 double nearby_radius_meters =
8697 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8700 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8701 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8702 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8703 wxArrayPtrVoid *proute_array =
8708 bool brp_viz =
false;
8710 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8712 if (pr->IsVisible()) {
8717 delete proute_array;
8719 pNearbyPoint->IsShared())
8722 pNearbyPoint->IsVisible();
8724 brp_viz = pNearbyPoint->IsVisible();
8727 wxString msg = _(
"Use nearby waypoint?");
8729 const bool noname(pNearbyPoint->GetName() ==
"");
8732 _(
"Use nearby nameless waypoint and name it M with"
8733 " a unique number?");
8736 m_FinishRouteOnKillFocus =
false;
8738 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8739 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8740 m_FinishRouteOnKillFocus =
true;
8741 if (dlg_return == wxID_YES) {
8743 if (m_pMouseRoute) {
8744 int last_wp_num = m_pMouseRoute->GetnPoints();
8746 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8747 wxString wp_name = wxString::Format(
8748 "M%002i-%s", last_wp_num + 1, guid_short);
8749 pNearbyPoint->SetName(wp_name);
8751 pNearbyPoint->SetName(
"WPXX");
8753 pMousePoint = pNearbyPoint;
8756 if (m_routeState > 1)
8757 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8758 Undo_HasParent, NULL);
8761 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8762 bool procede =
false;
8766 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8772 m_FinishRouteOnKillFocus =
false;
8778 _(
"Insert first part of this route in the new route?");
8779 if (tail->GetIndexOf(pMousePoint) ==
8782 dmsg = _(
"Insert this route in the new route?");
8784 if (tail->GetIndexOf(pMousePoint) > 0) {
8785 dlg_return = OCPNMessageBox(
8786 this, dmsg, _(
"OpenCPN Route Create"),
8787 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8788 m_FinishRouteOnKillFocus =
true;
8790 if (dlg_return == wxID_YES) {
8797 _(
"Append last part of this route to the new route?");
8798 if (tail->GetIndexOf(pMousePoint) == 1)
8800 "Append this route to the new route?");
8805 if (tail->GetLastPoint() != pMousePoint) {
8806 dlg_return = OCPNMessageBox(
8807 this, dmsg, _(
"OpenCPN Route Create"),
8808 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8809 m_FinishRouteOnKillFocus =
true;
8811 if (dlg_return == wxID_YES) {
8822 if (!FindRouteContainingWaypoint(pMousePoint))
8823 pMousePoint->SetShared(
true);
8828 if (NULL == pMousePoint) {
8829 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8831 pMousePoint->SetNameShown(
false);
8835 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8837 if (m_routeState > 1)
8838 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8839 Undo_IsOrphanded, NULL);
8842 if (m_pMouseRoute) {
8843 if (m_routeState == 1) {
8845 m_pMouseRoute->AddPoint(pMousePoint);
8848 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8849 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8850 &rhumbBearing, &rhumbDist);
8851 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8852 rlat, &gcDist, &gcBearing, NULL);
8853 double gcDistNM = gcDist / 1852.0;
8856 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8857 pow(rhumbDist - gcDistNM - 1, 0.5);
8860 msg << _(
"For this leg the Great Circle route is ")
8862 << _(
" shorter than rhumbline.\n\n")
8863 << _(
"Would you like include the Great Circle routing points "
8866 m_FinishRouteOnKillFocus =
false;
8867 m_disable_edge_pan =
true;
8870 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8871 wxYES_NO | wxNO_DEFAULT);
8873 m_disable_edge_pan =
false;
8874 m_FinishRouteOnKillFocus =
true;
8876 if (answer == wxID_YES) {
8878 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8879 wxRealPoint gcCoord;
8881 for (
int i = 1; i <= segmentCount; i++) {
8882 double fraction = (double)i * (1.0 / (
double)segmentCount);
8883 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8884 gcDist * fraction, gcBearing,
8885 &gcCoord.x, &gcCoord.y, NULL);
8887 if (i < segmentCount) {
8888 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8890 gcPoint->SetNameShown(
false);
8892 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8894 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8897 gcPoint = pMousePoint;
8900 m_pMouseRoute->AddPoint(gcPoint);
8901 pSelect->AddSelectableRouteSegment(
8902 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8903 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8904 prevGcPoint = gcPoint;
8907 undo->CancelUndoableAction(
true);
8910 m_pMouseRoute->AddPoint(pMousePoint);
8911 pSelect->AddSelectableRouteSegment(
8912 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8913 pMousePoint, m_pMouseRoute);
8914 undo->AfterUndoableAction(m_pMouseRoute);
8918 m_pMouseRoute->AddPoint(pMousePoint);
8919 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8920 rlon, m_prev_pMousePoint,
8921 pMousePoint, m_pMouseRoute);
8922 undo->AfterUndoableAction(m_pMouseRoute);
8928 m_prev_pMousePoint = pMousePoint;
8936 int connect = tail->GetIndexOf(pMousePoint);
8941 int length = tail->GetnPoints();
8946 start = connect + 1;
8952 m_pMouseRoute->RemovePoint(m_pMouseRoute->GetLastPoint());
8954 for (i = start; i <= stop; i++) {
8955 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8958 m_pMouseRoute->GetnPoints();
8960 top_frame::Get()->RefreshAllCanvas();
8964 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8966 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8967 m_pMouseRoute->FinalizeForRendering();
8969 top_frame::Get()->RefreshAllCanvas();
8973 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8975 SetCursor(*pCursorPencil);
8977 if (!m_pMeasureRoute) {
8978 m_pMeasureRoute =
new Route();
8982 if (m_nMeasureState == 1) {
8987 if (!
g_pRouteMan->IsRouteInList(m_pMeasureRoute)) {
8988 wxLogMessage(
"Stale measure route");
8989 CancelMeasureRoute();
8990 top_frame::Get()->RefreshAllCanvas();
8995 wxEmptyString, wxEmptyString);
8997 pMousePoint->SetShowWaypointRangeRings(
false);
8999 m_pMeasureRoute->AddPoint(pMousePoint);
9003 m_prev_pMousePoint = pMousePoint;
9005 m_pMeasureRoute->GetnPoints();
9008 top_frame::Get()->RefreshAllCanvas();
9014 FindRoutePointsAtCursor(SelectRadius,
true);
9018 m_last_touch_down_pos =
event.GetPosition();
9020 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
9028 if (ret)
return true;
9031 if (event.Dragging()) {
9038 if (m_pRoutePointEditTarget &&
9039 !
pSelect->IsSelectableRoutePointValid(m_pRoutePointEditTarget)) {
9040 m_pRoutePointEditTarget = NULL;
9041 m_lastRoutePointEditTarget = NULL;
9042 m_pFoundPoint = NULL;
9043 m_bRouteEditing =
false;
9044 m_bMarkEditing =
false;
9050 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9052 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
9054 SelectableItemList SelList =
pSelect->FindSelectionList(
9058 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
9063 if (m_pRoutePointEditTarget &&
9064 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
9066 SelectableItemList SelList =
pSelect->FindSelectionList(
9070 if (m_pRoutePointEditTarget == frp) {
9071 m_bIsInRadius =
true;
9076 if (!m_dragoffsetSet) {
9078 .PresetDragOffset(
this, mouse_x, mouse_y);
9079 m_dragoffsetSet =
true;
9084 if (m_bRouteEditing && m_pRoutePointEditTarget) {
9085 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9088 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9090 DraggingAllowed =
false;
9092 if (m_pRoutePointEditTarget &&
9093 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9094 DraggingAllowed =
false;
9096 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9098 if (DraggingAllowed) {
9099 if (!undo->InUndoableAction()) {
9100 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9101 Undo_NeedsCopy, m_pFoundPoint);
9107 if (!g_bopengl && m_pEditRouteArray) {
9108 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9109 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9116 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9117 pre_rect.Union(route_rect);
9125 if (CheckEdgePan(x, y,
true, 5, 2))
9133 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9135 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9136 m_pRoutePointEditTarget,
9137 SELTYPE_DRAGHANDLE);
9138 m_pFoundPoint->m_slat =
9139 m_pRoutePointEditTarget->m_lat;
9140 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9142 m_pRoutePointEditTarget->m_lat =
9144 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9145 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9146 m_pFoundPoint->m_slat =
9148 m_pFoundPoint->m_slon = new_cursor_lon;
9164 if (m_pEditRouteArray) {
9165 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9167 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9170 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9171 post_rect.Union(route_rect);
9177 pre_rect.Union(post_rect);
9178 RefreshRect(pre_rect,
false);
9180 top_frame::Get()->RefreshCanvasOther(
this);
9181 m_bRoutePoinDragging =
true;
9186 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9187 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9190 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9192 DraggingAllowed =
false;
9194 if (m_pRoutePointEditTarget &&
9195 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9196 DraggingAllowed =
false;
9198 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9200 if (DraggingAllowed) {
9201 if (!undo->InUndoableAction()) {
9202 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9203 Undo_NeedsCopy, m_pFoundPoint);
9217 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9223 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9224 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9225 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9226 (
int)(lppmax - (pre_rect.height / 2)));
9234 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9237 m_pRoutePointEditTarget,
9238 SELTYPE_DRAGHANDLE);
9239 m_pFoundPoint->m_slat =
9240 m_pRoutePointEditTarget->m_lat;
9241 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9243 m_pRoutePointEditTarget->m_lat =
9246 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9259 if (!g_btouch) InvalidateGL();
9265 .CalculateDCRect(m_dc_route,
this, &post_rect);
9266 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9267 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9268 (
int)(lppmax - (post_rect.height / 2)));
9271 pre_rect.Union(post_rect);
9272 RefreshRect(pre_rect,
false);
9274 top_frame::Get()->RefreshCanvasOther(
this);
9275 m_bRoutePoinDragging =
true;
9277 ret = g_btouch ? m_bRoutePoinDragging :
true;
9280 if (ret)
return true;
9283 if (event.LeftUp()) {
9284 bool b_startedit_route =
false;
9285 m_dragoffsetSet =
false;
9288 m_bChartDragging =
false;
9289 m_bIsInRadius =
false;
9296 int dx = x - m_touchdownPos.x;
9297 int dy = y - m_touchdownPos.y;
9298 int dist2 = dx * dx + dy * dy;
9299 bool wasPan = (dist2 > 20 * 20);
9306 m_bedge_pan =
false;
9311 bool appending =
false;
9312 bool inserting =
false;
9318 if (m_pRoutePointEditTarget) {
9324 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9325 RefreshRect(wp_rect,
true);
9327 m_pRoutePointEditTarget = NULL;
9329 m_bRouteEditing =
true;
9331 if (m_routeState == 1) {
9332 m_pMouseRoute =
new Route();
9333 m_pMouseRoute->SetHiLite(50);
9337 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9344 double nearby_radius_meters =
9345 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9348 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9349 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9350 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9353 m_FinishRouteOnKillFocus =
9355 dlg_return = OCPNMessageBox(
9356 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9357 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9358 m_FinishRouteOnKillFocus =
true;
9360 dlg_return = wxID_YES;
9362 if (dlg_return == wxID_YES) {
9363 pMousePoint = pNearbyPoint;
9366 if (m_routeState > 1)
9367 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9368 Undo_HasParent, NULL);
9369 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9371 bool procede =
false;
9375 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9381 m_FinishRouteOnKillFocus =
false;
9382 if (m_routeState == 1) {
9386 _(
"Insert first part of this route in the new route?");
9387 if (tail->GetIndexOf(pMousePoint) ==
9390 dmsg = _(
"Insert this route in the new route?");
9392 if (tail->GetIndexOf(pMousePoint) != 1) {
9394 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9395 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9396 m_FinishRouteOnKillFocus =
true;
9398 if (dlg_return == wxID_YES) {
9405 _(
"Append last part of this route to the new route?");
9406 if (tail->GetIndexOf(pMousePoint) == 1)
9408 "Append this route to the new route?");
9412 if (tail->GetLastPoint() != pMousePoint) {
9414 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9415 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9416 m_FinishRouteOnKillFocus =
true;
9418 if (dlg_return == wxID_YES) {
9429 if (!FindRouteContainingWaypoint(pMousePoint))
9430 pMousePoint->SetShared(
true);
9434 if (NULL == pMousePoint) {
9435 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9437 pMousePoint->SetNameShown(
false);
9439 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9441 if (m_routeState > 1)
9442 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9443 Undo_IsOrphanded, NULL);
9446 if (m_routeState == 1) {
9448 m_pMouseRoute->AddPoint(pMousePoint);
9449 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9453 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9454 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9455 &rhumbBearing, &rhumbDist);
9456 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9457 &gcDist, &gcBearing, NULL);
9458 double gcDistNM = gcDist / 1852.0;
9461 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9462 pow(rhumbDist - gcDistNM - 1, 0.5);
9465 msg << _(
"For this leg the Great Circle route is ")
9467 << _(
" shorter than rhumbline.\n\n")
9468 << _(
"Would you like include the Great Circle routing points "
9472 m_FinishRouteOnKillFocus =
false;
9473 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9474 wxYES_NO | wxNO_DEFAULT);
9475 m_FinishRouteOnKillFocus =
true;
9477 int answer = wxID_NO;
9480 if (answer == wxID_YES) {
9482 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9483 wxRealPoint gcCoord;
9485 for (
int i = 1; i <= segmentCount; i++) {
9486 double fraction = (double)i * (1.0 / (
double)segmentCount);
9487 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9488 gcDist * fraction, gcBearing,
9489 &gcCoord.x, &gcCoord.y, NULL);
9491 if (i < segmentCount) {
9492 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9494 gcPoint->SetNameShown(
false);
9495 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9498 gcPoint = pMousePoint;
9501 m_pMouseRoute->AddPoint(gcPoint);
9502 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9504 pSelect->AddSelectableRouteSegment(
9505 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9506 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9507 prevGcPoint = gcPoint;
9510 undo->CancelUndoableAction(
true);
9513 m_pMouseRoute->AddPoint(pMousePoint);
9514 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9515 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9516 rlon, m_prev_pMousePoint,
9517 pMousePoint, m_pMouseRoute);
9518 undo->AfterUndoableAction(m_pMouseRoute);
9522 m_pMouseRoute->AddPoint(pMousePoint);
9523 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9525 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9526 rlon, m_prev_pMousePoint,
9527 pMousePoint, m_pMouseRoute);
9528 undo->AfterUndoableAction(m_pMouseRoute);
9534 m_prev_pMousePoint = pMousePoint;
9541 int connect = tail->GetIndexOf(pMousePoint);
9546 int length = tail->GetnPoints();
9556 m_pMouseRoute->RemovePoint(
9560 for (i = start; i < stop; i++) {
9561 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i + 1),
false);
9564 m_pMouseRoute->GetnPoints();
9566 top_frame::Get()->RefreshAllCanvas();
9572 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9574 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9575 m_pMouseRoute->FinalizeForRendering();
9580 }
else if (m_bMeasure_Active && m_nMeasureState)
9583 m_bedge_pan =
false;
9589 int mdx = x - m_touchdownPos.x;
9590 int mdy = y - m_touchdownPos.y;
9591 if (mdx * mdx + mdy * mdy > 20 * 20)
return false;
9594 if (m_nMeasureState == 1) {
9595 m_pMeasureRoute =
new Route();
9601 if (!
g_pRouteMan->IsRouteInList(m_pMeasureRoute)) {
9602 wxLogMessage(
"Stale measure route");
9603 CancelMeasureRoute();
9604 top_frame::Get()->RefreshAllCanvas();
9607 if (m_pMeasureRoute) {
9610 wxEmptyString, wxEmptyString);
9613 m_pMeasureRoute->AddPoint(pMousePoint);
9617 m_prev_pMousePoint = pMousePoint;
9619 m_pMeasureRoute->GetnPoints();
9623 CancelMeasureRoute();
9629 bool bSelectAllowed =
true;
9631 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9633 bSelectAllowed =
false;
9637 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9638 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9639 significant_drag) ||
9640 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9641 significant_drag)) {
9642 bSelectAllowed =
false;
9650 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9652 if (bSelectAllowed) {
9653 bool b_was_editing_mark = m_bMarkEditing;
9654 bool b_was_editing_route = m_bRouteEditing;
9655 FindRoutePointsAtCursor(SelectRadius,
9661 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9662 m_pRoutePointEditTarget = NULL;
9664 if (!b_was_editing_route) {
9665 if (m_pEditRouteArray) {
9666 b_startedit_route =
true;
9670 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9671 m_pTrackRolloverWin->IsActive(
false);
9673 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9674 m_pRouteRolloverWin->IsActive(
false);
9678 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9680 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9688 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9689 pre_rect.Union(route_rect);
9692 RefreshRect(pre_rect,
true);
9695 b_startedit_route =
false;
9699 if (m_pRoutePointEditTarget) {
9700 if (b_was_editing_mark ||
9701 b_was_editing_route) {
9702 if (m_lastRoutePointEditTarget) {
9706 .EnableDragHandle(
false);
9707 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9708 SELTYPE_DRAGHANDLE);
9712 if (m_pRoutePointEditTarget) {
9715 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9716 wxPoint2DDouble dragHandlePoint =
9718 .GetDragHandlePoint(
this);
9720 dragHandlePoint.m_y, dragHandlePoint.m_x,
9721 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9724 if (m_lastRoutePointEditTarget) {
9728 .EnableDragHandle(
false);
9729 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9730 SELTYPE_DRAGHANDLE);
9733 wxArrayPtrVoid *lastEditRouteArray =
9735 m_lastRoutePointEditTarget);
9736 if (lastEditRouteArray) {
9737 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9739 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9744 delete lastEditRouteArray;
9755 if (m_lastRoutePointEditTarget) {
9758 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9759 RefreshRect(wp_rect,
true);
9762 if (m_pRoutePointEditTarget) {
9765 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9766 RefreshRect(wp_rect,
true);
9774 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9775 bool b_start_rollover =
false;
9779 if (pFind) b_start_rollover =
true;
9782 if (!b_start_rollover && !b_startedit_route) {
9783 SelectableItemList SelList =
pSelect->FindSelectionList(
9787 if (pr && pr->IsVisible()) {
9788 b_start_rollover =
true;
9794 if (!b_start_rollover && !b_startedit_route) {
9795 SelectableItemList SelList =
pSelect->FindSelectionList(
9799 if (tr && tr->IsVisible()) {
9800 b_start_rollover =
true;
9806 if (b_start_rollover)
9807 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9811 bool appending =
false;
9812 bool inserting =
false;
9814 if (m_bRouteEditing ) {
9816 if (m_pRoutePointEditTarget) {
9822 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9823 double nearby_radius_meters =
9824 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9825 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9826 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9827 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9829 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9833 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9835 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9839 std::find(list->begin(), list->end(), pNearbyPoint);
9840 if (pos != list->end()) {
9852 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9857 OCPNMessageBox(
this,
9858 _(
"Replace this RoutePoint by the nearby "
9860 _(
"OpenCPN RoutePoint change"),
9861 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9862 if (dlg_return == wxID_YES) {
9867 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9870 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9872 if (tail && current && (tail != current)) {
9874 connect = tail->GetIndexOf(pNearbyPoint);
9875 int index_current_route =
9876 current->GetIndexOf(m_pRoutePointEditTarget);
9877 index_last = current->GetIndexOf(current->GetLastPoint());
9878 dlg_return1 = wxID_NO;
9880 index_current_route) {
9882 if (connect != tail->GetnPoints()) {
9885 _(
"Last part of route to be appended to dragged "
9889 _(
"Full route to be appended to dragged route?");
9891 dlg_return1 = OCPNMessageBox(
9892 this, dmsg, _(
"OpenCPN Route Create"),
9893 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9894 if (dlg_return1 == wxID_YES) {
9898 }
else if (index_current_route ==
9903 _(
"First part of route to be inserted into dragged "
9905 if (connect == tail->GetnPoints())
9907 "Full route to be inserted into dragged route?");
9909 dlg_return1 = OCPNMessageBox(
9910 this, dmsg, _(
"OpenCPN Route Create"),
9911 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9912 if (dlg_return1 == wxID_YES) {
9919 if (m_pRoutePointEditTarget->IsShared()) {
9921 dlg_return = OCPNMessageBox(
9923 _(
"Do you really want to delete and replace this "
9925 "\n" + _(
"which has been created manually?"),
9926 (
"OpenCPN RoutePoint warning"),
9927 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9930 if (dlg_return == wxID_YES) {
9931 pMousePoint = pNearbyPoint;
9933 pMousePoint->SetShared(
true);
9943 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9945 if (m_pEditRouteArray) {
9946 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9948 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9953 auto pos = std::find(list->begin(), list->end(),
9954 m_pRoutePointEditTarget);
9956 pSelect->DeleteAllSelectableRoutePoints(pr);
9957 pSelect->DeleteAllSelectableRouteSegments(pr);
9960 pos = std::find(list->begin(), list->end(),
9961 m_pRoutePointEditTarget);
9964 pSelect->AddAllSelectableRouteSegments(pr);
9965 pSelect->AddAllSelectableRoutePoints(pr);
9967 pr->FinalizeForRendering();
9968 pr->UpdateSegmentDistances();
9969 if (m_bRoutePoinDragging) {
9971 NavObj_dB::GetInstance().UpdateRoute(pr);
9979 if (m_pEditRouteArray) {
9980 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9982 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10001 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10008 delete m_pRoutePointEditTarget;
10009 m_lastRoutePointEditTarget = NULL;
10010 m_pRoutePointEditTarget = NULL;
10011 undo->AfterUndoableAction(pMousePoint);
10012 undo->InvalidateUndo();
10017 else if (m_bMarkEditing) {
10018 if (m_pRoutePointEditTarget)
10019 if (m_bRoutePoinDragging) {
10021 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10025 if (m_pRoutePointEditTarget)
10026 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10028 if (!m_pRoutePointEditTarget) {
10029 delete m_pEditRouteArray;
10030 m_pEditRouteArray = NULL;
10031 m_bRouteEditing =
false;
10033 m_bRoutePoinDragging =
false;
10040 int length = tail->GetnPoints();
10041 for (
int i = connect + 1; i <= length; i++) {
10042 current->AddPointAndSegment(tail->GetPoint(i),
false);
10045 top_frame::Get()->RefreshAllCanvas();
10048 current->FinalizeForRendering();
10052 NavObj_dB::GetInstance().UpdateRoute(current);
10055 pSelect->DeleteAllSelectableRoutePoints(current);
10056 pSelect->DeleteAllSelectableRouteSegments(current);
10057 for (
int i = 1; i < connect + 1; i++) {
10058 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10060 pSelect->AddAllSelectableRouteSegments(current);
10061 pSelect->AddAllSelectableRoutePoints(current);
10062 current->FinalizeForRendering();
10065 NavObj_dB::GetInstance().UpdateRoute(current);
10070 if (m_pEditRouteArray) {
10071 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
10072 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10085 if (m_bRouteEditing) {
10087 Route *current = 0;
10088 bool appending =
false;
10089 bool inserting =
false;
10092 if (m_pRoutePointEditTarget) {
10093 m_pRoutePointEditTarget->
m_bBlink =
false;
10097 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
10098 double nearby_radius_meters =
10099 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
10100 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
10101 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
10102 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
10104 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
10105 bool duplicate =
false;
10107 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10109 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10113 std::find(list->begin(), list->end(), pNearbyPoint);
10114 if (pos != list->end()) {
10126 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
10131 OCPNMessageBox(
this,
10132 _(
"Replace this RoutePoint by the nearby "
10134 _(
"OpenCPN RoutePoint change"),
10135 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10136 if (dlg_return == wxID_YES) {
10140 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
10143 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
10145 if (tail && current && (tail != current)) {
10147 connect = tail->GetIndexOf(pNearbyPoint);
10148 int index_current_route =
10149 current->GetIndexOf(m_pRoutePointEditTarget);
10150 index_last = current->GetIndexOf(current->GetLastPoint());
10151 dlg_return1 = wxID_NO;
10153 index_current_route) {
10155 if (connect != tail->GetnPoints()) {
10158 _(
"Last part of route to be appended to dragged "
10162 _(
"Full route to be appended to dragged route?");
10164 dlg_return1 = OCPNMessageBox(
10165 this, dmsg, _(
"OpenCPN Route Create"),
10166 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10167 if (dlg_return1 == wxID_YES) {
10171 }
else if (index_current_route ==
10173 if (connect != 0) {
10176 _(
"First part of route to be inserted into dragged "
10178 if (connect == tail->GetnPoints())
10180 "Full route to be inserted into dragged route?");
10182 dlg_return1 = OCPNMessageBox(
10183 this, dmsg, _(
"OpenCPN Route Create"),
10184 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10185 if (dlg_return1 == wxID_YES) {
10192 if (m_pRoutePointEditTarget->IsShared()) {
10193 dlg_return = wxID_NO;
10194 dlg_return = OCPNMessageBox(
10196 _(
"Do you really want to delete and replace this "
10198 "\n" + _(
"which has been created manually?"),
10199 (
"OpenCPN RoutePoint warning"),
10200 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10203 if (dlg_return == wxID_YES) {
10204 pMousePoint = pNearbyPoint;
10206 pMousePoint->SetShared(
true);
10216 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10218 if (m_pEditRouteArray) {
10219 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10221 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10225 auto pos = std::find(list->begin(), list->end(),
10226 m_pRoutePointEditTarget);
10228 pSelect->DeleteAllSelectableRoutePoints(pr);
10229 pSelect->DeleteAllSelectableRouteSegments(pr);
10232 pos = std::find(list->begin(), list->end(),
10233 m_pRoutePointEditTarget);
10234 if (pos != list->end()) list->erase(pos);
10237 pSelect->AddAllSelectableRouteSegments(pr);
10238 pSelect->AddAllSelectableRoutePoints(pr);
10240 pr->FinalizeForRendering();
10241 pr->UpdateSegmentDistances();
10244 if (m_bRoutePoinDragging) {
10249 NavObj_dB::GetInstance().UpdateRoutePoint(
10250 m_pRoutePointEditTarget);
10252 NavObj_dB::GetInstance().UpdateRoute(pr);
10264 int length = tail->GetnPoints();
10265 for (
int i = connect + 1; i <= length; i++) {
10266 current->AddPointAndSegment(tail->GetPoint(i),
false);
10270 top_frame::Get()->RefreshAllCanvas();
10273 current->FinalizeForRendering();
10277 NavObj_dB::GetInstance().UpdateRoute(current);
10280 pSelect->DeleteAllSelectableRoutePoints(current);
10281 pSelect->DeleteAllSelectableRouteSegments(current);
10282 for (
int i = 1; i < connect + 1;
10284 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10287 pSelect->AddAllSelectableRouteSegments(current);
10288 pSelect->AddAllSelectableRoutePoints(current);
10289 current->FinalizeForRendering();
10292 NavObj_dB::GetInstance().UpdateRoute(current);
10297 if (m_pEditRouteArray) {
10298 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10300 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10312 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10319 delete m_pRoutePointEditTarget;
10320 m_lastRoutePointEditTarget = NULL;
10321 undo->AfterUndoableAction(pMousePoint);
10322 undo->InvalidateUndo();
10327 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10330 delete m_pEditRouteArray;
10331 m_pEditRouteArray = NULL;
10335 m_bRouteEditing =
false;
10336 m_pRoutePointEditTarget = NULL;
10342 else if (m_bMarkEditing) {
10343 if (m_pRoutePointEditTarget) {
10344 if (m_bRoutePoinDragging) {
10346 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10348 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10353 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10355 RefreshRect(wp_rect,
true);
10358 m_pRoutePointEditTarget = NULL;
10359 m_bMarkEditing =
false;
10364 else if (leftIsDown) {
10365 leftIsDown =
false;
10369 if (!m_bChartDragging && !m_bMeasure_Active) {
10371 m_bChartDragging =
false;
10375 m_bRoutePoinDragging =
false;
10378 if (ret)
return true;
10381 if (event.RightDown()) {
10392 m_FinishRouteOnKillFocus =
false;
10393 CallPopupMenu(mx, my);
10394 m_FinishRouteOnKillFocus =
true;
10404 if (event.ShiftDown()) {
10408 event.GetPosition(&x, &y);
10410 x *= m_displayScale;
10411 y *= m_displayScale;
10417 int wheel_dir =
event.GetWheelRotation();
10420 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10421 wheel_dir = wheel_dir > 0 ? 1 : -1;
10423 double factor = g_mouse_zoom_sensitivity;
10424 if (wheel_dir < 0) factor = 1 / factor;
10427 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10428 if (wheel_dir == m_last_wheel_dir) {
10429 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10434 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10435 m_wheelstopwatch.Start(0);
10440 m_last_wheel_dir = wheel_dir;
10445 if (event.LeftDown()) {
10451 last_drag.x = x, last_drag.y = y;
10452 m_touchdownPos = wxPoint(x, y);
10453 panleftIsDown =
true;
10456 if (event.LeftUp()) {
10457 if (panleftIsDown) {
10459 panleftIsDown =
false;
10462 if (!m_bChartDragging && !m_bMeasure_Active) {
10463 switch (cursor_region) {
10485 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10490 m_bChartDragging =
false;
10496 if (event.Dragging() && event.LeftIsDown()) {
10512 if (g_btouch && !m_inPinch) {
10513 struct timespec now;
10514 clock_gettime(CLOCK_MONOTONIC, &now);
10515 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10517 bool trigger_hold =
false;
10518 if (
false == m_bChartDragging) {
10519 if (m_DragTrigger < 0) {
10522 m_DragTriggerStartTime = tnow;
10523 trigger_hold =
true;
10525 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10526 m_DragTrigger = -1;
10531 if (trigger_hold)
return true;
10533 if (
false == m_bChartDragging) {
10536 last_drag.x = x - 1, last_drag.y = y - 1;
10537 m_bChartDragging =
true;
10538 m_chart_drag_total_time = 0;
10539 m_chart_drag_total_x = 0;
10540 m_chart_drag_total_y = 0;
10541 m_inertia_last_drag_x = x;
10542 m_inertia_last_drag_y = y;
10543 m_drag_vec_x.clear();
10544 m_drag_vec_y.clear();
10545 m_drag_vec_t.clear();
10546 m_last_drag_time = tnow;
10550 uint64_t delta_t = tnow - m_last_drag_time;
10551 double delta_tf = delta_t / 1e9;
10553 m_chart_drag_total_time += delta_tf;
10554 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10555 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10557 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10558 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10559 m_drag_vec_t.push_back(delta_tf);
10561 m_inertia_last_drag_x = x;
10562 m_inertia_last_drag_y = y;
10563 m_last_drag_time = tnow;
10565 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10566 m_bChartDragging =
true;
10567 StartTimedMovement();
10568 m_pan_drag.x += last_drag.x - x;
10569 m_pan_drag.y += last_drag.y - y;
10570 last_drag.x = x, last_drag.y = y;
10572 }
else if (!g_btouch) {
10573 if ((last_drag.x != x) || (last_drag.y != y)) {
10574 if (!m_routeState) {
10577 m_bChartDragging =
true;
10578 StartTimedMovement();
10579 m_pan_drag.x += last_drag.x - x;
10580 m_pan_drag.y += last_drag.y - y;
10581 last_drag.x = x, last_drag.y = y;
10588 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10590 m_DoubleClickTimer->Start();
10591 singleClickEventIsValid =
false;
10599void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10600 if (MouseEventOverlayWindows(event))
return;
10604 bool nm = MouseEventProcessObjects(event);
10608void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10611 wxCursor *ptarget_cursor = pCursorArrow;
10612 if (!pPlugIn_Cursor) {
10613 ptarget_cursor = pCursorArrow;
10614 if ((!m_routeState) &&
10615 (!m_bMeasure_Active) ) {
10616 if (cursor_region == MID_RIGHT) {
10617 ptarget_cursor = pCursorRight;
10618 }
else if (cursor_region == MID_LEFT) {
10619 ptarget_cursor = pCursorLeft;
10620 }
else if (cursor_region == MID_TOP) {
10621 ptarget_cursor = pCursorDown;
10622 }
else if (cursor_region == MID_BOT) {
10623 ptarget_cursor = pCursorUp;
10625 ptarget_cursor = pCursorArrow;
10627 }
else if (m_bMeasure_Active ||
10629 ptarget_cursor = pCursorPencil;
10631 ptarget_cursor = pPlugIn_Cursor;
10634 SetCursor(*ptarget_cursor);
10637void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10638 SetCursor(*pCursorArrow);
10641void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10645 wxArrayString files;
10647 ChartBase *target_chart = GetChartAtCursor();
10648 if (target_chart) {
10649 file.Assign(target_chart->GetFullPath());
10650 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10651 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10654 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10656 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10657 unsigned int im = stackIndexArray.size();
10658 int scale = 2147483647;
10659 if (VPoint.b_quilt && im > 0) {
10660 for (
unsigned int is = 0; is < im; is++) {
10661 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10662 CHART_TYPE_MBTILES) {
10663 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10665 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10666 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10668 .Contains(lat, lon)) {
10669 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10672 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10673 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10681 std::vector<Ais8_001_22 *> area_notices;
10683 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10686 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10687 auto target_data = target.second;
10688 if (!target_data->area_notices.empty()) {
10689 for (
auto &ani : target_data->area_notices) {
10694 for (Ais8_001_22_SubAreaList::iterator sa =
10695 area_notice.sub_areas.begin();
10696 sa != area_notice.sub_areas.end(); ++sa) {
10697 switch (sa->shape) {
10698 case AIS8_001_22_SHAPE_CIRCLE: {
10699 wxPoint target_point;
10701 bbox.Expand(target_point);
10702 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10705 case AIS8_001_22_SHAPE_RECT: {
10706 wxPoint target_point;
10708 bbox.Expand(target_point);
10709 if (sa->e_dim_m > sa->n_dim_m)
10710 bbox.EnLarge(sa->e_dim_m * vp_scale);
10712 bbox.EnLarge(sa->n_dim_m * vp_scale);
10715 case AIS8_001_22_SHAPE_POLYGON:
10716 case AIS8_001_22_SHAPE_POLYLINE: {
10717 for (
int i = 0; i < 4; ++i) {
10718 double lat = sa->latitude;
10719 double lon = sa->longitude;
10720 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10722 wxPoint target_point;
10724 bbox.Expand(target_point);
10728 case AIS8_001_22_SHAPE_SECTOR: {
10729 double lat1 = sa->latitude;
10730 double lon1 = sa->longitude;
10732 wxPoint target_point;
10734 bbox.Expand(target_point);
10735 for (
int i = 0; i < 18; ++i) {
10738 sa->left_bound_deg +
10739 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10740 sa->radius_m / 1852.0, &lat, &lon);
10742 bbox.Expand(target_point);
10744 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10747 bbox.Expand(target_point);
10753 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10754 area_notices.push_back(&area_notice);
10761 if (target_chart || !area_notices.empty() || file.HasName()) {
10763 int sel_rad_pix = 5;
10764 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10769 SetCursor(wxCURSOR_WAIT);
10770 bool lightsVis = m_encShowLights;
10771 if (!lightsVis) SetShowENCLights(
true);
10774 ListOfObjRazRules *rule_list = NULL;
10775 ListOfPI_S57Obj *pi_rule_list = NULL;
10778 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10779 else if (target_plugin_chart)
10780 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10781 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10783 ListOfObjRazRules *overlay_rule_list = NULL;
10784 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10787 if (CHs57_Overlay) {
10788 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10789 zlat, zlon, SelectRadius, &GetVP());
10792 if (!lightsVis) SetShowENCLights(
false);
10795 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10796 wxString face = dFont->GetFaceName();
10800 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10801 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10805 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10813 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10814 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10817 int points = dFont->GetPointSize();
10819 int points = dFont->GetPointSize() + 1;
10823 for (
int i = -2; i < 5; i++) {
10824 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10828 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10830 if (overlay_rule_list && CHs57_Overlay) {
10831 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10832 objText <<
"<hr noshade>";
10835 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10836 an != area_notices.end(); ++an) {
10837 objText <<
"<b>AIS Area Notice:</b> ";
10838 objText << ais8_001_22_notice_names[(*an)->notice_type];
10839 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10840 (*an)->sub_areas.begin();
10841 sa != (*an)->sub_areas.end(); ++sa)
10842 if (!sa->text.empty()) objText << sa->text;
10843 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10844 objText <<
"<hr noshade>";
10848 objText << Chs57->CreateObjDescriptions(rule_list);
10849 else if (target_plugin_chart)
10850 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10853 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10856 wxString AddFiles, filenameOK;
10858 if (!target_plugin_chart) {
10861 AddFiles = wxString::Format(
10862 "<hr noshade><br><b>Additional info files attached to: </b> "
10864 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10866 file.GetFullName());
10868 file.Assign(file.GetPath(),
"");
10869 wxDir dir(file.GetFullPath());
10871 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10873 file.Assign(dir.GetNameWithSep().append(filename));
10874 wxString FormatString =
10875 "<td valign=top><font size=-2><a "
10876 "href=\"%s\">%s</a></font></td>";
10877 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10878 filenameOK = file.GetFullPath();
10880 if (3 * ((
int)filecount / 3) == filecount)
10881 FormatString.Prepend(
"<tr>");
10883 FormatString.Prepend(
10884 "<td>  </td>");
10887 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10888 file.GetFullName());
10891 cont = dir.GetNext(&filename);
10893 objText << AddFiles <<
"</table>";
10895 objText <<
"</font>";
10896 objText <<
"</body></html>";
10898 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10902 if ((!Chs57 && filecount == 1)) {
10904 wxHtmlLinkInfo hli(filenameOK);
10905 wxHtmlLinkEvent hle(1, hli);
10909 if (rule_list) rule_list->Clear();
10912 if (overlay_rule_list) overlay_rule_list->Clear();
10913 delete overlay_rule_list;
10915 if (pi_rule_list) pi_rule_list->Clear();
10916 delete pi_rule_list;
10918 SetCursor(wxCURSOR_ARROW);
10922void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10931 wxSize canvas_size = GetSize();
10938 wxPoint canvas_pos = GetPosition();
10941 bool newFit =
false;
10942 if (canvas_size.x < fitted_size.x) {
10943 fitted_size.x = canvas_size.x - 40;
10944 if (canvas_size.y < fitted_size.y)
10945 fitted_size.y -= 40;
10947 if (canvas_size.y < fitted_size.y) {
10948 fitted_size.y = canvas_size.y - 40;
10949 if (canvas_size.x < fitted_size.x)
10950 fitted_size.x -= 40;
10961 wxString title_base = _(
"Mark Properties");
10963 title_base = _(
"Waypoint Properties");
10968 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10980void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10990 if (g_bresponsive) {
10991 wxSize canvas_size = GetSize();
10992 wxPoint canvas_pos = GetPosition();
10996 if (canvas_size.x < fitted_size.x) {
10997 fitted_size.x = canvas_size.x;
10998 if (canvas_size.y < fitted_size.y)
10999 fitted_size.y -= 20;
11001 if (canvas_size.y < fitted_size.y) {
11002 fitted_size.y = canvas_size.y;
11003 if (canvas_size.x < fitted_size.x)
11004 fitted_size.x -= 20;
11013 wxPoint xxp = ClientToScreen(canvas_pos);
11024void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
11036void pupHandler_PasteWaypoint() {
11039 int pasteBuffer = kml.ParsePasteBuffer();
11040 RoutePoint *pasted = kml.GetParsedRoutePoint();
11041 if (!pasted)
return;
11043 double nearby_radius_meters =
11044 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
11046 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
11047 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
11049 int answer = wxID_NO;
11053 "There is an existing waypoint at the same location as the one you are "
11054 "pasting. Would you like to merge the pasted data with it?\n\n");
11055 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
11056 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
11057 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
11060 if (answer == wxID_YES) {
11061 nearPoint->SetName(pasted->GetName());
11067 if (answer == wxID_NO) {
11070 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11073 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11082 top_frame::Get()->InvalidateAllGL();
11083 top_frame::Get()->RefreshAllCanvas(
false);
11086void pupHandler_PasteRoute() {
11089 int pasteBuffer = kml.ParsePasteBuffer();
11090 Route *pasted = kml.GetParsedRoute();
11091 if (!pasted)
return;
11093 double nearby_radius_meters =
11094 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
11100 bool mergepoints =
false;
11101 bool createNewRoute =
true;
11102 int existingWaypointCounter = 0;
11104 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11105 curPoint = pasted->GetPoint(i);
11106 nearPoint = pWayPointMan->GetNearbyWaypoint(
11107 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11109 mergepoints =
true;
11110 existingWaypointCounter++;
11118 int answer = wxID_NO;
11122 "There are existing waypoints at the same location as some of the ones "
11123 "you are pasting. Would you like to just merge the pasted data into "
11125 msg << _(
"Answering 'No' will create all new waypoints for this route.");
11126 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
11127 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
11129 if (answer == wxID_CANCEL) {
11136 if (mergepoints && answer == wxID_YES &&
11137 existingWaypointCounter == pasted->GetnPoints()) {
11140 createNewRoute =
false;
11146 Route *newRoute = 0;
11149 if (createNewRoute) {
11150 newRoute =
new Route();
11154 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11155 curPoint = pasted->GetPoint(i);
11158 newPoint = pWayPointMan->GetNearbyWaypoint(
11159 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11160 newPoint->SetName(curPoint->GetName());
11163 if (createNewRoute) newRoute->AddPoint(newPoint);
11169 newPoint->SetIconName(
"circle");
11172 newPoint->SetShared(
false);
11174 newRoute->AddPoint(newPoint);
11175 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11178 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11181 if (i > 1 && createNewRoute)
11182 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11183 curPoint->m_lat, curPoint->m_lon,
11184 prevPoint, newPoint, newRoute);
11185 prevPoint = newPoint;
11188 if (createNewRoute) {
11191 NavObj_dB::GetInstance().InsertRoute(newRoute);
11201 top_frame::Get()->InvalidateAllGL();
11202 top_frame::Get()->RefreshAllCanvas(
false);
11208void pupHandler_PasteTrack() {
11211 int pasteBuffer = kml.ParsePasteBuffer();
11212 Track *pasted = kml.GetParsedTrack();
11213 if (!pasted)
return;
11221 newTrack->SetName(pasted->GetName());
11223 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11224 curPoint = pasted->GetPoint(i);
11228 wxDateTime now = wxDateTime::Now();
11231 newTrack->AddPoint(newPoint);
11234 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11235 newPoint->m_lat, newPoint->m_lon,
11236 prevPoint, newPoint, newTrack);
11238 prevPoint = newPoint;
11243 NavObj_dB::GetInstance().InsertTrack(newTrack);
11245 top_frame::Get()->InvalidateAllGL();
11246 top_frame::Get()->RefreshAllCanvas(
false);
11249bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11252 v[
"CursorPosition_x"] = x;
11253 v[
"CursorPosition_y"] = y;
11256 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11257 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11258 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11263 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11265 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11268#define SELTYPE_UNKNOWN 0x0001
11269#define SELTYPE_ROUTEPOINT 0x0002
11270#define SELTYPE_ROUTESEGMENT 0x0004
11271#define SELTYPE_TIDEPOINT 0x0008
11272#define SELTYPE_CURRENTPOINT 0x0010
11273#define SELTYPE_ROUTECREATE 0x0020
11274#define SELTYPE_AISTARGET 0x0040
11275#define SELTYPE_MARKPOINT 0x0080
11276#define SELTYPE_TRACKSEGMENT 0x0100
11277#define SELTYPE_DRAGHANDLE 0x0200
11280 if (g_bhide_context_menus)
return true;
11282 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11283 m_pIDXCandidate, m_nmea_log);
11286 wxEVT_COMMAND_MENU_SELECTED,
11287 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11293 if (m_inLongPress) {
11294 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11295 m_inLongPress =
false;
11299 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11302 wxEVT_COMMAND_MENU_SELECTED,
11303 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11305 delete m_canvasMenu;
11306 m_canvasMenu = NULL;
11316void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11319 if (m_canvasMenu) {
11320 m_canvasMenu->PopupMenuHandler(event);
11325void ChartCanvas::StartRoute() {
11327 if (g_brouteCreating)
return;
11331 g_brouteCreating =
true;
11333 m_bDrawingRoute =
false;
11334 SetCursor(*pCursorPencil);
11336 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11338 HideGlobalToolbar();
11341 androidSetRouteAnnunciator(
true);
11345wxString ChartCanvas::FinishRoute() {
11347 m_prev_pMousePoint = NULL;
11348 m_bDrawingRoute =
false;
11350 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11353 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11355 androidSetRouteAnnunciator(
false);
11358 SetCursor(*pCursorArrow);
11360 if (m_pMouseRoute) {
11361 if (m_bAppendingRoute) {
11362 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11364 if (m_pMouseRoute->GetnPoints() > 1) {
11366 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11369 m_pMouseRoute = NULL;
11372 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11384 m_bAppendingRoute =
false;
11385 m_pMouseRoute = NULL;
11387 m_pSelectedRoute = NULL;
11389 undo->InvalidateUndo();
11390 top_frame::Get()->RefreshAllCanvas(
true);
11394 ShowGlobalToolbar();
11396 g_brouteCreating =
false;
11401void ChartCanvas::HideGlobalToolbar() {
11402 if (m_canvasIndex == 0) {
11403 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11407void ChartCanvas::ShowGlobalToolbar() {
11408 if (m_canvasIndex == 0) {
11409 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11413void ChartCanvas::ShowAISTargetList() {
11414 if (NULL == g_pAISTargetList) {
11418 g_pAISTargetList->UpdateAISTargetList();
11421void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11422 if (!m_bShowOutlines)
return;
11426 int nEntry =
ChartData->GetChartTableEntries();
11428 for (
int i = 0; i < nEntry; i++) {
11432 bool b_group_draw =
false;
11433 if (m_groupIndex > 0) {
11434 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11435 int index = pt->GetGroupArray()[ig];
11436 if (m_groupIndex == index) {
11437 b_group_draw =
true;
11442 b_group_draw =
true;
11445 if (pt->IsBasemap())
continue;
11447 if (b_group_draw) RenderChartOutline(dc, i, vp);
11453 if (VPoint.b_quilt) {
11454 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11455 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11459 }
else if (m_singleChart &&
11460 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11464 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11467 if (zoom_factor > 8.0) {
11468 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11471 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11475 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11479void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11481 if (g_bopengl && m_glcc) {
11483 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11488 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11489 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11492 float plylat, plylon;
11493 float plylat1, plylon1;
11495 int pixx, pixy, pixx1, pixy1;
11498 ChartData->GetDBBoundingBox(dbIndex, box);
11502 if (box.GetLonRange() == 360)
return;
11504 double lon_bias = 0;
11506 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11508 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11510 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11511 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11513 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11514 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11517 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11520 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11521 if (0 == nAuxPlyEntries)
11525 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11526 plylon += lon_bias;
11532 for (
int i = 0; i < nPly - 1; i++) {
11533 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11534 plylon1 += lon_bias;
11540 int pixxs1 = pixx1;
11541 int pixys1 = pixy1;
11543 bool b_skip =
false;
11547 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11548 pow((
double)(pixy1 - pixy), 2)) /
11554 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11559 if (fabs(dist - distgc) > 10000. * 1852.)
11565 ClipResult res = cohen_sutherland_line_clip_i(
11567 if (res != Invisible && !b_skip)
11568 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11576 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11577 plylon1 += lon_bias;
11583 ClipResult res = cohen_sutherland_line_clip_i(
11585 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11592 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11593 for (
int j = 0; j < nAuxPlyEntries; j++) {
11595 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11600 for (
int i = 0; i < nAuxPly - 1; i++) {
11601 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11607 int pixxs1 = pixx1;
11608 int pixys1 = pixy1;
11610 bool b_skip =
false;
11614 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11615 ((pixy1 - pixy) * (pixy1 - pixy))) /
11620 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11625 if (fabs(dist - distgc) > 10000. * 1852.)
11631 ClipResult res = cohen_sutherland_line_clip_i(
11633 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11641 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11646 ClipResult res = cohen_sutherland_line_clip_i(
11648 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11653static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11654 const wxArrayString &legend) {
11655 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11657 int pointsize = dFont->GetPointSize();
11661 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11662 false, dFont->GetFaceName());
11664 dc.SetFont(*psRLI_font);
11671 int hilite_offset = 3;
11673 for (wxString line : legend) {
11676 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11678 dc.GetTextExtent(line, &wl, &hl);
11687 xp = ref_point.x - w;
11689 yp += hilite_offset;
11691 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11693 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11694 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11696 for (wxString line : legend) {
11697 dc.DrawText(line, xp, yp);
11702void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11703 if (!g_bAllowShipToActive)
return;
11709 wxPoint2DDouble pa, pb;
11716 if (rt->
m_width != wxPENSTYLE_INVALID)
11718 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11719 g_shipToActiveStyle, 5)];
11720 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11722 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11725 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11728 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11731 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11732 (
int)pb.m_y, GetVP(),
true);
11736#ifdef USE_ANDROID_GLES2
11737 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11739 if (style != wxPENSTYLE_SOLID) {
11740 if (glChartCanvas::dash_map.find(style) !=
11741 glChartCanvas::dash_map.end()) {
11742 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11746 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11749 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11750 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11756void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11758 if (m_routeState >= 2) route = m_pMouseRoute;
11759 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11760 route = m_pMeasureRoute;
11762 if (!route)
return;
11770 int np = route->GetnPoints();
11772 if (g_btouch && (np > 1)) np--;
11774 render_lat = rp.m_lat;
11775 render_lon = rp.m_lon;
11778 double rhumbBearing, rhumbDist;
11780 &rhumbBearing, &rhumbDist);
11781 double brg = rhumbBearing;
11782 double dist = rhumbDist;
11786 double gcBearing, gcBearing2, gcDist;
11787 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11790 double gcDistm = gcDist / 1852.0;
11793 rhumbBearing = 90.;
11795 wxPoint destPoint, lastPoint;
11798 int milesDiff = rhumbDist - gcDistm;
11799 if (milesDiff > 1) {
11810 for (
int i = 1; i <= milesDiff; i++) {
11811 double p = (double)i * (1.0 / (
double)milesDiff);
11813 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11814 &pLon, &pLat, &gcBearing2);
11816 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11818 lastPoint = destPoint;
11821 if (r_rband.x && r_rband.y) {
11822 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11824 if (m_bMeasure_DistCircle) {
11825 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11826 powf((
float)(r_rband.y - lastPoint.y), 2));
11829 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11830 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11836 wxString routeInfo;
11837 wxArrayString infoArray;
11840 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11846 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11848 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11849 (
int)varBrg, 0x00B0);
11852 infoArray.Add(routeInfo);
11858 routeInfo <<
"Reverse: ";
11860 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11861 (
int)(brg + 180.) % 360, 0x00B0);
11863 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11864 (
int)(varBrg + 180.) % 360, 0x00B0);
11865 infoArray.Add(routeInfo);
11871 s0.Append(_(
"Route") +
": ");
11873 s0.Append(_(
"Layer Route: "));
11876 if (!g_btouch) disp_length += dist;
11882 RouteLegInfo(dc, r_rband, infoArray);
11884 m_brepaint_piano =
true;
11887void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11888 if (!m_bShowVisibleSectors)
return;
11890 if (g_bDeferredInitDone) {
11892 double rhumbBearing, rhumbDist;
11893 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11894 &rhumbBearing, &rhumbDist);
11896 if (rhumbDist > 0.05)
11898 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11899 m_sectorlegsVisible);
11900 m_sector_glat =
gLat;
11901 m_sector_glon =
gLon;
11903 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11907void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11915void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11916 if (!ps52plib)
return;
11918 if (VPoint.b_quilt) {
11919 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11921 if (m_pQuilt->IsQuiltVector()) {
11922 if (ps52plib->GetStateHash() != m_s52StateHash) {
11924 m_s52StateHash = ps52plib->GetStateHash();
11928 if (ps52plib->GetStateHash() != m_s52StateHash) {
11930 m_s52StateHash = ps52plib->GetStateHash();
11935 bool bSendPlibState =
true;
11936 if (VPoint.b_quilt) {
11937 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11940 if (bSendPlibState) {
11942 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11943 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11944 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11945 v[
"OpenCPN Version Date"] = VERSION_DATE;
11946 v[
"OpenCPN Version Full"] = VERSION_FULL;
11949 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11950 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11951 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11952 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11953 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11954 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11955 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11959 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11960 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11964 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11965 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11966 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11967 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11968 ps52plib->m_bShowS57ImportantTextOnly;
11969 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11970 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11971 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11972 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11973 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11976 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11977 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11978 v[
"OpenCPN Scale Factor Exp"] =
11979 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11986 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11987 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11988 g_lastS52PLIBPluginMessage = out;
11995 wxPaintDC dc(
this);
12005 if (!m_b_paint_enable) {
12013 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
12015 if (m_glcc && g_bopengl) {
12016 if (!s_in_update) {
12026 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
12028 wxRegion ru = GetUpdateRegion();
12030 int rx, ry, rwidth, rheight;
12031 ru.GetBox(rx, ry, rwidth, rheight);
12033#ifdef ocpnUSE_DIBSECTION
12036 wxMemoryDC temp_dc;
12044 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
12045 height += m_Piano->GetHeight();
12047 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
12051 int thumbx, thumby, thumbsx, thumbsy;
12052 pthumbwin->GetPosition(&thumbx, &thumby);
12053 pthumbwin->GetSize(&thumbsx, &thumbsy);
12054 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
12057 rgn_chart.Subtract(rgn_thumbwin);
12058 ru.Subtract(rgn_thumbwin);
12064 wxRegion rgn_blit = ru;
12065 if (g_bShowChartBar) {
12066 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
12067 GetClientSize().x, m_Piano->GetHeight());
12070 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
12071 if (style->chartStatusWindowTransparent)
12072 m_brepaint_piano =
true;
12074 ru.Subtract(chart_bar_rect);
12078 if (m_Compass && m_Compass->IsShown()) {
12079 wxRect compassRect = m_Compass->
GetRect();
12080 if (ru.Contains(compassRect) != wxOutRegion) {
12081 ru.Subtract(compassRect);
12085 if (m_notification_button) {
12086 wxRect noteRect = m_notification_button->
GetRect();
12087 if (ru.Contains(noteRect) != wxOutRegion) {
12088 ru.Subtract(noteRect);
12093 bool b_newview =
true;
12098 m_cache_vp.IsValid()) {
12104 bool b_rcache_ok =
false;
12105 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
12106 b_rcache_ok = !b_newview;
12109 if (VPoint.b_MercatorProjectionOverride)
12110 VPoint.SetProjectionType(PROJECTION_MERCATOR);
12124 if (b_rcache_ok) chart_get_region.Clear();
12127 if (VPoint.b_quilt)
12129 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
12131 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
12136 AbstractPlatform::ShowBusySpinner();
12140 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
12141 (m_working_bm.GetHeight() != svp.
pix_height))
12145 if (fabs(VPoint.
rotation) < 0.01) {
12146 bool b_save =
true;
12151 m_cache_vp.Invalidate();
12165 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12170 int dy = c_new.y - c_old.y;
12171 int dx = c_new.x - c_old.x;
12176 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12180 temp_dc.SelectObject(m_working_bm);
12182 wxMemoryDC cache_dc;
12183 cache_dc.SelectObject(m_cached_chart_bm);
12187 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12190 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12196 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12199 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12207 update_region.Union(
12210 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12215 update_region.Union(
12218 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12222 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12224 cache_dc.SelectObject(wxNullBitmap);
12228 temp_dc.SelectObject(m_cached_chart_bm);
12231 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12235 temp_dc.SelectObject(m_working_bm);
12236 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12241 temp_dc.SelectObject(m_cached_chart_bm);
12246 temp_dc.SelectObject(m_working_bm);
12247 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12260 wxMemoryDC scratch_dc_0;
12261 scratch_dc_0.SelectObject(m_cached_chart_bm);
12264 scratch_dc_0.SelectObject(wxNullBitmap);
12273 temp_dc.SelectObject(m_working_bm);
12276 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12277 chart_get_all_region);
12280 AbstractPlatform::HideBusySpinner();
12286 if (!m_singleChart) {
12287 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12292 if (!chart_get_region.IsEmpty()) {
12293 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12297 if (temp_dc.IsOk()) {
12302 if (!VPoint.b_quilt) {
12305 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12306 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12313 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12314 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12317 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12319 temp_dc.DestroyClippingRegion();
12324 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12326 if (!backgroundRegion.IsEmpty()) {
12332 wxColour water = pWorldBackgroundChart->water;
12333 if (water.IsOk()) {
12334 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12335 temp_dc.SetBrush(wxBrush(water));
12337 while (upd.HaveRects()) {
12338 wxRect rect = upd.GetRect();
12339 temp_dc.DrawRectangle(rect);
12344 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12345 temp_dc.SetDeviceClippingRegion(*clip_region);
12346 delete clip_region;
12350 SetVPRotation(VPoint.
skew);
12359 wxMemoryDC *pChartDC = &temp_dc;
12360 wxMemoryDC rotd_dc;
12362 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12364 if (!b_rcache_ok) {
12366 wxMemoryDC tbase_dc;
12368 tbase_dc.SelectObject(bm_base);
12370 tbase_dc.SelectObject(wxNullBitmap);
12372 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12375 wxImage base_image;
12376 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12384 bool b_rot_ok =
false;
12385 if (base_image.IsOk()) {
12388 m_b_rot_hidef =
false;
12392 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12393 m_b_rot_hidef, &m_roffset);
12398 rot_vp.IsValid() && (ri.IsOk())) {
12405 m_prot_bm =
new wxBitmap(ri);
12408 m_roffset.x += VPoint.rv_rect.x;
12409 m_roffset.y += VPoint.rv_rect.y;
12412 if (m_prot_bm && m_prot_bm->IsOk()) {
12413 rotd_dc.SelectObject(*m_prot_bm);
12414 pChartDC = &rotd_dc;
12416 pChartDC = &temp_dc;
12417 m_roffset = wxPoint(0, 0);
12420 pChartDC = &temp_dc;
12421 m_roffset = wxPoint(0, 0);
12424 wxPoint offset = m_roffset;
12427 m_cache_vp = VPoint;
12430 wxMemoryDC mscratch_dc;
12431 mscratch_dc.SelectObject(*pscratch_bm);
12433 mscratch_dc.ResetBoundingBox();
12434 mscratch_dc.DestroyClippingRegion();
12435 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12438 wxRegionIterator upd(rgn_blit);
12440 wxRect rect = upd.GetRect();
12442 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12443 rect.x - offset.x, rect.y - offset.y);
12449 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12450 if (
this == wxWindow::FindFocus()) {
12453 wxColour colour = GetGlobalColor(
"BLUE4");
12454 mscratch_dc.SetPen(wxPen(colour));
12455 mscratch_dc.SetBrush(wxBrush(colour));
12457 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12458 mscratch_dc.DrawRectangle(activeRect);
12463 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12464 unsigned int im = stackIndexArray.size();
12465 if (VPoint.b_quilt && im > 0) {
12466 std::vector<int> tiles_to_show;
12467 for (
unsigned int is = 0; is < im; is++) {
12469 ChartData->GetChartTableEntry(stackIndexArray[is]);
12470 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12473 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12474 tiles_to_show.push_back(stackIndexArray[is]);
12478 if (tiles_to_show.size())
12479 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12485 ocpnDC scratch_dc(mscratch_dc);
12486 RenderAlertMessage(mscratch_dc, GetVP());
12492#ifdef ocpnUSE_DIBSECTION
12497 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12498 q_dc.SelectObject(qbm);
12501 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12504 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12505 q_dc.SetBrush(qbr);
12506 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12509 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12512 q_dc.SelectObject(wxNullBitmap);
12521 if( VPoint.b_quilt ) {
12522 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12523 ChartBase *chart = m_pQuilt->GetRefChart();
12524 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12529 ChPI->ClearPLIBTextList();
12532 ps52plib->ClearTextList();
12536 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12538 wxColor maskBackground = wxColour(1,0,0);
12539 t_dc.SelectObject( qbm );
12540 t_dc.SetBackground(wxBrush(maskBackground));
12544 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12547 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12548 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12551 wxRegionIterator upd_final( ru );
12552 while( upd_final ) {
12553 wxRect rect = upd_final.GetRect();
12554 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12558 t_dc.SelectObject( wxNullBitmap );
12564 if (VPoint.b_quilt) {
12565 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12566 ChartBase *chart = m_pQuilt->GetRefChart();
12567 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12571 ChPI->ClearPLIBTextList();
12573 if (ps52plib) ps52plib->ClearTextList();
12578 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12580 if (g_bShowChartBar && m_Piano) {
12581 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12582 GetVP().pix_width, m_Piano->GetHeight());
12585 if (!style->chartStatusWindowTransparent)
12586 chart_all_text_region.Subtract(chart_bar_rect);
12589 if (m_Compass && m_Compass->IsShown()) {
12590 wxRect compassRect = m_Compass->
GetRect();
12591 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12592 chart_all_text_region.Subtract(compassRect);
12596 mscratch_dc.DestroyClippingRegion();
12598 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12599 chart_all_text_region);
12605 ocpnDC scratch_dc(mscratch_dc);
12606 DrawOverlayObjects(scratch_dc, ru);
12609 wxRegionIterator upd_final(rgn_blit);
12610 while (upd_final) {
12611 wxRect rect = upd_final.GetRect();
12612 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12619 temp_dc.SelectObject(wxNullBitmap);
12621 mscratch_dc.SelectObject(wxNullBitmap);
12623 dc.DestroyClippingRegion();
12628void ChartCanvas::PaintCleanup() {
12630 if (m_inPinch)
return;
12641 m_bTCupdate =
false;
12645 WarpPointer(warp_x, warp_y);
12652 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12653 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12657wxColour GetErrorGraphicColor(
double val)
12676 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12677 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12678 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12679 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12680 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12681 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12682 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12683 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12684 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12685 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12686 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12687 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12688 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12689 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12690 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12691 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12692 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12693 else if( val >= 48) c.Set(
"#410000");
12698void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12701 gr_image.InitAlpha();
12703 double maxval = -10000;
12704 double minval = 10000;
12721 maxval = wxMax(maxval, (glat - rlat));
12722 minval = wxMin(minval, (glat - rlat));
12739 double f = ((glat - rlat)-minval)/(maxval - minval);
12741 double dy = (f * 40);
12743 wxColour c = GetErrorGraphicColor(dy);
12744 unsigned char r = c.Red();
12745 unsigned char g = c.Green();
12746 unsigned char b = c.Blue();
12748 gr_image.SetRGB(j, i, r,g,b);
12749 if((glat - rlat )!= 0)
12750 gr_image.SetAlpha(j, i, 128);
12752 gr_image.SetAlpha(j, i, 255);
12759 wxBitmap *pbm =
new wxBitmap(gr_image);
12760 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12761 pbm->SetMask(gr_mask);
12763 pmdc->DrawBitmap(*pbm, 0,0);
12771void ChartCanvas::CancelMouseRoute() {
12773 m_pMouseRoute = NULL;
12774 m_bDrawingRoute =
false;
12777int ChartCanvas::GetNextContextMenuId() {
12778 return CanvasMenuHandler::GetNextContextMenuId();
12781bool ChartCanvas::SetCursor(
const wxCursor &c) {
12783 if (g_bopengl && m_glcc)
12784 return m_glcc->SetCursor(c);
12787 return wxWindow::SetCursor(c);
12790void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12791 if (g_bquiting)
return;
12801 if (!m_RolloverPopupTimer.IsRunning() &&
12802 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12803 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12804 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12805 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12808 if (m_glcc && g_bopengl) {
12811 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12813 m_glcc->Refresh(eraseBackground,
12830 if (m_pCIWin && m_pCIWin->IsShown()) {
12832 m_pCIWin->Refresh(
false);
12840 wxWindow::Refresh(eraseBackground, rect);
12843void ChartCanvas::Update() {
12844 if (m_glcc && g_bopengl) {
12849 wxWindow::Update();
12853 if (!pemboss)
return;
12854 int x = pemboss->x, y = pemboss->y;
12855 const double factor = 200;
12857 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12858 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12859 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12862 wxMemoryDC snip_dc;
12863 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12864 snip_dc.SelectObject(snip_bmp);
12866 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12867 snip_dc.SelectObject(wxNullBitmap);
12869 wxImage snip_img = snip_bmp.ConvertToImage();
12872 unsigned char *pdata = snip_img.GetData();
12874 for (
int y = 0; y < pemboss->height; y++) {
12875 int map_index = (y * pemboss->width);
12876 for (
int x = 0; x < pemboss->width; x++) {
12877 double val = (pemboss->pmap[map_index] * factor) / 256.;
12879 int nred = (int)((*pdata) + val);
12880 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12881 *pdata++ = (
unsigned char)nred;
12883 int ngreen = (int)((*pdata) + val);
12884 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12885 *pdata++ = (
unsigned char)ngreen;
12887 int nblue = (int)((*pdata) + val);
12888 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12889 *pdata++ = (
unsigned char)nblue;
12897 wxBitmap emb_bmp(snip_img);
12900 wxMemoryDC result_dc;
12901 result_dc.SelectObject(emb_bmp);
12904 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12906 result_dc.SelectObject(wxNullBitmap);
12912 if (GetQuiltMode()) {
12914 int refIndex = GetQuiltRefChartdbIndex();
12915 if (refIndex >= 0) {
12917 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12918 if (current_type == CHART_TYPE_MBTILES) {
12919 ChartBase *pChart = m_pQuilt->GetRefChart();
12922 zoom_factor = ptc->GetZoomFactor();
12927 if (zoom_factor <= 3.9)
return NULL;
12929 if (m_singleChart) {
12930 if (zoom_factor <= 3.9)
return NULL;
12935 if (m_pEM_OverZoom) {
12936 m_pEM_OverZoom->x = 4;
12937 m_pEM_OverZoom->y = 0;
12939 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12940 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12943 return m_pEM_OverZoom;
12946void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12959 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12960 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12964 AISDrawAreaNotices(dc, GetVP(),
this);
12966 wxDC *pdc = dc.GetDC();
12968 pdc->DestroyClippingRegion();
12969 wxDCClipper(*pdc, ru);
12972 if (m_bShowNavobjects) {
12973 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12974 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12975 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12976 DrawAnchorWatchPoints(dc);
12978 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12979 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12982 AISDraw(dc, GetVP(),
this);
12986 RenderVisibleSectorLights(dc);
12988 RenderAllChartOutlines(dc, GetVP());
12989 RenderRouteLegs(dc);
12990 RenderShipToActive(dc,
false);
12992 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12994 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12998 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12999 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
13002 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
13007 RebuildTideSelectList(GetVP().GetBBox());
13008 DrawAllTidesInBBox(dc, GetVP().GetBBox());
13011 if (m_bShowCurrent) {
13012 RebuildCurrentSelectList(GetVP().GetBBox());
13013 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
13016 if (!g_PrintingInProgress) {
13017 if (IsPrimaryCanvas()) {
13021 if (IsPrimaryCanvas()) {
13025 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
13027 if (m_pTrackRolloverWin) {
13028 m_pTrackRolloverWin->Draw(dc);
13029 m_brepaint_piano =
true;
13032 if (m_pRouteRolloverWin) {
13033 m_pRouteRolloverWin->Draw(dc);
13034 m_brepaint_piano =
true;
13037 if (m_pAISRolloverWin) {
13038 m_pAISRolloverWin->Draw(dc);
13039 m_brepaint_piano =
true;
13041 if (m_brepaint_piano && g_bShowChartBar) {
13042 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
13045 if (m_Compass) m_Compass->Paint(dc);
13047 if (!g_CanvasHideNotificationIcon) {
13048 if (IsPrimaryCanvas()) {
13049 auto ¬eman = NotificationManager::GetInstance();
13050 if (m_notification_button) {
13051 if (noteman.GetNotificationCount()) {
13052 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
13053 if (m_notification_button->UpdateStatus()) Refresh();
13054 m_notification_button->Show(
true);
13055 m_notification_button->Paint(dc);
13057 m_notification_button->Show(
false);
13064 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
13070 if (!m_bShowDepthUnits)
return NULL;
13072 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
13074 if (GetQuiltMode()) {
13075 wxString s = m_pQuilt->GetQuiltDepthUnit();
13078 depth_unit_type = DEPTH_UNIT_FEET;
13079 else if (s.StartsWith(
"FATHOMS"))
13080 depth_unit_type = DEPTH_UNIT_FATHOMS;
13081 else if (s.StartsWith(
"METERS"))
13082 depth_unit_type = DEPTH_UNIT_METERS;
13083 else if (s.StartsWith(
"METRES"))
13084 depth_unit_type = DEPTH_UNIT_METERS;
13085 else if (s.StartsWith(
"METRIC"))
13086 depth_unit_type = DEPTH_UNIT_METERS;
13087 else if (s.StartsWith(
"METER"))
13088 depth_unit_type = DEPTH_UNIT_METERS;
13091 if (m_singleChart) {
13092 depth_unit_type = m_singleChart->GetDepthUnitType();
13093 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
13094 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
13099 switch (depth_unit_type) {
13100 case DEPTH_UNIT_FEET:
13103 case DEPTH_UNIT_METERS:
13104 ped = m_pEM_Meters;
13106 case DEPTH_UNIT_FATHOMS:
13107 ped = m_pEM_Fathoms;
13113 ped->x = (GetVP().
pix_width - ped->width);
13115 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
13116 wxRect r = m_Compass->
GetRect();
13117 ped->y = r.y + r.height;
13124void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
13127 if (style->embossFont == wxEmptyString) {
13128 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13130 font.SetPointSize(60);
13131 font.SetWeight(wxFONTWEIGHT_BOLD);
13133 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13134 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13136 int emboss_width = 500;
13137 int emboss_height = 200;
13141 delete m_pEM_Meters;
13142 delete m_pEM_Fathoms;
13146 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
13148 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
13150 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
13153#define OVERZOOM_TEXT _("OverZoom")
13155void ChartCanvas::SetOverzoomFont() {
13160 if (style->embossFont == wxEmptyString) {
13161 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13163 font.SetPointSize(40);
13164 font.SetWeight(wxFONTWEIGHT_BOLD);
13166 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13167 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13169 wxClientDC dc(
this);
13171 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13173 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13174 font.SetPointSize(font.GetPointSize() - 1);
13176 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13178 m_overzoomFont = font;
13179 m_overzoomTextWidth = w;
13180 m_overzoomTextHeight = h;
13183void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13184 delete m_pEM_OverZoom;
13186 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13188 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13189 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13192emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13193 int height,
const wxString &str,
13198 wxBitmap bmp(width, height, -1);
13201 wxMemoryDC temp_dc;
13202 temp_dc.SelectObject(bmp);
13205 temp_dc.SetBackground(*wxWHITE_BRUSH);
13206 temp_dc.SetTextBackground(*wxWHITE);
13207 temp_dc.SetTextForeground(*wxBLACK);
13211 temp_dc.SetFont(font);
13214 temp_dc.GetTextExtent(str, &str_w, &str_h);
13216 temp_dc.DrawText(str, 1, 1);
13219 temp_dc.SelectObject(wxNullBitmap);
13222 wxImage img = bmp.ConvertToImage();
13224 int image_width = str_w * 105 / 100;
13225 int image_height = str_h * 105 / 100;
13226 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13227 wxMin(image_height, img.GetHeight()));
13228 wxImage imgs = img.GetSubImage(r);
13232 case GLOBAL_COLOR_SCHEME_DAY:
13236 case GLOBAL_COLOR_SCHEME_DUSK:
13239 case GLOBAL_COLOR_SCHEME_NIGHT:
13246 const int w = imgs.GetWidth();
13247 const int h = imgs.GetHeight();
13248 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13253 for (
int y = 1; y < h - 1; y++) {
13254 for (
int x = 1; x < w - 1; x++) {
13256 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13257 val = (int)(val * val_factor);
13258 index = (y * w) + x;
13271void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13272 Track *active_track = NULL;
13275 active_track = pTrackDraw;
13279 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13282 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13285void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13286 Track *active_track = NULL;
13289 active_track = pTrackDraw;
13293 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13296void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13297 Route *active_route = NULL;
13299 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13300 active_route = pRouteDraw;
13305 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13310 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13313void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13314 Route *active_route = NULL;
13317 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13318 active_route = pRouteDraw;
13322 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13325void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13326 if (!pWayPointMan)
return;
13328 auto node = pWayPointMan->GetWaypointList()->begin();
13330 while (node != pWayPointMan->GetWaypointList()->end()) {
13339 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13343 if (pWP->GetShowWaypointRangeRings() &&
13344 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13345 double factor = 1.00;
13346 if (pWP->GetWaypointRangeRingsStepUnits() ==
13348 factor = 1 / 1.852;
13350 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13351 pWP->GetWaypointRangeRingsStep() / 60.;
13355 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13356 pWP->m_lat + radius, pWP->m_lon + radius);
13357 if (!BltBBox.IntersectOut(radar_box)) {
13368void ChartCanvas::DrawBlinkObjects() {
13370 wxRect update_rect;
13372 if (!pWayPointMan)
return;
13374 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13381 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13384void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13389 wxPoint lAnchorPoint1, lAnchorPoint2;
13403 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13404 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13406 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13407 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13408 dc.SetBrush(*ppBrush);
13412 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13417 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13422 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13427 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13432double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13435 wxPoint lAnchorPoint;
13438 double tlat1, tlon1;
13440 if (pAnchorWatchPoint) {
13441 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13443 dabs = fabs(d1 / 1852.);
13444 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13449 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13450 pow((
double)(lAnchorPoint.y - r1.y), 2));
13453 if (d1 < 0) lpp = -lpp;
13461void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13463 if (
this != wxWindow::FindFocus())
return;
13465 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13467 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13473 if ((type ==
't') || (type ==
'T')) {
13474 if (BBox.Contains(lat, lon)) {
13476 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13482void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13485 wxDateTime this_now = gTimeSource;
13486 bool cur_time = !gTimeSource.IsValid();
13487 if (cur_time) this_now = wxDateTime::Now();
13488 time_t t_this_now = this_now.GetTicks();
13490 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13492 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13493 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13494 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13495 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13497 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13498 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13499 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13500 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13501 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13502 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13504 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13505 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13506 int font_size = wxMax(10, dFont->GetPointSize());
13509 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13510 false, dFont->GetFaceName());
13512 dc.SetPen(*pblack_pen);
13513 dc.SetBrush(*pgreen_brush);
13517 case GLOBAL_COLOR_SCHEME_DAY:
13520 case GLOBAL_COLOR_SCHEME_DUSK:
13523 case GLOBAL_COLOR_SCHEME_NIGHT:
13524 bm = m_bmTideNight;
13531 int bmw = bm.GetWidth();
13532 int bmh = bm.GetHeight();
13534 float scale_factor = 1.0;
13538 float icon_pixelRefDim = 45;
13543 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13545 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13547 scale_factor *= pix_factor;
13554 scale_factor *= user_scale_factor;
13555 scale_factor *= GetContentScaleFactor();
13558 double marge = 0.05;
13559 std::vector<LLBBox> drawn_boxes;
13560 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13564 if ((type ==
't') || (type ==
'T'))
13569 if (BBox.ContainsMarge(lat, lon, marge)) {
13571 if (GetVP().chart_scale < 500000) {
13572 bool bdrawn =
false;
13573 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13574 if (drawn_boxes[i].Contains(lat, lon)) {
13579 if (bdrawn)
continue;
13582 this_box.Set(lat, lon, lat, lon);
13583 this_box.EnLarge(.005);
13584 drawn_boxes.push_back(this_box);
13590 if (GetVP().chart_scale > 500000) {
13591 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13595 dc.SetFont(*plabelFont);
13607 if (
ptcmgr->GetTideFlowSens(
13608 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13612 ptcmgr->GetHightOrLowTide(
13613 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13614 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13626 if (tctime > t_this_now)
13627 ptcmgr->GetHightOrLowTide(
13628 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13629 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13633 ptcmgr->GetHightOrLowTide(
13634 t_this_now, FORWARD_TEN_MINUTES_STEP,
13635 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13649 int width = (int)(12 * scale_factor + 0.5);
13650 int height = (int)(45 * scale_factor + 0.5);
13651 int linew = wxMax(1, (
int)(scale_factor));
13652 int xDraw = r.x - (width / 2);
13653 int yDraw = r.y - (height / 2);
13656 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13657 int hs = (httime > lttime) ? -4 : 4;
13658 hs *= (int)(scale_factor + 0.5);
13659 if (ts > 0.995 || ts < 0.005) hs = 0;
13660 int ht_y = (int)(height * ts);
13663 pblack_pen->SetWidth(linew);
13664 dc.SetPen(*pblack_pen);
13665 dc.SetBrush(*pyelo_brush);
13666 dc.DrawRectangle(xDraw, yDraw, width, height);
13670 dc.SetPen(*pblue_pen);
13671 dc.SetBrush(*pblue_brush);
13672 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13673 (width - (4 * linew)), height - ht_y);
13679 arrow[0].x = xDraw + 2 * linew;
13680 arrow[1].x = xDraw + width / 2;
13681 arrow[2].x = xDraw + width - 2 * linew;
13682 pyelo_pen->SetWidth(linew);
13683 pblue_pen->SetWidth(linew);
13684 if (ts > 0.35 || ts < 0.15)
13686 hl = (int)(height * 0.25) + yDraw;
13688 arrow[1].y = hl + hs;
13691 dc.SetPen(*pyelo_pen);
13693 dc.SetPen(*pblue_pen);
13694 dc.DrawLines(3, arrow);
13696 if (ts > 0.60 || ts < 0.40)
13698 hl = (int)(height * 0.5) + yDraw;
13700 arrow[1].y = hl + hs;
13703 dc.SetPen(*pyelo_pen);
13705 dc.SetPen(*pblue_pen);
13706 dc.DrawLines(3, arrow);
13708 if (ts < 0.65 || ts > 0.85)
13710 hl = (int)(height * 0.75) + yDraw;
13712 arrow[1].y = hl + hs;
13715 dc.SetPen(*pyelo_pen);
13717 dc.SetPen(*pblue_pen);
13718 dc.DrawLines(3, arrow);
13722 double nowlev_converted = nowlev;
13726 int unit_c = TCDataFactory::findunit(pmsd->unit);
13730 TCDataFactory::known_units[unit_c].conv_factor;
13733 nowlev_converted =
toUsrHeight(nowlev_converted);
13737 s.Printf(
"%3.1f", nowlev_converted);
13741 dc.GetTextExtent(s, &wx1, NULL);
13743 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13758void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13761 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13763 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13769 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13770 if ((BBox.Contains(lat, lon))) {
13772 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13778void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13781 float tcvalue, dir;
13785 double lon_last = 0.;
13786 double lat_last = 0.;
13788 double marge = 0.2;
13789 bool cur_time = !gTimeSource.IsValid();
13791 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13792 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13794 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13796 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13797 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13798 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13799 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13800 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13801 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13802 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13803 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13805 double skew_angle = GetVPRotation();
13807 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13808 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13809 int font_size = wxMax(10, dFont->GetPointSize());
13812 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13813 false, dFont->GetFaceName());
13815 float scale_factor = 1.0;
13821 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13823 float nominal_icon_size_pixels = 15;
13824 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13826 scale_factor *= pix_factor;
13833 scale_factor *= user_scale_factor;
13835 scale_factor *= GetContentScaleFactor();
13838 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13844 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13845 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13850 int dd = (int)(5.0 * scale_factor + 0.5);
13861 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13862 dc.SetPen(*pblack_pen);
13863 dc.SetBrush(*porange_brush);
13864 dc.DrawPolygon(4, d);
13867 dc.SetBrush(*pblack_brush);
13868 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13872 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13886 double a1 = fabs(tcvalue) * 10.;
13888 a1 = wxMax(1.0, a1);
13889 double a2 = log10(a1);
13891 float cscale = scale_factor * a2 * 0.3;
13893 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13894 dc.SetPen(*porange_pen);
13895 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13899 if (bDrawCurrentValues) {
13900 dc.SetFont(*pTCFont);
13901 tcvalue = toUsrSpeed(tcvalue);
13902 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13903 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13929 if (!pvIDX)
return;
13934 if (pCwin && pCwin->IsShown()) {
13942 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13957 pCwin =
new TCWin(
this, x, y, pvIDX);
13975#define NUM_CURRENT_ARROW_POINTS 9
13976static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13977 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13978 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13979 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13981void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13983 if (
scale > 1e-2) {
13984 float sin_rot = sin(rot_angle * PI / 180.);
13985 float cos_rot = cos(rot_angle * PI / 180.);
13989 float xt = CurrentArrowArray[0].x;
13990 float yt = CurrentArrowArray[0].y;
13992 float xp = (xt * cos_rot) - (yt * sin_rot);
13993 float yp = (xt * sin_rot) + (yt * cos_rot);
13994 int x1 = (int)(xp *
scale);
13995 int y1 = (int)(yp *
scale);
13998 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13999 xt = CurrentArrowArray[ip].x;
14000 yt = CurrentArrowArray[ip].y;
14002 float xp = (xt * cos_rot) - (yt * sin_rot);
14003 float yp = (xt * sin_rot) + (yt * cos_rot);
14004 int x2 = (int)(xp *
scale);
14005 int y2 = (int)(yp *
scale);
14007 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
14015wxString ChartCanvas::FindValidUploadPort() {
14018 if (!g_uploadConnection.IsEmpty() &&
14019 g_uploadConnection.StartsWith(
"Serial")) {
14020 port = g_uploadConnection;
14026 for (
auto *cp : TheConnectionParams()) {
14027 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
14028 port <<
"Serial:" << cp->Port;
14034void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
14037 if (NULL == g_pais_query_dialog_active) {
14038 int pos_x = g_ais_query_dialog_x;
14039 int pos_y = g_ais_query_dialog_y;
14041 if (g_pais_query_dialog_active) {
14042 g_pais_query_dialog_active->Destroy();
14048 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
14049 wxPoint(pos_x, pos_y));
14051 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
14052 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
14053 g_pais_query_dialog_active->SetMMSI(mmsi);
14054 g_pais_query_dialog_active->UpdateText();
14055 wxSize sz = g_pais_query_dialog_active->GetSize();
14057 bool b_reset_pos =
false;
14062 RECT frame_title_rect;
14063 frame_title_rect.left = pos_x;
14064 frame_title_rect.top = pos_y;
14065 frame_title_rect.right = pos_x + sz.x;
14066 frame_title_rect.bottom = pos_y + 30;
14068 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
14069 b_reset_pos =
true;
14074 wxRect window_title_rect;
14075 window_title_rect.x = pos_x;
14076 window_title_rect.y = pos_y;
14077 window_title_rect.width = sz.x;
14078 window_title_rect.height = 30;
14080 wxRect ClientRect = wxGetClientDisplayRect();
14081 ClientRect.Deflate(
14083 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
14087 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
14090 g_pais_query_dialog_active->SetMMSI(mmsi);
14091 g_pais_query_dialog_active->UpdateText();
14094 g_pais_query_dialog_active->Show();
14097void ChartCanvas::ToggleCanvasQuiltMode() {
14098 bool cur_mode = GetQuiltMode();
14100 if (!GetQuiltMode())
14101 SetQuiltMode(
true);
14102 else if (GetQuiltMode()) {
14103 SetQuiltMode(
false);
14104 g_sticky_chart = GetQuiltReferenceChartIndex();
14107 if (cur_mode != GetQuiltMode()) {
14108 SetupCanvasQuiltMode();
14117 if (ps52plib) ps52plib->GenerateStateHash();
14119 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14120 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14123void ChartCanvas::DoCanvasStackDelta(
int direction) {
14124 if (!GetQuiltMode()) {
14125 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
14126 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
14127 if ((current_stack_index + direction) < 0)
return;
14129 if (m_bpersistent_quilt ) {
14131 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
14133 if (IsChartQuiltableRef(new_dbIndex)) {
14134 ToggleCanvasQuiltMode();
14135 SelectQuiltRefdbChart(new_dbIndex);
14136 m_bpersistent_quilt =
false;
14139 SelectChartFromStack(current_stack_index + direction);
14142 std::vector<int> piano_chart_index_array =
14143 GetQuiltExtendedStackdbIndexArray();
14144 int refdb = GetQuiltRefChartdbIndex();
14147 int current_index = -1;
14148 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14149 if (refdb == piano_chart_index_array[i]) {
14154 if (current_index == -1)
return;
14157 int target_family = ctet.GetChartFamily();
14159 int new_index = -1;
14160 int check_index = current_index + direction;
14161 bool found =
false;
14162 int check_dbIndex = -1;
14163 int new_dbIndex = -1;
14167 (
unsigned int)check_index < piano_chart_index_array.size() &&
14168 (check_index >= 0)) {
14169 check_dbIndex = piano_chart_index_array[check_index];
14171 if (target_family == cte.GetChartFamily()) {
14173 new_index = check_index;
14174 new_dbIndex = check_dbIndex;
14178 check_index += direction;
14181 if (!found)
return;
14183 if (!IsChartQuiltableRef(new_dbIndex)) {
14184 ToggleCanvasQuiltMode();
14185 SelectdbChart(new_dbIndex);
14186 m_bpersistent_quilt =
true;
14188 SelectQuiltRefChart(new_index);
14193 top_frame::Get()->UpdateGlobalMenuItems();
14194 SetQuiltChartHiLiteIndex(-1);
14205void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14208 switch (event.GetId()) {
14220 DoCanvasStackDelta(1);
14225 DoCanvasStackDelta(-1);
14235 ShowCurrents(!GetbShowCurrent());
14242 ShowTides(!GetbShowTide());
14249 if (0 == m_routeState) {
14256 androidSetRouteAnnunciator(m_routeState == 1);
14262 SetAISCanvasDisplayStyle(-1);
14274void ChartCanvas::SetShowAIS(
bool show) {
14276 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14277 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14280void ChartCanvas::SetAttenAIS(
bool show) {
14281 m_bShowAISScaled = show;
14282 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14283 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14286void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14289 bool bShowAIS_Array[3] = {
true,
true,
false};
14290 bool bShowScaled_Array[3] = {
false,
true,
true};
14291 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14292 _(
"Attenuate less critical AIS targets"),
14293 _(
"Hide AIS Targets")};
14294 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14296 int AIS_Toolbar_Switch = 0;
14297 if (StyleIndx == -1) {
14299 for (
int i = 1; i < ArraySize; i++) {
14300 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14301 (bShowScaled_Array[i] == m_bShowAISScaled))
14302 AIS_Toolbar_Switch = i;
14304 AIS_Toolbar_Switch++;
14305 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14306 AIS_Toolbar_Switch++;
14309 AIS_Toolbar_Switch = StyleIndx;
14312 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14314 int AIS_Toolbar_Switch_Next =
14315 AIS_Toolbar_Switch + 1;
14316 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14317 AIS_Toolbar_Switch_Next++;
14318 if (AIS_Toolbar_Switch_Next >= ArraySize)
14319 AIS_Toolbar_Switch_Next = 0;
14322 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14323 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14326void ChartCanvas::TouchAISToolActive() {}
14328void ChartCanvas::UpdateAISTBTool() {}
14336void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14338 bool b_update =
false;
14339 int cc1_edge_comp = 2;
14340 wxRect rect = m_Compass->
GetRect();
14341 wxSize parent_size = GetSize();
14343 parent_size *= m_displayScale;
14347 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14348 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14349 wxRect compass_rect(compass_pt, rect.GetSize());
14351 m_Compass->Move(compass_pt);
14353 if (m_Compass && m_Compass->IsShown())
14354 m_Compass->UpdateStatus(b_force_new | b_update);
14356 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14357 scaler = wxMax(scaler, 1.0);
14358 wxPoint note_point = wxPoint(
14359 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14360 if (m_notification_button) {
14361 m_notification_button->Move(note_point);
14362 m_notification_button->UpdateStatus();
14365 if (b_force_new | b_update) Refresh();
14368void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14369 ChartTypeEnum New_Type,
14370 ChartFamilyEnum New_Family) {
14371 if (!GetpCurrentStack())
return;
14374 if (index < GetpCurrentStack()->nEntry) {
14377 pTentative_Chart =
ChartData->OpenStackChartConditional(
14378 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14380 if (pTentative_Chart) {
14381 if (m_singleChart) m_singleChart->Deactivate();
14383 m_singleChart = pTentative_Chart;
14384 m_singleChart->Activate();
14386 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14387 GetpCurrentStack(), m_singleChart->GetFullPath());
14400 double best_scale_ppm = GetBestVPScale(m_singleChart);
14401 double rotation = GetVPRotation();
14402 double oldskew = GetVPSkew();
14403 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14405 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14406 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14407 if (fabs(newskew) > 0.0001) rotation = newskew;
14410 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14412 UpdateGPSCompassStatusBox(
true);
14416 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14417 if (idx < 0)
return;
14419 std::vector<int> piano_active_chart_index_array;
14420 piano_active_chart_index_array.push_back(
14421 GetpCurrentStack()->GetCurrentEntrydbIndex());
14422 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14425void ChartCanvas::SelectdbChart(
int dbindex) {
14426 if (!GetpCurrentStack())
return;
14429 if (dbindex >= 0) {
14432 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14434 if (pTentative_Chart) {
14435 if (m_singleChart) m_singleChart->Deactivate();
14437 m_singleChart = pTentative_Chart;
14438 m_singleChart->Activate();
14440 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14441 GetpCurrentStack(), m_singleChart->GetFullPath());
14454 double best_scale_ppm = GetBestVPScale(m_singleChart);
14458 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14468void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14471 if (!GetQuiltMode()) {
14472 if (GetpCurrentStack()) {
14473 int stack_index = -1;
14474 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14475 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14476 if (check_dbIndex < 0)
continue;
14478 ChartData->GetChartTableEntry(check_dbIndex);
14479 if (type == cte.GetChartType()) {
14482 }
else if (family == cte.GetChartFamily()) {
14488 if (stack_index >= 0) {
14489 SelectChartFromStack(stack_index);
14493 int sel_dbIndex = -1;
14494 std::vector<int> piano_chart_index_array =
14495 GetQuiltExtendedStackdbIndexArray();
14496 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14497 int check_dbIndex = piano_chart_index_array[i];
14499 if (type == cte.GetChartType()) {
14500 if (IsChartQuiltableRef(check_dbIndex)) {
14501 sel_dbIndex = check_dbIndex;
14504 }
else if (family == cte.GetChartFamily()) {
14505 if (IsChartQuiltableRef(check_dbIndex)) {
14506 sel_dbIndex = check_dbIndex;
14512 if (sel_dbIndex >= 0) {
14513 SelectQuiltRefdbChart(sel_dbIndex,
false);
14515 AdjustQuiltRefChart();
14522 SetQuiltChartHiLiteIndex(-1);
14527bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14528 return std::find(m_tile_yesshow_index_array.begin(),
14529 m_tile_yesshow_index_array.end(),
14530 index) != m_tile_yesshow_index_array.end();
14533bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14534 return std::find(m_tile_noshow_index_array.begin(),
14535 m_tile_noshow_index_array.end(),
14536 index) != m_tile_noshow_index_array.end();
14539void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14540 if (std::find(m_tile_noshow_index_array.begin(),
14541 m_tile_noshow_index_array.end(),
14542 index) == m_tile_noshow_index_array.end()) {
14543 m_tile_noshow_index_array.push_back(index);
14553void ChartCanvas::HandlePianoClick(
14554 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14557 if (!m_pCurrentStack)
return;
14573 double distance = 25000;
14574 int closest_index = -1;
14575 for (
int chart_index : selected_dbIndex_array) {
14577 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14578 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14581 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14582 if (test_distance < distance) {
14583 distance = test_distance;
14584 closest_index = chart_index;
14588 int selected_dbIndex = selected_dbIndex_array[0];
14589 if (closest_index >= 0) selected_dbIndex = closest_index;
14591 if (!GetQuiltMode()) {
14592 if (m_bpersistent_quilt ) {
14593 if (IsChartQuiltableRef(selected_dbIndex)) {
14594 ToggleCanvasQuiltMode();
14595 SelectQuiltRefdbChart(selected_dbIndex);
14596 m_bpersistent_quilt =
false;
14598 SelectChartFromStack(selected_index);
14601 SelectChartFromStack(selected_index);
14602 g_sticky_chart = selected_dbIndex;
14606 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14610 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14611 bool bfound =
false;
14612 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14613 if (m_tile_noshow_index_array[i] ==
14614 selected_dbIndex) {
14615 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14622 m_tile_noshow_index_array.push_back(selected_dbIndex);
14626 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14627 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14631 if (IsChartQuiltableRef(selected_dbIndex)) {
14637 bool set_scale =
false;
14638 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14639 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14645 SelectQuiltRefdbChart(selected_dbIndex,
true);
14647 SelectQuiltRefdbChart(selected_dbIndex,
false);
14652 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14654 double proposed_scale_onscreen =
14657 if (g_bPreserveScaleOnX) {
14658 proposed_scale_onscreen =
14659 wxMin(proposed_scale_onscreen,
14661 GetCanvasWidth()));
14663 proposed_scale_onscreen =
14664 wxMin(proposed_scale_onscreen,
14666 GetCanvasWidth()));
14668 proposed_scale_onscreen =
14669 wxMax(proposed_scale_onscreen,
14678 ToggleCanvasQuiltMode();
14679 SelectdbChart(selected_dbIndex);
14680 m_bpersistent_quilt =
true;
14685 SetQuiltChartHiLiteIndex(-1);
14687 top_frame::Get()->UpdateGlobalMenuItems();
14688 HideChartInfoWindow();
14693void ChartCanvas::HandlePianoRClick(
14694 int x,
int y,
int selected_index,
14695 const std::vector<int> &selected_dbIndex_array) {
14698 if (!GetpCurrentStack())
return;
14700 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14701 UpdateCanvasControlBar();
14703 SetQuiltChartHiLiteIndex(-1);
14706void ChartCanvas::HandlePianoRollover(
14707 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14708 int n_charts,
int scale) {
14711 if (!GetpCurrentStack())
return;
14716 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14718 if (!GetQuiltMode()) {
14719 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14722 std::vector<int> piano_chart_index_array;
14723 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14724 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14725 if ((GetpCurrentStack()->nEntry > 1) ||
14726 (piano_chart_index_array.size() >= 1)) {
14727 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14729 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14731 }
else if (GetpCurrentStack()->nEntry == 1) {
14733 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14734 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14735 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14737 }
else if ((-1 == selected_index) &&
14738 (0 == selected_dbIndex_array.size())) {
14739 ShowChartInfoWindow(key_location.x, -1);
14743 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14745 if ((GetpCurrentStack()->nEntry > 1) ||
14746 (piano_chart_index_array.size() >= 1)) {
14748 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14749 selected_dbIndex_array);
14750 else if (n_charts == 1)
14751 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14753 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14760void ChartCanvas::ClearPianoRollover() {
14761 ClearQuiltChartHiLiteIndexArray();
14762 ShowChartInfoWindow(0, -1);
14763 std::vector<int> vec;
14764 ShowCompositeInfoWindow(0, 0, 0, vec);
14768void ChartCanvas::UpdateCanvasControlBar() {
14769 if (m_pianoFrozen)
return;
14771 if (!GetpCurrentStack())
return;
14773 if (!g_bShowChartBar)
return;
14776 int sel_family = -1;
14778 std::vector<int> piano_chart_index_array;
14779 std::vector<int> empty_piano_chart_index_array;
14781 wxString old_hash = m_Piano->GetStoredHash();
14783 if (GetQuiltMode()) {
14784 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14785 GetQuiltFullScreendbIndexArray());
14787 std::vector<int> piano_active_chart_index_array =
14788 GetQuiltCandidatedbIndexArray();
14789 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14791 std::vector<int> piano_eclipsed_chart_index_array =
14792 GetQuiltEclipsedStackdbIndexArray();
14793 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14795 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14796 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14798 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14799 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14801 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14802 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14805 if (m_singleChart) {
14806 sel_type = m_singleChart->GetChartType();
14807 sel_family = m_singleChart->GetChartFamily();
14812 std::vector<int> piano_skew_chart_index_array;
14813 std::vector<int> piano_tmerc_chart_index_array;
14814 std::vector<int> piano_poly_chart_index_array;
14816 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14818 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14819 double skew_norm = ctei.GetChartSkew();
14820 if (skew_norm > 180.) skew_norm -= 360.;
14822 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14823 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14826 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14827 if (fabs(skew_norm) > 1.)
14828 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14830 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14831 }
else if (fabs(skew_norm) > 1.)
14832 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14834 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14835 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14836 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14838 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14839 if (new_hash != old_hash) {
14840 m_Piano->FormatKeys();
14841 HideChartInfoWindow();
14842 m_Piano->ResetRollover();
14843 SetQuiltChartHiLiteIndex(-1);
14844 m_brepaint_piano =
true;
14850 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14852 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14853 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14854 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14855 if (e == CHART_FAMILY_RASTER) mask |= 1;
14856 if (e == CHART_FAMILY_VECTOR) {
14857 if (t == CHART_TYPE_CM93COMP)
14864 wxString s_indicated;
14865 if (sel_type == CHART_TYPE_CM93COMP)
14866 s_indicated =
"cm93";
14868 if (sel_family == CHART_FAMILY_RASTER)
14869 s_indicated =
"raster";
14870 else if (sel_family == CHART_FAMILY_VECTOR)
14871 s_indicated =
"vector";
14874 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14877void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14879void ChartCanvas::PianoPopupMenu(
14880 int x,
int y,
int selected_index,
14881 const std::vector<int> &selected_dbIndex_array) {
14882 if (!GetpCurrentStack())
return;
14885 if (!GetQuiltMode())
return;
14887 m_piano_ctx_menu =
new wxMenu();
14889 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14899 menu_selected_dbIndex = selected_dbIndex_array[0];
14900 menu_selected_index = selected_index;
14903 bool b_is_in_noshow =
false;
14904 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14905 if (m_quilt_noshow_index_array[i] ==
14906 menu_selected_dbIndex)
14908 b_is_in_noshow =
true;
14913 if (b_is_in_noshow) {
14914 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14915 _(
"Show This Chart"));
14916 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14917 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14918 }
else if (GetpCurrentStack()->nEntry > 1) {
14919 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14920 _(
"Hide This Chart"));
14921 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14922 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14926 wxPoint pos = wxPoint(x, y - 30);
14929 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14930 PopupMenu(m_piano_ctx_menu, pos);
14932 delete m_piano_ctx_menu;
14933 m_piano_ctx_menu = NULL;
14935 HideChartInfoWindow();
14936 m_Piano->ResetRollover();
14938 SetQuiltChartHiLiteIndex(-1);
14939 ClearQuiltChartHiLiteIndexArray();
14944void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14945 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14946 if (m_quilt_noshow_index_array[i] ==
14947 menu_selected_dbIndex)
14949 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14955void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14956 if (!GetpCurrentStack())
return;
14959 RemoveChartFromQuilt(menu_selected_dbIndex);
14963 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14964 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14966 int i = menu_selected_index + 1;
14967 bool b_success =
false;
14968 while (i < GetpCurrentStack()->nEntry - 1) {
14969 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14970 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14971 SelectQuiltRefChart(i);
14981 i = menu_selected_index - 1;
14983 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14984 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14985 SelectQuiltRefChart(i);
14995void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14997 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14998 if (m_quilt_noshow_index_array[i] ==
15001 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
15006 m_quilt_noshow_index_array.push_back(dbIndex);
15009bool ChartCanvas::UpdateS52State() {
15010 bool retval =
false;
15013 ps52plib->SetShowS57Text(m_encShowText);
15014 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
15015 ps52plib->m_bShowSoundg = m_encShowDepth;
15016 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
15017 ps52plib->m_bShowLdisText = m_encShowLightDesc;
15020 if (!m_encShowLights)
15021 ps52plib->AddObjNoshow(
"LIGHTS");
15023 ps52plib->RemoveObjNoshow(
"LIGHTS");
15024 ps52plib->SetLightsOff(!m_encShowLights);
15025 ps52plib->m_bExtendLightSectors =
true;
15028 ps52plib->SetAnchorOn(m_encShowAnchor);
15029 ps52plib->SetQualityOfData(m_encShowDataQual);
15035void ChartCanvas::SetShowENCDataQual(
bool show) {
15036 m_encShowDataQual = show;
15037 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
15038 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
15040 m_s52StateHash = 0;
15043void ChartCanvas::SetShowENCText(
bool show) {
15044 m_encShowText = show;
15045 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
15046 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
15048 m_s52StateHash = 0;
15051void ChartCanvas::SetENCDisplayCategory(
int category) {
15052 m_encDisplayCategory = category;
15053 m_s52StateHash = 0;
15056void ChartCanvas::SetShowENCDepth(
bool show) {
15057 m_encShowDepth = show;
15058 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
15059 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
15061 m_s52StateHash = 0;
15064void ChartCanvas::SetShowENCLightDesc(
bool show) {
15065 m_encShowLightDesc = show;
15066 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
15067 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
15069 m_s52StateHash = 0;
15072void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
15073 m_encShowBuoyLabels = show;
15074 m_s52StateHash = 0;
15077void ChartCanvas::SetShowENCLights(
bool show) {
15078 m_encShowLights = show;
15079 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
15080 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
15082 m_s52StateHash = 0;
15085void ChartCanvas::SetShowENCAnchor(
bool show) {
15086 m_encShowAnchor = show;
15087 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
15088 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
15090 m_s52StateHash = 0;
15093wxRect ChartCanvas::GetMUIBarRect() {
15096 rv = m_muiBar->GetRect();
15102void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
15103 if (!GetAlertString().IsEmpty()) {
15104 wxFont *pfont = wxTheFontList->FindOrCreateFont(
15105 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
15107 dc.SetFont(*pfont);
15108 dc.SetPen(*wxTRANSPARENT_PEN);
15110 dc.SetBrush(wxColour(243, 229, 47));
15112 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
15116 wxRect sbr = GetScaleBarRect();
15117 int xp = sbr.x + sbr.width + 10;
15118 int yp = (sbr.y + sbr.height) - h;
15120 int wdraw = w + 10;
15121 dc.DrawRectangle(xp, yp, wdraw, h);
15122 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
15123 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
15133#define BRIGHT_XCALIB
15134#define __OPCPN_USEICC__
15137#ifdef __OPCPN_USEICC__
15138int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15139 double co_green,
double co_blue);
15141wxString temp_file_name;
15145class ocpnCurtain:
public wxDialog
15147 DECLARE_CLASS( ocpnCurtain )
15148 DECLARE_EVENT_TABLE()
15151 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
15153 bool ProcessEvent(wxEvent& event);
15157IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
15159BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
15162ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
15164 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
15167ocpnCurtain::~ocpnCurtain()
15171bool ocpnCurtain::ProcessEvent(wxEvent& event)
15173 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
15174 return GetParent()->GetEventHandler()->ProcessEvent(event);
15179#include <windows.h>
15182typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15183typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15184SetDeviceGammaRamp_ptr_type
15185 g_pSetDeviceGammaRamp;
15186GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15188WORD *g_pSavedGammaMap;
15192int InitScreenBrightness() {
15195 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15199 if (NULL == hGDI32DLL) {
15200 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15202 if (NULL != hGDI32DLL) {
15204 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15205 hGDI32DLL,
"SetDeviceGammaRamp");
15206 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15207 hGDI32DLL,
"GetDeviceGammaRamp");
15210 if ((NULL == g_pSetDeviceGammaRamp) ||
15211 (NULL == g_pGetDeviceGammaRamp)) {
15212 FreeLibrary(hGDI32DLL);
15221 if (!g_pSavedGammaMap) {
15222 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15225 bbr = g_pGetDeviceGammaRamp(
15226 hDC, g_pSavedGammaMap);
15227 ReleaseDC(NULL, hDC);
15232 wxRegKey *pRegKey =
new wxRegKey(
15233 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15234 "NT\\CurrentVersion\\ICM");
15235 if (!pRegKey->Exists()) pRegKey->Create();
15236 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15238 g_brightness_init =
true;
15244 if (NULL == g_pcurtain) {
15245 if (top_frame::Get()->CanSetTransparent()) {
15247 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15248 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15249 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15250 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15257 g_pcurtain->Hide();
15259 HWND hWnd = GetHwndOf(g_pcurtain);
15260 SetWindowLong(hWnd, GWL_EXSTYLE,
15261 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15262 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15263 g_pcurtain->SetTransparent(0);
15265 g_pcurtain->Maximize();
15266 g_pcurtain->Show();
15269 g_pcurtain->Enable();
15270 g_pcurtain->Disable();
15272 top_frame::Get()->Disable();
15273 top_frame::Get()->Enable();
15277 g_brightness_init =
true;
15283 wxString cmd(
"xcalib -version");
15285 wxArrayString output;
15286 long r = wxExecute(cmd, output);
15289 " External application \"xcalib\" not found. Screen brightness "
15292 g_brightness_init =
true;
15297int RestoreScreenBrightness() {
15300 if (g_pSavedGammaMap) {
15301 HDC hDC = GetDC(NULL);
15302 g_pSetDeviceGammaRamp(hDC,
15304 ReleaseDC(NULL, hDC);
15306 free(g_pSavedGammaMap);
15307 g_pSavedGammaMap = NULL;
15311 g_pcurtain->Close();
15312 g_pcurtain->Destroy();
15316 g_brightness_init =
false;
15321#ifdef BRIGHT_XCALIB
15322 if (g_brightness_init) {
15324 cmd =
"xcalib -clear";
15325 wxExecute(cmd, wxEXEC_ASYNC);
15326 g_brightness_init =
false;
15336int SetScreenBrightness(
int brightness) {
15343 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15345 g_pcurtain->Close();
15346 g_pcurtain->Destroy();
15350 InitScreenBrightness();
15352 if (NULL == hGDI32DLL) {
15354 wchar_t wdll_name[80];
15355 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15356 LPCWSTR cstr = wdll_name;
15358 hGDI32DLL = LoadLibrary(cstr);
15360 if (NULL != hGDI32DLL) {
15362 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15363 hGDI32DLL,
"SetDeviceGammaRamp");
15364 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15365 hGDI32DLL,
"GetDeviceGammaRamp");
15368 if ((NULL == g_pSetDeviceGammaRamp) ||
15369 (NULL == g_pGetDeviceGammaRamp)) {
15370 FreeLibrary(hGDI32DLL);
15377 HDC hDC = GetDC(NULL);
15388 int increment = brightness * 256 / 100;
15391 WORD GammaTable[3][256];
15394 for (
int i = 0; i < 256; i++) {
15395 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15396 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15397 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15399 table_val += increment;
15401 if (table_val > 65535) table_val = 65535;
15404 g_pSetDeviceGammaRamp(hDC, GammaTable);
15405 ReleaseDC(NULL, hDC);
15412 if (g_pSavedGammaMap) {
15413 HDC hDC = GetDC(NULL);
15414 g_pSetDeviceGammaRamp(hDC,
15416 ReleaseDC(NULL, hDC);
15419 if (brightness < 100) {
15420 if (NULL == g_pcurtain) InitScreenBrightness();
15423 int sbrite = wxMax(1, brightness);
15424 sbrite = wxMin(100, sbrite);
15426 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15430 g_pcurtain->Close();
15431 g_pcurtain->Destroy();
15441#ifdef BRIGHT_XCALIB
15443 if (!g_brightness_init) {
15444 last_brightness = 100;
15445 g_brightness_init =
true;
15446 temp_file_name = wxFileName::CreateTempFileName(
"");
15447 InitScreenBrightness();
15450#ifdef __OPCPN_USEICC__
15453 if (!CreateSimpleICCProfileFile(
15454 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15455 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15456 wxString cmd(
"xcalib ");
15457 cmd += temp_file_name;
15459 wxExecute(cmd, wxEXEC_ASYNC);
15468 if (brightness > last_brightness) {
15470 cmd =
"xcalib -clear";
15471 wxExecute(cmd, wxEXEC_ASYNC);
15473 ::wxMilliSleep(10);
15475 int brite_adj = wxMax(1, brightness);
15476 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15477 wxExecute(cmd, wxEXEC_ASYNC);
15479 int brite_adj = wxMax(1, brightness);
15480 int factor = (brite_adj * 100) / last_brightness;
15481 factor = wxMax(1, factor);
15483 cmd.Printf(
"xcalib -co %2d -a", factor);
15484 wxExecute(cmd, wxEXEC_ASYNC);
15489 last_brightness = brightness;
15496#ifdef __OPCPN_USEICC__
15498#define MLUT_TAG 0x6d4c5554L
15499#define VCGT_TAG 0x76636774L
15501int GetIntEndian(
unsigned char *s) {
15506 p = (
unsigned char *)&ret;
15509 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15511 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15516unsigned short GetShortEndian(
unsigned char *s) {
15517 unsigned short ret;
15521 p = (
unsigned char *)&ret;
15524 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15526 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15532int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15533 double co_green,
double co_blue) {
15537 fp = fopen(file_name,
"wb");
15538 if (!fp)
return -1;
15544 for (
int i = 0; i < 128; i++) header[i] = 0;
15546 fwrite(header, 128, 1, fp);
15550 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15551 fwrite(&numTags, 1, 4, fp);
15553 int tagName0 = VCGT_TAG;
15554 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15555 fwrite(&tagName, 1, 4, fp);
15557 int tagOffset0 = 128 + 4 *
sizeof(int);
15558 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15559 fwrite(&tagOffset, 1, 4, fp);
15562 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15563 fwrite(&tagSize, 1, 4, fp);
15565 fwrite(&tagName, 1, 4, fp);
15567 fwrite(&tagName, 1, 4, fp);
15572 int gammatype0 = 0;
15573 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15574 fwrite(&gammatype, 1, 4, fp);
15576 int numChannels0 = 3;
15577 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15578 fwrite(&numChannels, 1, 2, fp);
15580 int numEntries0 = 256;
15581 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15582 fwrite(&numEntries, 1, 2, fp);
15584 int entrySize0 = 1;
15585 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15586 fwrite(&entrySize, 1, 2, fp);
15588 unsigned char ramp[256];
15591 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15592 fwrite(ramp, 256, 1, fp);
15595 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15596 fwrite(ramp, 256, 1, fp);
15599 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15600 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.
Locked down interface published in 5.14.1.
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.
wxString getUsrHeightUnit(int unit)
Get the abbreviation for the preferred height unit.
double toUsrHeight(double m_height, int unit)
Convert height from meters to preferred height units.
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.