35#include <wx/graphics.h>
36#include <wx/clipbrd.h>
37#include <wx/aui/aui.h>
41#include "o_sound/o_sound.h"
48#include "model/geodesic.h"
54#include "model/nav_object_database.h"
116#include "tide_time.h"
123#include "user_colors.h"
125#include "s57_ocpn_utils.h"
128#include "androidUTIL.h"
138#include <wx/msw/msvcrt.h>
147#define printf printf2
149int __cdecl printf2(
const char *format, ...) {
153 va_start(argptr, format);
154 int ret = vsnprintf(str,
sizeof(str), format, argptr);
156 OutputDebugStringA(str);
161#if defined(__MSVC__) && (_MSC_VER < 1700)
162#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
168#define OCPN_ALT_MENUBAR 1
175static bool g_bSmoothRecenter =
true;
176static bool bDrawCurrentValues;
197static bool mouse_leftisdown;
198static bool g_brouteCreating;
199static int r_gamma_mult;
200static int g_gamma_mult;
201static int b_gamma_mult;
202static int gamma_state;
203static bool g_brightness_init;
204static int last_brightness;
205static wxGLContext *g_pGLcontext;
208static wxDialog *g_pcurtain;
210static wxString g_lastS52PLIBPluginMessage;
213#define MAX_BRIGHT 100
220EVT_ACTIVATE(ChartCanvas::OnActivate)
221EVT_SIZE(ChartCanvas::OnSize)
222#ifndef HAVE_WX_GESTURE_EVENTS
223EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
225EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
226EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
227EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
228EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
229EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
230EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
231EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
232EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
233EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
234EVT_KEY_UP(ChartCanvas::OnKeyUp)
235EVT_CHAR(ChartCanvas::OnKeyChar)
236EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
237EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
238EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
239EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
240EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
241EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
242EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
243EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
244EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
245EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
252 m_nmea_log(nmea_log) {
253 parent_frame = frame;
254 m_canvasIndex = canvasIndex;
258 SetBackgroundColour(wxColour(0, 0, 0));
259 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
263 m_bDrawingRoute =
false;
264 m_bRouteEditing =
false;
265 m_bMarkEditing =
false;
266 m_bRoutePoinDragging =
false;
267 m_bIsInRadius =
false;
268 m_bMayToggleMenuBar =
true;
271 m_bShowNavobjects =
true;
273 m_bAppendingRoute =
false;
274 pThumbDIBShow = NULL;
275 m_bShowCurrent =
false;
277 bShowingCurrent =
false;
281 m_b_paint_enable =
true;
284 pss_overlay_bmp = NULL;
285 pss_overlay_mask = NULL;
286 m_bChartDragging =
false;
287 m_bMeasure_Active =
false;
288 m_bMeasure_DistCircle =
false;
289 m_pMeasureRoute = NULL;
290 m_pTrackRolloverWin = NULL;
291 m_pRouteRolloverWin = NULL;
292 m_pAISRolloverWin = NULL;
294 m_disable_edge_pan =
false;
295 m_dragoffsetSet =
false;
299 m_singleChart = NULL;
300 m_upMode = NORTH_UP_MODE;
302 m_bShowAISScaled =
false;
303 m_timed_move_vp_active =
false;
305 m_disable_adjust_on_zoom =
false;
312 m_pSelectedRoute = NULL;
313 m_pSelectedTrack = NULL;
314 m_pRoutePointEditTarget = NULL;
315 m_pFoundPoint = NULL;
316 m_pMouseRoute = NULL;
317 m_prev_pMousePoint = NULL;
318 m_pEditRouteArray = NULL;
319 m_pFoundRoutePoint = NULL;
320 m_FinishRouteOnKillFocus =
true;
322 m_pRolloverRouteSeg = NULL;
323 m_pRolloverTrackSeg = NULL;
324 m_bsectors_shown =
false;
326 m_bbrightdir =
false;
331 m_pos_image_user_day = NULL;
332 m_pos_image_user_dusk = NULL;
333 m_pos_image_user_night = NULL;
334 m_pos_image_user_grey_day = NULL;
335 m_pos_image_user_grey_dusk = NULL;
336 m_pos_image_user_grey_night = NULL;
339 m_rotation_speed = 0;
345 m_pos_image_user_yellow_day = NULL;
346 m_pos_image_user_yellow_dusk = NULL;
347 m_pos_image_user_yellow_night = NULL;
349 SetOwnShipState(SHIP_INVALID);
351 undo =
new Undo(
this);
357 m_focus_indicator_pix = 1;
359 m_pCurrentStack = NULL;
360 m_bpersistent_quilt =
false;
361 m_piano_ctx_menu = NULL;
363 m_NotificationsList = NULL;
364 m_notification_button = NULL;
366 g_ChartNotRenderScaleFactor = 2.0;
367 m_bShowScaleInStatusBar =
true;
370 m_bShowScaleInStatusBar =
false;
371 m_show_focus_bar =
true;
373 m_bShowOutlines =
false;
374 m_bDisplayGrid =
false;
375 m_bShowDepthUnits =
true;
376 m_encDisplayCategory = (int)STANDARD;
378 m_encShowLights =
true;
379 m_encShowAnchor =
true;
380 m_encShowDataQual =
false;
382 m_pQuilt =
new Quilt(
this);
387 g_PrintingInProgress =
false;
389#ifdef HAVE_WX_GESTURE_EVENTS
390 m_oldVPSScale = -1.0;
391 m_popupWanted =
false;
394 m_inLongPress =
false;
397 m_sw_left_down.Start();
398 m_sw_left_up.Start();
402 singleClickEventIsValid =
false;
411 pCursorPencil = NULL;
416 SetCursor(*pCursorArrow);
418 pPanTimer =
new wxTimer(
this, m_MouseDragging);
421 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
422 pMovementTimer->Stop();
424 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
425 pMovementStopTimer->Stop();
427 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
428 pRotDefTimer->Stop();
430 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
431 m_DoubleClickTimer->Stop();
433 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
434 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
435 m_chart_drag_inertia_active =
false;
437 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
438 m_animationActive =
false;
439 m_menuTimer.SetOwner(
this, MENU_TIMER);
440 m_tap_timer.SetOwner(
this, TAP_TIMER);
444 m_panx_target_final = m_pany_target_final = 0;
445 m_panx_target_now = m_pany_target_now = 0;
448 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
449 pCurTrackTimer->Stop();
450 m_curtrack_timer_msec = 10;
452 m_wheelzoom_stop_oneshot = 0;
453 m_last_wheel_dir = 0;
455 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
457 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
459 m_rollover_popup_timer_msec = 20;
461 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
463 m_b_rot_hidef =
true;
468 m_upMode = NORTH_UP_MODE;
469 m_bLookAhead =
false;
473 m_cs = GLOBAL_COLOR_SCHEME_DAY;
476 VPoint.view_scale_ppm = 1;
479 m_ignore_next_leftup =
false;
481 m_canvas_scale_factor = 1.;
483 m_canvas_width = 1000;
485 m_overzoomTextWidth = 0;
486 m_overzoomTextHeight = 0;
495 m_pEM_Fathoms = NULL;
497 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
499 m_pEM_OverZoom = NULL;
501 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
509 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
512 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
515 double factor_dusk = 0.5;
516 double factor_night = 0.25;
519 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
521 int rimg_width = m_os_image_red_day.GetWidth();
522 int rimg_height = m_os_image_red_day.GetHeight();
524 m_os_image_red_dusk = m_os_image_red_day.Copy();
525 m_os_image_red_night = m_os_image_red_day.Copy();
527 for (
int iy = 0; iy < rimg_height; iy++) {
528 for (
int ix = 0; ix < rimg_width; ix++) {
529 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
530 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
531 m_os_image_red_day.GetGreen(ix, iy),
532 m_os_image_red_day.GetBlue(ix, iy));
533 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
534 hsv.value = hsv.value * factor_dusk;
535 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
536 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
538 hsv = wxImage::RGBtoHSV(rgb);
539 hsv.value = hsv.value * factor_night;
540 nrgb = wxImage::HSVtoRGB(hsv);
541 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
547 m_os_image_grey_day =
548 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
550 int gimg_width = m_os_image_grey_day.GetWidth();
551 int gimg_height = m_os_image_grey_day.GetHeight();
553 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
554 m_os_image_grey_night = m_os_image_grey_day.Copy();
556 for (
int iy = 0; iy < gimg_height; iy++) {
557 for (
int ix = 0; ix < gimg_width; ix++) {
558 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
559 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
560 m_os_image_grey_day.GetGreen(ix, iy),
561 m_os_image_grey_day.GetBlue(ix, iy));
562 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
563 hsv.value = hsv.value * factor_dusk;
564 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
565 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
567 hsv = wxImage::RGBtoHSV(rgb);
568 hsv.value = hsv.value * factor_night;
569 nrgb = wxImage::HSVtoRGB(hsv);
570 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
576 m_os_image_yellow_day = m_os_image_red_day.Copy();
578 gimg_width = m_os_image_yellow_day.GetWidth();
579 gimg_height = m_os_image_yellow_day.GetHeight();
581 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
582 m_os_image_yellow_night = m_os_image_red_day.Copy();
584 for (
int iy = 0; iy < gimg_height; iy++) {
585 for (
int ix = 0; ix < gimg_width; ix++) {
586 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
587 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
588 m_os_image_yellow_day.GetGreen(ix, iy),
589 m_os_image_yellow_day.GetBlue(ix, iy));
590 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
591 hsv.hue += 60. / 360.;
592 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
593 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
595 hsv = wxImage::RGBtoHSV(rgb);
596 hsv.value = hsv.value * factor_dusk;
597 hsv.hue += 60. / 360.;
598 nrgb = wxImage::HSVtoRGB(hsv);
599 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
601 hsv = wxImage::RGBtoHSV(rgb);
602 hsv.hue += 60. / 360.;
603 hsv.value = hsv.value * factor_night;
604 nrgb = wxImage::HSVtoRGB(hsv);
605 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
611 m_pos_image_red = &m_os_image_red_day;
612 m_pos_image_yellow = &m_os_image_yellow_day;
613 m_pos_image_grey = &m_os_image_grey_day;
617 m_pBrightPopup = NULL;
620 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
625 m_Piano =
new Piano(
this);
627 m_bShowCompassWin =
true;
629 m_Compass->SetScaleFactor(g_compass_scalefactor);
630 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
632 if (IsPrimaryCanvas()) {
634 m_notification_button->SetScaleFactor(g_compass_scalefactor);
635 m_notification_button->Show(
true);
638 m_pianoFrozen =
false;
640 SetMinSize(wxSize(200, 200));
642 m_displayScale = 1.0;
643#if defined(__WXOSX__) || defined(__WXGTK3__)
645 m_displayScale = GetContentScaleFactor();
647 VPoint.SetPixelScale(m_displayScale);
649#ifdef HAVE_WX_GESTURE_EVENTS
652 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
653 wxLogError(
"Failed to enable touch events");
658 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
659 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
661 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
662 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
664 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
665 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
667 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
668 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
673 auto ¬eman = NotificationManager::GetInstance();
675 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
676 evt_notificationlist_change_listener.Listen(
677 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
678 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
679 if (m_NotificationsList && m_NotificationsList->IsShown()) {
680 m_NotificationsList->ReloadNotificationList();
686ChartCanvas::~ChartCanvas() {
687 delete pThumbDIBShow;
695 delete pCursorPencil;
699 delete pMovementTimer;
700 delete pMovementStopTimer;
701 delete pCurTrackTimer;
703 delete m_DoubleClickTimer;
705 delete m_pTrackRolloverWin;
706 delete m_pRouteRolloverWin;
707 delete m_pAISRolloverWin;
708 delete m_pBrightPopup;
714 m_dc_route.SelectObject(wxNullBitmap);
717 delete pWorldBackgroundChart;
718 delete pss_overlay_bmp;
722 delete m_pEM_Fathoms;
724 delete m_pEM_OverZoom;
729 delete m_pos_image_user_day;
730 delete m_pos_image_user_dusk;
731 delete m_pos_image_user_night;
732 delete m_pos_image_user_grey_day;
733 delete m_pos_image_user_grey_dusk;
734 delete m_pos_image_user_grey_night;
735 delete m_pos_image_user_yellow_day;
736 delete m_pos_image_user_yellow_dusk;
737 delete m_pos_image_user_yellow_night;
741 if (!g_bdisable_opengl) {
744#if wxCHECK_VERSION(2, 9, 0)
745 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
752 MUIBar *muiBar = m_muiBar;
756 delete m_pCurrentStack;
759 delete m_notification_button;
762void ChartCanvas::SetupGridFont() {
763 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
765 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
767 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
768 FALSE, wxString(
"Arial"));
771void ChartCanvas::RebuildCursors() {
777 delete pCursorPencil;
781 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
786 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
787 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
788 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
789 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
790 wxImage ICursorPencil =
791 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
792 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
794#if !defined(__WXMSW__) && !defined(__WXQT__)
795 ICursorLeft.ConvertAlphaToMask(128);
796 ICursorRight.ConvertAlphaToMask(128);
797 ICursorUp.ConvertAlphaToMask(128);
798 ICursorDown.ConvertAlphaToMask(128);
799 ICursorPencil.ConvertAlphaToMask(10);
800 ICursorCross.ConvertAlphaToMask(10);
803 if (ICursorLeft.Ok()) {
804 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
805 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
806 pCursorLeft =
new wxCursor(ICursorLeft);
808 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
810 if (ICursorRight.Ok()) {
811 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
812 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
813 pCursorRight =
new wxCursor(ICursorRight);
815 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
817 if (ICursorUp.Ok()) {
818 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
819 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
820 pCursorUp =
new wxCursor(ICursorUp);
822 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
824 if (ICursorDown.Ok()) {
825 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
826 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
827 pCursorDown =
new wxCursor(ICursorDown);
829 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
831 if (ICursorPencil.Ok()) {
832 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
833 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
834 pCursorPencil =
new wxCursor(ICursorPencil);
836 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
838 if (ICursorCross.Ok()) {
839 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
840 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
841 pCursorCross =
new wxCursor(ICursorCross);
843 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
845 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
846 pPlugIn_Cursor = NULL;
849void ChartCanvas::CanvasApplyLocale() {
850 CreateDepthUnitEmbossMaps(m_cs);
851 CreateOZEmbossMapData(m_cs);
854void ChartCanvas::SetupGlCanvas() {
857 if (!g_bdisable_opengl) {
859 wxLogMessage(
"Creating glChartCanvas");
864 if (IsPrimaryCanvas()) {
871 wxGLContext *pctx =
new wxGLContext(m_glcc);
872 m_glcc->SetContext(pctx);
876 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
878 m_glcc->SetContext(g_pGLcontext);
888 if (!g_bdisable_opengl) {
891 wxLogMessage(
"Creating glChartCanvas");
895 if (IsPrimaryCanvas()) {
896 qDebug() <<
"Creating Primary glChartCanvas";
904 wxGLContext *pctx =
new wxGLContext(m_glcc);
905 m_glcc->SetContext(pctx);
907 m_glcc->m_pParentCanvas =
this;
910 qDebug() <<
"Creating Secondary glChartCanvas";
917 top_frame::Get()->GetWxGlCanvas());
920 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
921 m_glcc->SetContext(pwxctx);
922 m_glcc->m_pParentCanvas =
this;
930void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
931 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
946 if (m_routeState && m_FinishRouteOnKillFocus)
947 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
949 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
953void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
954 m_routeFinishTimer.Stop();
958 top_frame::Get()->UpdateGlobalMenuItems(
this);
960 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
963void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
964 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
967#ifdef HAVE_WX_GESTURE_EVENTS
968void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
975 m_popupWanted =
true;
977 m_inLongPress = !g_bhide_context_menus;
980 m_menuPos =
event.GetPosition();
981 wxMouseEvent ev(wxEVT_LEFT_UP);
982 ev.m_x = m_menuPos.x;
983 ev.m_y = m_menuPos.y;
984 wxPostEvent(
this, ev);
988 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
989 ev_right_click.m_x = m_menuPos.x;
990 ev_right_click.m_y = m_menuPos.y;
991 MouseEvent(ev_right_click);
996void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1000void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1002void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1004void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1006 long dt = m_sw_left_up.Time() - m_sw_up_time;
1007 m_sw_up_time = m_sw_left_up.Time();
1018 wxPoint pos =
event.GetPosition();
1022 if (!m_popupWanted) {
1023 wxMouseEvent ev(wxEVT_LEFT_UP);
1030 m_popupWanted =
false;
1032 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1039void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1044 long dt = m_sw_left_down.Time() - m_sw_down_time;
1045 m_sw_down_time = m_sw_left_down.Time();
1069 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1071 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1072 m_lastTapPos.y - max_double_click_distance,
1073 max_double_click_distance * 2, max_double_click_distance * 2);
1076 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1082 m_lastTapPos =
event.GetPosition();
1083 m_tap_timer.StartOnce(
1087 if (m_tap_count == 2) {
1091 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1104void ChartCanvas::OnMotion(wxMouseEvent &event) {
1109 event.m_leftDown = m_leftdown;
1113void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1115 if (event.IsGestureEnd())
return;
1117 double factor =
event.GetZoomFactor();
1119 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1124 double wanted_factor = m_oldVPSScale / current_vps * factor;
1129 if (event.IsGestureStart()) {
1130 m_zoomStartPoint =
event.GetPosition();
1132 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1134 m_zoomStartPoint =
event.GetPosition();
1138void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1140void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1141 DoRotateCanvas(0.0);
1145void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1150void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1151 m_FinishRouteOnKillFocus =
false;
1152 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1153 m_FinishRouteOnKillFocus =
true;
1156void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1161 m_restore_dbindex = pcc->DBindex;
1163 if (pcc->GroupID < 0) pcc->GroupID = 0;
1168 m_groupIndex = pcc->GroupID;
1170 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1184 m_encDisplayCategory = pcc->nENCDisplayCategory;
1185 m_encShowDepth = pcc->bShowENCDepths;
1186 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1187 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1188 m_encShowLights = pcc->bShowENCLights;
1189 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1190 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1191 m_encShowDataQual = pcc->bShowENCDataQuality;
1195 m_upMode = NORTH_UP_MODE;
1197 m_upMode = COURSE_UP_MODE;
1199 m_upMode = HEAD_UP_MODE;
1203 m_singleChart = NULL;
1206void ChartCanvas::ApplyGlobalSettings() {
1209 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1210 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1212 if (m_notification_button) m_notification_button->UpdateStatus();
1215void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1216 bool groupOK = CheckGroup(m_groupIndex);
1219 SetGroupIndex(m_groupIndex,
true);
1223void ChartCanvas::SetShowGPS(
bool bshow) {
1224 if (m_bShowGPS != bshow) {
1227 m_Compass->SetScaleFactor(g_compass_scalefactor);
1228 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1233void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1234 m_bShowCompassWin = bshow;
1236 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1237 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1241int ChartCanvas::GetPianoHeight() {
1243 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1248void ChartCanvas::ConfigureChartBar() {
1251 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1252 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1254 if (GetQuiltMode()) {
1255 m_Piano->SetRoundedRectangles(
true);
1257 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1258 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1259 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1262void ChartCanvas::ShowTides(
bool bShow) {
1263 top_frame::Get()->LoadHarmonics();
1266 SetbShowTide(bShow);
1268 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1270 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1271 SetbShowTide(
false);
1272 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1275 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1276 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1287void ChartCanvas::ShowCurrents(
bool bShow) {
1288 top_frame::Get()->LoadHarmonics();
1291 SetbShowCurrent(bShow);
1292 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1294 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1295 SetbShowCurrent(
false);
1296 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1299 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1300 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1317void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1319void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1322 int new_index = index;
1325 bool bgroup_override =
false;
1326 int old_group_index = new_index;
1328 if (!CheckGroup(new_index)) {
1330 bgroup_override =
true;
1333 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1337 int current_chart_native_scale = GetCanvasChartNativeScale();
1340 m_groupIndex = new_index;
1346 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1350 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1354 g_sticky_chart = -1;
1358 UpdateCanvasOnGroupChange();
1361 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1363 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1366 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1367 double best_scale = GetBestStartScale(dbi_hint, vp);
1371 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1375 canvasChartsRefresh(dbi_hint);
1377 UpdateCanvasControlBar();
1379 if (!autoSwitch && bgroup_override) {
1381 wxString msg(_(
"Group \""));
1384 msg += pGroup->m_group_name;
1386 msg += _(
"\" is empty.");
1388 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1395 if (bgroup_override) {
1396 wxString msg(_(
"Group \""));
1399 msg += pGroup->m_group_name;
1401 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1403 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1407bool ChartCanvas::CheckGroup(
int igroup) {
1410 if (igroup == 0)
return true;
1417 if (pGroup->m_element_array.empty())
1421 for (
const auto &elem : pGroup->m_element_array) {
1422 for (
unsigned int ic = 0;
1423 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1424 auto &cte =
ChartData->GetChartTableEntry(ic);
1425 wxString chart_full_path(cte.GetpFullPath(), wxConvUTF8);
1427 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1432 for (
const auto &elem : pGroup->m_element_array) {
1433 const wxString &element_root = elem.m_element_name;
1434 wxString test_string =
"GSHH";
1435 if (element_root.Upper().Contains(test_string))
return true;
1441void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1444 AbstractPlatform::ShowBusySpinner();
1448 SetQuiltRefChart(-1);
1450 m_singleChart = NULL;
1456 if (!m_pCurrentStack) {
1458 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1461 if (-1 != dbi_hint) {
1462 if (GetQuiltMode()) {
1463 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1464 SetQuiltRefChart(dbi_hint);
1468 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1470 if (pTentative_Chart) {
1473 if (m_singleChart) m_singleChart->Deactivate();
1475 m_singleChart = pTentative_Chart;
1476 m_singleChart->Activate();
1478 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1479 GetpCurrentStack(), m_singleChart->GetFullPath());
1487 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1488 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1489 SetQuiltRefChart(selected_index);
1493 SetupCanvasQuiltMode();
1494 if (!GetQuiltMode() && m_singleChart == 0) {
1496 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1497 m_singleChart = pDummyChart;
1503 UpdateCanvasControlBar();
1504 UpdateGPSCompassStatusBox(
true);
1506 SetCursor(wxCURSOR_ARROW);
1508 AbstractPlatform::HideBusySpinner();
1511bool ChartCanvas::DoCanvasUpdate() {
1513 double vpLat, vpLon;
1514 bool blong_jump =
false;
1515 meters_to_shift = 0;
1518 bool bNewChart =
false;
1519 bool bNewView =
false;
1520 bool bCanvasChartAutoOpen =
true;
1522 bool bNewPiano =
false;
1523 bool bOpenSpecified;
1529 if (bDBUpdateInProgress)
return false;
1533 if (m_chart_drag_inertia_active)
return false;
1559 double dx = m_OSoffsetx;
1560 double dy = m_OSoffsety;
1564 if (GetUpMode() == NORTH_UP_MODE) {
1565 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1567 double offset_angle = atan2(d_north, d_east);
1568 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1569 double chart_angle = GetVPRotation();
1570 double target_angle = chart_angle + offset_angle;
1571 double d_east_mod = offset_distance * cos(target_angle);
1572 double d_north_mod = offset_distance * sin(target_angle);
1573 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1577 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1578 double cog_to_use =
gCog;
1580 (fabs(
gCog - gCog_gt) > 20)) {
1581 cog_to_use = gCog_gt;
1584 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1586 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1588 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1589 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1591 double pixel_delta_tent =
1592 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1594 double pixel_delta = 0;
1599 if (!std::isnan(
gSog)) {
1603 pixel_delta = pixel_delta_tent;
1606 meters_to_shift = 0;
1608 if (!std::isnan(
gCog)) {
1609 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1610 dir_to_shift = cog_to_use;
1611 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1617 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1631 if (GetQuiltMode()) {
1632 int current_db_index = -1;
1633 if (m_pCurrentStack)
1636 ->GetCurrentEntrydbIndex();
1644 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1646 if (m_pCurrentStack->nEntry) {
1647 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1649 SelectQuiltRefdbChart(new_dbIndex,
true);
1650 m_bautofind =
false;
1654 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1655 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1660 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1666 double proposed_scale_onscreen =
1669 int initial_db_index = m_restore_dbindex;
1670 if (initial_db_index < 0) {
1671 if (m_pCurrentStack->nEntry) {
1673 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1678 if (m_pCurrentStack->nEntry) {
1679 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1684 if (!IsChartQuiltableRef(initial_db_index)) {
1688 int stack_index = 0;
1690 if (stack_index >= 0) {
1691 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1692 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1693 if (IsChartQuiltableRef(test_db_index) &&
1695 ChartData->GetDBChartType(initial_db_index))) {
1696 initial_db_index = test_db_index;
1706 SetQuiltRefChart(initial_db_index);
1707 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1715 0, GetVPRotation());
1720 bool super_jump =
false;
1722 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1723 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1724 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1727 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1729 if (blong_jump) nstep = 20;
1730 StartTimedMovementVP(vpLat, vpLon, nstep);
1741 pLast_Ch = m_singleChart;
1742 ChartTypeEnum new_open_type;
1743 ChartFamilyEnum new_open_family;
1745 new_open_type = pLast_Ch->GetChartType();
1746 new_open_family = pLast_Ch->GetChartFamily();
1748 new_open_type = CHART_TYPE_KAP;
1749 new_open_family = CHART_FAMILY_RASTER;
1752 bOpenSpecified = m_bFirstAuto;
1755 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1758 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1760 if (NULL == pDummyChart) {
1766 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1768 m_singleChart = pDummyChart;
1773 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1775 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1778 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1779 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1786 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1792 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1797 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1800 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1805 if (NULL != m_singleChart)
1806 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1807 m_singleChart->GetFullPath());
1810 m_pCurrentStack->CurrentStackEntry = tEntry;
1820 if (bCanvasChartAutoOpen) {
1821 bool search_direction =
1823 int start_index = 0;
1827 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1828 (LastStack.nEntry == 0)) {
1829 search_direction =
true;
1830 start_index = m_pCurrentStack->nEntry - 1;
1834 if (bOpenSpecified) {
1835 search_direction =
false;
1837 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1840 new_open_type = CHART_TYPE_DONTCARE;
1843 pProposed =
ChartData->OpenStackChartConditional(
1844 m_pCurrentStack, start_index, search_direction, new_open_type,
1848 if (NULL == pProposed)
1849 pProposed =
ChartData->OpenStackChartConditional(
1850 m_pCurrentStack, start_index, search_direction,
1851 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1853 if (NULL == pProposed)
1854 pProposed =
ChartData->OpenStackChartConditional(
1855 m_pCurrentStack, start_index, search_direction,
1856 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1867 if (NULL == pProposed) {
1868 if (NULL == pDummyChart) {
1874 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1876 pProposed = pDummyChart;
1880 if (m_singleChart) m_singleChart->Deactivate();
1881 m_singleChart = pProposed;
1883 if (m_singleChart) {
1884 m_singleChart->Activate();
1885 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1886 m_pCurrentStack, m_singleChart->GetFullPath());
1891 if (NULL != m_singleChart) {
1897 if (!GetVP().IsValid())
1898 set_scale = 1. / 20000.;
1900 double proposed_scale_onscreen;
1903 double new_scale_ppm =
1904 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1912 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1913 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1914 double equivalent_vp_scale =
1916 double new_scale_ppm =
1917 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1922 proposed_scale_onscreen =
1923 wxMin(proposed_scale_onscreen,
1926 proposed_scale_onscreen =
1927 wxMax(proposed_scale_onscreen,
1936 m_singleChart->GetChartSkew() * PI / 180.,
1943 if ((m_bFollow) && m_singleChart)
1945 m_singleChart->GetChartSkew() * PI / 180.,
1954 m_bFirstAuto =
false;
1958 if (bNewChart && !bNewView) Refresh(
false);
1963 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1966 return bNewChart | bNewView;
1969void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1970 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1972 SetQuiltRefChart(db_index);
1977 double best_scale_ppm = GetBestVPScale(pc);
1981 SetQuiltRefChart(-1);
1983 SetQuiltRefChart(-1);
1986void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1987 std::vector<int> piano_chart_index_array =
1988 GetQuiltExtendedStackdbIndexArray();
1989 int current_db_index = piano_chart_index_array[selected_index];
1991 SelectQuiltRefdbChart(current_db_index);
1994double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1998 if ((g_bPreserveScaleOnX) ||
1999 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2005 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2006 double equivalent_vp_scale =
2008 double new_scale_ppm =
2009 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2016 double max_underzoom_multiplier = 2.0;
2017 if (GetVP().b_quilt) {
2018 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2019 pchart->GetChartType(),
2020 pchart->GetChartFamily());
2021 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2024 proposed_scale_onscreen = wxMin(
2025 proposed_scale_onscreen,
2027 max_underzoom_multiplier);
2030 proposed_scale_onscreen =
2031 wxMax(proposed_scale_onscreen,
2039void ChartCanvas::SetupCanvasQuiltMode() {
2044 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2048 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2049 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2050 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2051 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2053 m_Piano->SetRoundedRectangles(
true);
2056 int target_new_dbindex = -1;
2057 if (m_pCurrentStack) {
2058 target_new_dbindex =
2059 GetQuiltReferenceChartIndex();
2061 if (-1 != target_new_dbindex) {
2062 if (!IsChartQuiltableRef(target_new_dbindex)) {
2063 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2064 int type =
ChartData->GetDBChartType(target_new_dbindex);
2067 int stack_index = m_pCurrentStack->CurrentStackEntry;
2069 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2070 (stack_index >= 0)) {
2071 int proj_tent =
ChartData->GetDBChartProj(
2072 m_pCurrentStack->GetDBIndex(stack_index));
2073 int type_tent =
ChartData->GetDBChartType(
2074 m_pCurrentStack->GetDBIndex(stack_index));
2076 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2077 if ((proj == proj_tent) && (type_tent == type)) {
2078 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2088 if (IsChartQuiltableRef(target_new_dbindex))
2089 SelectQuiltRefdbChart(target_new_dbindex,
2092 SelectQuiltRefdbChart(-1,
false);
2094 m_singleChart = NULL;
2097 AdjustQuiltRefChart();
2105 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2109 std::vector<int> empty_array;
2110 m_Piano->SetActiveKeyArray(empty_array);
2111 m_Piano->SetNoshowIndexArray(empty_array);
2112 m_Piano->SetEclipsedIndexArray(empty_array);
2115 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2116 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2117 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2118 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2120 m_Piano->SetRoundedRectangles(
false);
2126 if (!GetQuiltMode()) {
2131 if (m_bFollow ==
true) {
2139 if (!m_singleChart) {
2142 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2150 int cur_max_scale = (int)1e8;
2152 ChartBase *pChart = GetFirstQuiltChart();
2156 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2158 if (pChart->GetNativeScale() < cur_max_scale) {
2159 Candidate_Chart = pChart;
2160 cur_max_scale = pChart->GetNativeScale();
2163 pChart = GetNextQuiltChart();
2166 m_singleChart = Candidate_Chart;
2170 if (NULL == m_singleChart) {
2171 m_singleChart =
ChartData->OpenStackChartConditional(
2172 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2173 CHART_FAMILY_DONTCARE);
2179 InvalidateAllQuiltPatchs();
2181 if (m_singleChart) {
2182 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2183 std::vector<int> one_array;
2184 one_array.push_back(dbi);
2185 m_Piano->SetActiveKeyArray(one_array);
2188 if (m_singleChart) {
2189 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2193 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2197bool ChartCanvas::IsTempMenuBarEnabled() {
2200 wxGetOsVersion(&major);
2208double ChartCanvas::GetCanvasRangeMeters() {
2210 GetSize(&width, &height);
2211 int minDimension = wxMin(width, height);
2214 range *= cos(GetVP().clat * PI / 180.);
2218void ChartCanvas::SetCanvasRangeMeters(
double range) {
2220 GetSize(&width, &height);
2221 int minDimension = wxMin(width, height);
2223 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2227bool ChartCanvas::SetUserOwnship() {
2231 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2232 double factor_dusk = 0.5;
2233 double factor_night = 0.25;
2235 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2236 m_pos_image_user_day =
new wxImage;
2237 *m_pos_image_user_day = pbmp->ConvertToImage();
2238 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2240 int gimg_width = m_pos_image_user_day->GetWidth();
2241 int gimg_height = m_pos_image_user_day->GetHeight();
2244 m_pos_image_user_dusk =
new wxImage;
2245 m_pos_image_user_night =
new wxImage;
2247 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2248 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2250 for (
int iy = 0; iy < gimg_height; iy++) {
2251 for (
int ix = 0; ix < gimg_width; ix++) {
2252 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2253 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2254 m_pos_image_user_day->GetGreen(ix, iy),
2255 m_pos_image_user_day->GetBlue(ix, iy));
2256 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2257 hsv.value = hsv.value * factor_dusk;
2258 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2259 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2262 hsv = wxImage::RGBtoHSV(rgb);
2263 hsv.value = hsv.value * factor_night;
2264 nrgb = wxImage::HSVtoRGB(hsv);
2265 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2272 m_pos_image_user_grey_day =
new wxImage;
2273 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2275 m_pos_image_user_grey_dusk =
new wxImage;
2276 m_pos_image_user_grey_night =
new wxImage;
2278 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2279 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2281 for (
int iy = 0; iy < gimg_height; iy++) {
2282 for (
int ix = 0; ix < gimg_width; ix++) {
2283 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2284 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2285 m_pos_image_user_grey_day->GetGreen(ix, iy),
2286 m_pos_image_user_grey_day->GetBlue(ix, iy));
2287 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2288 hsv.value = hsv.value * factor_dusk;
2289 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2290 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2293 hsv = wxImage::RGBtoHSV(rgb);
2294 hsv.value = hsv.value * factor_night;
2295 nrgb = wxImage::HSVtoRGB(hsv);
2296 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2303 m_pos_image_user_yellow_day =
new wxImage;
2304 m_pos_image_user_yellow_dusk =
new wxImage;
2305 m_pos_image_user_yellow_night =
new wxImage;
2307 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2308 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2309 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2311 for (
int iy = 0; iy < gimg_height; iy++) {
2312 for (
int ix = 0; ix < gimg_width; ix++) {
2313 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2314 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2315 m_pos_image_user_grey_day->GetGreen(ix, iy),
2316 m_pos_image_user_grey_day->GetBlue(ix, iy));
2320 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2321 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2322 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2324 hsv = wxImage::RGBtoHSV(rgb);
2325 hsv.value = hsv.value * factor_dusk;
2326 nrgb = wxImage::HSVtoRGB(hsv);
2327 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2329 hsv = wxImage::RGBtoHSV(rgb);
2330 hsv.value = hsv.value * factor_night;
2331 nrgb = wxImage::HSVtoRGB(hsv);
2332 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2344 m_display_size_mm = size;
2351 double horizontal = sd.x;
2355 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2356 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2360 ps52plib->SetPPMM(m_pix_per_mm);
2365 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2367 m_display_size_mm, sd.x, sd.y);
2373 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2376 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2379void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2381 wxString msg(event.m_string.c_str(), wxConvUTF8);
2383 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2384 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2387 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2389 compress_msg_array.RemoveAt(event.thread);
2390 compress_msg_array.Insert( msg, event.thread);
2393 compress_msg_array.Add(msg);
2396 wxString combined_msg;
2397 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2398 combined_msg += compress_msg_array[i];
2399 combined_msg +=
"\n";
2403 pprog->Update(pprog_count, combined_msg, &skip );
2404 pprog->SetSize(pprog_size);
2409void ChartCanvas::InvalidateGL() {
2410 if (!m_glcc)
return;
2412 if (g_bopengl) m_glcc->Invalidate();
2414 if (m_Compass) m_Compass->UpdateStatus(
true);
2417int ChartCanvas::GetCanvasChartNativeScale() {
2419 if (!VPoint.b_quilt) {
2420 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2422 ret = (int)m_pQuilt->GetRefNativeScale();
2427ChartBase *ChartCanvas::GetChartAtCursor() {
2429 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2430 target_chart = m_singleChart;
2431 else if (VPoint.b_quilt)
2432 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2434 target_chart = NULL;
2435 return target_chart;
2438ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2442 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2444 target_chart = NULL;
2445 return target_chart;
2448int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2449 int new_dbIndex = -1;
2450 if (!VPoint.b_quilt) {
2451 if (m_pCurrentStack) {
2452 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2453 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2455 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2465 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2467 for (
unsigned int is = 0; is < im; is++) {
2469 m_pQuilt->GetExtendedStackIndexArray()[is]);
2472 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2482void ChartCanvas::EnablePaint(
bool b_enable) {
2483 m_b_paint_enable = b_enable;
2485 if (m_glcc) m_glcc->EnablePaint(b_enable);
2489bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2491void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2493std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2494 return m_pQuilt->GetQuiltIndexArray();
2498void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2499 VPoint.b_quilt = b_quilt;
2500 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2503bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2505int ChartCanvas::GetQuiltReferenceChartIndex() {
2506 return m_pQuilt->GetRefChartdbIndex();
2509void ChartCanvas::InvalidateAllQuiltPatchs() {
2510 m_pQuilt->InvalidateAllQuiltPatchs();
2513ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2514 return m_pQuilt->GetLargestScaleChart();
2517ChartBase *ChartCanvas::GetFirstQuiltChart() {
2518 return m_pQuilt->GetFirstChart();
2521ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2523int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2525void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2526 m_pQuilt->SetHiliteIndex(dbIndex);
2529void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2530 m_pQuilt->SetHiliteIndexArray(hilite_array);
2533void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2534 m_pQuilt->ClearHiliteIndexArray();
2537std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2539 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2542int ChartCanvas::GetQuiltRefChartdbIndex() {
2543 return m_pQuilt->GetRefChartdbIndex();
2546std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2547 return m_pQuilt->GetExtendedStackIndexArray();
2550std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2551 return m_pQuilt->GetFullscreenIndexArray();
2554std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2555 return m_pQuilt->GetEclipsedStackIndexArray();
2558void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2560double ChartCanvas::GetQuiltMaxErrorFactor() {
2561 return m_pQuilt->GetMaxErrorFactor();
2564bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2565 return m_pQuilt->IsChartQuiltableRef(db_index);
2569 double chartMaxScale =
2571 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2574void ChartCanvas::StartMeasureRoute() {
2575 if (!m_routeState) {
2576 if (m_bMeasure_Active) {
2578 m_pMeasureRoute = NULL;
2581 m_bMeasure_Active =
true;
2582 m_nMeasureState = 1;
2583 m_bDrawingRoute =
false;
2585 SetCursor(*pCursorPencil);
2590void ChartCanvas::CancelMeasureRoute() {
2591 m_bMeasure_Active =
false;
2592 m_nMeasureState = 0;
2593 m_bDrawingRoute =
false;
2596 m_pMeasureRoute = NULL;
2598 SetCursor(*pCursorArrow);
2601ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2603void ChartCanvas::SetVP(
ViewPort &vp) {
2614void ChartCanvas::TriggerDeferredFocus() {
2617 m_deferredFocusTimer.Start(20,
true);
2619#if defined(__WXGTK__) || defined(__WXOSX__)
2620 top_frame::Get()->Raise();
2630void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2635void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2636 if (SendKeyEventToPlugins(event))
2640 int key_char =
event.GetKeyCode();
2643 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2649 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2654 if (g_benable_rotate) {
2675void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2676 if (SendKeyEventToPlugins(event))
2680 bool b_handled =
false;
2682 m_modkeys =
event.GetModifiers();
2684 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2686#ifdef OCPN_ALT_MENUBAR
2692 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2694 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2695 if (!g_bTempShowMenuBar) {
2696 g_bTempShowMenuBar =
true;
2697 top_frame::Get()->ApplyGlobalSettings(
false);
2699 m_bMayToggleMenuBar =
false;
2705 if (event.GetKeyCode() != WXK_ALT) {
2706 m_bMayToggleMenuBar =
false;
2713 switch (event.GetKeyCode()) {
2720 event.GetPosition(&x, &y);
2721 m_FinishRouteOnKillFocus =
false;
2722 CallPopupMenu(x, y);
2723 m_FinishRouteOnKillFocus =
true;
2727 m_modkeys |= wxMOD_ALT;
2731 m_modkeys |= wxMOD_CONTROL;
2736 case WXK_RAW_CONTROL:
2737 m_modkeys |= wxMOD_RAW_CONTROL;
2742 if (m_modkeys == wxMOD_CONTROL)
2743 top_frame::Get()->DoStackDown(
this);
2745 StartTimedMovement();
2755 StartTimedMovement();
2763 if (m_modkeys == wxMOD_CONTROL)
2764 top_frame::Get()->DoStackUp(
this);
2766 StartTimedMovement();
2776 StartTimedMovement();
2784 if (event.ShiftDown()) {
2786 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2788 std::shared_ptr<HostApi> host_api;
2790 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2793 api_121->SelectChartFamily(m_canvasIndex,
2800 if (event.ShiftDown()) {
2802 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2804 std::shared_ptr<HostApi> host_api;
2806 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2809 api_121->SelectChartFamily(m_canvasIndex,
2812 SetShowENCText(!GetShowENCText());
2819 if (!m_bMeasure_Active) {
2820 if (event.ShiftDown())
2821 m_bMeasure_DistCircle =
true;
2823 m_bMeasure_DistCircle =
false;
2825 StartMeasureRoute();
2827 CancelMeasureRoute();
2829 SetCursor(*pCursorArrow);
2839 top_frame::Get()->ToggleColorScheme();
2840 top_frame::Get()->Raise();
2841 TriggerDeferredFocus();
2845 int mod = m_modkeys & wxMOD_SHIFT;
2846 if (mod != m_brightmod) {
2848 m_bbrightdir = !m_bbrightdir;
2851 if (!m_bbrightdir) {
2852 g_nbrightness -= 10;
2853 if (g_nbrightness <= MIN_BRIGHT) {
2854 g_nbrightness = MIN_BRIGHT;
2855 m_bbrightdir =
true;
2858 g_nbrightness += 10;
2859 if (g_nbrightness >= MAX_BRIGHT) {
2860 g_nbrightness = MAX_BRIGHT;
2861 m_bbrightdir =
false;
2865 SetScreenBrightness(g_nbrightness);
2866 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2869 top_frame::Get()->Raise();
2875 top_frame::Get()->DoStackDown(
this);
2879 top_frame::Get()->DoStackUp(
this);
2884 ToggleCanvasQuiltMode();
2890 top_frame::Get()->ToggleFullScreen();
2895 if (m_modkeys == wxMOD_ALT) {
2898 ToggleChartOutlines();
2904 top_frame::Get()->ActivateMOB();
2908 case WXK_NUMPAD_ADD:
2913 case WXK_NUMPAD_SUBTRACT:
2914 case WXK_PAGEDOWN: {
2915 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2920 if (m_bMeasure_Active) {
2921 if (m_nMeasureState > 2) {
2922 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2924 m_pMeasureRoute->GetnPoints();
2926 top_frame::Get()->RefreshAllCanvas();
2928 CancelMeasureRoute();
2929 StartMeasureRoute();
2937 if (event.GetKeyCode() < 128)
2939 int key_char =
event.GetKeyCode();
2943 if (!g_b_assume_azerty) {
2945 if (g_benable_rotate) {
2977 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2984 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2985 m_modkeys & wxMOD_RAW_CONTROL) {
2986 top_frame::Get()->ToggleFullScreen();
2991 if (event.ControlDown()) key_char -= 64;
2993 if (key_char >=
'0' && key_char <=
'9')
2994 SetGroupIndex(key_char -
'0');
2999 SetShowENCAnchor(!GetShowENCAnchor());
3005 top_frame::Get()->ToggleColorScheme();
3010 event.GetPosition(&x, &y);
3011 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3012 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3015 if (VPoint.b_quilt) {
3017 if (m_pQuilt->GetChartAtPix(
3022 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3024 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3029 if (m_singleChart) {
3030 ChartType = m_singleChart->GetChartType();
3031 ChartFam = m_singleChart->GetChartFamily();
3035 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3036 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3038 this, -1, ChartType, ChartFam,
3039 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3040 wxDefaultSize, wxSIMPLE_BORDER,
"");
3053 m_nmea_log->Raise();
3057 SetShowENCLights(!GetShowENCLights());
3063 if (event.ShiftDown())
3064 m_bMeasure_DistCircle =
true;
3066 m_bMeasure_DistCircle =
false;
3068 StartMeasureRoute();
3072 if (g_bInlandEcdis && ps52plib) {
3073 SetENCDisplayCategory((_DisCat)STANDARD);
3078 ToggleChartOutlines();
3082 ToggleCanvasQuiltMode();
3086 top_frame::Get()->ToggleTestPause();
3089 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3090 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3091 g_iNavAidRadarRingsNumberVisible = 1;
3092 else if (!g_bNavAidRadarRingsShown &&
3093 g_iNavAidRadarRingsNumberVisible == 1)
3094 g_iNavAidRadarRingsNumberVisible = 0;
3097 SetShowENCDepth(!m_encShowDepth);
3102 SetShowENCText(!GetShowENCText());
3107 SetShowENCDataQual(!GetShowENCDataQual());
3112 m_bShowNavobjects = !m_bShowNavobjects;
3127 if (g_bShowMenuBar ==
false) top_frame::Get()->ToggleChartBar(
this);
3132 if (event.ControlDown()) top_frame::Get()->DropMarker(
false);
3139 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3140 if ((indexActive + 1) <= r->GetnPoints()) {
3151 if (!g_bShowMenuBar) top_frame::Get()->DropMarker(
true);
3157 if (g_bSpaceDropMark) top_frame::Get()->DropMarker(
true);
3163 if (m_modkeys == wxMOD_CONTROL) top_frame::Get()->ActivateMOB();
3170 top_frame::Get()->DoSettings();
3174 parent_frame->Close();
3190 if (undo->AnythingToRedo()) {
3191 undo->RedoNextAction();
3198 if (event.ShiftDown()) {
3199 if (undo->AnythingToRedo()) {
3200 undo->RedoNextAction();
3205 if (undo->AnythingToUndo()) {
3206 undo->UndoLastAction();
3215 if (m_bMeasure_Active) {
3216 CancelMeasureRoute();
3218 SetCursor(*pCursorArrow);
3221 top_frame::Get()->RefreshAllCanvas();
3235 switch (gamma_state) {
3255 SetScreenBrightness(g_nbrightness);
3260 if (event.ControlDown()) {
3261 m_bShowCompassWin = !m_bShowCompassWin;
3262 SetShowGPSCompassWindow(m_bShowCompassWin);
3279void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3280 if (SendKeyEventToPlugins(event))
3284 switch (event.GetKeyCode()) {
3286 top_frame::Get()->SwitchKBFocus(
this);
3292 if (!m_pany) m_panspeed = 0;
3298 if (!m_panx) m_panspeed = 0;
3301 case WXK_NUMPAD_ADD:
3302 case WXK_NUMPAD_SUBTRACT:
3311 m_modkeys &= ~wxMOD_ALT;
3312#ifdef OCPN_ALT_MENUBAR
3317 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3318 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3319 top_frame::Get()->ApplyGlobalSettings(
false);
3321 m_bMayToggleMenuBar =
true;
3327 m_modkeys &= ~wxMOD_CONTROL;
3331 if (event.GetKeyCode() < 128)
3333 int key_char =
event.GetKeyCode();
3337 if (!g_b_assume_azerty) {
3352 m_rotation_speed = 0;
3370void ChartCanvas::ToggleChartOutlines() {
3371 m_bShowOutlines = !m_bShowOutlines;
3377 if (g_bopengl) InvalidateGL();
3381void ChartCanvas::ToggleLookahead() {
3382 m_bLookAhead = !m_bLookAhead;
3387void ChartCanvas::SetUpMode(
int mode) {
3390 if (mode != NORTH_UP_MODE) {
3393 if (!std::isnan(
gCog)) stuff =
gCog;
3396 auto cog_table = top_frame::Get()->GetCOGTable();
3397 for (
int i = 0; i <
g_COGAvgSec; i++) cog_table[i] = stuff;
3400 top_frame::Get()->StartCogTimer();
3402 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3403 SetVPRotation(GetVPSkew());
3408 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3409 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3411 UpdateGPSCompassStatusBox(
true);
3412 top_frame::Get()->DoChartUpdate();
3415bool ChartCanvas::DoCanvasCOGSet() {
3416 if (GetUpMode() == NORTH_UP_MODE)
return false;
3418 if (g_btenhertz) cog_use =
gCog;
3420 double rotation = 0;
3421 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3422 rotation = -
gHdt * PI / 180.;
3423 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3424 rotation = -cog_use * PI / 180.;
3426 SetVPRotation(rotation);
3430double easeOutCubic(
double t) {
3432 return 1.0 - pow(1.0 - t, 3.0);
3435void ChartCanvas::StartChartDragInertia() {
3436 m_bChartDragging =
false;
3439 m_chart_drag_inertia_time = 750;
3440 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3445 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3449 size_t length = m_drag_vec_t.size();
3450 for (
size_t i = 0; i < n_vel; i++) {
3451 xacc += m_drag_vec_x.at(length - 1 - i);
3452 yacc += m_drag_vec_y.at(length - 1 - i);
3453 tacc += m_drag_vec_t.at(length - 1 - i);
3456 if (tacc == 0)
return;
3458 double drag_velocity_x = xacc / tacc;
3459 double drag_velocity_y = yacc / tacc;
3465 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3467 m_chart_drag_velocity_x = drag_velocity_x;
3468 m_chart_drag_velocity_y = drag_velocity_y;
3470 m_chart_drag_inertia_active =
true;
3472 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3475void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3476 if (!m_chart_drag_inertia_active)
return;
3478 wxLongLong now = wxGetLocalTimeMillis();
3479 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3480 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3481 if (t > 1.0) t = 1.0;
3482 double e = 1.0 - easeOutCubic(t);
3485 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3487 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3489 m_last_elapsed = elapsed;
3493 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3494 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3495 double inertia_lat, inertia_lon;
3499 if (!IsOwnshipOnScreen()) {
3501 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3502 UpdateFollowButtonState();
3513 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3514 m_chart_drag_inertia_timer.Stop();
3517 m_target_lat = GetVP().
clat;
3518 m_target_lon = GetVP().
clon;
3519 m_pan_drag.x = m_pan_drag.y = 0;
3520 m_panx = m_pany = 0;
3521 m_chart_drag_inertia_active =
false;
3525 int target_redraw_interval = 40;
3526 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3530void ChartCanvas::StopMovement() {
3531 m_panx = m_pany = 0;
3534 m_rotation_speed = 0;
3537#if !defined(__WXGTK__) && !defined(__WXQT__)
3539 top_frame::Get()->Raise();
3548bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3550 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3552 if (!pMovementTimer->IsRunning()) {
3553 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3556 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3561 m_last_movement_time = wxDateTime::UNow();
3565void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3568 m_target_lat = target_lat;
3569 m_target_lon = target_lon;
3572 m_start_lat = GetVP().
clat;
3573 m_start_lon = GetVP().
clon;
3575 m_VPMovementTimer.Start(1,
true);
3576 m_timed_move_vp_active =
true;
3578 m_timedVP_step = nstep;
3581void ChartCanvas::DoTimedMovementVP() {
3582 if (!m_timed_move_vp_active)
return;
3583 if (m_stvpc++ > m_timedVP_step * 2) {
3590 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3605 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3606 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3608 m_run_lat = new_lat;
3609 m_run_lon = new_lon;
3614void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3616void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3618void ChartCanvas::StartTimedMovementTarget() {}
3620void ChartCanvas::DoTimedMovementTarget() {}
3622void ChartCanvas::StopMovementTarget() {}
3625void ChartCanvas::DoTimedMovement() {
3626 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3630 wxDateTime now = wxDateTime::UNow();
3632 if (m_last_movement_time.IsValid())
3633 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3635 m_last_movement_time = now;
3645 if (dt == 0) dt = 1;
3648 if (m_mustmove < 0) m_mustmove = 0;
3651 if (m_pan_drag.x || m_pan_drag.y) {
3653 m_pan_drag.x = m_pan_drag.y = 0;
3656 if (m_panx || m_pany) {
3657 const double slowpan = .1, maxpan = 2;
3658 if (m_modkeys == wxMOD_ALT)
3659 m_panspeed = slowpan;
3661 m_panspeed += (double)dt / 500;
3662 m_panspeed = wxMin(maxpan, m_panspeed);
3664 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3667 if (m_zoom_factor != 1) {
3668 double alpha = 400, beta = 1.5;
3669 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3671 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3673 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3678 if (zoom_factor > 1) {
3679 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3683 else if (zoom_factor < 1) {
3684 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3689 if (fabs(zoom_factor - 1) > 1e-4) {
3690 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3695 if (m_wheelzoom_stop_oneshot > 0) {
3696 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3697 m_wheelzoom_stop_oneshot = 0;
3702 if (zoom_factor > 1) {
3704 m_wheelzoom_stop_oneshot = 0;
3707 }
else if (zoom_factor < 1) {
3709 m_wheelzoom_stop_oneshot = 0;
3716 if (m_rotation_speed) {
3717 double speed = m_rotation_speed;
3718 if (m_modkeys == wxMOD_ALT) speed /= 10;
3719 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3723void ChartCanvas::SetColorScheme(ColorScheme cs) {
3728 case GLOBAL_COLOR_SCHEME_DAY:
3729 m_pos_image_red = &m_os_image_red_day;
3730 m_pos_image_grey = &m_os_image_grey_day;
3731 m_pos_image_yellow = &m_os_image_yellow_day;
3732 m_pos_image_user = m_pos_image_user_day;
3733 m_pos_image_user_grey = m_pos_image_user_grey_day;
3734 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3735 m_cTideBitmap = m_bmTideDay;
3736 m_cCurrentBitmap = m_bmCurrentDay;
3739 case GLOBAL_COLOR_SCHEME_DUSK:
3740 m_pos_image_red = &m_os_image_red_dusk;
3741 m_pos_image_grey = &m_os_image_grey_dusk;
3742 m_pos_image_yellow = &m_os_image_yellow_dusk;
3743 m_pos_image_user = m_pos_image_user_dusk;
3744 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3745 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3746 m_cTideBitmap = m_bmTideDusk;
3747 m_cCurrentBitmap = m_bmCurrentDusk;
3749 case GLOBAL_COLOR_SCHEME_NIGHT:
3750 m_pos_image_red = &m_os_image_red_night;
3751 m_pos_image_grey = &m_os_image_grey_night;
3752 m_pos_image_yellow = &m_os_image_yellow_night;
3753 m_pos_image_user = m_pos_image_user_night;
3754 m_pos_image_user_grey = m_pos_image_user_grey_night;
3755 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3756 m_cTideBitmap = m_bmTideNight;
3757 m_cCurrentBitmap = m_bmCurrentNight;
3760 m_pos_image_red = &m_os_image_red_day;
3761 m_pos_image_grey = &m_os_image_grey_day;
3762 m_pos_image_yellow = &m_os_image_yellow_day;
3763 m_pos_image_user = m_pos_image_user_day;
3764 m_pos_image_user_grey = m_pos_image_user_grey_day;
3765 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3766 m_cTideBitmap = m_bmTideDay;
3767 m_cCurrentBitmap = m_bmCurrentDay;
3771 CreateDepthUnitEmbossMaps(cs);
3772 CreateOZEmbossMapData(cs);
3775 m_fog_color = wxColor(
3779 case GLOBAL_COLOR_SCHEME_DUSK:
3782 case GLOBAL_COLOR_SCHEME_NIGHT:
3788 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3789 m_fog_color.Blue() * dim);
3793 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3794 SetBackgroundColour( wxColour(0,0,0) );
3796 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3799 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3801 SetBackgroundColour( wxNullColour );
3808 m_Piano->SetColorScheme(cs);
3810 m_Compass->SetColorScheme(cs);
3812 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3814 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3816 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3817 if (m_notification_button) {
3818 m_notification_button->SetColorScheme(cs);
3822 if (g_bopengl && m_glcc) {
3823 m_glcc->SetColorScheme(cs);
3829 m_brepaint_piano =
true;
3836wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3837 wxImage img = Bitmap.ConvertToImage();
3838 int sx = img.GetWidth();
3839 int sy = img.GetHeight();
3841 wxImage new_img(img);
3843 for (
int i = 0; i < sx; i++) {
3844 for (
int j = 0; j < sy; j++) {
3845 if (!img.IsTransparent(i, j)) {
3846 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3847 (
unsigned char)(img.GetGreen(i, j) * factor),
3848 (
unsigned char)(img.GetBlue(i, j) * factor));
3853 wxBitmap ret = wxBitmap(new_img);
3858void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3861 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3863 if (!m_pBrightPopup) {
3866 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3870 m_pBrightPopup->SetSize(x, y);
3871 m_pBrightPopup->Move(120, 120);
3874 int bmpsx = m_pBrightPopup->GetSize().x;
3875 int bmpsy = m_pBrightPopup->GetSize().y;
3877 wxBitmap bmp(bmpsx, bmpsx);
3878 wxMemoryDC mdc(bmp);
3880 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3881 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3882 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3883 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3886 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3888 mdc.SetFont(*pfont);
3891 if (brightness == max)
3893 else if (brightness == min)
3896 val.Printf(
"%3d", brightness);
3898 mdc.DrawText(val, 0, 0);
3900 mdc.SelectObject(wxNullBitmap);
3902 m_pBrightPopup->SetBitmap(bmp);
3903 m_pBrightPopup->Show();
3904 m_pBrightPopup->Refresh();
3907void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3908 m_b_rot_hidef =
true;
3912void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3915 bool b_need_refresh =
false;
3917 wxSize win_size = GetSize() * m_displayScale;
3921 bool showAISRollover =
false;
3923 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3927 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3928 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3931 showAISRollover =
true;
3933 if (NULL == m_pAISRolloverWin) {
3935 m_pAISRolloverWin->IsActive(
false);
3936 b_need_refresh =
true;
3937 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3938 m_AISRollover_MMSI != FoundAIS_MMSI) {
3944 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3945 m_pAISRolloverWin->IsActive(
false);
3946 m_AISRollover_MMSI = 0;
3951 m_AISRollover_MMSI = FoundAIS_MMSI;
3953 if (!m_pAISRolloverWin->IsActive()) {
3954 wxString s = ptarget->GetRolloverString();
3955 m_pAISRolloverWin->SetString(s);
3957 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3958 AIS_ROLLOVER, win_size);
3959 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3960 m_pAISRolloverWin->IsActive(
true);
3961 b_need_refresh =
true;
3965 m_AISRollover_MMSI = 0;
3966 showAISRollover =
false;
3971 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3972 m_pAISRolloverWin->IsActive(
false);
3973 m_AISRollover_MMSI = 0;
3974 b_need_refresh =
true;
3979 bool showRouteRollover =
false;
3981 if (NULL == m_pRolloverRouteSeg) {
3985 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3986 SelectableItemList SelList =
pSelect->FindSelectionList(
3988 auto node = SelList.begin();
3989 while (node != SelList.end()) {
3994 if (pr && pr->IsVisible()) {
3995 m_pRolloverRouteSeg = pFindSel;
3996 showRouteRollover =
true;
3998 if (NULL == m_pRouteRolloverWin) {
4000 m_pRouteRolloverWin->IsActive(
false);
4003 if (!m_pRouteRolloverWin->IsActive()) {
4011 DistanceBearingMercator(
4012 segShow_point_b->m_lat, segShow_point_b->m_lon,
4013 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4015 if (!pr->m_bIsInLayer)
4016 s.Append(_(
"Route") +
": ");
4018 s.Append(_(
"Layer Route: "));
4020 if (pr->m_RouteNameString.IsEmpty())
4021 s.Append(_(
"(unnamed)"));
4023 s.Append(pr->m_RouteNameString);
4028 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4029 << segShow_point_b->GetName() <<
"\n";
4032 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4033 (
int)floor(brg + 0.5), 0x00B0);
4036 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4038 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4040 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4042 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4043 (
int)floor(varBrg + 0.5), 0x00B0);
4051 double shiptoEndLeg = 0.;
4052 bool validActive =
false;
4053 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4056 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4057 auto node = pr->pRoutePointList->begin();
4059 float dist_to_endleg = 0;
4062 for (++node; node != pr->pRoutePointList->end(); ++node) {
4069 if (prp->IsSame(segShow_point_a))
break;
4077 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4080 ->GetCurrentRngToActivePoint();
4089 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4094 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4095 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4097 << wxString(ttg_sec > SECONDS_PER_DAY
4098 ? ttg_span.Format(_(
"%Dd %H:%M"))
4099 : ttg_span.Format(_(
"%H:%M")));
4100 wxDateTime dtnow, eta;
4101 eta = dtnow.SetToCurrent().Add(ttg_span);
4102 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4103 << eta.Format(
" %d %H:%M");
4107 m_pRouteRolloverWin->SetString(s);
4109 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4110 LEG_ROLLOVER, win_size);
4111 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4112 m_pRouteRolloverWin->IsActive(
true);
4113 b_need_refresh =
true;
4114 showRouteRollover =
true;
4123 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4125 m_pRolloverRouteSeg))
4126 showRouteRollover =
false;
4127 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4128 showRouteRollover =
false;
4130 showRouteRollover =
true;
4134 if (m_routeState) showRouteRollover =
false;
4137 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4138 showRouteRollover =
false;
4140 if (m_pRouteRolloverWin &&
4141 !showRouteRollover) {
4142 m_pRouteRolloverWin->IsActive(
false);
4143 m_pRolloverRouteSeg = NULL;
4144 m_pRouteRolloverWin->Destroy();
4145 m_pRouteRolloverWin = NULL;
4146 b_need_refresh =
true;
4147 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4148 m_pRouteRolloverWin->IsActive(
true);
4149 b_need_refresh =
true;
4154 bool showTrackRollover =
false;
4156 if (NULL == m_pRolloverTrackSeg) {
4160 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4161 SelectableItemList SelList =
pSelect->FindSelectionList(
4164 auto node = SelList.begin();
4165 while (node != SelList.end()) {
4170 if (pt && pt->IsVisible()) {
4171 m_pRolloverTrackSeg = pFindSel;
4172 showTrackRollover =
true;
4174 if (NULL == m_pTrackRolloverWin) {
4176 m_pTrackRolloverWin->IsActive(
false);
4179 if (!m_pTrackRolloverWin->IsActive()) {
4187 DistanceBearingMercator(
4188 segShow_point_b->m_lat, segShow_point_b->m_lon,
4189 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4191 if (!pt->m_bIsInLayer)
4192 s.Append(_(
"Track") +
": ");
4194 s.Append(_(
"Layer Track: "));
4196 if (pt->GetName().IsEmpty())
4197 s.Append(_(
"(unnamed)"));
4199 s.Append(pt->GetName());
4200 double tlenght = pt->Length();
4202 if (pt->GetLastPoint()->GetTimeString() &&
4203 pt->GetPoint(0)->GetTimeString()) {
4204 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4205 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4206 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4207 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4208 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4209 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4210 << getUsrSpeedUnit();
4211 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4212 : ttime.Format(
" %H:%M"));
4216 if (g_bShowTrackPointTime &&
4217 strlen(segShow_point_b->GetTimeString())) {
4218 wxString stamp = segShow_point_b->GetTimeString();
4219 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4220 if (timestamp.IsValid()) {
4224 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4226 s <<
"\n" << _(
"Segment Created: ") << stamp;
4231 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4236 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4238 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4240 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4242 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4248 if (segShow_point_a->GetTimeString() &&
4249 segShow_point_b->GetTimeString()) {
4250 wxDateTime apoint = segShow_point_a->GetCreateTime();
4251 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4252 if (apoint.IsValid() && bpoint.IsValid()) {
4253 double segmentSpeed = toUsrSpeed(
4254 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4255 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4256 << getUsrSpeedUnit();
4260 m_pTrackRolloverWin->SetString(s);
4262 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4263 LEG_ROLLOVER, win_size);
4264 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4265 m_pTrackRolloverWin->IsActive(
true);
4266 b_need_refresh =
true;
4267 showTrackRollover =
true;
4276 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4278 m_pRolloverTrackSeg))
4279 showTrackRollover =
false;
4280 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4281 showTrackRollover =
false;
4283 showTrackRollover =
true;
4287 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4288 showTrackRollover =
false;
4291 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4292 showTrackRollover =
false;
4298 if (m_pTrackRolloverWin &&
4299 !showTrackRollover) {
4300 m_pTrackRolloverWin->IsActive(
false);
4301 m_pRolloverTrackSeg = NULL;
4302 m_pTrackRolloverWin->Destroy();
4303 m_pTrackRolloverWin = NULL;
4304 b_need_refresh =
true;
4305 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4306 m_pTrackRolloverWin->IsActive(
true);
4307 b_need_refresh =
true;
4310 if (b_need_refresh) Refresh();
4313void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4314 if ((GetShowENCLights() || m_bsectors_shown) &&
4315 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4316 extendedSectorLegs)) {
4317 if (!m_bsectors_shown) {
4319 m_bsectors_shown =
true;
4322 if (m_bsectors_shown) {
4324 m_bsectors_shown =
false;
4332#if defined(__WXGTK__) || defined(__WXQT__)
4337 double cursor_lat, cursor_lon;
4340 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4341 while (cursor_lon < -180.) cursor_lon += 360.;
4343 while (cursor_lon > 180.) cursor_lon -= 360.;
4345 SetCursorStatus(cursor_lat, cursor_lon);
4351void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4352 if (!top_frame::Get()->GetFrameStatusBar())
return;
4356 s1 += toSDMM(1, cursor_lat);
4358 s1 += toSDMM(2, cursor_lon);
4360 if (STAT_FIELD_CURSOR_LL >= 0)
4361 top_frame::Get()->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4363 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4368 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4369 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4370 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4372 wxString s = st + sm;
4385 if (g_bShowLiveETA) {
4388 float boatSpeedDefault = g_defaultBoatSpeed;
4393 if (!std::isnan(
gSog)) {
4395 if (boatSpeed < 0.5) {
4398 realTimeETA = dist / boatSpeed * 60;
4407 s << minutesToHoursDays(realTimeETA);
4412 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4413 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4415 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4420 top_frame::Get()->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4428wxString minutesToHoursDays(
float timeInMinutes) {
4431 if (timeInMinutes == 0) {
4436 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4437 s << wxString::Format(
"%d", (
int)timeInMinutes);
4442 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4445 hours = (int)timeInMinutes / 60;
4446 min = (int)timeInMinutes % 60;
4449 s << wxString::Format(
"%d", hours);
4452 s << wxString::Format(
"%d", hours);
4454 s << wxString::Format(
"%d", min);
4461 else if (timeInMinutes > 24 * 60) {
4464 days = (int)(timeInMinutes / 60) / 24;
4465 hours = (int)(timeInMinutes / 60) % 24;
4468 s << wxString::Format(
"%d", days);
4471 s << wxString::Format(
"%d", days);
4473 s << wxString::Format(
"%d", hours);
4485void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4493 wxPoint2DDouble *r) {
4498 double rlon, wxPoint2DDouble *r) {
4509 if (!g_bopengl && m_singleChart &&
4510 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4511 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4512 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4513 (m_singleChart->GetChartProjectionType() !=
4514 PROJECTION_TRANSVERSE_MERCATOR) &&
4515 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4516 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4517 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4531 Cur_BSB_Ch->SetVPRasterParms(vp);
4532 double rpixxd, rpixyd;
4533 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4559 if (std::isnan(p.m_x)) {
4560 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4564 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4565 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4567 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4586 if (!g_bopengl && m_singleChart &&
4587 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4588 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4589 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4590 (m_singleChart->GetChartProjectionType() !=
4591 PROJECTION_TRANSVERSE_MERCATOR) &&
4592 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4593 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4594 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4605 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4608 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4613 else if (slon > 180.)
4624 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4630 DoZoomCanvas(factor,
false);
4631 extendedSectorLegs.clear();
4636 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4639 if (StartTimedMovement(stoptimer)) {
4641 m_zoom_factor = factor;
4646 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4648 DoZoomCanvas(factor, can_zoom_to_cursor);
4651 extendedSectorLegs.clear();
4654void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4657 if (!m_pCurrentStack)
return;
4663 if (m_bzooming)
return;
4672 double proposed_scale_onscreen =
4675 bool b_do_zoom =
false;
4684 if (!VPoint.b_quilt) {
4687 if (!m_disable_adjust_on_zoom) {
4688 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4689 if (new_db_index >= 0)
4690 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4694 int current_ref_stack_index = -1;
4695 if (m_pCurrentStack->nEntry) {
4697 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4698 m_pQuilt->SetReferenceChart(trial_index);
4699 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4700 if (new_db_index >= 0)
4701 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4705 if (m_pCurrentStack)
4706 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4717 double min_allowed_scale =
4720 if (proposed_scale_onscreen < min_allowed_scale) {
4725 proposed_scale_onscreen = min_allowed_scale;
4729 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4732 }
else if (factor < 1) {
4737 bool b_smallest =
false;
4739 if (!VPoint.b_quilt) {
4744 LLBBox viewbox = VPoint.GetBBox();
4746 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4747 double max_allowed_scale;
4761 if (proposed_scale_onscreen > max_allowed_scale) {
4763 proposed_scale_onscreen = max_allowed_scale;
4768 if (!m_disable_adjust_on_zoom) {
4770 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4771 if (new_db_index >= 0)
4772 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4774 if (m_pCurrentStack)
4775 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4778 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4780 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4781 proposed_scale_onscreen =
4782 wxMin(proposed_scale_onscreen,
4788 m_absolute_min_scale_ppm)
4789 proposed_scale_onscreen =
4798 bool b_allow_ztc =
true;
4799 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4800 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4802 double brg, distance;
4803 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4806 meters_to_shift = distance * 1852;
4814 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4817 if (m_bFollow) DoCanvasUpdate();
4824void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4826 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4830void ChartCanvas::RotateCanvas(
double dir) {
4834 if (StartTimedMovement()) {
4836 m_rotation_speed = dir * 60;
4839 double speed = dir * 10;
4840 if (m_modkeys == wxMOD_ALT) speed /= 20;
4841 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4845void ChartCanvas::DoRotateCanvas(
double rotation) {
4846 while (rotation < 0) rotation += 2 * PI;
4847 while (rotation > 2 * PI) rotation -= 2 * PI;
4849 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4851 SetVPRotation(rotation);
4852 top_frame::Get()->UpdateRotationState(VPoint.
rotation);
4855void ChartCanvas::DoTiltCanvas(
double tilt) {
4856 while (tilt < 0) tilt = 0;
4857 while (tilt > .95) tilt = .95;
4859 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4865void ChartCanvas::TogglebFollow() {
4872void ChartCanvas::ClearbFollow() {
4875 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4877 UpdateFollowButtonState();
4881 top_frame::Get()->SetChartUpdatePeriod();
4884void ChartCanvas::SetbFollow() {
4887 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4888 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4896 p.m_x += m_OSoffsetx;
4897 p.m_y -= m_OSoffsety;
4906 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4907 UpdateFollowButtonState();
4909 if (!g_bSmoothRecenter) {
4913 top_frame::Get()->SetChartUpdatePeriod();
4916void ChartCanvas::UpdateFollowButtonState() {
4919 m_muiBar->SetFollowButtonState(0);
4922 m_muiBar->SetFollowButtonState(2);
4924 m_muiBar->SetFollowButtonState(1);
4930 androidSetFollowTool(0);
4933 androidSetFollowTool(2);
4935 androidSetFollowTool(1);
4942 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4943 if (pic->m_enabled && pic->m_init_state) {
4944 switch (pic->m_api_version) {
4947 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4958void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4959 if (g_bSmoothRecenter && !m_routeState) {
4960 if (StartSmoothJump(lat, lon, scale_ppm))
4964 double gcDist, gcBearingEnd;
4965 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4967 gcBearingEnd += 180;
4968 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4971 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4972 double new_lat = lat + (lat_offset / (1852 * 60));
4973 double new_lon = lon + (lon_offset / (1852 * 60));
4976 StartSmoothJump(lat, lon, scale_ppm);
4981 if (lon > 180.0) lon -= 360.0;
4987 if (!GetQuiltMode()) {
4989 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4990 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4994 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4995 AdjustQuiltRefChart();
5002 UpdateFollowButtonState();
5010bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5015 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5016 double distance_pixels = gcDist *
GetVPScale();
5017 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5023 m_startLat = m_vLat;
5024 m_startLon = m_vLon;
5029 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5030 m_endScale = scale_ppm;
5033 m_animationDuration = 600;
5034 m_animationStart = wxGetLocalTimeMillis();
5041 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5042 m_animationActive =
true;
5047void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5049 wxLongLong now = wxGetLocalTimeMillis();
5050 double elapsed = (now - m_animationStart).ToDouble();
5051 double t = elapsed / m_animationDuration.ToDouble();
5052 if (t > 1.0) t = 1.0;
5055 double e = easeOutCubic(t);
5058 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5059 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5060 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5065 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5071 m_animationActive =
false;
5072 UpdateFollowButtonState();
5081 extendedSectorLegs.clear();
5090 if (iters++ > 5)
return false;
5091 if (!std::isnan(dlat))
break;
5094 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5100 else if (dlat < -90)
5103 if (dlon > 360.) dlon -= 360.;
5104 if (dlon < -360.) dlon += 360.;
5119 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5123 if (VPoint.b_quilt) {
5124 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5125 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5129 double tweak_scale_ppm =
5135 if (new_ref_dbIndex == -1) {
5136#pragma GCC diagnostic push
5137#pragma GCC diagnostic ignored "-Warray-bounds"
5144 int trial_index = -1;
5145 if (m_pCurrentStack->nEntry) {
5147 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5150 if (trial_index < 0) {
5151 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5152 if (full_screen_array.size())
5153 trial_index = full_screen_array[full_screen_array.size() - 1];
5156 if (trial_index >= 0) {
5157 m_pQuilt->SetReferenceChart(trial_index);
5162#pragma GCC diagnostic pop
5169 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5171 double offset_angle = atan2(offy, offx);
5172 double offset_distance = sqrt((offy * offy) + (offx * offx));
5173 double chart_angle = GetVPRotation();
5174 double target_angle = chart_angle - offset_angle;
5175 double d_east_mod = offset_distance * cos(target_angle);
5176 double d_north_mod = offset_distance * sin(target_angle);
5181 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5182 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5184 UpdateFollowButtonState();
5190 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5195bool ChartCanvas::IsOwnshipOnScreen() {
5198 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5199 ((r.y > 0) && r.y < GetCanvasHeight()))
5205void ChartCanvas::ReloadVP(
bool b_adjust) {
5206 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5208 LoadVP(VPoint, b_adjust);
5211void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5213 if (g_bopengl && m_glcc) {
5214 m_glcc->Invalidate();
5215 if (m_glcc->GetSize() != GetSize()) {
5216 m_glcc->SetSize(GetSize());
5221 m_cache_vp.Invalidate();
5222 m_bm_cache_vp.Invalidate();
5225 VPoint.Invalidate();
5227 if (m_pQuilt) m_pQuilt->Invalidate();
5236 vp.m_projection_type, b_adjust);
5239void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5240 m_pQuilt->SetReferenceChart(dbIndex);
5241 VPoint.Invalidate();
5242 m_pQuilt->Invalidate();
5245double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5247 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5254int ChartCanvas::AdjustQuiltRefChart() {
5259 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5261 double min_ref_scale =
5262 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5263 double max_ref_scale =
5264 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5267 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5268 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5269 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5271 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5274 int target_stack_index = wxNOT_FOUND;
5276 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5277 if (index == m_pQuilt->GetRefChartdbIndex()) {
5278 target_stack_index = il;
5283 if (wxNOT_FOUND == target_stack_index)
5284 target_stack_index = 0;
5286 int ref_family = pc->GetChartFamily();
5287 int extended_array_count =
5288 m_pQuilt->GetExtendedStackIndexArray().size();
5289 while ((!brender_ok) &&
5290 ((
int)target_stack_index < (extended_array_count - 1))) {
5291 target_stack_index++;
5293 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5295 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5296 IsChartQuiltableRef(test_db_index)) {
5299 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5301 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5308 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5309 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5310 IsChartQuiltableRef(new_db_index)) {
5311 m_pQuilt->SetReferenceChart(new_db_index);
5314 ret = m_pQuilt->GetRefChartdbIndex();
5316 ret = m_pQuilt->GetRefChartdbIndex();
5319 ret = m_pQuilt->GetRefChartdbIndex();
5328void ChartCanvas::UpdateCanvasOnGroupChange() {
5329 delete m_pCurrentStack;
5341bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5342 double latNE,
double lonNE) {
5344 double latc = (latSW + latNE) / 2.0;
5345 double lonc = (lonSW + lonNE) / 2.0;
5348 double ne_easting, ne_northing;
5349 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5351 double sw_easting, sw_northing;
5352 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5354 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5361 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5364bool ChartCanvas::SetVPProjection(
int projection) {
5370 double prev_true_scale_ppm = m_true_scale_ppm;
5375 m_absolute_min_scale_ppm));
5383bool ChartCanvas::SetVPRotation(
double angle) {
5385 VPoint.
skew, angle);
5388 double skew,
double rotation,
int projection,
5389 bool b_adjust,
bool b_refresh) {
5395 if (VPoint.IsValid()) {
5396 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5397 (fabs(VPoint.
skew - skew) < 1e-9) &&
5398 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5399 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5400 (VPoint.m_projection_type == projection ||
5401 projection == PROJECTION_UNKNOWN))
5404 if (VPoint.m_projection_type != projection)
5405 VPoint.InvalidateTransformCache();
5415 if (projection != PROJECTION_UNKNOWN)
5416 VPoint.SetProjectionType(projection);
5417 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5418 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5421 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5422 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5423 if (VPoint.
clat > 89.5)
5425 else if (VPoint.
clat < -89.5)
5426 VPoint.
clat = -89.5;
5431 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5432 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5444 bool bwasValid = VPoint.IsValid();
5449 m_cache_vp.Invalidate();
5454 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5458 if (top_frame::Get()->GetCanvasIndexUnderMouse() == m_canvasIndex) {
5459 int mouseX = mouse_x;
5460 int mouseY = mouse_y;
5461 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5463 double lat_mouse, lon_mouse;
5471 if (!VPoint.b_quilt && m_singleChart) {
5476 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5480 if ((!m_cache_vp.IsValid()) ||
5485 wxPoint cp_last, cp_this;
5489 if (cp_last != cp_this) {
5495 if (m_pCurrentStack) {
5497 int current_db_index;
5499 m_pCurrentStack->GetCurrentEntrydbIndex();
5501 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5503 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5506 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5510 if (VPoint.b_quilt) {
5514 m_pQuilt->InvalidateAllQuiltPatchs();
5518 if (!m_pCurrentStack)
return false;
5520 int current_db_index;
5522 m_pCurrentStack->GetCurrentEntrydbIndex();
5524 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5525 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5528 int current_ref_stack_index = -1;
5529 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5530 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5531 current_ref_stack_index = i;
5534 if (g_bFullScreenQuilt) {
5535 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5539 bool b_needNewRef =
false;
5542 if ((-1 == current_ref_stack_index) &&
5543 (m_pQuilt->GetRefChartdbIndex() >= 0))
5544 b_needNewRef =
true;
5551 bool renderable =
true;
5553 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5554 if (referenceChart) {
5555 double chartMaxScale = referenceChart->GetNormalScaleMax(
5557 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5559 if (!renderable) b_needNewRef =
true;
5562 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5564 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5565 int target_scale = cte_ref.GetScale();
5566 int target_type = cte_ref.GetChartType();
5567 int candidate_stack_index;
5574 candidate_stack_index = 0;
5575 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5577 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5578 int candidate_scale = cte_candidate.GetScale();
5579 int candidate_type = cte_candidate.GetChartType();
5581 if ((candidate_scale >= target_scale) &&
5582 (candidate_type == target_type)) {
5583 bool renderable =
true;
5585 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5586 if (tentative_referenceChart) {
5587 double chartMaxScale =
5588 tentative_referenceChart->GetNormalScaleMax(
5590 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5593 if (renderable)
break;
5596 candidate_stack_index++;
5601 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5602 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5603 while (candidate_stack_index >= 0) {
5604 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5608 int candidate_scale = cte_candidate.GetScale();
5609 int candidate_type = cte_candidate.GetChartType();
5611 if ((candidate_scale <= target_scale) &&
5612 (candidate_type == target_type))
5615 candidate_stack_index--;
5620 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5621 (candidate_stack_index < 0))
5622 candidate_stack_index = 0;
5624 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5626 m_pQuilt->SetReferenceChart(new_ref_index);
5632 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5637 bool renderable =
true;
5639 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5640 if (referenceChart) {
5641 double chartMaxScale = referenceChart->GetNormalScaleMax(
5643 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5644 proj =
ChartData->GetDBChartProj(ref_db_index);
5646 proj = PROJECTION_MERCATOR;
5648 VPoint.b_MercatorProjectionOverride =
5649 (m_pQuilt->GetnCharts() == 0 || !renderable);
5651 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5653 VPoint.SetProjectionType(proj);
5658 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5663 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5683 m_pQuilt->Invalidate();
5700 if (b_refresh) Refresh(
false);
5707 }
else if (!g_bopengl) {
5708 OcpnProjType projection = PROJECTION_UNKNOWN;
5711 projection = m_singleChart->GetChartProjectionType();
5712 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5713 VPoint.SetProjectionType(projection);
5717 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5718 m_cache_vp.Invalidate();
5722 UpdateCanvasControlBar();
5726 if (VPoint.GetBBox().GetValid()) {
5729 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5738 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5741 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5748 wxPoint2DDouble r, r1;
5750 double delta_check =
5754 double check_point = wxMin(89., VPoint.
clat);
5756 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5759 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5760 VPoint.
clon, 0, &rhumbDist);
5765 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5766 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5768 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5772 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5778 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5780 if (m_true_scale_ppm)
5781 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5786 double round_factor = 1000.;
5790 round_factor = 100.;
5792 round_factor = 1000.;
5795 double retina_coef = 1;
5799 retina_coef = GetContentScaleFactor();
5810 double true_scale_display =
5811 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5816 if (m_displayed_scale_factor > 10.0)
5817 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5818 m_displayed_scale_factor);
5819 else if (m_displayed_scale_factor > 1.0)
5820 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5821 m_displayed_scale_factor);
5822 else if (m_displayed_scale_factor > 0.1) {
5823 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5824 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5825 }
else if (m_displayed_scale_factor > 0.01) {
5826 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5827 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5830 "%s %4.0f (---)", _(
"Scale"),
5831 true_scale_display);
5834 m_scaleValue = true_scale_display;
5836 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5838 if (m_bShowScaleInStatusBar && top_frame::Get()->GetStatusBar() &&
5839 (top_frame::Get()->GetStatusBar()->GetFieldsCount() >
5840 STAT_FIELD_SCALE)) {
5842 bool b_noshow =
false;
5846 wxClientDC dc(top_frame::Get()->GetStatusBar());
5848 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5849 dc.SetFont(*templateFont);
5850 dc.GetTextExtent(text, &w, &h);
5855 top_frame::Get()->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE,
5857 if (w && w > rect.width) {
5858 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5862 dc.GetTextExtent(text, &w, &h);
5864 if (w && w > rect.width) {
5870 if (!b_noshow) top_frame::Get()->SetStatusText(text, STAT_FIELD_SCALE);
5875 m_vLat = VPoint.
clat;
5876 m_vLon = VPoint.
clon;
5890static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5894static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5895 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5897wxColour ChartCanvas::PredColor() {
5900 if (SHIP_NORMAL == m_ownship_state)
5901 return GetGlobalColor(
"URED");
5903 else if (SHIP_LOWACCURACY == m_ownship_state)
5904 return GetGlobalColor(
"YELO1");
5906 return GetGlobalColor(
"NODTA");
5909wxColour ChartCanvas::ShipColor() {
5913 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5915 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5917 return GetGlobalColor(
"URED");
5920void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5921 wxPoint2DDouble lShipMidPoint) {
5922 dc.SetPen(wxPen(PredColor(), 2));
5924 if (SHIP_NORMAL == m_ownship_state)
5925 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5927 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5929 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5930 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5932 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5934 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5935 lShipMidPoint.m_y + 12);
5938void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5939 wxPoint GPSOffsetPixels,
5940 wxPoint2DDouble lGPSPoint) {
5945 float ref_dim = m_display_size_mm / 24;
5946 ref_dim = wxMin(ref_dim, 12);
5947 ref_dim = wxMax(ref_dim, 6);
5950 cPred.Set(g_cog_predictor_color);
5951 if (cPred == wxNullColour) cPred = PredColor();
5958 double nominal_line_width_pix = wxMax(
5960 floor(m_pix_per_mm / 2));
5964 if (nominal_line_width_pix > g_cog_predictor_width)
5965 g_cog_predictor_width = nominal_line_width_pix;
5968 wxPoint lPredPoint, lHeadPoint;
5970 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5971 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5973 double pred_lat, pred_lon;
5974 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5975 &pred_lat, &pred_lon);
5986 float ndelta_pix = 10.;
5987 double hdg_pred_lat, hdg_pred_lon;
5988 bool b_render_hdt =
false;
5989 if (!std::isnan(
gHdt)) {
5991 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5994 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5995 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5996 if (dist > ndelta_pix ) {
5997 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5998 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6003 wxPoint lShipMidPoint;
6004 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6005 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6006 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6007 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6009 if (lpp >= img_height / 2) {
6010 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6011 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6012 !std::isnan(
gSog)) {
6014 float dash_length = ref_dim;
6015 wxDash dash_long[2];
6017 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6018 g_cog_predictor_width);
6019 dash_long[1] = dash_long[0] / 2.0;
6023 if (dash_length > 250.) {
6024 dash_long[0] = 250. / g_cog_predictor_width;
6025 dash_long[1] = dash_long[0] / 2;
6028 wxPen ppPen2(cPred, g_cog_predictor_width,
6029 (wxPenStyle)g_cog_predictor_style);
6030 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6031 ppPen2.SetDashes(2, dash_long);
6034 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6035 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6037 if (g_cog_predictor_width > 1) {
6038 float line_width = g_cog_predictor_width / 3.;
6040 wxDash dash_long3[2];
6041 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6042 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6044 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6045 (wxPenStyle)g_cog_predictor_style);
6046 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6047 ppPen3.SetDashes(2, dash_long3);
6049 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6050 lGPSPoint.m_y + GPSOffsetPixels.y,
6051 lPredPoint.x + GPSOffsetPixels.x,
6052 lPredPoint.y + GPSOffsetPixels.y);
6055 if (g_cog_predictor_endmarker) {
6057 double png_pred_icon_scale_factor = .4;
6058 if (g_ShipScaleFactorExp > 1.0)
6059 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6060 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6064 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6065 (
float)(lPredPoint.x - lShipMidPoint.x));
6066 cog_rad += (float)PI;
6068 for (
int i = 0; i < 4; i++) {
6070 double pxa = (double)(s_png_pred_icon[j]);
6071 double pya = (double)(s_png_pred_icon[j + 1]);
6073 pya *= png_pred_icon_scale_factor;
6074 pxa *= png_pred_icon_scale_factor;
6076 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6077 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6079 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6080 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6084 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6087 dc.SetBrush(wxBrush(cPred));
6089 dc.StrokePolygon(4, icon);
6096 float hdt_dash_length = ref_dim * 0.4;
6098 cPred.Set(g_ownship_HDTpredictor_color);
6099 if (cPred == wxNullColour) cPred = PredColor();
6101 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6102 : g_cog_predictor_width * 0.8);
6103 wxDash dash_short[2];
6105 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6108 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6111 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6112 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6113 ppPen2.SetDashes(2, dash_short);
6117 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6118 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6120 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6122 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6124 if (g_ownship_HDTpredictor_endmarker) {
6125 double nominal_circle_size_pixels = wxMax(
6126 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6129 if (g_ShipScaleFactorExp > 1.0)
6130 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6132 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6133 lHeadPoint.y + GPSOffsetPixels.y,
6134 nominal_circle_size_pixels / 2);
6139 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6140 double factor = 1.00;
6141 if (g_pNavAidRadarRingsStepUnits == 1)
6143 else if (g_pNavAidRadarRingsStepUnits == 2) {
6144 if (std::isnan(
gSog))
6149 factor *= g_fNavAidRadarRingsStep;
6153 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6156 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6157 pow((
double)(lGPSPoint.m_y - r.y), 2));
6158 int pix_radius = (int)lpp;
6160 wxColor rangeringcolour =
6161 user_colors::GetDimColor(g_colourOwnshipRangeRingsColour);
6163 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6166 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6168 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6169 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6174void ChartCanvas::ResetGlGridFont() { GetglCanvas()->ResetGridFont(); }
6175bool ChartCanvas::CanAccelerateGlPanning() {
6176 return GetglCanvas()->CanAcceleratePanning();
6178void ChartCanvas::SetupGlCompression() { GetglCanvas()->SetupCompression(); }
6181void ChartCanvas::ResetGlGridFont() {}
6182bool ChartCanvas::CanAccelerateGlPanning() {
return false; }
6183void ChartCanvas::SetupGlCompression() {}
6186void ChartCanvas::ComputeShipScaleFactor(
6187 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6188 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6189 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6190 float screenResolution = m_pix_per_mm;
6193 double ship_bow_lat, ship_bow_lon;
6194 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6195 &ship_bow_lat, &ship_bow_lon);
6196 wxPoint lShipBowPoint;
6197 wxPoint2DDouble b_point =
6201 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6202 powf((
float)(b_point.m_y - a_point.m_y), 2));
6205 float shipLength_mm = shipLength_px / screenResolution;
6208 float ownship_min_mm = g_n_ownship_min_mm;
6209 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6212 float hdt_ant = icon_hdt + 180.;
6213 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6214 float dx = g_n_gps_antenna_offset_x / 1852.;
6215 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6223 if (shipLength_mm < ownship_min_mm) {
6224 dy /= shipLength_mm / ownship_min_mm;
6225 dx /= shipLength_mm / ownship_min_mm;
6228 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6230 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6231 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6237 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6238 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6240 float scale_factor = shipLength_px / ownShipLength;
6243 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6246 scale_factor = wxMax(scale_factor, scale_factor_min);
6248 scale_factor_y = scale_factor;
6249 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6250 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6253void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6254 if (!GetVP().IsValid())
return;
6256 wxPoint GPSOffsetPixels(0, 0);
6257 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6260 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6261 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6265 lShipMidPoint = lGPSPoint;
6269 float icon_hdt = pCog;
6270 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6273 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6277 double osd_head_lat, osd_head_lon;
6278 wxPoint osd_head_point;
6280 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6285 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6286 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6287 icon_rad += (float)PI;
6289 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6293 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6297 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6298 if (GetVP().chart_scale >
6301 ShipDrawLargeScale(dc, lShipMidPoint);
6307 if (m_pos_image_user)
6308 pos_image = m_pos_image_user->Copy();
6309 else if (SHIP_NORMAL == m_ownship_state)
6310 pos_image = m_pos_image_red->Copy();
6311 if (SHIP_LOWACCURACY == m_ownship_state)
6312 pos_image = m_pos_image_yellow->Copy();
6313 else if (SHIP_NORMAL != m_ownship_state)
6314 pos_image = m_pos_image_grey->Copy();
6317 if (m_pos_image_user) {
6318 pos_image = m_pos_image_user->Copy();
6320 if (SHIP_LOWACCURACY == m_ownship_state)
6321 pos_image = m_pos_image_user_yellow->Copy();
6322 else if (SHIP_NORMAL != m_ownship_state)
6323 pos_image = m_pos_image_user_grey->Copy();
6326 img_height = pos_image.GetHeight();
6328 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6329 g_OwnShipIconType > 0)
6331 int ownShipWidth = 22;
6332 int ownShipLength = 84;
6333 if (g_OwnShipIconType == 1) {
6334 ownShipWidth = pos_image.GetWidth();
6335 ownShipLength = pos_image.GetHeight();
6338 float scale_factor_x, scale_factor_y;
6339 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6340 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6341 scale_factor_x, scale_factor_y);
6343 if (g_OwnShipIconType == 1) {
6344 pos_image.Rescale(ownShipWidth * scale_factor_x,
6345 ownShipLength * scale_factor_y,
6346 wxIMAGE_QUALITY_HIGH);
6347 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6349 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6352 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6353 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6354 if (rot_image.GetAlpha(ip, jp) > 64)
6355 rot_image.SetAlpha(ip, jp, 255);
6357 wxBitmap os_bm(rot_image);
6359 int w = os_bm.GetWidth();
6360 int h = os_bm.GetHeight();
6363 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6364 lShipMidPoint.m_y - h / 2,
true);
6367 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6368 lShipMidPoint.m_y - h / 2);
6369 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6370 lShipMidPoint.m_y - h / 2 + h);
6373 else if (g_OwnShipIconType == 2) {
6374 wxPoint ownship_icon[10];
6376 for (
int i = 0; i < 10; i++) {
6378 float pxa = (float)(s_ownship_icon[j]);
6379 float pya = (float)(s_ownship_icon[j + 1]);
6380 pya *= scale_factor_y;
6381 pxa *= scale_factor_x;
6383 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6384 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6386 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6387 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6390 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6392 dc.SetBrush(wxBrush(ShipColor()));
6394 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6397 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6399 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6403 img_height = ownShipLength * scale_factor_y;
6407 if (m_pos_image_user) circle_rad = 1;
6409 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6410 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6411 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6414 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6416 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6419 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6420 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6421 if (rot_image.GetAlpha(ip, jp) > 64)
6422 rot_image.SetAlpha(ip, jp, 255);
6424 wxBitmap os_bm(rot_image);
6426 if (g_ShipScaleFactorExp > 1) {
6427 wxImage scaled_image = os_bm.ConvertToImage();
6428 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6430 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6431 scaled_image.GetHeight() * factor,
6432 wxIMAGE_QUALITY_HIGH));
6434 int w = os_bm.GetWidth();
6435 int h = os_bm.GetHeight();
6438 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6439 lShipMidPoint.m_y - h / 2,
true);
6443 if (m_pos_image_user) circle_rad = 1;
6445 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6446 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6447 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6450 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6451 lShipMidPoint.m_y - h / 2);
6452 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6453 lShipMidPoint.m_y - h / 2 + h);
6458 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6471void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6472 float &MinorSpacing) {
6477 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6478 {.000001f, 45.0f, 15.0f},
6479 {.0002f, 30.0f, 10.0f},
6480 {.0003f, 10.0f, 2.0f},
6481 {.0008f, 5.0f, 1.0f},
6482 {.001f, 2.0f, 30.0f / 60.0f},
6483 {.003f, 1.0f, 20.0f / 60.0f},
6484 {.006f, 0.5f, 10.0f / 60.0f},
6485 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6486 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6487 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6488 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6489 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6490 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6491 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6492 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6495 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6496 if (view_scale_ppm < lltab[tabi][0])
break;
6497 MajorSpacing = lltab[tabi][1];
6498 MinorSpacing = lltab[tabi][2];
6512wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6513 int deg = (int)fabs(latlon);
6514 float min = fabs((fabs(latlon) - deg) * 60.0);
6524 }
else if (latlon < 0.0) {
6536 if (spacing >= 1.0) {
6537 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6538 }
else if (spacing >= (1.0 / 60.0)) {
6539 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6541 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6558void ChartCanvas::GridDraw(
ocpnDC &dc) {
6559 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6561 double nlat, elon, slat, wlon;
6564 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6566 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6568 if (!m_pgridFont) SetupGridFont();
6569 dc.SetFont(*m_pgridFont);
6570 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6573 h = m_canvas_height;
6584 dlon = dlon + 360.0;
6587 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6590 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6593 while (lat < nlat) {
6596 CalcGridText(lat, gridlatMajor,
true);
6598 dc.
DrawLine(0, r.y, w, r.y,
false);
6599 dc.DrawText(st, 0, r.y);
6600 lat = lat + gridlatMajor;
6602 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6606 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6609 while (lat < nlat) {
6612 dc.
DrawLine(0, r.y, 10, r.y,
false);
6613 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6614 lat = lat + gridlatMinor;
6618 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6621 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6624 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6626 wxString st = CalcGridText(lon, gridlonMajor,
false);
6628 dc.
DrawLine(r.x, 0, r.x, h,
false);
6629 dc.DrawText(st, r.x, 0);
6630 lon = lon + gridlonMajor;
6635 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6639 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6641 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6644 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6645 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6646 lon = lon + gridlonMinor;
6653void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6655 double blat, blon, tlat, tlon;
6658 int x_origin = m_bDisplayGrid ? 60 : 20;
6659 int y_origin = m_canvas_height - 50;
6665 if (GetVP().chart_scale > 80000)
6669 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6670 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6675 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6676 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6680 double rotation = -VPoint.
rotation;
6682 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6684 int l1 = (y_origin - r.y) / count;
6686 for (
int i = 0; i < count; i++) {
6693 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6696 double blat, blon, tlat, tlon;
6703 int y_origin = m_canvas_height - chartbar_height - 5;
6707 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6714 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6719 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6720 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6724 float places = floor(logdist), rem = logdist - places;
6725 dist = pow(10, places);
6732 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6733 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6734 double rotation = -VPoint.
rotation;
6740 int l1 = r.x - x_origin;
6742 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6747 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6748 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6749 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6751 if (!m_pgridFont) SetupGridFont();
6752 dc.SetFont(*m_pgridFont);
6753 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6755 dc.GetTextExtent(s, &w, &h);
6761 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6765void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6770 double ra_max = 40.;
6772 wxPen pen_save = dc.GetPen();
6774 wxDateTime now = wxDateTime::Now();
6780 x0 = x1 = x + radius;
6785 while (angle < 360.) {
6786 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6789 if (angle > 360.) angle = 360.;
6791 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6799 x1 = (int)(x + cos(angle * PI / 180.) * r);
6800 y1 = (int)(y + sin(angle * PI / 180.) * r);
6810 dc.
DrawLine(x + radius, y, x1, y1);
6812 dc.SetPen(pen_save);
6815static bool bAnchorSoundPlaying =
false;
6817static void onAnchorSoundFinished(
void *ptr) {
6818 o_sound::g_anchorwatch_sound->UnLoad();
6819 bAnchorSoundPlaying =
false;
6822void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6823 using namespace o_sound;
6825 bool play_sound =
false;
6827 if (AnchorAlertOn1) {
6828 wxPoint TargetPoint;
6831 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6832 TargetPoint.y, 100);
6836 AnchorAlertOn1 =
false;
6839 if (AnchorAlertOn2) {
6840 wxPoint TargetPoint;
6843 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6844 TargetPoint.y, 100);
6848 AnchorAlertOn2 =
false;
6851 if (!bAnchorSoundPlaying) {
6852 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6853 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6854 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6855 if (g_anchorwatch_sound->IsOk()) {
6856 bAnchorSoundPlaying =
true;
6857 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6858 g_anchorwatch_sound->Play();
6864void ChartCanvas::UpdateShips() {
6867 wxClientDC dc(
this);
6868 if (!dc.IsOk())
return;
6870 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6871 if (!test_bitmap.IsOk())
return;
6873 wxMemoryDC temp_dc(test_bitmap);
6875 temp_dc.ResetBoundingBox();
6876 temp_dc.DestroyClippingRegion();
6877 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6888 ocpndc.CalcBoundingBox(px.x, px.y);
6893 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6894 temp_dc.MaxY() - temp_dc.MinY());
6896 wxRect own_ship_update_rect = ship_draw_rect;
6898 if (!own_ship_update_rect.IsEmpty()) {
6901 own_ship_update_rect.Union(ship_draw_last_rect);
6902 own_ship_update_rect.Inflate(2);
6905 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6907 ship_draw_last_rect = ship_draw_rect;
6909 temp_dc.SelectObject(wxNullBitmap);
6912void ChartCanvas::UpdateAlerts() {
6917 wxClientDC dc(
this);
6921 dc.GetSize(&sx, &sy);
6924 wxBitmap test_bitmap(sx, sy, -1);
6928 temp_dc.SelectObject(test_bitmap);
6930 temp_dc.ResetBoundingBox();
6931 temp_dc.DestroyClippingRegion();
6932 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6939 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6940 temp_dc.MaxX() - temp_dc.MinX(),
6941 temp_dc.MaxY() - temp_dc.MinY());
6943 if (!alert_rect.IsEmpty())
6944 alert_rect.Inflate(2);
6946 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6949 wxRect alert_update_rect = alert_draw_rect;
6950 alert_update_rect.Union(alert_rect);
6953 RefreshRect(alert_update_rect,
false);
6957 alert_draw_rect = alert_rect;
6959 temp_dc.SelectObject(wxNullBitmap);
6962void ChartCanvas::UpdateAIS() {
6968 wxClientDC dc(
this);
6972 dc.GetSize(&sx, &sy);
6980 if (
g_pAIS->GetTargetList().size() > 10) {
6981 ais_rect = wxRect(0, 0, sx, sy);
6984 wxBitmap test_bitmap(sx, sy, -1);
6988 temp_dc.SelectObject(test_bitmap);
6990 temp_dc.ResetBoundingBox();
6991 temp_dc.DestroyClippingRegion();
6992 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6996 AISDraw(ocpndc, GetVP(),
this);
6997 AISDrawAreaNotices(ocpndc, GetVP(),
this);
7001 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
7002 temp_dc.MaxY() - temp_dc.MinY());
7004 if (!ais_rect.IsEmpty())
7005 ais_rect.Inflate(2);
7007 temp_dc.SelectObject(wxNullBitmap);
7010 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7013 wxRect ais_update_rect = ais_draw_rect;
7014 ais_update_rect.Union(ais_rect);
7017 RefreshRect(ais_update_rect,
false);
7021 ais_draw_rect = ais_rect;
7024void ChartCanvas::ToggleCPAWarn() {
7025 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7031 g_bTCPA_Max =
false;
7035 if (STAT_FIELD_SCALE >= 4 && top_frame::Get()->GetStatusBar()) {
7036 top_frame::Get()->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7038 if (!g_AisFirstTimeUse) {
7039 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7040 _(
"CPA") +
" " + mess, 4, 4);
7045void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7047void ChartCanvas::OnSize(wxSizeEvent &event) {
7048 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7050 GetClientSize(&m_canvas_width, &m_canvas_height);
7054 m_displayScale = GetContentScaleFactor();
7058 m_canvas_width *= m_displayScale;
7059 m_canvas_height *= m_displayScale;
7072 m_absolute_min_scale_ppm =
7074 (1.2 * WGS84_semimajor_axis_meters * PI);
7077 top_frame::Get()->ProcessCanvasResize();
7087 SetMUIBarPosition();
7088 UpdateFollowButtonState();
7089 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7093 xr_margin = m_canvas_width * 95 / 100;
7094 xl_margin = m_canvas_width * 5 / 100;
7095 yt_margin = m_canvas_height * 5 / 100;
7096 yb_margin = m_canvas_height * 95 / 100;
7099 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7104 m_brepaint_piano =
true;
7107 m_dc_route.SelectObject(wxNullBitmap);
7110 m_dc_route.SelectObject(*proute_bm);
7124 m_glcc->OnSize(event);
7133void ChartCanvas::ProcessNewGUIScale() {
7141void ChartCanvas::CreateMUIBar() {
7142 if (g_useMUI && !m_muiBar) {
7143 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7144 m_muiBar->SetColorScheme(m_cs);
7145 m_muiBarHOSize = m_muiBar->m_size;
7153 SetMUIBarPosition();
7154 UpdateFollowButtonState();
7155 m_muiBar->UpdateDynamicValues();
7156 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7160void ChartCanvas::SetMUIBarPosition() {
7164 int pianoWidth = GetClientSize().x * 0.6f;
7169 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7170 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7172 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7173 m_muiBar->SetColorScheme(m_cs);
7177 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7178 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7180 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7181 m_muiBar->SetColorScheme(m_cs);
7185 m_muiBar->SetBestPosition();
7189void ChartCanvas::DestroyMuiBar() {
7196void ChartCanvas::ShowCompositeInfoWindow(
7197 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7199 if (NULL == m_pCIWin) {
7204 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7207 s = _(
"Composite of ");
7210 s1.Printf(
"%d ", n_charts);
7218 s1.Printf(_(
"Chart scale"));
7221 s2.Printf(
"1:%d\n",
scale);
7225 s1 = _(
"Zoom in for more information");
7229 int char_width = s1.Length();
7230 int char_height = 3;
7232 if (g_bChartBarEx) {
7235 for (
int i : index_vector) {
7237 wxString path = cte.GetFullSystemPath();
7241 char_width = wxMax(char_width, path.Length());
7242 if (j++ >= 9)
break;
7245 s +=
" .\n .\n .\n";
7254 m_pCIWin->SetString(s);
7256 m_pCIWin->FitToChars(char_width, char_height);
7259 p.x = x / GetContentScaleFactor();
7260 if ((p.x + m_pCIWin->GetWinSize().x) >
7261 (m_canvas_width / GetContentScaleFactor()))
7262 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7263 m_pCIWin->GetWinSize().x) /
7266 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7267 4 - m_pCIWin->GetWinSize().y;
7269 m_pCIWin->dbIndex = 0;
7270 m_pCIWin->chart_scale = 0;
7271 m_pCIWin->SetPosition(p);
7272 m_pCIWin->SetBitmap();
7273 m_pCIWin->Refresh();
7277 HideChartInfoWindow();
7281void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7283 if (NULL == m_pCIWin) {
7288 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7297 dbIndex, FULL_INIT);
7299 int char_width, char_height;
7300 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7301 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7303 m_pCIWin->SetString(s);
7304 m_pCIWin->FitToChars(char_width, char_height);
7307 p.x = x / GetContentScaleFactor();
7308 if ((p.x + m_pCIWin->GetWinSize().x) >
7309 (m_canvas_width / GetContentScaleFactor()))
7310 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7311 m_pCIWin->GetWinSize().x) /
7314 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7315 4 - m_pCIWin->GetWinSize().y;
7317 m_pCIWin->dbIndex = dbIndex;
7318 m_pCIWin->SetPosition(p);
7319 m_pCIWin->SetBitmap();
7320 m_pCIWin->Refresh();
7324 HideChartInfoWindow();
7328void ChartCanvas::HideChartInfoWindow() {
7331 m_pCIWin->Destroy();
7335 androidForceFullRepaint();
7340void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7341 wxMouseEvent ev(wxEVT_MOTION);
7344 ev.m_leftDown = mouse_leftisdown;
7346 wxEvtHandler *evthp = GetEventHandler();
7348 ::wxPostEvent(evthp, ev);
7351void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7352 if ((m_panx_target_final - m_panx_target_now) ||
7353 (m_pany_target_final - m_pany_target_now)) {
7354 DoTimedMovementTarget();
7359void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7361bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7363 if (m_disable_edge_pan)
return false;
7366 int pan_margin = m_canvas_width * margin / 100;
7367 int pan_timer_set = 200;
7368 double pan_delta = GetVP().
pix_width * delta / 100;
7372 if (x > m_canvas_width - pan_margin) {
7377 else if (x < pan_margin) {
7382 if (y < pan_margin) {
7387 else if (y > m_canvas_height - pan_margin) {
7396 wxMouseState state = ::wxGetMouseState();
7397#if wxCHECK_VERSION(3, 0, 0)
7398 if (!state.LeftIsDown())
7400 if (!state.LeftDown())
7405 if ((bft) && !pPanTimer->IsRunning()) {
7407 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7413 if ((!bft) && pPanTimer->IsRunning()) {
7423void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7424 bool setBeingEdited) {
7425 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7426 m_pRoutePointEditTarget = NULL;
7427 m_pFoundPoint = NULL;
7430 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7431 SelectableItemList SelList =
pSelect->FindSelectionList(
7441 bool brp_viz =
false;
7442 if (m_pEditRouteArray) {
7443 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7444 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7445 if (pr->IsVisible()) {
7451 brp_viz = frp->IsVisible();
7455 if (m_pEditRouteArray)
7457 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7458 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7461 m_bRouteEditing = setBeingEdited;
7464 frp->m_bRPIsBeingEdited = setBeingEdited;
7465 m_bMarkEditing = setBeingEdited;
7468 m_pRoutePointEditTarget = frp;
7469 m_pFoundPoint = pFind;
7474std::shared_ptr<HostApi121::PiPointContext>
7475ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7489 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7490 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7491 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7492 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7493 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7497 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7500 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7505 int FoundAIS_MMSI = 0;
7507 FoundAIS_MMSI = pFindAIS->GetUserData();
7510 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7511 seltype |= SELTYPE_AISTARGET;
7517 Route *SelectedRoute = NULL;
7523 Route *pSelectedActiveRoute = NULL;
7524 Route *pSelectedVizRoute = NULL;
7527 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7528 SelectableItemList SelList =
7529 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7537 bool brp_viz =
false;
7539 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7541 if (pr->IsVisible()) {
7546 if (!brp_viz && prp->IsShared())
7548 brp_viz = prp->IsVisible();
7551 brp_viz = prp->IsVisible();
7553 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7559 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7562 pSelectedActiveRoute = pr;
7563 pFoundActiveRoutePoint = prp;
7568 if (NULL == pSelectedVizRoute) {
7569 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7571 if (pr->IsVisible()) {
7572 pSelectedVizRoute = pr;
7573 pFoundVizRoutePoint = prp;
7579 delete proute_array;
7584 if (pFoundActiveRoutePoint) {
7585 FoundRoutePoint = pFoundActiveRoutePoint;
7586 SelectedRoute = pSelectedActiveRoute;
7587 }
else if (pFoundVizRoutePoint) {
7588 FoundRoutePoint = pFoundVizRoutePoint;
7589 SelectedRoute = pSelectedVizRoute;
7592 FoundRoutePoint = pFirstVizPoint;
7594 if (SelectedRoute) {
7595 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7596 }
else if (FoundRoutePoint) {
7597 seltype |= SELTYPE_MARKPOINT;
7602 if (m_pFoundRoutePoint) {
7606 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7607 RefreshRect(wp_rect,
true);
7616 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7617 SelectableItemList SelList =
7618 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7620 if (NULL == SelectedRoute)
7625 if (pr->IsVisible()) {
7632 if (SelectedRoute) {
7633 if (NULL == FoundRoutePoint)
7634 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7637 seltype |= SELTYPE_ROUTESEGMENT;
7641 if (pFindTrackSeg) {
7642 m_pSelectedTrack = NULL;
7643 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7644 SelectableItemList SelList =
7645 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7650 if (pt->IsVisible()) {
7651 m_pSelectedTrack = pt;
7655 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7658 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7661 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7662 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7663 rstruct->object_ident =
"";
7665 if (seltype == SELTYPE_AISTARGET) {
7666 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7668 val.Printf(
"%d", FoundAIS_MMSI);
7669 rstruct->object_ident = val.ToStdString();
7670 }
else if (seltype & SELTYPE_MARKPOINT) {
7671 if (FoundRoutePoint) {
7672 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7673 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7675 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7676 if (SelectedRoute) {
7677 rstruct->object_type =
7678 HostApi121::PiContextObjectType::kObjectRoutesegment;
7679 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7681 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7682 if (m_pSelectedTrack) {
7683 rstruct->object_type =
7684 HostApi121::PiContextObjectType::kObjectTracksegment;
7685 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7692void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7693 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7694 singleClickEventIsValid =
false;
7695 m_DoubleClickTimer->Stop();
7700bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7701 if (!m_bChartDragging && !m_bDrawingRoute) {
7706 if (m_Compass && m_Compass->IsShown()) {
7708 bool isInCompass = logicalRect.Contains(event.GetPosition());
7709 if (isInCompass || m_mouseWasInCompass) {
7710 if (m_Compass->MouseEvent(event)) {
7711 cursor_region = CENTER;
7712 if (!g_btouch) SetCanvasCursor(event);
7713 m_mouseWasInCompass = isInCompass;
7717 m_mouseWasInCompass = isInCompass;
7720 if (m_notification_button && m_notification_button->IsShown()) {
7722 bool isinButton = logicalRect.Contains(event.GetPosition());
7724 SetCursor(*pCursorArrow);
7725 if (event.LeftDown()) HandleNotificationMouseClick();
7730 if (MouseEventToolbar(event))
return true;
7732 if (MouseEventChartBar(event))
return true;
7734 if (MouseEventMUIBar(event))
return true;
7736 if (MouseEventIENCBar(event))
return true;
7741void ChartCanvas::HandleNotificationMouseClick() {
7742 if (!m_NotificationsList) {
7746 m_NotificationsList->RecalculateSize();
7747 m_NotificationsList->Hide();
7750 if (m_NotificationsList->IsShown()) {
7751 m_NotificationsList->Hide();
7753 m_NotificationsList->RecalculateSize();
7754 m_NotificationsList->ReloadNotificationList();
7755 m_NotificationsList->Show();
7758bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7759 if (!g_bShowChartBar)
return false;
7761 if (!m_Piano->MouseEvent(event))
return false;
7763 cursor_region = CENTER;
7764 if (!g_btouch) SetCanvasCursor(event);
7768bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7769 if (!IsPrimaryCanvas())
return false;
7778 cursor_region = CENTER;
7779 if (!g_btouch) SetCanvasCursor(event);
7783bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7784 if (!IsPrimaryCanvas())
return false;
7797bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7799 if (!m_muiBar->MouseEvent(event))
return false;
7802 cursor_region = CENTER;
7803 if (!g_btouch) SetCanvasCursor(event);
7815 event.GetPosition(&x, &y);
7817 x *= m_displayScale;
7818 y *= m_displayScale;
7820 m_MouseDragging =
event.Dragging();
7826 if (event.Dragging()) {
7827 if ((x == mouse_x) && (y == mouse_y))
return true;
7833 mouse_leftisdown =
event.LeftDown();
7837 cursor_region = CENTER;
7841 if (m_Compass && m_Compass->IsShown() &&
7842 m_Compass->
GetRect().Contains(event.GetPosition())) {
7843 cursor_region = CENTER;
7844 }
else if (x > xr_margin) {
7845 cursor_region = MID_RIGHT;
7846 }
else if (x < xl_margin) {
7847 cursor_region = MID_LEFT;
7848 }
else if (y > yb_margin - chartbar_height &&
7849 y < m_canvas_height - chartbar_height) {
7850 cursor_region = MID_TOP;
7851 }
else if (y < yt_margin) {
7852 cursor_region = MID_BOT;
7854 cursor_region = CENTER;
7857 if (!g_btouch) SetCanvasCursor(event);
7861 leftIsDown =
event.LeftDown();
7864 if (event.LeftDown()) {
7865 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7868 g_bTempShowMenuBar =
false;
7869 top_frame::Get()->ApplyGlobalSettings(
false);
7877 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7878 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7882 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7883 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7886 event.SetEventObject(
this);
7887 if (SendMouseEventToPlugins(event))
7894 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7895 StartChartDragInertia();
7898 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7899 !singleClickEventIsValid) {
7901 if (m_DoubleClickTimer->IsRunning()) {
7902 m_DoubleClickTimer->Stop();
7907 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7908 singleClickEvent = event;
7909 singleClickEventIsValid =
true;
7918 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7919 if (g_click_stop > 0) {
7927 if (GetUpMode() == COURSE_UP_MODE) {
7928 m_b_rot_hidef =
false;
7929 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7931 pRotDefTimer->Stop();
7934 bool bRoll = !g_btouch;
7939 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7940 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7941 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7942 m_RolloverPopupTimer.Start(
7946 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7950 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7959#if !defined(__WXGTK__) && !defined(__WXQT__)
7967 if ((x >= 0) && (y >= 0))
7972 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7973 wxPoint p = ClientToScreen(wxPoint(x, y));
7979 if (m_routeState >= 2) {
7982 m_bDrawingRoute =
true;
7984 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7989 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7992 m_bDrawingRoute =
true;
7994 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8007#if defined(__WXMAC__) || defined(__ANDROID__)
8011 wxClientDC cdc(GetParent());
8023 if (m_pSelectedRoute) {
8025 m_pSelectedRoute->DeSelectRoute();
8027 if (g_bopengl && m_glcc) {
8032 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8035 if (m_pFoundRoutePoint) {
8043 if (g_btouch && m_pRoutePointEditTarget) {
8046 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8050 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8051 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8052 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8053 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8054 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8058 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8061 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8067 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8070 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8071 seltype |= SELTYPE_AISTARGET;
8076 m_pFoundRoutePoint = NULL;
8081 Route *pSelectedActiveRoute = NULL;
8082 Route *pSelectedVizRoute = NULL;
8085 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8086 SelectableItemList SelList =
8087 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8095 bool brp_viz =
false;
8097 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8099 if (pr->IsVisible()) {
8104 if (!brp_viz && prp->IsShared())
8106 brp_viz = prp->IsVisible();
8109 brp_viz = prp->IsVisible();
8111 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8116 m_pSelectedRoute = NULL;
8118 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8121 pSelectedActiveRoute = pr;
8122 pFoundActiveRoutePoint = prp;
8127 if (NULL == pSelectedVizRoute) {
8128 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8130 if (pr->IsVisible()) {
8131 pSelectedVizRoute = pr;
8132 pFoundVizRoutePoint = prp;
8138 delete proute_array;
8143 if (pFoundActiveRoutePoint) {
8144 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8145 m_pSelectedRoute = pSelectedActiveRoute;
8146 }
else if (pFoundVizRoutePoint) {
8147 m_pFoundRoutePoint = pFoundVizRoutePoint;
8148 m_pSelectedRoute = pSelectedVizRoute;
8151 m_pFoundRoutePoint = pFirstVizPoint;
8153 if (m_pSelectedRoute) {
8154 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8155 }
else if (m_pFoundRoutePoint) {
8156 seltype |= SELTYPE_MARKPOINT;
8160 if (m_pFoundRoutePoint) {
8164 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8165 RefreshRect(wp_rect,
true);
8173 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8174 SelectableItemList SelList =
8175 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8177 if (NULL == m_pSelectedRoute)
8182 if (pr->IsVisible()) {
8183 m_pSelectedRoute = pr;
8189 if (m_pSelectedRoute) {
8190 if (NULL == m_pFoundRoutePoint)
8191 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8196 if (g_bopengl && m_glcc) {
8201 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8203 seltype |= SELTYPE_ROUTESEGMENT;
8207 if (pFindTrackSeg) {
8208 m_pSelectedTrack = NULL;
8209 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8210 SelectableItemList SelList =
8211 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8216 if (pt->IsVisible()) {
8217 m_pSelectedTrack = pt;
8221 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8227 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8228 seltype |= SELTYPE_CURRENTPOINT;
8231 else if (pFindTide) {
8232 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8233 seltype |= SELTYPE_TIDEPOINT;
8238 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8243IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8253 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8254 SelectableItemList SelList =
8255 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8258 pFind = *SelList.begin();
8259 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8261 auto node = SelList.begin();
8262 if (SelList.size() > 1) {
8263 for (++node; node != SelList.end(); ++node) {
8266 if (pIDX_candidate->
IDX_type ==
'c') {
8267 pIDX_best_candidate = pIDX_candidate;
8272 pFind = *SelList.begin();
8273 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8276 return pIDX_best_candidate;
8278void ChartCanvas::CallPopupMenu(
int x,
int y) {
8282 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8290 if (SELTYPE_CURRENTPOINT == seltype) {
8296 if (SELTYPE_TIDEPOINT == seltype) {
8302 InvokeCanvasMenu(x, y, seltype);
8305 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8309 m_pSelectedRoute = NULL;
8311 if (m_pFoundRoutePoint) {
8312 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8315 m_pFoundRoutePoint = NULL;
8321bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8329 event.GetPosition(&x, &y);
8335 SelectRadius = g_Platform->GetSelectRadiusPix() /
8336 (m_true_scale_ppm * 1852 * 60);
8343 if (event.LeftDClick() && (cursor_region == CENTER)) {
8344 m_DoubleClickTimer->Start();
8345 singleClickEventIsValid =
false;
8351 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8354 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8357 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8358 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8359 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8365 SelectableItemList rpSelList =
8366 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8367 bool b_onRPtarget =
false;
8370 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8371 b_onRPtarget =
true;
8379 std::unique_ptr<HostApi> host_api =
GetHostApi();
8380 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8382 if (m_pRoutePointEditTarget) {
8384 if ((api_121->GetContextMenuMask() &
8385 api_121->kContextMenuDisableWaypoint))
8387 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8393 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8396 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8397 m_pRoutePointEditTarget = NULL;
8398 RefreshRect(wp_rect,
true);
8402 auto node = rpSelList.begin();
8403 if (node != rpSelList.end()) {
8407 wxArrayPtrVoid *proute_array =
8412 bool brp_viz =
false;
8414 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8416 if (pr->IsVisible()) {
8421 delete proute_array;
8425 brp_viz = frp->IsVisible();
8427 brp_viz = frp->IsVisible();
8430 if ((api_121->GetContextMenuMask() &
8431 api_121->kContextMenuDisableWaypoint))
8434 ShowMarkPropertiesDialog(frp);
8443 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8445 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8448 if (pr->IsVisible()) {
8449 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8454 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8456 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8459 if (pt->IsVisible()) {
8460 ShowTrackPropertiesDialog(pt);
8469 if (m_bShowCurrent) {
8471 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8473 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8475 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8476 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8478 if (pic->m_enabled && pic->m_init_state &&
8479 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8482 if (m_pIDXCandidate) {
8483 info.point_type = CURRENT_STATION;
8487 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8488 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8492 if (plugin) plugin->OnTideCurrentClick(info);
8507 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8509 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8511 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8512 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8514 if (pic->m_enabled && pic->m_init_state &&
8515 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8518 if (m_pIDXCandidate) {
8519 info.point_type = TIDE_STATION;
8523 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8524 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8528 if (plugin) plugin->OnTideCurrentClick(info);
8543 ShowObjectQueryWindow(x, y, zlat, zlon);
8548 if (event.LeftDown()) {
8564 bool appending =
false;
8565 bool inserting =
false;
8568 SetCursor(*pCursorPencil);
8572 m_bRouteEditing =
true;
8574 if (m_routeState == 1) {
8575 m_pMouseRoute =
new Route();
8576 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8586 double nearby_radius_meters =
8587 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8590 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8591 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8592 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8593 wxArrayPtrVoid *proute_array =
8598 bool brp_viz =
false;
8600 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8602 if (pr->IsVisible()) {
8607 delete proute_array;
8609 pNearbyPoint->IsShared())
8612 pNearbyPoint->IsVisible();
8614 brp_viz = pNearbyPoint->IsVisible();
8617 wxString msg = _(
"Use nearby waypoint?");
8619 const bool noname(pNearbyPoint->GetName() ==
"");
8622 _(
"Use nearby nameless waypoint and name it M with"
8623 " a unique number?");
8626 m_FinishRouteOnKillFocus =
false;
8628 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8629 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8630 m_FinishRouteOnKillFocus =
true;
8631 if (dlg_return == wxID_YES) {
8633 if (m_pMouseRoute) {
8634 int last_wp_num = m_pMouseRoute->GetnPoints();
8636 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8637 wxString wp_name = wxString::Format(
8638 "M%002i-%s", last_wp_num + 1, guid_short);
8639 pNearbyPoint->SetName(wp_name);
8641 pNearbyPoint->SetName(
"WPXX");
8643 pMousePoint = pNearbyPoint;
8646 if (m_routeState > 1)
8647 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8648 Undo_HasParent, NULL);
8651 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8652 bool procede =
false;
8656 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8662 m_FinishRouteOnKillFocus =
false;
8668 _(
"Insert first part of this route in the new route?");
8669 if (tail->GetIndexOf(pMousePoint) ==
8672 dmsg = _(
"Insert this route in the new route?");
8674 if (tail->GetIndexOf(pMousePoint) != 1) {
8675 dlg_return = OCPNMessageBox(
8676 this, dmsg, _(
"OpenCPN Route Create"),
8677 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8678 m_FinishRouteOnKillFocus =
true;
8680 if (dlg_return == wxID_YES) {
8687 _(
"Append last part of this route to the new route?");
8688 if (tail->GetIndexOf(pMousePoint) == 1)
8690 "Append this route to the new route?");
8695 if (tail->GetLastPoint() != pMousePoint) {
8696 dlg_return = OCPNMessageBox(
8697 this, dmsg, _(
"OpenCPN Route Create"),
8698 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8699 m_FinishRouteOnKillFocus =
true;
8701 if (dlg_return == wxID_YES) {
8712 if (!FindRouteContainingWaypoint(pMousePoint))
8713 pMousePoint->SetShared(
true);
8718 if (NULL == pMousePoint) {
8719 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8721 pMousePoint->SetNameShown(
false);
8725 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8727 if (m_routeState > 1)
8728 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8729 Undo_IsOrphanded, NULL);
8732 if (m_pMouseRoute) {
8733 if (m_routeState == 1) {
8735 m_pMouseRoute->AddPoint(pMousePoint);
8739 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8740 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8741 &rhumbBearing, &rhumbDist);
8742 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8743 rlat, &gcDist, &gcBearing, NULL);
8744 double gcDistNM = gcDist / 1852.0;
8747 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8748 pow(rhumbDist - gcDistNM - 1, 0.5);
8751 msg << _(
"For this leg the Great Circle route is ")
8753 << _(
" shorter than rhumbline.\n\n")
8754 << _(
"Would you like include the Great Circle routing points "
8757 m_FinishRouteOnKillFocus =
false;
8758 m_disable_edge_pan =
true;
8761 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8762 wxYES_NO | wxNO_DEFAULT);
8764 m_disable_edge_pan =
false;
8765 m_FinishRouteOnKillFocus =
true;
8767 if (answer == wxID_YES) {
8769 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8770 wxRealPoint gcCoord;
8772 for (
int i = 1; i <= segmentCount; i++) {
8773 double fraction = (double)i * (1.0 / (
double)segmentCount);
8774 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8775 gcDist * fraction, gcBearing,
8776 &gcCoord.x, &gcCoord.y, NULL);
8778 if (i < segmentCount) {
8779 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8781 gcPoint->SetNameShown(
false);
8783 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8785 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8788 gcPoint = pMousePoint;
8791 m_pMouseRoute->AddPoint(gcPoint);
8792 pSelect->AddSelectableRouteSegment(
8793 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8794 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8795 prevGcPoint = gcPoint;
8798 undo->CancelUndoableAction(
true);
8801 m_pMouseRoute->AddPoint(pMousePoint);
8802 pSelect->AddSelectableRouteSegment(
8803 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8804 pMousePoint, m_pMouseRoute);
8805 undo->AfterUndoableAction(m_pMouseRoute);
8809 m_pMouseRoute->AddPoint(pMousePoint);
8810 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8811 rlon, m_prev_pMousePoint,
8812 pMousePoint, m_pMouseRoute);
8813 undo->AfterUndoableAction(m_pMouseRoute);
8819 m_prev_pMousePoint = pMousePoint;
8827 int connect = tail->GetIndexOf(pMousePoint);
8832 int length = tail->GetnPoints();
8837 start = connect + 1;
8842 m_pMouseRoute->RemovePoint(
8846 for (i = start; i <= stop; i++) {
8847 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8850 m_pMouseRoute->GetnPoints();
8852 top_frame::Get()->RefreshAllCanvas();
8856 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8858 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8859 m_pMouseRoute->FinalizeForRendering();
8861 top_frame::Get()->RefreshAllCanvas();
8865 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8867 SetCursor(*pCursorPencil);
8869 if (!m_pMeasureRoute) {
8870 m_pMeasureRoute =
new Route();
8874 if (m_nMeasureState == 1) {
8881 wxEmptyString, wxEmptyString);
8883 pMousePoint->SetShowWaypointRangeRings(
false);
8885 m_pMeasureRoute->AddPoint(pMousePoint);
8889 m_prev_pMousePoint = pMousePoint;
8893 top_frame::Get()->RefreshAllCanvas();
8898 FindRoutePointsAtCursor(SelectRadius,
true);
8902 m_last_touch_down_pos =
event.GetPosition();
8904 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8912 if (ret)
return true;
8915 if (event.Dragging()) {
8918 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8920 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8922 SelectableItemList SelList =
pSelect->FindSelectionList(
8926 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8931 if (m_pRoutePointEditTarget &&
8932 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8934 SelectableItemList SelList =
pSelect->FindSelectionList(
8938 if (m_pRoutePointEditTarget == frp) {
8939 m_bIsInRadius =
true;
8944 if (!m_dragoffsetSet) {
8946 .PresetDragOffset(
this, mouse_x, mouse_y);
8947 m_dragoffsetSet =
true;
8952 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8953 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8956 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8958 DraggingAllowed =
false;
8960 if (m_pRoutePointEditTarget &&
8961 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8962 DraggingAllowed =
false;
8964 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8966 if (DraggingAllowed) {
8967 if (!undo->InUndoableAction()) {
8968 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8969 Undo_NeedsCopy, m_pFoundPoint);
8975 if (!g_bopengl && m_pEditRouteArray) {
8976 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8977 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8984 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8985 pre_rect.Union(route_rect);
8993 if (CheckEdgePan(x, y,
true, 5, 2))
9001 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9003 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9004 m_pRoutePointEditTarget,
9005 SELTYPE_DRAGHANDLE);
9006 m_pFoundPoint->m_slat =
9007 m_pRoutePointEditTarget->m_lat;
9008 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9010 m_pRoutePointEditTarget->m_lat =
9012 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9013 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9014 m_pFoundPoint->m_slat =
9016 m_pFoundPoint->m_slon = new_cursor_lon;
9032 if (m_pEditRouteArray) {
9033 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9035 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9038 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9039 post_rect.Union(route_rect);
9045 pre_rect.Union(post_rect);
9046 RefreshRect(pre_rect,
false);
9048 top_frame::Get()->RefreshCanvasOther(
this);
9049 m_bRoutePoinDragging =
true;
9054 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9055 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9058 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9060 DraggingAllowed =
false;
9062 if (m_pRoutePointEditTarget &&
9063 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9064 DraggingAllowed =
false;
9066 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9068 if (DraggingAllowed) {
9069 if (!undo->InUndoableAction()) {
9070 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9071 Undo_NeedsCopy, m_pFoundPoint);
9085 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9091 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9092 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9093 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9094 (
int)(lppmax - (pre_rect.height / 2)));
9102 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9105 m_pRoutePointEditTarget,
9106 SELTYPE_DRAGHANDLE);
9107 m_pFoundPoint->m_slat =
9108 m_pRoutePointEditTarget->m_lat;
9109 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9111 m_pRoutePointEditTarget->m_lat =
9114 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9127 if (!g_btouch) InvalidateGL();
9133 .CalculateDCRect(m_dc_route,
this, &post_rect);
9134 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9135 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9136 (
int)(lppmax - (post_rect.height / 2)));
9139 pre_rect.Union(post_rect);
9140 RefreshRect(pre_rect,
false);
9142 top_frame::Get()->RefreshCanvasOther(
this);
9143 m_bRoutePoinDragging =
true;
9145 ret = g_btouch ? m_bRoutePoinDragging :
true;
9148 if (ret)
return true;
9151 if (event.LeftUp()) {
9152 bool b_startedit_route =
false;
9153 m_dragoffsetSet =
false;
9156 m_bChartDragging =
false;
9157 m_bIsInRadius =
false;
9161 if (m_ignore_next_leftup) {
9162 m_ignore_next_leftup =
false;
9167 m_bedge_pan =
false;
9172 bool appending =
false;
9173 bool inserting =
false;
9179 if (m_pRoutePointEditTarget) {
9185 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9186 RefreshRect(wp_rect,
true);
9188 m_pRoutePointEditTarget = NULL;
9190 m_bRouteEditing =
true;
9192 if (m_routeState == 1) {
9193 m_pMouseRoute =
new Route();
9194 m_pMouseRoute->SetHiLite(50);
9198 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9205 double nearby_radius_meters =
9206 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9209 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9210 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9211 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9214 m_FinishRouteOnKillFocus =
9216 dlg_return = OCPNMessageBox(
9217 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9218 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9219 m_FinishRouteOnKillFocus =
true;
9221 dlg_return = wxID_YES;
9223 if (dlg_return == wxID_YES) {
9224 pMousePoint = pNearbyPoint;
9227 if (m_routeState > 1)
9228 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9229 Undo_HasParent, NULL);
9230 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9232 bool procede =
false;
9236 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9242 m_FinishRouteOnKillFocus =
false;
9243 if (m_routeState == 1) {
9247 _(
"Insert first part of this route in the new route?");
9248 if (tail->GetIndexOf(pMousePoint) ==
9251 dmsg = _(
"Insert this route in the new route?");
9253 if (tail->GetIndexOf(pMousePoint) != 1) {
9255 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9256 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9257 m_FinishRouteOnKillFocus =
true;
9259 if (dlg_return == wxID_YES) {
9266 _(
"Append last part of this route to the new route?");
9267 if (tail->GetIndexOf(pMousePoint) == 1)
9269 "Append this route to the new route?");
9273 if (tail->GetLastPoint() != pMousePoint) {
9275 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9276 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9277 m_FinishRouteOnKillFocus =
true;
9279 if (dlg_return == wxID_YES) {
9290 if (!FindRouteContainingWaypoint(pMousePoint))
9291 pMousePoint->SetShared(
true);
9295 if (NULL == pMousePoint) {
9296 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9298 pMousePoint->SetNameShown(
false);
9300 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9302 if (m_routeState > 1)
9303 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9304 Undo_IsOrphanded, NULL);
9307 if (m_routeState == 1) {
9309 m_pMouseRoute->AddPoint(pMousePoint);
9310 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9314 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9315 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9316 &rhumbBearing, &rhumbDist);
9317 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9318 &gcDist, &gcBearing, NULL);
9319 double gcDistNM = gcDist / 1852.0;
9322 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9323 pow(rhumbDist - gcDistNM - 1, 0.5);
9326 msg << _(
"For this leg the Great Circle route is ")
9328 << _(
" shorter than rhumbline.\n\n")
9329 << _(
"Would you like include the Great Circle routing points "
9333 m_FinishRouteOnKillFocus =
false;
9334 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9335 wxYES_NO | wxNO_DEFAULT);
9336 m_FinishRouteOnKillFocus =
true;
9338 int answer = wxID_NO;
9341 if (answer == wxID_YES) {
9343 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9344 wxRealPoint gcCoord;
9346 for (
int i = 1; i <= segmentCount; i++) {
9347 double fraction = (double)i * (1.0 / (
double)segmentCount);
9348 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9349 gcDist * fraction, gcBearing,
9350 &gcCoord.x, &gcCoord.y, NULL);
9352 if (i < segmentCount) {
9353 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9355 gcPoint->SetNameShown(
false);
9356 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9359 gcPoint = pMousePoint;
9362 m_pMouseRoute->AddPoint(gcPoint);
9363 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9365 pSelect->AddSelectableRouteSegment(
9366 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9367 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9368 prevGcPoint = gcPoint;
9371 undo->CancelUndoableAction(
true);
9374 m_pMouseRoute->AddPoint(pMousePoint);
9375 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9376 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9377 rlon, m_prev_pMousePoint,
9378 pMousePoint, m_pMouseRoute);
9379 undo->AfterUndoableAction(m_pMouseRoute);
9383 m_pMouseRoute->AddPoint(pMousePoint);
9384 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9386 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9387 rlon, m_prev_pMousePoint,
9388 pMousePoint, m_pMouseRoute);
9389 undo->AfterUndoableAction(m_pMouseRoute);
9395 m_prev_pMousePoint = pMousePoint;
9402 int connect = tail->GetIndexOf(pMousePoint);
9407 int length = tail->GetnPoints();
9412 start = connect + 1;
9417 m_pMouseRoute->RemovePoint(
9421 for (i = start; i <= stop; i++) {
9422 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9425 m_pMouseRoute->GetnPoints();
9427 top_frame::Get()->RefreshAllCanvas();
9431 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9433 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9434 m_pMouseRoute->FinalizeForRendering();
9439 }
else if (m_bMeasure_Active && m_nMeasureState)
9442 m_bedge_pan =
false;
9446 if (m_ignore_next_leftup) {
9447 m_ignore_next_leftup =
false;
9451 if (m_nMeasureState == 1) {
9452 m_pMeasureRoute =
new Route();
9458 if (m_pMeasureRoute) {
9461 wxEmptyString, wxEmptyString);
9464 m_pMeasureRoute->AddPoint(pMousePoint);
9468 m_prev_pMousePoint = pMousePoint;
9470 m_pMeasureRoute->GetnPoints();
9474 CancelMeasureRoute();
9480 bool bSelectAllowed =
true;
9482 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9484 bSelectAllowed =
false;
9488 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9489 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9490 significant_drag) ||
9491 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9492 significant_drag)) {
9493 bSelectAllowed =
false;
9501 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9503 if (bSelectAllowed) {
9504 bool b_was_editing_mark = m_bMarkEditing;
9505 bool b_was_editing_route = m_bRouteEditing;
9506 FindRoutePointsAtCursor(SelectRadius,
9512 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9513 m_pRoutePointEditTarget = NULL;
9515 if (!b_was_editing_route) {
9516 if (m_pEditRouteArray) {
9517 b_startedit_route =
true;
9521 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9522 m_pTrackRolloverWin->IsActive(
false);
9524 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9525 m_pRouteRolloverWin->IsActive(
false);
9529 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9531 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9539 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9540 pre_rect.Union(route_rect);
9543 RefreshRect(pre_rect,
true);
9546 b_startedit_route =
false;
9550 if (m_pRoutePointEditTarget) {
9551 if (b_was_editing_mark ||
9552 b_was_editing_route) {
9553 if (m_lastRoutePointEditTarget) {
9557 .EnableDragHandle(
false);
9558 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9559 SELTYPE_DRAGHANDLE);
9563 if (m_pRoutePointEditTarget) {
9566 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9567 wxPoint2DDouble dragHandlePoint =
9569 .GetDragHandlePoint(
this);
9571 dragHandlePoint.m_y, dragHandlePoint.m_x,
9572 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9575 if (m_lastRoutePointEditTarget) {
9579 .EnableDragHandle(
false);
9580 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9581 SELTYPE_DRAGHANDLE);
9584 wxArrayPtrVoid *lastEditRouteArray =
9586 m_lastRoutePointEditTarget);
9587 if (lastEditRouteArray) {
9588 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9590 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9595 delete lastEditRouteArray;
9606 if (m_lastRoutePointEditTarget) {
9609 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9610 RefreshRect(wp_rect,
true);
9613 if (m_pRoutePointEditTarget) {
9616 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9617 RefreshRect(wp_rect,
true);
9625 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9626 bool b_start_rollover =
false;
9630 if (pFind) b_start_rollover =
true;
9633 if (!b_start_rollover && !b_startedit_route) {
9634 SelectableItemList SelList =
pSelect->FindSelectionList(
9638 if (pr && pr->IsVisible()) {
9639 b_start_rollover =
true;
9645 if (!b_start_rollover && !b_startedit_route) {
9646 SelectableItemList SelList =
pSelect->FindSelectionList(
9650 if (tr && tr->IsVisible()) {
9651 b_start_rollover =
true;
9657 if (b_start_rollover)
9658 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9662 bool appending =
false;
9663 bool inserting =
false;
9665 if (m_bRouteEditing ) {
9667 if (m_pRoutePointEditTarget) {
9673 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9674 double nearby_radius_meters =
9675 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9676 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9677 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9678 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9680 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9684 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9686 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9690 std::find(list->begin(), list->end(), pNearbyPoint);
9691 if (pos != list->end()) {
9703 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9708 OCPNMessageBox(
this,
9709 _(
"Replace this RoutePoint by the nearby "
9711 _(
"OpenCPN RoutePoint change"),
9712 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9713 if (dlg_return == wxID_YES) {
9718 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9721 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9723 if (tail && current && (tail != current)) {
9725 connect = tail->GetIndexOf(pNearbyPoint);
9726 int index_current_route =
9727 current->GetIndexOf(m_pRoutePointEditTarget);
9728 index_last = current->GetIndexOf(current->GetLastPoint());
9729 dlg_return1 = wxID_NO;
9731 index_current_route) {
9733 if (connect != tail->GetnPoints()) {
9736 _(
"Last part of route to be appended to dragged "
9740 _(
"Full route to be appended to dragged route?");
9742 dlg_return1 = OCPNMessageBox(
9743 this, dmsg, _(
"OpenCPN Route Create"),
9744 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9745 if (dlg_return1 == wxID_YES) {
9749 }
else if (index_current_route ==
9754 _(
"First part of route to be inserted into dragged "
9756 if (connect == tail->GetnPoints())
9758 "Full route to be inserted into dragged route?");
9760 dlg_return1 = OCPNMessageBox(
9761 this, dmsg, _(
"OpenCPN Route Create"),
9762 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9763 if (dlg_return1 == wxID_YES) {
9770 if (m_pRoutePointEditTarget->IsShared()) {
9772 dlg_return = OCPNMessageBox(
9774 _(
"Do you really want to delete and replace this "
9776 "\n" + _(
"which has been created manually?"),
9777 (
"OpenCPN RoutePoint warning"),
9778 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9781 if (dlg_return == wxID_YES) {
9782 pMousePoint = pNearbyPoint;
9784 pMousePoint->SetShared(
true);
9794 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9796 if (m_pEditRouteArray) {
9797 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9799 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9804 auto pos = std::find(list->begin(), list->end(),
9805 m_pRoutePointEditTarget);
9807 pSelect->DeleteAllSelectableRoutePoints(pr);
9808 pSelect->DeleteAllSelectableRouteSegments(pr);
9811 pos = std::find(list->begin(), list->end(),
9812 m_pRoutePointEditTarget);
9815 pSelect->AddAllSelectableRouteSegments(pr);
9816 pSelect->AddAllSelectableRoutePoints(pr);
9818 pr->FinalizeForRendering();
9819 pr->UpdateSegmentDistances();
9820 if (m_bRoutePoinDragging) {
9822 NavObj_dB::GetInstance().UpdateRoute(pr);
9830 if (m_pEditRouteArray) {
9831 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9833 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9852 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9859 delete m_pRoutePointEditTarget;
9860 m_lastRoutePointEditTarget = NULL;
9861 m_pRoutePointEditTarget = NULL;
9862 undo->AfterUndoableAction(pMousePoint);
9863 undo->InvalidateUndo();
9868 else if (m_bMarkEditing) {
9869 if (m_pRoutePointEditTarget)
9870 if (m_bRoutePoinDragging) {
9872 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9876 if (m_pRoutePointEditTarget)
9877 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9879 if (!m_pRoutePointEditTarget) {
9880 delete m_pEditRouteArray;
9881 m_pEditRouteArray = NULL;
9882 m_bRouteEditing =
false;
9884 m_bRoutePoinDragging =
false;
9891 int length = tail->GetnPoints();
9892 for (
int i = connect + 1; i <= length; i++) {
9893 current->AddPointAndSegment(tail->GetPoint(i),
false);
9896 top_frame::Get()->RefreshAllCanvas();
9899 current->FinalizeForRendering();
9905 pSelect->DeleteAllSelectableRoutePoints(current);
9906 pSelect->DeleteAllSelectableRouteSegments(current);
9907 for (
int i = 1; i < connect; i++) {
9908 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9910 pSelect->AddAllSelectableRouteSegments(current);
9911 pSelect->AddAllSelectableRoutePoints(current);
9912 current->FinalizeForRendering();
9919 if (m_pEditRouteArray) {
9920 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9921 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9934 if (m_bRouteEditing) {
9937 bool appending =
false;
9938 bool inserting =
false;
9941 if (m_pRoutePointEditTarget) {
9942 m_pRoutePointEditTarget->
m_bBlink =
false;
9946 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9947 double nearby_radius_meters =
9948 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9949 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9950 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9951 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9953 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9954 bool duplicate =
false;
9956 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9958 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9962 std::find(list->begin(), list->end(), pNearbyPoint);
9963 if (pos != list->end()) {
9975 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9980 OCPNMessageBox(
this,
9981 _(
"Replace this RoutePoint by the nearby "
9983 _(
"OpenCPN RoutePoint change"),
9984 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9985 if (dlg_return == wxID_YES) {
9989 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9992 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9994 if (tail && current && (tail != current)) {
9996 connect = tail->GetIndexOf(pNearbyPoint);
9997 int index_current_route =
9998 current->GetIndexOf(m_pRoutePointEditTarget);
9999 index_last = current->GetIndexOf(current->GetLastPoint());
10000 dlg_return1 = wxID_NO;
10002 index_current_route) {
10004 if (connect != tail->GetnPoints()) {
10007 _(
"Last part of route to be appended to dragged "
10011 _(
"Full route to be appended to dragged route?");
10013 dlg_return1 = OCPNMessageBox(
10014 this, dmsg, _(
"OpenCPN Route Create"),
10015 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10016 if (dlg_return1 == wxID_YES) {
10020 }
else if (index_current_route ==
10022 if (connect != 1) {
10025 _(
"First part of route to be inserted into dragged "
10027 if (connect == tail->GetnPoints())
10029 "Full route to be inserted into dragged route?");
10031 dlg_return1 = OCPNMessageBox(
10032 this, dmsg, _(
"OpenCPN Route Create"),
10033 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10034 if (dlg_return1 == wxID_YES) {
10041 if (m_pRoutePointEditTarget->IsShared()) {
10042 dlg_return = wxID_NO;
10043 dlg_return = OCPNMessageBox(
10045 _(
"Do you really want to delete and replace this "
10047 "\n" + _(
"which has been created manually?"),
10048 (
"OpenCPN RoutePoint warning"),
10049 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10052 if (dlg_return == wxID_YES) {
10053 pMousePoint = pNearbyPoint;
10055 pMousePoint->SetShared(
true);
10065 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10067 if (m_pEditRouteArray) {
10068 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10070 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10074 auto pos = std::find(list->begin(), list->end(),
10075 m_pRoutePointEditTarget);
10077 pSelect->DeleteAllSelectableRoutePoints(pr);
10078 pSelect->DeleteAllSelectableRouteSegments(pr);
10081 pos = std::find(list->begin(), list->end(),
10082 m_pRoutePointEditTarget);
10083 if (pos != list->end()) list->erase(pos);
10086 pSelect->AddAllSelectableRouteSegments(pr);
10087 pSelect->AddAllSelectableRoutePoints(pr);
10089 pr->FinalizeForRendering();
10090 pr->UpdateSegmentDistances();
10093 if (m_bRoutePoinDragging) {
10098 NavObj_dB::GetInstance().UpdateRoutePoint(
10099 m_pRoutePointEditTarget);
10101 NavObj_dB::GetInstance().UpdateRoute(pr);
10113 int length = tail->GetnPoints();
10114 for (
int i = connect + 1; i <= length; i++) {
10115 current->AddPointAndSegment(tail->GetPoint(i),
false);
10119 top_frame::Get()->RefreshAllCanvas();
10122 current->FinalizeForRendering();
10128 pSelect->DeleteAllSelectableRoutePoints(current);
10129 pSelect->DeleteAllSelectableRouteSegments(current);
10130 for (
int i = 1; i < connect; i++) {
10131 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10133 pSelect->AddAllSelectableRouteSegments(current);
10134 pSelect->AddAllSelectableRoutePoints(current);
10135 current->FinalizeForRendering();
10142 if (m_pEditRouteArray) {
10143 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10145 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10157 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10164 delete m_pRoutePointEditTarget;
10165 m_lastRoutePointEditTarget = NULL;
10166 undo->AfterUndoableAction(pMousePoint);
10167 undo->InvalidateUndo();
10172 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10175 delete m_pEditRouteArray;
10176 m_pEditRouteArray = NULL;
10180 m_bRouteEditing =
false;
10181 m_pRoutePointEditTarget = NULL;
10187 else if (m_bMarkEditing) {
10188 if (m_pRoutePointEditTarget) {
10189 if (m_bRoutePoinDragging) {
10191 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10193 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10198 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10200 RefreshRect(wp_rect,
true);
10203 m_pRoutePointEditTarget = NULL;
10204 m_bMarkEditing =
false;
10209 else if (leftIsDown) {
10210 leftIsDown =
false;
10214 if (!m_bChartDragging && !m_bMeasure_Active) {
10216 m_bChartDragging =
false;
10220 m_bRoutePoinDragging =
false;
10223 if (ret)
return true;
10226 if (event.RightDown()) {
10237 m_FinishRouteOnKillFocus =
false;
10238 CallPopupMenu(mx, my);
10239 m_FinishRouteOnKillFocus =
true;
10249 if (event.ShiftDown()) {
10253 event.GetPosition(&x, &y);
10255 x *= m_displayScale;
10256 y *= m_displayScale;
10262 int wheel_dir =
event.GetWheelRotation();
10265 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10266 wheel_dir = wheel_dir > 0 ? 1 : -1;
10268 double factor = g_mouse_zoom_sensitivity;
10269 if (wheel_dir < 0) factor = 1 / factor;
10272 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10273 if (wheel_dir == m_last_wheel_dir) {
10274 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10279 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10280 m_wheelstopwatch.Start(0);
10285 m_last_wheel_dir = wheel_dir;
10290 if (event.LeftDown()) {
10296 last_drag.x = x, last_drag.y = y;
10297 panleftIsDown =
true;
10300 if (event.LeftUp()) {
10301 if (panleftIsDown) {
10303 panleftIsDown =
false;
10306 if (!m_bChartDragging && !m_bMeasure_Active) {
10307 switch (cursor_region) {
10329 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10334 m_bChartDragging =
false;
10340 if (event.Dragging() && event.LeftIsDown()) {
10356 if (g_btouch && !m_inPinch) {
10357 struct timespec now;
10358 clock_gettime(CLOCK_MONOTONIC, &now);
10359 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10361 bool trigger_hold =
false;
10362 if (
false == m_bChartDragging) {
10363 if (m_DragTrigger < 0) {
10366 m_DragTriggerStartTime = tnow;
10367 trigger_hold =
true;
10369 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10370 m_DragTrigger = -1;
10375 if (trigger_hold)
return true;
10377 if (
false == m_bChartDragging) {
10380 last_drag.x = x - 1, last_drag.y = y - 1;
10381 m_bChartDragging =
true;
10382 m_chart_drag_total_time = 0;
10383 m_chart_drag_total_x = 0;
10384 m_chart_drag_total_y = 0;
10385 m_inertia_last_drag_x = x;
10386 m_inertia_last_drag_y = y;
10387 m_drag_vec_x.clear();
10388 m_drag_vec_y.clear();
10389 m_drag_vec_t.clear();
10390 m_last_drag_time = tnow;
10394 uint64_t delta_t = tnow - m_last_drag_time;
10395 double delta_tf = delta_t / 1e9;
10397 m_chart_drag_total_time += delta_tf;
10398 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10399 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10401 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10402 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10403 m_drag_vec_t.push_back(delta_tf);
10405 m_inertia_last_drag_x = x;
10406 m_inertia_last_drag_y = y;
10407 m_last_drag_time = tnow;
10409 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10410 m_bChartDragging =
true;
10411 StartTimedMovement();
10412 m_pan_drag.x += last_drag.x - x;
10413 m_pan_drag.y += last_drag.y - y;
10414 last_drag.x = x, last_drag.y = y;
10416 }
else if (!g_btouch) {
10417 if ((last_drag.x != x) || (last_drag.y != y)) {
10418 if (!m_routeState) {
10421 m_bChartDragging =
true;
10422 StartTimedMovement();
10423 m_pan_drag.x += last_drag.x - x;
10424 m_pan_drag.y += last_drag.y - y;
10425 last_drag.x = x, last_drag.y = y;
10432 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10434 m_ignore_next_leftup =
true;
10435 m_DoubleClickTimer->Start();
10436 singleClickEventIsValid =
false;
10444void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10445 if (MouseEventOverlayWindows(event))
return;
10449 bool nm = MouseEventProcessObjects(event);
10453void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10456 wxCursor *ptarget_cursor = pCursorArrow;
10457 if (!pPlugIn_Cursor) {
10458 ptarget_cursor = pCursorArrow;
10459 if ((!m_routeState) &&
10460 (!m_bMeasure_Active) ) {
10461 if (cursor_region == MID_RIGHT) {
10462 ptarget_cursor = pCursorRight;
10463 }
else if (cursor_region == MID_LEFT) {
10464 ptarget_cursor = pCursorLeft;
10465 }
else if (cursor_region == MID_TOP) {
10466 ptarget_cursor = pCursorDown;
10467 }
else if (cursor_region == MID_BOT) {
10468 ptarget_cursor = pCursorUp;
10470 ptarget_cursor = pCursorArrow;
10472 }
else if (m_bMeasure_Active ||
10474 ptarget_cursor = pCursorPencil;
10476 ptarget_cursor = pPlugIn_Cursor;
10479 SetCursor(*ptarget_cursor);
10482void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10483 SetCursor(*pCursorArrow);
10486void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10490 wxArrayString files;
10492 ChartBase *target_chart = GetChartAtCursor();
10493 if (target_chart) {
10494 file.Assign(target_chart->GetFullPath());
10495 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10496 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10499 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10501 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10502 unsigned int im = stackIndexArray.size();
10503 int scale = 2147483647;
10504 if (VPoint.b_quilt && im > 0) {
10505 for (
unsigned int is = 0; is < im; is++) {
10506 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10507 CHART_TYPE_MBTILES) {
10508 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10510 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10511 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10513 .Contains(lat, lon)) {
10514 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10517 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10518 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10526 std::vector<Ais8_001_22 *> area_notices;
10528 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10531 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10532 auto target_data = target.second;
10533 if (!target_data->area_notices.empty()) {
10534 for (
auto &ani : target_data->area_notices) {
10539 for (Ais8_001_22_SubAreaList::iterator sa =
10540 area_notice.sub_areas.begin();
10541 sa != area_notice.sub_areas.end(); ++sa) {
10542 switch (sa->shape) {
10543 case AIS8_001_22_SHAPE_CIRCLE: {
10544 wxPoint target_point;
10546 bbox.Expand(target_point);
10547 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10550 case AIS8_001_22_SHAPE_RECT: {
10551 wxPoint target_point;
10553 bbox.Expand(target_point);
10554 if (sa->e_dim_m > sa->n_dim_m)
10555 bbox.EnLarge(sa->e_dim_m * vp_scale);
10557 bbox.EnLarge(sa->n_dim_m * vp_scale);
10560 case AIS8_001_22_SHAPE_POLYGON:
10561 case AIS8_001_22_SHAPE_POLYLINE: {
10562 for (
int i = 0; i < 4; ++i) {
10563 double lat = sa->latitude;
10564 double lon = sa->longitude;
10565 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10567 wxPoint target_point;
10569 bbox.Expand(target_point);
10573 case AIS8_001_22_SHAPE_SECTOR: {
10574 double lat1 = sa->latitude;
10575 double lon1 = sa->longitude;
10577 wxPoint target_point;
10579 bbox.Expand(target_point);
10580 for (
int i = 0; i < 18; ++i) {
10583 sa->left_bound_deg +
10584 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10585 sa->radius_m / 1852.0, &lat, &lon);
10587 bbox.Expand(target_point);
10589 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10592 bbox.Expand(target_point);
10598 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10599 area_notices.push_back(&area_notice);
10606 if (target_chart || !area_notices.empty() || file.HasName()) {
10608 int sel_rad_pix = 5;
10609 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10614 SetCursor(wxCURSOR_WAIT);
10615 bool lightsVis = m_encShowLights;
10616 if (!lightsVis) SetShowENCLights(
true);
10619 ListOfObjRazRules *rule_list = NULL;
10620 ListOfPI_S57Obj *pi_rule_list = NULL;
10623 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10624 else if (target_plugin_chart)
10625 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10626 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10628 ListOfObjRazRules *overlay_rule_list = NULL;
10629 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10632 if (CHs57_Overlay) {
10633 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10634 zlat, zlon, SelectRadius, &GetVP());
10637 if (!lightsVis) SetShowENCLights(
false);
10640 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10641 wxString face = dFont->GetFaceName();
10645 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10646 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10650 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10658 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10659 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10662 int points = dFont->GetPointSize();
10664 int points = dFont->GetPointSize() + 1;
10668 for (
int i = -2; i < 5; i++) {
10669 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10673 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10675 if (overlay_rule_list && CHs57_Overlay) {
10676 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10677 objText <<
"<hr noshade>";
10680 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10681 an != area_notices.end(); ++an) {
10682 objText <<
"<b>AIS Area Notice:</b> ";
10683 objText << ais8_001_22_notice_names[(*an)->notice_type];
10684 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10685 (*an)->sub_areas.begin();
10686 sa != (*an)->sub_areas.end(); ++sa)
10687 if (!sa->text.empty()) objText << sa->text;
10688 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10689 objText <<
"<hr noshade>";
10693 objText << Chs57->CreateObjDescriptions(rule_list);
10694 else if (target_plugin_chart)
10695 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10698 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10701 wxString AddFiles, filenameOK;
10703 if (!target_plugin_chart) {
10706 AddFiles = wxString::Format(
10707 "<hr noshade><br><b>Additional info files attached to: </b> "
10709 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10711 file.GetFullName());
10713 file.Assign(file.GetPath(),
"");
10714 wxDir dir(file.GetFullPath());
10716 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10718 file.Assign(dir.GetNameWithSep().append(filename));
10719 wxString FormatString =
10720 "<td valign=top><font size=-2><a "
10721 "href=\"%s\">%s</a></font></td>";
10722 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10723 filenameOK = file.GetFullPath();
10725 if (3 * ((
int)filecount / 3) == filecount)
10726 FormatString.Prepend(
"<tr>");
10728 FormatString.Prepend(
10729 "<td>  </td>");
10732 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10733 file.GetFullName());
10736 cont = dir.GetNext(&filename);
10738 objText << AddFiles <<
"</table>";
10740 objText <<
"</font>";
10741 objText <<
"</body></html>";
10743 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10747 if ((!Chs57 && filecount == 1)) {
10749 wxHtmlLinkInfo hli(filenameOK);
10750 wxHtmlLinkEvent hle(1, hli);
10754 if (rule_list) rule_list->Clear();
10757 if (overlay_rule_list) overlay_rule_list->Clear();
10758 delete overlay_rule_list;
10760 if (pi_rule_list) pi_rule_list->Clear();
10761 delete pi_rule_list;
10763 SetCursor(wxCURSOR_ARROW);
10767void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10776 wxSize canvas_size = GetSize();
10783 wxPoint canvas_pos = GetPosition();
10786 bool newFit =
false;
10787 if (canvas_size.x < fitted_size.x) {
10788 fitted_size.x = canvas_size.x - 40;
10789 if (canvas_size.y < fitted_size.y)
10790 fitted_size.y -= 40;
10792 if (canvas_size.y < fitted_size.y) {
10793 fitted_size.y = canvas_size.y - 40;
10794 if (canvas_size.x < fitted_size.x)
10795 fitted_size.x -= 40;
10806 wxString title_base = _(
"Mark Properties");
10808 title_base = _(
"Waypoint Properties");
10813 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10825void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10835 if (g_bresponsive) {
10836 wxSize canvas_size = GetSize();
10837 wxPoint canvas_pos = GetPosition();
10841 if (canvas_size.x < fitted_size.x) {
10842 fitted_size.x = canvas_size.x;
10843 if (canvas_size.y < fitted_size.y)
10844 fitted_size.y -= 20;
10846 if (canvas_size.y < fitted_size.y) {
10847 fitted_size.y = canvas_size.y;
10848 if (canvas_size.x < fitted_size.x)
10849 fitted_size.x -= 20;
10858 wxPoint xxp = ClientToScreen(canvas_pos);
10869void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10881void pupHandler_PasteWaypoint() {
10884 int pasteBuffer = kml.ParsePasteBuffer();
10885 RoutePoint *pasted = kml.GetParsedRoutePoint();
10886 if (!pasted)
return;
10888 double nearby_radius_meters =
10889 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10891 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10892 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10894 int answer = wxID_NO;
10898 "There is an existing waypoint at the same location as the one you are "
10899 "pasting. Would you like to merge the pasted data with it?\n\n");
10900 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10901 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10902 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10905 if (answer == wxID_YES) {
10906 nearPoint->SetName(pasted->GetName());
10912 if (answer == wxID_NO) {
10915 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10918 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10927 top_frame::Get()->InvalidateAllGL();
10928 top_frame::Get()->RefreshAllCanvas(
false);
10931void pupHandler_PasteRoute() {
10934 int pasteBuffer = kml.ParsePasteBuffer();
10935 Route *pasted = kml.GetParsedRoute();
10936 if (!pasted)
return;
10938 double nearby_radius_meters =
10939 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10945 bool mergepoints =
false;
10946 bool createNewRoute =
true;
10947 int existingWaypointCounter = 0;
10949 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10950 curPoint = pasted->GetPoint(i);
10951 nearPoint = pWayPointMan->GetNearbyWaypoint(
10952 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10954 mergepoints =
true;
10955 existingWaypointCounter++;
10963 int answer = wxID_NO;
10967 "There are existing waypoints at the same location as some of the ones "
10968 "you are pasting. Would you like to just merge the pasted data into "
10970 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10971 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10972 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10974 if (answer == wxID_CANCEL) {
10981 if (mergepoints && answer == wxID_YES &&
10982 existingWaypointCounter == pasted->GetnPoints()) {
10985 createNewRoute =
false;
10991 Route *newRoute = 0;
10994 if (createNewRoute) {
10995 newRoute =
new Route();
10999 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11000 curPoint = pasted->GetPoint(i);
11003 newPoint = pWayPointMan->GetNearbyWaypoint(
11004 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11005 newPoint->SetName(curPoint->GetName());
11008 if (createNewRoute) newRoute->AddPoint(newPoint);
11014 newPoint->SetIconName(
"circle");
11017 newPoint->SetShared(
false);
11019 newRoute->AddPoint(newPoint);
11020 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11023 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11026 if (i > 1 && createNewRoute)
11027 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11028 curPoint->m_lat, curPoint->m_lon,
11029 prevPoint, newPoint, newRoute);
11030 prevPoint = newPoint;
11033 if (createNewRoute) {
11036 NavObj_dB::GetInstance().InsertRoute(newRoute);
11046 top_frame::Get()->InvalidateAllGL();
11047 top_frame::Get()->RefreshAllCanvas(
false);
11053void pupHandler_PasteTrack() {
11056 int pasteBuffer = kml.ParsePasteBuffer();
11057 Track *pasted = kml.GetParsedTrack();
11058 if (!pasted)
return;
11066 newTrack->SetName(pasted->GetName());
11068 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11069 curPoint = pasted->GetPoint(i);
11073 wxDateTime now = wxDateTime::Now();
11076 newTrack->AddPoint(newPoint);
11079 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11080 newPoint->m_lat, newPoint->m_lon,
11081 prevPoint, newPoint, newTrack);
11083 prevPoint = newPoint;
11088 NavObj_dB::GetInstance().InsertTrack(newTrack);
11090 top_frame::Get()->InvalidateAllGL();
11091 top_frame::Get()->RefreshAllCanvas(
false);
11094bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11097 v[
"CursorPosition_x"] = x;
11098 v[
"CursorPosition_y"] = y;
11101 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11102 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11103 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11108 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11110 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11113#define SELTYPE_UNKNOWN 0x0001
11114#define SELTYPE_ROUTEPOINT 0x0002
11115#define SELTYPE_ROUTESEGMENT 0x0004
11116#define SELTYPE_TIDEPOINT 0x0008
11117#define SELTYPE_CURRENTPOINT 0x0010
11118#define SELTYPE_ROUTECREATE 0x0020
11119#define SELTYPE_AISTARGET 0x0040
11120#define SELTYPE_MARKPOINT 0x0080
11121#define SELTYPE_TRACKSEGMENT 0x0100
11122#define SELTYPE_DRAGHANDLE 0x0200
11125 if (g_bhide_context_menus)
return true;
11127 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11128 m_pIDXCandidate, m_nmea_log);
11131 wxEVT_COMMAND_MENU_SELECTED,
11132 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11138 if (m_inLongPress) {
11139 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11140 m_inLongPress =
false;
11144 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11147 wxEVT_COMMAND_MENU_SELECTED,
11148 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11150 delete m_canvasMenu;
11151 m_canvasMenu = NULL;
11161void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11164 if (m_canvasMenu) {
11165 m_canvasMenu->PopupMenuHandler(event);
11170void ChartCanvas::StartRoute() {
11172 if (g_brouteCreating)
return;
11176 g_brouteCreating =
true;
11178 m_bDrawingRoute =
false;
11179 SetCursor(*pCursorPencil);
11181 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11183 HideGlobalToolbar();
11186 androidSetRouteAnnunciator(
true);
11190wxString ChartCanvas::FinishRoute() {
11192 m_prev_pMousePoint = NULL;
11193 m_bDrawingRoute =
false;
11195 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11198 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11200 androidSetRouteAnnunciator(
false);
11203 SetCursor(*pCursorArrow);
11205 if (m_pMouseRoute) {
11206 if (m_bAppendingRoute) {
11208 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11210 if (m_pMouseRoute->GetnPoints() > 1) {
11212 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11215 m_pMouseRoute = NULL;
11218 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11230 m_bAppendingRoute =
false;
11231 m_pMouseRoute = NULL;
11233 m_pSelectedRoute = NULL;
11235 undo->InvalidateUndo();
11236 top_frame::Get()->RefreshAllCanvas(
true);
11240 ShowGlobalToolbar();
11242 g_brouteCreating =
false;
11247void ChartCanvas::HideGlobalToolbar() {
11248 if (m_canvasIndex == 0) {
11249 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11253void ChartCanvas::ShowGlobalToolbar() {
11254 if (m_canvasIndex == 0) {
11255 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11259void ChartCanvas::ShowAISTargetList() {
11260 if (NULL == g_pAISTargetList) {
11264 g_pAISTargetList->UpdateAISTargetList();
11267void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11268 if (!m_bShowOutlines)
return;
11272 int nEntry =
ChartData->GetChartTableEntries();
11274 for (
int i = 0; i < nEntry; i++) {
11278 bool b_group_draw =
false;
11279 if (m_groupIndex > 0) {
11280 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11281 int index = pt->GetGroupArray()[ig];
11282 if (m_groupIndex == index) {
11283 b_group_draw =
true;
11288 b_group_draw =
true;
11290 if (b_group_draw) RenderChartOutline(dc, i, vp);
11296 if (VPoint.b_quilt) {
11297 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11298 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11302 }
else if (m_singleChart &&
11303 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11307 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11310 if (zoom_factor > 8.0) {
11311 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11314 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11318 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11322void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11324 if (g_bopengl && m_glcc) {
11326 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11331 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11332 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11335 float plylat, plylon;
11336 float plylat1, plylon1;
11338 int pixx, pixy, pixx1, pixy1;
11341 ChartData->GetDBBoundingBox(dbIndex, box);
11345 if (box.GetLonRange() == 360)
return;
11347 double lon_bias = 0;
11349 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11351 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11353 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11354 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11356 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11357 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11360 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11363 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11364 if (0 == nAuxPlyEntries)
11368 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11369 plylon += lon_bias;
11375 for (
int i = 0; i < nPly - 1; i++) {
11376 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11377 plylon1 += lon_bias;
11383 int pixxs1 = pixx1;
11384 int pixys1 = pixy1;
11386 bool b_skip =
false;
11390 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11391 pow((
double)(pixy1 - pixy), 2)) /
11397 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11402 if (fabs(dist - distgc) > 10000. * 1852.)
11408 ClipResult res = cohen_sutherland_line_clip_i(
11410 if (res != Invisible && !b_skip)
11411 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11419 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11420 plylon1 += lon_bias;
11426 ClipResult res = cohen_sutherland_line_clip_i(
11428 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11435 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11436 for (
int j = 0; j < nAuxPlyEntries; j++) {
11438 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11443 for (
int i = 0; i < nAuxPly - 1; i++) {
11444 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11450 int pixxs1 = pixx1;
11451 int pixys1 = pixy1;
11453 bool b_skip =
false;
11457 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11458 ((pixy1 - pixy) * (pixy1 - pixy))) /
11463 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11468 if (fabs(dist - distgc) > 10000. * 1852.)
11474 ClipResult res = cohen_sutherland_line_clip_i(
11476 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11484 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11489 ClipResult res = cohen_sutherland_line_clip_i(
11491 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11496static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11497 const wxArrayString &legend) {
11498 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11500 int pointsize = dFont->GetPointSize();
11504 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11505 false, dFont->GetFaceName());
11507 dc.SetFont(*psRLI_font);
11514 int hilite_offset = 3;
11516 for (wxString line : legend) {
11519 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11521 dc.GetTextExtent(line, &wl, &hl);
11530 xp = ref_point.x - w;
11532 yp += hilite_offset;
11534 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11536 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11537 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11539 for (wxString line : legend) {
11540 dc.DrawText(line, xp, yp);
11545void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11546 if (!g_bAllowShipToActive)
return;
11552 wxPoint2DDouble pa, pb;
11559 if (rt->
m_width != wxPENSTYLE_INVALID)
11561 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11562 g_shipToActiveStyle, 5)];
11563 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11565 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11568 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11571 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11574 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11575 (
int)pb.m_y, GetVP(),
true);
11579#ifdef USE_ANDROID_GLES2
11580 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11582 if (style != wxPENSTYLE_SOLID) {
11583 if (glChartCanvas::dash_map.find(style) !=
11584 glChartCanvas::dash_map.end()) {
11585 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11589 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11592 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11593 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11599void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11601 if (m_routeState >= 2) route = m_pMouseRoute;
11602 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11603 route = m_pMeasureRoute;
11605 if (!route)
return;
11613 int np = route->GetnPoints();
11615 if (g_btouch && (np > 1)) np--;
11617 render_lat = rp.m_lat;
11618 render_lon = rp.m_lon;
11621 double rhumbBearing, rhumbDist;
11623 &rhumbBearing, &rhumbDist);
11624 double brg = rhumbBearing;
11625 double dist = rhumbDist;
11629 double gcBearing, gcBearing2, gcDist;
11630 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11633 double gcDistm = gcDist / 1852.0;
11636 rhumbBearing = 90.;
11638 wxPoint destPoint, lastPoint;
11641 int milesDiff = rhumbDist - gcDistm;
11642 if (milesDiff > 1) {
11653 for (
int i = 1; i <= milesDiff; i++) {
11654 double p = (double)i * (1.0 / (
double)milesDiff);
11656 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11657 &pLon, &pLat, &gcBearing2);
11659 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11661 lastPoint = destPoint;
11664 if (r_rband.x && r_rband.y) {
11665 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11667 if (m_bMeasure_DistCircle) {
11668 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11669 powf((
float)(r_rband.y - lastPoint.y), 2));
11672 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11673 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11679 wxString routeInfo;
11680 wxArrayString infoArray;
11683 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11689 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11691 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11692 (
int)varBrg, 0x00B0);
11695 infoArray.Add(routeInfo);
11701 routeInfo <<
"Reverse: ";
11703 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11704 (
int)(brg + 180.) % 360, 0x00B0);
11706 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11707 (
int)(varBrg + 180.) % 360, 0x00B0);
11708 infoArray.Add(routeInfo);
11714 s0.Append(_(
"Route") +
": ");
11716 s0.Append(_(
"Layer Route: "));
11719 if (!g_btouch) disp_length += dist;
11725 RouteLegInfo(dc, r_rband, infoArray);
11727 m_brepaint_piano =
true;
11730void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11731 if (!m_bShowVisibleSectors)
return;
11733 if (g_bDeferredInitDone) {
11735 double rhumbBearing, rhumbDist;
11736 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11737 &rhumbBearing, &rhumbDist);
11739 if (rhumbDist > 0.05)
11741 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11742 m_sectorlegsVisible);
11743 m_sector_glat =
gLat;
11744 m_sector_glon =
gLon;
11746 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11750void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11758void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11759 if (!ps52plib)
return;
11761 if (VPoint.b_quilt) {
11762 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11764 if (m_pQuilt->IsQuiltVector()) {
11765 if (ps52plib->GetStateHash() != m_s52StateHash) {
11767 m_s52StateHash = ps52plib->GetStateHash();
11771 if (ps52plib->GetStateHash() != m_s52StateHash) {
11773 m_s52StateHash = ps52plib->GetStateHash();
11778 bool bSendPlibState =
true;
11779 if (VPoint.b_quilt) {
11780 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11783 if (bSendPlibState) {
11785 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11786 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11787 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11788 v[
"OpenCPN Version Date"] = VERSION_DATE;
11789 v[
"OpenCPN Version Full"] = VERSION_FULL;
11792 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11793 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11794 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11795 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11796 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11797 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11798 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11802 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11803 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11807 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11808 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11809 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11810 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11811 ps52plib->m_bShowS57ImportantTextOnly;
11812 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11813 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11814 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11815 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11816 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11819 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11820 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11821 v[
"OpenCPN Scale Factor Exp"] =
11822 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11829 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11830 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11831 g_lastS52PLIBPluginMessage = out;
11838 wxPaintDC dc(
this);
11848 if (!m_b_paint_enable) {
11856 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11858 if (m_glcc && g_bopengl) {
11859 if (!s_in_update) {
11869 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11871 wxRegion ru = GetUpdateRegion();
11873 int rx, ry, rwidth, rheight;
11874 ru.GetBox(rx, ry, rwidth, rheight);
11876#ifdef ocpnUSE_DIBSECTION
11879 wxMemoryDC temp_dc;
11887 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11888 height += m_Piano->GetHeight();
11890 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11894 int thumbx, thumby, thumbsx, thumbsy;
11895 pthumbwin->GetPosition(&thumbx, &thumby);
11896 pthumbwin->GetSize(&thumbsx, &thumbsy);
11897 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11900 rgn_chart.Subtract(rgn_thumbwin);
11901 ru.Subtract(rgn_thumbwin);
11907 wxRegion rgn_blit = ru;
11908 if (g_bShowChartBar) {
11909 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11910 GetClientSize().x, m_Piano->GetHeight());
11913 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11914 if (style->chartStatusWindowTransparent)
11915 m_brepaint_piano =
true;
11917 ru.Subtract(chart_bar_rect);
11921 if (m_Compass && m_Compass->IsShown()) {
11922 wxRect compassRect = m_Compass->
GetRect();
11923 if (ru.Contains(compassRect) != wxOutRegion) {
11924 ru.Subtract(compassRect);
11928 if (m_notification_button) {
11929 wxRect noteRect = m_notification_button->
GetRect();
11930 if (ru.Contains(noteRect) != wxOutRegion) {
11931 ru.Subtract(noteRect);
11936 bool b_newview =
true;
11941 m_cache_vp.IsValid()) {
11947 bool b_rcache_ok =
false;
11948 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11949 b_rcache_ok = !b_newview;
11952 if (VPoint.b_MercatorProjectionOverride)
11953 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11967 if (b_rcache_ok) chart_get_region.Clear();
11970 if (VPoint.b_quilt)
11972 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11974 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11979 AbstractPlatform::ShowBusySpinner();
11983 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11984 (m_working_bm.GetHeight() != svp.
pix_height))
11988 if (fabs(VPoint.
rotation) < 0.01) {
11989 bool b_save =
true;
11994 m_cache_vp.Invalidate();
12008 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12013 int dy = c_new.y - c_old.y;
12014 int dx = c_new.x - c_old.x;
12019 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12023 temp_dc.SelectObject(m_working_bm);
12025 wxMemoryDC cache_dc;
12026 cache_dc.SelectObject(m_cached_chart_bm);
12030 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12033 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12039 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12042 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12050 update_region.Union(
12053 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12058 update_region.Union(
12061 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12065 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12067 cache_dc.SelectObject(wxNullBitmap);
12071 temp_dc.SelectObject(m_cached_chart_bm);
12074 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12078 temp_dc.SelectObject(m_working_bm);
12079 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12084 temp_dc.SelectObject(m_cached_chart_bm);
12089 temp_dc.SelectObject(m_working_bm);
12090 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12103 wxMemoryDC scratch_dc_0;
12104 scratch_dc_0.SelectObject(m_cached_chart_bm);
12107 scratch_dc_0.SelectObject(wxNullBitmap);
12116 temp_dc.SelectObject(m_working_bm);
12119 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12120 chart_get_all_region);
12123 AbstractPlatform::HideBusySpinner();
12129 if (!m_singleChart) {
12130 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12135 if (!chart_get_region.IsEmpty()) {
12136 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12140 if (temp_dc.IsOk()) {
12145 if (!VPoint.b_quilt) {
12148 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12149 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12156 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12157 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12160 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12162 temp_dc.DestroyClippingRegion();
12167 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12169 if (!backgroundRegion.IsEmpty()) {
12175 wxColour water = pWorldBackgroundChart->water;
12176 if (water.IsOk()) {
12177 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12178 temp_dc.SetBrush(wxBrush(water));
12180 while (upd.HaveRects()) {
12181 wxRect rect = upd.GetRect();
12182 temp_dc.DrawRectangle(rect);
12187 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12188 temp_dc.SetDeviceClippingRegion(*clip_region);
12189 delete clip_region;
12193 SetVPRotation(VPoint.
skew);
12202 wxMemoryDC *pChartDC = &temp_dc;
12203 wxMemoryDC rotd_dc;
12205 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12207 if (!b_rcache_ok) {
12209 wxMemoryDC tbase_dc;
12211 tbase_dc.SelectObject(bm_base);
12213 tbase_dc.SelectObject(wxNullBitmap);
12215 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12218 wxImage base_image;
12219 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12227 bool b_rot_ok =
false;
12228 if (base_image.IsOk()) {
12231 m_b_rot_hidef =
false;
12235 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12236 m_b_rot_hidef, &m_roffset);
12241 rot_vp.IsValid() && (ri.IsOk())) {
12248 m_prot_bm =
new wxBitmap(ri);
12251 m_roffset.x += VPoint.rv_rect.x;
12252 m_roffset.y += VPoint.rv_rect.y;
12255 if (m_prot_bm && m_prot_bm->IsOk()) {
12256 rotd_dc.SelectObject(*m_prot_bm);
12257 pChartDC = &rotd_dc;
12259 pChartDC = &temp_dc;
12260 m_roffset = wxPoint(0, 0);
12263 pChartDC = &temp_dc;
12264 m_roffset = wxPoint(0, 0);
12267 wxPoint offset = m_roffset;
12270 m_cache_vp = VPoint;
12273 wxMemoryDC mscratch_dc;
12274 mscratch_dc.SelectObject(*pscratch_bm);
12276 mscratch_dc.ResetBoundingBox();
12277 mscratch_dc.DestroyClippingRegion();
12278 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12281 wxRegionIterator upd(rgn_blit);
12283 wxRect rect = upd.GetRect();
12285 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12286 rect.x - offset.x, rect.y - offset.y);
12292 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12293 if (
this == wxWindow::FindFocus()) {
12296 wxColour colour = GetGlobalColor(
"BLUE4");
12297 mscratch_dc.SetPen(wxPen(colour));
12298 mscratch_dc.SetBrush(wxBrush(colour));
12300 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12301 mscratch_dc.DrawRectangle(activeRect);
12306 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12307 unsigned int im = stackIndexArray.size();
12308 if (VPoint.b_quilt && im > 0) {
12309 std::vector<int> tiles_to_show;
12310 for (
unsigned int is = 0; is < im; is++) {
12312 ChartData->GetChartTableEntry(stackIndexArray[is]);
12313 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12316 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12317 tiles_to_show.push_back(stackIndexArray[is]);
12321 if (tiles_to_show.size())
12322 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12328 ocpnDC scratch_dc(mscratch_dc);
12329 RenderAlertMessage(mscratch_dc, GetVP());
12335#ifdef ocpnUSE_DIBSECTION
12340 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12341 q_dc.SelectObject(qbm);
12344 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12347 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12348 q_dc.SetBrush(qbr);
12349 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12352 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12355 q_dc.SelectObject(wxNullBitmap);
12364 if( VPoint.b_quilt ) {
12365 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12366 ChartBase *chart = m_pQuilt->GetRefChart();
12367 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12372 ChPI->ClearPLIBTextList();
12375 ps52plib->ClearTextList();
12379 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12381 wxColor maskBackground = wxColour(1,0,0);
12382 t_dc.SelectObject( qbm );
12383 t_dc.SetBackground(wxBrush(maskBackground));
12387 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12390 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12391 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12394 wxRegionIterator upd_final( ru );
12395 while( upd_final ) {
12396 wxRect rect = upd_final.GetRect();
12397 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12401 t_dc.SelectObject( wxNullBitmap );
12407 if (VPoint.b_quilt) {
12408 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12409 ChartBase *chart = m_pQuilt->GetRefChart();
12410 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12414 ChPI->ClearPLIBTextList();
12416 if (ps52plib) ps52plib->ClearTextList();
12421 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12423 if (g_bShowChartBar && m_Piano) {
12424 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12425 GetVP().pix_width, m_Piano->GetHeight());
12428 if (!style->chartStatusWindowTransparent)
12429 chart_all_text_region.Subtract(chart_bar_rect);
12432 if (m_Compass && m_Compass->IsShown()) {
12433 wxRect compassRect = m_Compass->
GetRect();
12434 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12435 chart_all_text_region.Subtract(compassRect);
12439 mscratch_dc.DestroyClippingRegion();
12441 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12442 chart_all_text_region);
12448 ocpnDC scratch_dc(mscratch_dc);
12449 DrawOverlayObjects(scratch_dc, ru);
12452 wxRegionIterator upd_final(rgn_blit);
12453 while (upd_final) {
12454 wxRect rect = upd_final.GetRect();
12455 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12462 temp_dc.SelectObject(wxNullBitmap);
12464 mscratch_dc.SelectObject(wxNullBitmap);
12466 dc.DestroyClippingRegion();
12471void ChartCanvas::PaintCleanup() {
12473 if (m_inPinch)
return;
12484 m_bTCupdate =
false;
12488 WarpPointer(warp_x, warp_y);
12495 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12496 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12500wxColour GetErrorGraphicColor(
double val)
12519 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12520 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12521 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12522 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12523 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12524 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12525 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12526 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12527 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12528 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12529 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12530 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12531 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12532 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12533 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12534 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12535 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12536 else if( val >= 48) c.Set(
"#410000");
12541void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12544 gr_image.InitAlpha();
12546 double maxval = -10000;
12547 double minval = 10000;
12564 maxval = wxMax(maxval, (glat - rlat));
12565 minval = wxMin(minval, (glat - rlat));
12582 double f = ((glat - rlat)-minval)/(maxval - minval);
12584 double dy = (f * 40);
12586 wxColour c = GetErrorGraphicColor(dy);
12587 unsigned char r = c.Red();
12588 unsigned char g = c.Green();
12589 unsigned char b = c.Blue();
12591 gr_image.SetRGB(j, i, r,g,b);
12592 if((glat - rlat )!= 0)
12593 gr_image.SetAlpha(j, i, 128);
12595 gr_image.SetAlpha(j, i, 255);
12602 wxBitmap *pbm =
new wxBitmap(gr_image);
12603 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12604 pbm->SetMask(gr_mask);
12606 pmdc->DrawBitmap(*pbm, 0,0);
12614void ChartCanvas::CancelMouseRoute() {
12616 m_pMouseRoute = NULL;
12617 m_bDrawingRoute =
false;
12620int ChartCanvas::GetNextContextMenuId() {
12621 return CanvasMenuHandler::GetNextContextMenuId();
12624bool ChartCanvas::SetCursor(
const wxCursor &c) {
12626 if (g_bopengl && m_glcc)
12627 return m_glcc->SetCursor(c);
12630 return wxWindow::SetCursor(c);
12633void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12634 if (g_bquiting)
return;
12644 if (!m_RolloverPopupTimer.IsRunning() &&
12645 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12646 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12647 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12648 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12651 if (m_glcc && g_bopengl) {
12654 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12656 m_glcc->Refresh(eraseBackground,
12673 if (m_pCIWin && m_pCIWin->IsShown()) {
12675 m_pCIWin->Refresh(
false);
12683 wxWindow::Refresh(eraseBackground, rect);
12686void ChartCanvas::Update() {
12687 if (m_glcc && g_bopengl) {
12692 wxWindow::Update();
12696 if (!pemboss)
return;
12697 int x = pemboss->x, y = pemboss->y;
12698 const double factor = 200;
12700 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12701 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12702 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12705 wxMemoryDC snip_dc;
12706 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12707 snip_dc.SelectObject(snip_bmp);
12709 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12710 snip_dc.SelectObject(wxNullBitmap);
12712 wxImage snip_img = snip_bmp.ConvertToImage();
12715 unsigned char *pdata = snip_img.GetData();
12717 for (
int y = 0; y < pemboss->height; y++) {
12718 int map_index = (y * pemboss->width);
12719 for (
int x = 0; x < pemboss->width; x++) {
12720 double val = (pemboss->pmap[map_index] * factor) / 256.;
12722 int nred = (int)((*pdata) + val);
12723 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12724 *pdata++ = (
unsigned char)nred;
12726 int ngreen = (int)((*pdata) + val);
12727 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12728 *pdata++ = (
unsigned char)ngreen;
12730 int nblue = (int)((*pdata) + val);
12731 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12732 *pdata++ = (
unsigned char)nblue;
12740 wxBitmap emb_bmp(snip_img);
12743 wxMemoryDC result_dc;
12744 result_dc.SelectObject(emb_bmp);
12747 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12749 result_dc.SelectObject(wxNullBitmap);
12755 if (GetQuiltMode()) {
12757 int refIndex = GetQuiltRefChartdbIndex();
12758 if (refIndex >= 0) {
12760 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12761 if (current_type == CHART_TYPE_MBTILES) {
12762 ChartBase *pChart = m_pQuilt->GetRefChart();
12765 zoom_factor = ptc->GetZoomFactor();
12770 if (zoom_factor <= 3.9)
return NULL;
12772 if (m_singleChart) {
12773 if (zoom_factor <= 3.9)
return NULL;
12778 if (m_pEM_OverZoom) {
12779 m_pEM_OverZoom->x = 4;
12780 m_pEM_OverZoom->y = 0;
12782 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12783 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12786 return m_pEM_OverZoom;
12789void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12802 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12803 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12807 AISDrawAreaNotices(dc, GetVP(),
this);
12809 wxDC *pdc = dc.GetDC();
12811 pdc->DestroyClippingRegion();
12812 wxDCClipper(*pdc, ru);
12815 if (m_bShowNavobjects) {
12816 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12817 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12818 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12819 DrawAnchorWatchPoints(dc);
12821 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12822 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12825 AISDraw(dc, GetVP(),
this);
12829 RenderVisibleSectorLights(dc);
12831 RenderAllChartOutlines(dc, GetVP());
12832 RenderRouteLegs(dc);
12833 RenderShipToActive(dc,
false);
12835 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12837 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12841 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12842 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12845 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12850 RebuildTideSelectList(GetVP().GetBBox());
12851 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12854 if (m_bShowCurrent) {
12855 RebuildCurrentSelectList(GetVP().GetBBox());
12856 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12859 if (!g_PrintingInProgress) {
12860 if (IsPrimaryCanvas()) {
12864 if (IsPrimaryCanvas()) {
12868 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12870 if (m_pTrackRolloverWin) {
12871 m_pTrackRolloverWin->Draw(dc);
12872 m_brepaint_piano =
true;
12875 if (m_pRouteRolloverWin) {
12876 m_pRouteRolloverWin->Draw(dc);
12877 m_brepaint_piano =
true;
12880 if (m_pAISRolloverWin) {
12881 m_pAISRolloverWin->Draw(dc);
12882 m_brepaint_piano =
true;
12884 if (m_brepaint_piano && g_bShowChartBar) {
12885 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12888 if (m_Compass) m_Compass->Paint(dc);
12890 if (!g_CanvasHideNotificationIcon) {
12891 if (IsPrimaryCanvas()) {
12892 auto ¬eman = NotificationManager::GetInstance();
12893 if (noteman.GetNotificationCount()) {
12894 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12895 if (m_notification_button->UpdateStatus()) Refresh();
12896 m_notification_button->Show(
true);
12897 m_notification_button->Paint(dc);
12899 m_notification_button->Show(
false);
12905 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12911 if (!m_bShowDepthUnits)
return NULL;
12913 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12915 if (GetQuiltMode()) {
12916 wxString s = m_pQuilt->GetQuiltDepthUnit();
12919 depth_unit_type = DEPTH_UNIT_FEET;
12920 else if (s.StartsWith(
"FATHOMS"))
12921 depth_unit_type = DEPTH_UNIT_FATHOMS;
12922 else if (s.StartsWith(
"METERS"))
12923 depth_unit_type = DEPTH_UNIT_METERS;
12924 else if (s.StartsWith(
"METRES"))
12925 depth_unit_type = DEPTH_UNIT_METERS;
12926 else if (s.StartsWith(
"METRIC"))
12927 depth_unit_type = DEPTH_UNIT_METERS;
12928 else if (s.StartsWith(
"METER"))
12929 depth_unit_type = DEPTH_UNIT_METERS;
12932 if (m_singleChart) {
12933 depth_unit_type = m_singleChart->GetDepthUnitType();
12934 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12935 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12940 switch (depth_unit_type) {
12941 case DEPTH_UNIT_FEET:
12944 case DEPTH_UNIT_METERS:
12945 ped = m_pEM_Meters;
12947 case DEPTH_UNIT_FATHOMS:
12948 ped = m_pEM_Fathoms;
12954 ped->x = (GetVP().
pix_width - ped->width);
12956 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12957 wxRect r = m_Compass->
GetRect();
12958 ped->y = r.y + r.height;
12965void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12968 if (style->embossFont == wxEmptyString) {
12969 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12971 font.SetPointSize(60);
12972 font.SetWeight(wxFONTWEIGHT_BOLD);
12974 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12975 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12977 int emboss_width = 500;
12978 int emboss_height = 200;
12982 delete m_pEM_Meters;
12983 delete m_pEM_Fathoms;
12987 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12989 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12991 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12994#define OVERZOOM_TEXT _("OverZoom")
12996void ChartCanvas::SetOverzoomFont() {
13001 if (style->embossFont == wxEmptyString) {
13002 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13004 font.SetPointSize(40);
13005 font.SetWeight(wxFONTWEIGHT_BOLD);
13007 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13008 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13010 wxClientDC dc(
this);
13012 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13014 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13015 font.SetPointSize(font.GetPointSize() - 1);
13017 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13019 m_overzoomFont = font;
13020 m_overzoomTextWidth = w;
13021 m_overzoomTextHeight = h;
13024void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13025 delete m_pEM_OverZoom;
13027 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13029 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13030 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13033emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13034 int height,
const wxString &str,
13039 wxBitmap bmp(width, height, -1);
13042 wxMemoryDC temp_dc;
13043 temp_dc.SelectObject(bmp);
13046 temp_dc.SetBackground(*wxWHITE_BRUSH);
13047 temp_dc.SetTextBackground(*wxWHITE);
13048 temp_dc.SetTextForeground(*wxBLACK);
13052 temp_dc.SetFont(font);
13055 temp_dc.GetTextExtent(str, &str_w, &str_h);
13057 temp_dc.DrawText(str, 1, 1);
13060 temp_dc.SelectObject(wxNullBitmap);
13063 wxImage img = bmp.ConvertToImage();
13065 int image_width = str_w * 105 / 100;
13066 int image_height = str_h * 105 / 100;
13067 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13068 wxMin(image_height, img.GetHeight()));
13069 wxImage imgs = img.GetSubImage(r);
13073 case GLOBAL_COLOR_SCHEME_DAY:
13077 case GLOBAL_COLOR_SCHEME_DUSK:
13080 case GLOBAL_COLOR_SCHEME_NIGHT:
13087 const int w = imgs.GetWidth();
13088 const int h = imgs.GetHeight();
13089 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13094 for (
int y = 1; y < h - 1; y++) {
13095 for (
int x = 1; x < w - 1; x++) {
13097 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13098 val = (int)(val * val_factor);
13099 index = (y * w) + x;
13112void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13113 Track *active_track = NULL;
13116 active_track = pTrackDraw;
13120 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13123 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13126void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13127 Track *active_track = NULL;
13130 active_track = pTrackDraw;
13134 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13137void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13138 Route *active_route = NULL;
13140 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13141 active_route = pRouteDraw;
13146 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13151 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13154void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13155 Route *active_route = NULL;
13158 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13159 active_route = pRouteDraw;
13163 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13166void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13167 if (!pWayPointMan)
return;
13169 auto node = pWayPointMan->GetWaypointList()->begin();
13171 while (node != pWayPointMan->GetWaypointList()->end()) {
13180 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13184 if (pWP->GetShowWaypointRangeRings() &&
13185 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13186 double factor = 1.00;
13187 if (pWP->GetWaypointRangeRingsStepUnits() ==
13189 factor = 1 / 1.852;
13191 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13192 pWP->GetWaypointRangeRingsStep() / 60.;
13196 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13197 pWP->m_lat + radius, pWP->m_lon + radius);
13198 if (!BltBBox.IntersectOut(radar_box)) {
13209void ChartCanvas::DrawBlinkObjects() {
13211 wxRect update_rect;
13213 if (!pWayPointMan)
return;
13215 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13222 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13225void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13230 wxPoint lAnchorPoint1, lAnchorPoint2;
13244 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13245 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13247 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13248 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13249 dc.SetBrush(*ppBrush);
13253 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13258 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13263 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13268 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13273double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13276 wxPoint lAnchorPoint;
13279 double tlat1, tlon1;
13281 if (pAnchorWatchPoint) {
13282 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13284 dabs = fabs(d1 / 1852.);
13285 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13290 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13291 pow((
double)(lAnchorPoint.y - r1.y), 2));
13294 if (d1 < 0) lpp = -lpp;
13302void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13305 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13307 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13313 if ((type ==
't') || (type ==
'T')) {
13314 if (BBox.Contains(lat, lon)) {
13316 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13322void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13325 wxDateTime this_now = gTimeSource;
13326 bool cur_time = !gTimeSource.IsValid();
13327 if (cur_time) this_now = wxDateTime::Now();
13328 time_t t_this_now = this_now.GetTicks();
13330 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13332 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13333 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13334 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13335 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13337 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13338 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13339 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13340 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13341 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13342 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13344 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13345 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13346 int font_size = wxMax(10, dFont->GetPointSize());
13349 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13350 false, dFont->GetFaceName());
13352 dc.SetPen(*pblack_pen);
13353 dc.SetBrush(*pgreen_brush);
13357 case GLOBAL_COLOR_SCHEME_DAY:
13360 case GLOBAL_COLOR_SCHEME_DUSK:
13363 case GLOBAL_COLOR_SCHEME_NIGHT:
13364 bm = m_bmTideNight;
13371 int bmw = bm.GetWidth();
13372 int bmh = bm.GetHeight();
13374 float scale_factor = 1.0;
13378 float icon_pixelRefDim = 45;
13383 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13385 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13387 scale_factor *= pix_factor;
13394 scale_factor *= user_scale_factor;
13395 scale_factor *= GetContentScaleFactor();
13398 double marge = 0.05;
13399 std::vector<LLBBox> drawn_boxes;
13400 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13404 if ((type ==
't') || (type ==
'T'))
13409 if (BBox.ContainsMarge(lat, lon, marge)) {
13411 if (GetVP().chart_scale < 500000) {
13412 bool bdrawn =
false;
13413 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13414 if (drawn_boxes[i].Contains(lat, lon)) {
13419 if (bdrawn)
continue;
13422 this_box.Set(lat, lon, lat, lon);
13423 this_box.EnLarge(.005);
13424 drawn_boxes.push_back(this_box);
13430 if (GetVP().chart_scale > 500000) {
13431 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13435 dc.SetFont(*plabelFont);
13447 if (
ptcmgr->GetTideFlowSens(
13448 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13452 ptcmgr->GetHightOrLowTide(
13453 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13454 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13466 if (tctime > t_this_now)
13467 ptcmgr->GetHightOrLowTide(
13468 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13469 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13473 ptcmgr->GetHightOrLowTide(
13474 t_this_now, FORWARD_TEN_MINUTES_STEP,
13475 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13489 int width = (int)(12 * scale_factor + 0.5);
13490 int height = (int)(45 * scale_factor + 0.5);
13491 int linew = wxMax(1, (
int)(scale_factor));
13492 int xDraw = r.x - (width / 2);
13493 int yDraw = r.y - (height / 2);
13496 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13497 int hs = (httime > lttime) ? -4 : 4;
13498 hs *= (int)(scale_factor + 0.5);
13499 if (ts > 0.995 || ts < 0.005) hs = 0;
13500 int ht_y = (int)(height * ts);
13503 pblack_pen->SetWidth(linew);
13504 dc.SetPen(*pblack_pen);
13505 dc.SetBrush(*pyelo_brush);
13506 dc.DrawRectangle(xDraw, yDraw, width, height);
13510 dc.SetPen(*pblue_pen);
13511 dc.SetBrush(*pblue_brush);
13512 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13513 (width - (4 * linew)), height - ht_y);
13519 arrow[0].x = xDraw + 2 * linew;
13520 arrow[1].x = xDraw + width / 2;
13521 arrow[2].x = xDraw + width - 2 * linew;
13522 pyelo_pen->SetWidth(linew);
13523 pblue_pen->SetWidth(linew);
13524 if (ts > 0.35 || ts < 0.15)
13526 hl = (int)(height * 0.25) + yDraw;
13528 arrow[1].y = hl + hs;
13531 dc.SetPen(*pyelo_pen);
13533 dc.SetPen(*pblue_pen);
13534 dc.DrawLines(3, arrow);
13536 if (ts > 0.60 || ts < 0.40)
13538 hl = (int)(height * 0.5) + yDraw;
13540 arrow[1].y = hl + hs;
13543 dc.SetPen(*pyelo_pen);
13545 dc.SetPen(*pblue_pen);
13546 dc.DrawLines(3, arrow);
13548 if (ts < 0.65 || ts > 0.85)
13550 hl = (int)(height * 0.75) + yDraw;
13552 arrow[1].y = hl + hs;
13555 dc.SetPen(*pyelo_pen);
13557 dc.SetPen(*pblue_pen);
13558 dc.DrawLines(3, arrow);
13562 s.Printf(
"%3.1f", nowlev);
13564 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13566 dc.GetTextExtent(s, &wx1, NULL);
13568 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13583void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13586 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13588 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13594 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13595 if ((BBox.Contains(lat, lon))) {
13597 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13603void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13606 float tcvalue, dir;
13610 double lon_last = 0.;
13611 double lat_last = 0.;
13613 double marge = 0.2;
13614 bool cur_time = !gTimeSource.IsValid();
13616 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13617 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13619 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13621 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13622 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13623 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13624 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13625 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13626 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13627 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13628 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13630 double skew_angle = GetVPRotation();
13632 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13633 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13634 int font_size = wxMax(10, dFont->GetPointSize());
13637 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13638 false, dFont->GetFaceName());
13640 float scale_factor = 1.0;
13646 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13648 float nominal_icon_size_pixels = 15;
13649 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13651 scale_factor *= pix_factor;
13658 scale_factor *= user_scale_factor;
13660 scale_factor *= GetContentScaleFactor();
13663 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13669 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13670 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13675 int dd = (int)(5.0 * scale_factor + 0.5);
13686 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13687 dc.SetPen(*pblack_pen);
13688 dc.SetBrush(*porange_brush);
13689 dc.DrawPolygon(4, d);
13692 dc.SetBrush(*pblack_brush);
13693 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13697 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13711 double a1 = fabs(tcvalue) * 10.;
13713 a1 = wxMax(1.0, a1);
13714 double a2 = log10(a1);
13716 float cscale = scale_factor * a2 * 0.3;
13718 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13719 dc.SetPen(*porange_pen);
13720 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13724 if (bDrawCurrentValues) {
13725 dc.SetFont(*pTCFont);
13726 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13727 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13753 if (!pvIDX)
return;
13758 if (pCwin && pCwin->IsShown()) {
13766 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13781 pCwin =
new TCWin(
this, x, y, pvIDX);
13799#define NUM_CURRENT_ARROW_POINTS 9
13800static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13801 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13802 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13803 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13805void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13807 if (
scale > 1e-2) {
13808 float sin_rot = sin(rot_angle * PI / 180.);
13809 float cos_rot = cos(rot_angle * PI / 180.);
13813 float xt = CurrentArrowArray[0].x;
13814 float yt = CurrentArrowArray[0].y;
13816 float xp = (xt * cos_rot) - (yt * sin_rot);
13817 float yp = (xt * sin_rot) + (yt * cos_rot);
13818 int x1 = (int)(xp *
scale);
13819 int y1 = (int)(yp *
scale);
13822 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13823 xt = CurrentArrowArray[ip].x;
13824 yt = CurrentArrowArray[ip].y;
13826 float xp = (xt * cos_rot) - (yt * sin_rot);
13827 float yp = (xt * sin_rot) + (yt * cos_rot);
13828 int x2 = (int)(xp *
scale);
13829 int y2 = (int)(yp *
scale);
13831 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13839wxString ChartCanvas::FindValidUploadPort() {
13842 if (!g_uploadConnection.IsEmpty() &&
13843 g_uploadConnection.StartsWith(
"Serial")) {
13844 port = g_uploadConnection;
13850 for (
auto *cp : TheConnectionParams()) {
13851 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13852 port <<
"Serial:" << cp->Port;
13858void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13861 if (NULL == g_pais_query_dialog_active) {
13862 int pos_x = g_ais_query_dialog_x;
13863 int pos_y = g_ais_query_dialog_y;
13865 if (g_pais_query_dialog_active) {
13866 g_pais_query_dialog_active->Destroy();
13872 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13873 wxPoint(pos_x, pos_y));
13875 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13876 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13877 g_pais_query_dialog_active->SetMMSI(mmsi);
13878 g_pais_query_dialog_active->UpdateText();
13879 wxSize sz = g_pais_query_dialog_active->GetSize();
13881 bool b_reset_pos =
false;
13886 RECT frame_title_rect;
13887 frame_title_rect.left = pos_x;
13888 frame_title_rect.top = pos_y;
13889 frame_title_rect.right = pos_x + sz.x;
13890 frame_title_rect.bottom = pos_y + 30;
13892 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13893 b_reset_pos =
true;
13898 wxRect window_title_rect;
13899 window_title_rect.x = pos_x;
13900 window_title_rect.y = pos_y;
13901 window_title_rect.width = sz.x;
13902 window_title_rect.height = 30;
13904 wxRect ClientRect = wxGetClientDisplayRect();
13905 ClientRect.Deflate(
13907 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13911 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13914 g_pais_query_dialog_active->SetMMSI(mmsi);
13915 g_pais_query_dialog_active->UpdateText();
13918 g_pais_query_dialog_active->Show();
13921void ChartCanvas::ToggleCanvasQuiltMode() {
13922 bool cur_mode = GetQuiltMode();
13924 if (!GetQuiltMode())
13925 SetQuiltMode(
true);
13926 else if (GetQuiltMode()) {
13927 SetQuiltMode(
false);
13928 g_sticky_chart = GetQuiltReferenceChartIndex();
13931 if (cur_mode != GetQuiltMode()) {
13932 SetupCanvasQuiltMode();
13941 if (ps52plib) ps52plib->GenerateStateHash();
13943 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13944 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13947void ChartCanvas::DoCanvasStackDelta(
int direction) {
13948 if (!GetQuiltMode()) {
13949 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13950 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13951 if ((current_stack_index + direction) < 0)
return;
13953 if (m_bpersistent_quilt ) {
13955 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13957 if (IsChartQuiltableRef(new_dbIndex)) {
13958 ToggleCanvasQuiltMode();
13959 SelectQuiltRefdbChart(new_dbIndex);
13960 m_bpersistent_quilt =
false;
13963 SelectChartFromStack(current_stack_index + direction);
13966 std::vector<int> piano_chart_index_array =
13967 GetQuiltExtendedStackdbIndexArray();
13968 int refdb = GetQuiltRefChartdbIndex();
13971 int current_index = -1;
13972 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13973 if (refdb == piano_chart_index_array[i]) {
13978 if (current_index == -1)
return;
13981 int target_family = ctet.GetChartFamily();
13983 int new_index = -1;
13984 int check_index = current_index + direction;
13985 bool found =
false;
13986 int check_dbIndex = -1;
13987 int new_dbIndex = -1;
13991 (
unsigned int)check_index < piano_chart_index_array.size() &&
13992 (check_index >= 0)) {
13993 check_dbIndex = piano_chart_index_array[check_index];
13995 if (target_family == cte.GetChartFamily()) {
13997 new_index = check_index;
13998 new_dbIndex = check_dbIndex;
14002 check_index += direction;
14005 if (!found)
return;
14007 if (!IsChartQuiltableRef(new_dbIndex)) {
14008 ToggleCanvasQuiltMode();
14009 SelectdbChart(new_dbIndex);
14010 m_bpersistent_quilt =
true;
14012 SelectQuiltRefChart(new_index);
14017 top_frame::Get()->UpdateGlobalMenuItems();
14018 SetQuiltChartHiLiteIndex(-1);
14029void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14032 switch (event.GetId()) {
14044 DoCanvasStackDelta(1);
14049 DoCanvasStackDelta(-1);
14059 ShowCurrents(!GetbShowCurrent());
14066 ShowTides(!GetbShowTide());
14073 if (0 == m_routeState) {
14080 androidSetRouteAnnunciator(m_routeState == 1);
14086 SetAISCanvasDisplayStyle(-1);
14098void ChartCanvas::SetShowAIS(
bool show) {
14100 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14101 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14104void ChartCanvas::SetAttenAIS(
bool show) {
14105 m_bShowAISScaled = show;
14106 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14107 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14110void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14113 bool bShowAIS_Array[3] = {
true,
true,
false};
14114 bool bShowScaled_Array[3] = {
false,
true,
true};
14115 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14116 _(
"Attenuate less critical AIS targets"),
14117 _(
"Hide AIS Targets")};
14118 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14120 int AIS_Toolbar_Switch = 0;
14121 if (StyleIndx == -1) {
14123 for (
int i = 1; i < ArraySize; i++) {
14124 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14125 (bShowScaled_Array[i] == m_bShowAISScaled))
14126 AIS_Toolbar_Switch = i;
14128 AIS_Toolbar_Switch++;
14129 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14130 AIS_Toolbar_Switch++;
14133 AIS_Toolbar_Switch = StyleIndx;
14136 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14138 int AIS_Toolbar_Switch_Next =
14139 AIS_Toolbar_Switch + 1;
14140 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14141 AIS_Toolbar_Switch_Next++;
14142 if (AIS_Toolbar_Switch_Next >= ArraySize)
14143 AIS_Toolbar_Switch_Next = 0;
14146 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14147 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14150void ChartCanvas::TouchAISToolActive() {}
14152void ChartCanvas::UpdateAISTBTool() {}
14160void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14162 bool b_update =
false;
14163 int cc1_edge_comp = 2;
14164 wxRect rect = m_Compass->
GetRect();
14165 wxSize parent_size = GetSize();
14167 parent_size *= m_displayScale;
14171 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14172 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14173 wxRect compass_rect(compass_pt, rect.GetSize());
14175 m_Compass->Move(compass_pt);
14177 if (m_Compass && m_Compass->IsShown())
14178 m_Compass->UpdateStatus(b_force_new | b_update);
14180 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14181 scaler = wxMax(scaler, 1.0);
14182 wxPoint note_point = wxPoint(
14183 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14184 if (m_notification_button) {
14185 m_notification_button->Move(note_point);
14186 m_notification_button->UpdateStatus();
14189 if (b_force_new | b_update) Refresh();
14192void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14193 ChartTypeEnum New_Type,
14194 ChartFamilyEnum New_Family) {
14195 if (!GetpCurrentStack())
return;
14198 if (index < GetpCurrentStack()->nEntry) {
14201 pTentative_Chart =
ChartData->OpenStackChartConditional(
14202 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14204 if (pTentative_Chart) {
14205 if (m_singleChart) m_singleChart->Deactivate();
14207 m_singleChart = pTentative_Chart;
14208 m_singleChart->Activate();
14210 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14211 GetpCurrentStack(), m_singleChart->GetFullPath());
14224 double best_scale_ppm = GetBestVPScale(m_singleChart);
14225 double rotation = GetVPRotation();
14226 double oldskew = GetVPSkew();
14227 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14229 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14230 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14231 if (fabs(newskew) > 0.0001) rotation = newskew;
14234 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14236 UpdateGPSCompassStatusBox(
true);
14240 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14241 if (idx < 0)
return;
14243 std::vector<int> piano_active_chart_index_array;
14244 piano_active_chart_index_array.push_back(
14245 GetpCurrentStack()->GetCurrentEntrydbIndex());
14246 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14249void ChartCanvas::SelectdbChart(
int dbindex) {
14250 if (!GetpCurrentStack())
return;
14253 if (dbindex >= 0) {
14256 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14258 if (pTentative_Chart) {
14259 if (m_singleChart) m_singleChart->Deactivate();
14261 m_singleChart = pTentative_Chart;
14262 m_singleChart->Activate();
14264 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14265 GetpCurrentStack(), m_singleChart->GetFullPath());
14278 double best_scale_ppm = GetBestVPScale(m_singleChart);
14282 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14292void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14295 if (!GetQuiltMode()) {
14296 if (GetpCurrentStack()) {
14297 int stack_index = -1;
14298 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14299 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14300 if (check_dbIndex < 0)
continue;
14302 ChartData->GetChartTableEntry(check_dbIndex);
14303 if (type == cte.GetChartType()) {
14306 }
else if (family == cte.GetChartFamily()) {
14312 if (stack_index >= 0) {
14313 SelectChartFromStack(stack_index);
14317 int sel_dbIndex = -1;
14318 std::vector<int> piano_chart_index_array =
14319 GetQuiltExtendedStackdbIndexArray();
14320 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14321 int check_dbIndex = piano_chart_index_array[i];
14323 if (type == cte.GetChartType()) {
14324 if (IsChartQuiltableRef(check_dbIndex)) {
14325 sel_dbIndex = check_dbIndex;
14328 }
else if (family == cte.GetChartFamily()) {
14329 if (IsChartQuiltableRef(check_dbIndex)) {
14330 sel_dbIndex = check_dbIndex;
14336 if (sel_dbIndex >= 0) {
14337 SelectQuiltRefdbChart(sel_dbIndex,
false);
14339 AdjustQuiltRefChart();
14346 SetQuiltChartHiLiteIndex(-1);
14351bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14352 return std::find(m_tile_yesshow_index_array.begin(),
14353 m_tile_yesshow_index_array.end(),
14354 index) != m_tile_yesshow_index_array.end();
14357bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14358 return std::find(m_tile_noshow_index_array.begin(),
14359 m_tile_noshow_index_array.end(),
14360 index) != m_tile_noshow_index_array.end();
14363void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14364 if (std::find(m_tile_noshow_index_array.begin(),
14365 m_tile_noshow_index_array.end(),
14366 index) == m_tile_noshow_index_array.end()) {
14367 m_tile_noshow_index_array.push_back(index);
14377void ChartCanvas::HandlePianoClick(
14378 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14381 if (!m_pCurrentStack)
return;
14397 double distance = 25000;
14398 int closest_index = -1;
14399 for (
int chart_index : selected_dbIndex_array) {
14401 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14402 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14405 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14406 if (test_distance < distance) {
14407 distance = test_distance;
14408 closest_index = chart_index;
14412 int selected_dbIndex = selected_dbIndex_array[0];
14413 if (closest_index >= 0) selected_dbIndex = closest_index;
14415 if (!GetQuiltMode()) {
14416 if (m_bpersistent_quilt ) {
14417 if (IsChartQuiltableRef(selected_dbIndex)) {
14418 ToggleCanvasQuiltMode();
14419 SelectQuiltRefdbChart(selected_dbIndex);
14420 m_bpersistent_quilt =
false;
14422 SelectChartFromStack(selected_index);
14425 SelectChartFromStack(selected_index);
14426 g_sticky_chart = selected_dbIndex;
14430 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14434 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14435 bool bfound =
false;
14436 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14437 if (m_tile_noshow_index_array[i] ==
14438 selected_dbIndex) {
14439 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14446 m_tile_noshow_index_array.push_back(selected_dbIndex);
14450 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14451 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14455 if (IsChartQuiltableRef(selected_dbIndex)) {
14461 bool set_scale =
false;
14462 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14463 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14469 SelectQuiltRefdbChart(selected_dbIndex,
true);
14471 SelectQuiltRefdbChart(selected_dbIndex,
false);
14476 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14478 double proposed_scale_onscreen =
14481 if (g_bPreserveScaleOnX) {
14482 proposed_scale_onscreen =
14483 wxMin(proposed_scale_onscreen,
14485 GetCanvasWidth()));
14487 proposed_scale_onscreen =
14488 wxMin(proposed_scale_onscreen,
14490 GetCanvasWidth()));
14492 proposed_scale_onscreen =
14493 wxMax(proposed_scale_onscreen,
14502 ToggleCanvasQuiltMode();
14503 SelectdbChart(selected_dbIndex);
14504 m_bpersistent_quilt =
true;
14509 SetQuiltChartHiLiteIndex(-1);
14511 top_frame::Get()->UpdateGlobalMenuItems();
14512 HideChartInfoWindow();
14517void ChartCanvas::HandlePianoRClick(
14518 int x,
int y,
int selected_index,
14519 const std::vector<int> &selected_dbIndex_array) {
14522 if (!GetpCurrentStack())
return;
14524 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14525 UpdateCanvasControlBar();
14527 SetQuiltChartHiLiteIndex(-1);
14530void ChartCanvas::HandlePianoRollover(
14531 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14532 int n_charts,
int scale) {
14535 if (!GetpCurrentStack())
return;
14540 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14542 if (!GetQuiltMode()) {
14543 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14546 std::vector<int> piano_chart_index_array;
14547 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14548 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14549 if ((GetpCurrentStack()->nEntry > 1) ||
14550 (piano_chart_index_array.size() >= 1)) {
14551 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14553 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14555 }
else if (GetpCurrentStack()->nEntry == 1) {
14557 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14558 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14559 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14561 }
else if ((-1 == selected_index) &&
14562 (0 == selected_dbIndex_array.size())) {
14563 ShowChartInfoWindow(key_location.x, -1);
14567 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14569 if ((GetpCurrentStack()->nEntry > 1) ||
14570 (piano_chart_index_array.size() >= 1)) {
14572 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14573 selected_dbIndex_array);
14574 else if (n_charts == 1)
14575 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14577 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14584void ChartCanvas::ClearPianoRollover() {
14585 ClearQuiltChartHiLiteIndexArray();
14586 ShowChartInfoWindow(0, -1);
14587 std::vector<int> vec;
14588 ShowCompositeInfoWindow(0, 0, 0, vec);
14592void ChartCanvas::UpdateCanvasControlBar() {
14593 if (m_pianoFrozen)
return;
14595 if (!GetpCurrentStack())
return;
14597 if (!g_bShowChartBar)
return;
14600 int sel_family = -1;
14602 std::vector<int> piano_chart_index_array;
14603 std::vector<int> empty_piano_chart_index_array;
14605 wxString old_hash = m_Piano->GetStoredHash();
14607 if (GetQuiltMode()) {
14608 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14609 GetQuiltFullScreendbIndexArray());
14611 std::vector<int> piano_active_chart_index_array =
14612 GetQuiltCandidatedbIndexArray();
14613 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14615 std::vector<int> piano_eclipsed_chart_index_array =
14616 GetQuiltEclipsedStackdbIndexArray();
14617 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14619 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14620 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14622 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14623 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14625 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14626 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14629 if (m_singleChart) {
14630 sel_type = m_singleChart->GetChartType();
14631 sel_family = m_singleChart->GetChartFamily();
14636 std::vector<int> piano_skew_chart_index_array;
14637 std::vector<int> piano_tmerc_chart_index_array;
14638 std::vector<int> piano_poly_chart_index_array;
14640 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14642 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14643 double skew_norm = ctei.GetChartSkew();
14644 if (skew_norm > 180.) skew_norm -= 360.;
14646 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14647 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14650 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14651 if (fabs(skew_norm) > 1.)
14652 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14654 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14655 }
else if (fabs(skew_norm) > 1.)
14656 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14658 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14659 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14660 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14662 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14663 if (new_hash != old_hash) {
14664 m_Piano->FormatKeys();
14665 HideChartInfoWindow();
14666 m_Piano->ResetRollover();
14667 SetQuiltChartHiLiteIndex(-1);
14668 m_brepaint_piano =
true;
14674 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14676 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14677 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14678 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14679 if (e == CHART_FAMILY_RASTER) mask |= 1;
14680 if (e == CHART_FAMILY_VECTOR) {
14681 if (t == CHART_TYPE_CM93COMP)
14688 wxString s_indicated;
14689 if (sel_type == CHART_TYPE_CM93COMP)
14690 s_indicated =
"cm93";
14692 if (sel_family == CHART_FAMILY_RASTER)
14693 s_indicated =
"raster";
14694 else if (sel_family == CHART_FAMILY_VECTOR)
14695 s_indicated =
"vector";
14698 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14701void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14703void ChartCanvas::PianoPopupMenu(
14704 int x,
int y,
int selected_index,
14705 const std::vector<int> &selected_dbIndex_array) {
14706 if (!GetpCurrentStack())
return;
14709 if (!GetQuiltMode())
return;
14711 m_piano_ctx_menu =
new wxMenu();
14713 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14723 menu_selected_dbIndex = selected_dbIndex_array[0];
14724 menu_selected_index = selected_index;
14727 bool b_is_in_noshow =
false;
14728 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14729 if (m_quilt_noshow_index_array[i] ==
14730 menu_selected_dbIndex)
14732 b_is_in_noshow =
true;
14737 if (b_is_in_noshow) {
14738 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14739 _(
"Show This Chart"));
14740 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14741 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14742 }
else if (GetpCurrentStack()->nEntry > 1) {
14743 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14744 _(
"Hide This Chart"));
14745 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14746 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14750 wxPoint pos = wxPoint(x, y - 30);
14753 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14754 PopupMenu(m_piano_ctx_menu, pos);
14756 delete m_piano_ctx_menu;
14757 m_piano_ctx_menu = NULL;
14759 HideChartInfoWindow();
14760 m_Piano->ResetRollover();
14762 SetQuiltChartHiLiteIndex(-1);
14763 ClearQuiltChartHiLiteIndexArray();
14768void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14769 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14770 if (m_quilt_noshow_index_array[i] ==
14771 menu_selected_dbIndex)
14773 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14779void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14780 if (!GetpCurrentStack())
return;
14783 RemoveChartFromQuilt(menu_selected_dbIndex);
14787 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14788 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14790 int i = menu_selected_index + 1;
14791 bool b_success =
false;
14792 while (i < GetpCurrentStack()->nEntry - 1) {
14793 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14794 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14795 SelectQuiltRefChart(i);
14805 i = menu_selected_index - 1;
14807 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14808 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14809 SelectQuiltRefChart(i);
14819void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14821 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14822 if (m_quilt_noshow_index_array[i] ==
14825 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14830 m_quilt_noshow_index_array.push_back(dbIndex);
14833bool ChartCanvas::UpdateS52State() {
14834 bool retval =
false;
14837 ps52plib->SetShowS57Text(m_encShowText);
14838 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14839 ps52plib->m_bShowSoundg = m_encShowDepth;
14840 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14841 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14844 if (!m_encShowLights)
14845 ps52plib->AddObjNoshow(
"LIGHTS");
14847 ps52plib->RemoveObjNoshow(
"LIGHTS");
14848 ps52plib->SetLightsOff(!m_encShowLights);
14849 ps52plib->m_bExtendLightSectors =
true;
14852 ps52plib->SetAnchorOn(m_encShowAnchor);
14853 ps52plib->SetQualityOfData(m_encShowDataQual);
14859void ChartCanvas::SetShowENCDataQual(
bool show) {
14860 m_encShowDataQual = show;
14861 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14862 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14864 m_s52StateHash = 0;
14867void ChartCanvas::SetShowENCText(
bool show) {
14868 m_encShowText = show;
14869 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14870 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14872 m_s52StateHash = 0;
14875void ChartCanvas::SetENCDisplayCategory(
int category) {
14876 m_encDisplayCategory = category;
14877 m_s52StateHash = 0;
14880void ChartCanvas::SetShowENCDepth(
bool show) {
14881 m_encShowDepth = show;
14882 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14883 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14885 m_s52StateHash = 0;
14888void ChartCanvas::SetShowENCLightDesc(
bool show) {
14889 m_encShowLightDesc = show;
14890 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14891 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14893 m_s52StateHash = 0;
14896void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14897 m_encShowBuoyLabels = show;
14898 m_s52StateHash = 0;
14901void ChartCanvas::SetShowENCLights(
bool show) {
14902 m_encShowLights = show;
14903 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14904 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14906 m_s52StateHash = 0;
14909void ChartCanvas::SetShowENCAnchor(
bool show) {
14910 m_encShowAnchor = show;
14911 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14912 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14914 m_s52StateHash = 0;
14917wxRect ChartCanvas::GetMUIBarRect() {
14920 rv = m_muiBar->GetRect();
14926void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14927 if (!GetAlertString().IsEmpty()) {
14928 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14929 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14931 dc.SetFont(*pfont);
14932 dc.SetPen(*wxTRANSPARENT_PEN);
14934 dc.SetBrush(wxColour(243, 229, 47));
14936 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14940 wxRect sbr = GetScaleBarRect();
14941 int xp = sbr.x + sbr.width + 10;
14942 int yp = (sbr.y + sbr.height) - h;
14944 int wdraw = w + 10;
14945 dc.DrawRectangle(xp, yp, wdraw, h);
14946 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14947 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14957#define BRIGHT_XCALIB
14958#define __OPCPN_USEICC__
14961#ifdef __OPCPN_USEICC__
14962int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14963 double co_green,
double co_blue);
14965wxString temp_file_name;
14969class ocpnCurtain:
public wxDialog
14971 DECLARE_CLASS( ocpnCurtain )
14972 DECLARE_EVENT_TABLE()
14975 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14977 bool ProcessEvent(wxEvent& event);
14981IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14983BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14986ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14988 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14991ocpnCurtain::~ocpnCurtain()
14995bool ocpnCurtain::ProcessEvent(wxEvent& event)
14997 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14998 return GetParent()->GetEventHandler()->ProcessEvent(event);
15003#include <windows.h>
15006typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15007typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15008SetDeviceGammaRamp_ptr_type
15009 g_pSetDeviceGammaRamp;
15010GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15012WORD *g_pSavedGammaMap;
15016int InitScreenBrightness() {
15019 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15023 if (NULL == hGDI32DLL) {
15024 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15026 if (NULL != hGDI32DLL) {
15028 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15029 hGDI32DLL,
"SetDeviceGammaRamp");
15030 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15031 hGDI32DLL,
"GetDeviceGammaRamp");
15034 if ((NULL == g_pSetDeviceGammaRamp) ||
15035 (NULL == g_pGetDeviceGammaRamp)) {
15036 FreeLibrary(hGDI32DLL);
15045 if (!g_pSavedGammaMap) {
15046 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15049 bbr = g_pGetDeviceGammaRamp(
15050 hDC, g_pSavedGammaMap);
15051 ReleaseDC(NULL, hDC);
15056 wxRegKey *pRegKey =
new wxRegKey(
15057 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15058 "NT\\CurrentVersion\\ICM");
15059 if (!pRegKey->Exists()) pRegKey->Create();
15060 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15062 g_brightness_init =
true;
15068 if (NULL == g_pcurtain) {
15069 if (top_frame::Get()->CanSetTransparent()) {
15071 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15072 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15073 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15074 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15081 g_pcurtain->Hide();
15083 HWND hWnd = GetHwndOf(g_pcurtain);
15084 SetWindowLong(hWnd, GWL_EXSTYLE,
15085 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15086 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15087 g_pcurtain->SetTransparent(0);
15089 g_pcurtain->Maximize();
15090 g_pcurtain->Show();
15093 g_pcurtain->Enable();
15094 g_pcurtain->Disable();
15096 top_frame::Get()->Disable();
15097 top_frame::Get()->Enable();
15101 g_brightness_init =
true;
15107 wxString cmd(
"xcalib -version");
15109 wxArrayString output;
15110 long r = wxExecute(cmd, output);
15113 " External application \"xcalib\" not found. Screen brightness "
15116 g_brightness_init =
true;
15121int RestoreScreenBrightness() {
15124 if (g_pSavedGammaMap) {
15125 HDC hDC = GetDC(NULL);
15126 g_pSetDeviceGammaRamp(hDC,
15128 ReleaseDC(NULL, hDC);
15130 free(g_pSavedGammaMap);
15131 g_pSavedGammaMap = NULL;
15135 g_pcurtain->Close();
15136 g_pcurtain->Destroy();
15140 g_brightness_init =
false;
15145#ifdef BRIGHT_XCALIB
15146 if (g_brightness_init) {
15148 cmd =
"xcalib -clear";
15149 wxExecute(cmd, wxEXEC_ASYNC);
15150 g_brightness_init =
false;
15160int SetScreenBrightness(
int brightness) {
15167 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15169 g_pcurtain->Close();
15170 g_pcurtain->Destroy();
15174 InitScreenBrightness();
15176 if (NULL == hGDI32DLL) {
15178 wchar_t wdll_name[80];
15179 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15180 LPCWSTR cstr = wdll_name;
15182 hGDI32DLL = LoadLibrary(cstr);
15184 if (NULL != hGDI32DLL) {
15186 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15187 hGDI32DLL,
"SetDeviceGammaRamp");
15188 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15189 hGDI32DLL,
"GetDeviceGammaRamp");
15192 if ((NULL == g_pSetDeviceGammaRamp) ||
15193 (NULL == g_pGetDeviceGammaRamp)) {
15194 FreeLibrary(hGDI32DLL);
15201 HDC hDC = GetDC(NULL);
15212 int increment = brightness * 256 / 100;
15215 WORD GammaTable[3][256];
15218 for (
int i = 0; i < 256; i++) {
15219 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15220 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15221 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15223 table_val += increment;
15225 if (table_val > 65535) table_val = 65535;
15228 g_pSetDeviceGammaRamp(hDC, GammaTable);
15229 ReleaseDC(NULL, hDC);
15236 if (g_pSavedGammaMap) {
15237 HDC hDC = GetDC(NULL);
15238 g_pSetDeviceGammaRamp(hDC,
15240 ReleaseDC(NULL, hDC);
15243 if (brightness < 100) {
15244 if (NULL == g_pcurtain) InitScreenBrightness();
15247 int sbrite = wxMax(1, brightness);
15248 sbrite = wxMin(100, sbrite);
15250 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15254 g_pcurtain->Close();
15255 g_pcurtain->Destroy();
15265#ifdef BRIGHT_XCALIB
15267 if (!g_brightness_init) {
15268 last_brightness = 100;
15269 g_brightness_init =
true;
15270 temp_file_name = wxFileName::CreateTempFileName(
"");
15271 InitScreenBrightness();
15274#ifdef __OPCPN_USEICC__
15277 if (!CreateSimpleICCProfileFile(
15278 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15279 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15280 wxString cmd(
"xcalib ");
15281 cmd += temp_file_name;
15283 wxExecute(cmd, wxEXEC_ASYNC);
15292 if (brightness > last_brightness) {
15294 cmd =
"xcalib -clear";
15295 wxExecute(cmd, wxEXEC_ASYNC);
15297 ::wxMilliSleep(10);
15299 int brite_adj = wxMax(1, brightness);
15300 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15301 wxExecute(cmd, wxEXEC_ASYNC);
15303 int brite_adj = wxMax(1, brightness);
15304 int factor = (brite_adj * 100) / last_brightness;
15305 factor = wxMax(1, factor);
15307 cmd.Printf(
"xcalib -co %2d -a", factor);
15308 wxExecute(cmd, wxEXEC_ASYNC);
15313 last_brightness = brightness;
15320#ifdef __OPCPN_USEICC__
15322#define MLUT_TAG 0x6d4c5554L
15323#define VCGT_TAG 0x76636774L
15325int GetIntEndian(
unsigned char *s) {
15330 p = (
unsigned char *)&ret;
15333 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15335 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15340unsigned short GetShortEndian(
unsigned char *s) {
15341 unsigned short ret;
15345 p = (
unsigned char *)&ret;
15348 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15350 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15356int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15357 double co_green,
double co_blue) {
15361 fp = fopen(file_name,
"wb");
15362 if (!fp)
return -1;
15368 for (
int i = 0; i < 128; i++) header[i] = 0;
15370 fwrite(header, 128, 1, fp);
15374 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15375 fwrite(&numTags, 1, 4, fp);
15377 int tagName0 = VCGT_TAG;
15378 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15379 fwrite(&tagName, 1, 4, fp);
15381 int tagOffset0 = 128 + 4 *
sizeof(int);
15382 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15383 fwrite(&tagOffset, 1, 4, fp);
15386 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15387 fwrite(&tagSize, 1, 4, fp);
15389 fwrite(&tagName, 1, 4, fp);
15391 fwrite(&tagName, 1, 4, fp);
15396 int gammatype0 = 0;
15397 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15398 fwrite(&gammatype, 1, 4, fp);
15400 int numChannels0 = 3;
15401 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15402 fwrite(&numChannels, 1, 2, fp);
15404 int numEntries0 = 256;
15405 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15406 fwrite(&numEntries, 1, 2, fp);
15408 int entrySize0 = 1;
15409 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15410 fwrite(&entrySize, 1, 2, fp);
15412 unsigned char ramp[256];
15415 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15416 fwrite(ramp, 256, 1, fp);
15419 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15420 fwrite(ramp, 256, 1, fp);
15423 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15424 fwrite(ramp, 256, 1, fp);
Select * pSelectAIS
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetQueryDialog.
std::unique_ptr< HostApi > GetHostApi()
HostApi factory,.
Chart canvas configuration state
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
ChartCanvas * g_focusCanvas
Global instance.
arrayofCanvasPtr g_canvasArray
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Minimal ChartCAnvas interface with very little dependencies.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void CloseTideDialog()
Close any open tide dialog.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
void OnPaint(wxPaintEvent &event)
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void DoMovement(long dt)
Performs a step of smooth movement animation on the chart canvas.
void ShowSingleTideDialog(int x, int y, void *pvIDX)
Display tide/current dialog with single-instance management.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
int PrepareContextSelections(double lat, double lon)
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
EventVar json_msg
Notified with message targeting all plugins.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
bool IsTideDialogOpen() const
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Centers the view on a specific lat/lon position.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
int station_tz_offset
Offset in seconds to convert from harmonic data (epochs) to the station time zone.
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
Data for a loaded plugin, including dl-loaded library.
int m_cap_flag
PlugIn Capabilities descriptor.
PluginLoader is a backend module without any direct GUI functionality.
const ArrayOfPlugIns * GetPlugInArray()
Return list of currently loaded plugins.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute)
Dialog for displaying query results of S57 objects.
IDX_entry * GetCurrentIDX() const
Represents a single point in a track.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
APConsole * console
Global instance.
Primary navigation console display for route and vessel tracking.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
bool g_bRollover
enable/disable mouse rollover GUI effects
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
double g_display_size_mm
Physical display width (mm)
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
GoToPositionDialog * pGoToPositionDialog
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Hooks into gui available in model.
size_t g_current_monitor
Current monitor displaying main application frame.
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
bool g_b_overzoom_x
Allow high overzoom.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Hotheys help dialog (the '?' button).
GUI constant definitions.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
double AnchorDistFix(double const d, double const AnchorPointMinDist, double const AnchorPointMaxDist)
Return constrained value of d so that AnchorPointMinDist < abs(d) < AnchorPointMaxDist.
MySQL based storage for routes, tracks, etc.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
User notifications manager.
Notification Manager GUI.
OCPN_AUIManager * g_pauimgr
Global instance.
Optimized wxBitmap Object.
ChartFamilyEnumPI
Enumeration of chart families (broad categories).
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
int GetChartbarHeight()
Gets height of chart bar in pixels.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Miscellaneous utilities, many of which string related.
Layer to use wxDC or opengl.
options * g_options
Global instance.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
double gHdt
True heading in degrees (0-359.99).
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Purpose: Track and Trackpoint drawing stuff.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
RoutePoint * pAnchorWatchPoint2
Global instance.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RoutePoint * pAnchorWatchPoint1
Global instance.
float g_ChartScaleFactorExp
Global instance.
RouteManagerDialog * pRouteManagerDialog
Global instance.
S57QueryDialog * g_pObjectQueryDialog
Global instance.
S57 object query result window.
Select * pSelect
Global instance.
Select * pSelectTC
Global instance.
Selected route, segment, waypoint, etc.
A single, selected generic item.
SENCThreadManager * g_SencThreadManager
Global instance.
ShapeBaseChartSet gShapeBasemap
global instance
Represents an entry in the chart table, containing information about a single chart.
Tide and currents window.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
Timer identification constants.
Abstract gFrame/MyFrame interface.
ActiveTrack * g_pActiveTrack
global instance
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Track and Trackpoint drawing stuff.
TrackPropDlg * pTrackPropDialog
Global instance.
Framework for Undo features.