35#include <wx/graphics.h>
36#include <wx/clipbrd.h>
37#include <wx/aui/aui.h>
41#include "o_sound/o_sound.h"
48#include "model/geodesic.h"
54#include "model/nav_object_database.h"
116#include "tide_time.h"
123#include "user_colors.h"
125#include "s57_ocpn_utils.h"
128#include "androidUTIL.h"
138#include <wx/msw/msvcrt.h>
147#define printf printf2
149int __cdecl printf2(
const char *format, ...) {
153 va_start(argptr, format);
154 int ret = vsnprintf(str,
sizeof(str), format, argptr);
156 OutputDebugStringA(str);
161#if defined(__MSVC__) && (_MSC_VER < 1700)
162#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
168#define OCPN_ALT_MENUBAR 1
175static bool g_bSmoothRecenter =
true;
176static bool bDrawCurrentValues;
197static bool mouse_leftisdown;
198static bool g_brouteCreating;
199static int r_gamma_mult;
200static int g_gamma_mult;
201static int b_gamma_mult;
202static int gamma_state;
203static bool g_brightness_init;
204static int last_brightness;
205static wxGLContext *g_pGLcontext;
208static wxDialog *g_pcurtain;
210static wxString g_lastS52PLIBPluginMessage;
213#define MAX_BRIGHT 100
220EVT_ACTIVATE(ChartCanvas::OnActivate)
221EVT_SIZE(ChartCanvas::OnSize)
222#ifndef HAVE_WX_GESTURE_EVENTS
223EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
225EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
226EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
227EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
228EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
229EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
230EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
231EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
232EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
233EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
234EVT_KEY_UP(ChartCanvas::OnKeyUp)
235EVT_CHAR(ChartCanvas::OnKeyChar)
236EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
237EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
238EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
239EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
240EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
241EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
242EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
243EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
244EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
245EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
252 m_nmea_log(nmea_log) {
253 parent_frame = frame;
254 m_canvasIndex = canvasIndex;
258 SetBackgroundColour(wxColour(0, 0, 0));
259 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
263 m_bDrawingRoute =
false;
264 m_bRouteEditing =
false;
265 m_bMarkEditing =
false;
266 m_bRoutePoinDragging =
false;
267 m_bIsInRadius =
false;
268 m_bMayToggleMenuBar =
true;
271 m_bShowNavobjects =
true;
273 m_bAppendingRoute =
false;
274 pThumbDIBShow = NULL;
275 m_bShowCurrent =
false;
277 bShowingCurrent =
false;
281 m_b_paint_enable =
true;
284 pss_overlay_bmp = NULL;
285 pss_overlay_mask = NULL;
286 m_bChartDragging =
false;
287 m_bMeasure_Active =
false;
288 m_bMeasure_DistCircle =
false;
289 m_pMeasureRoute = NULL;
290 m_pTrackRolloverWin = NULL;
291 m_pRouteRolloverWin = NULL;
292 m_pAISRolloverWin = NULL;
294 m_disable_edge_pan =
false;
295 m_dragoffsetSet =
false;
299 m_singleChart = NULL;
300 m_upMode = NORTH_UP_MODE;
302 m_bShowAISScaled =
false;
303 m_timed_move_vp_active =
false;
305 m_disable_adjust_on_zoom =
false;
312 m_pSelectedRoute = NULL;
313 m_pSelectedTrack = NULL;
314 m_pRoutePointEditTarget = NULL;
315 m_pFoundPoint = NULL;
316 m_pMouseRoute = NULL;
317 m_prev_pMousePoint = NULL;
318 m_pEditRouteArray = NULL;
319 m_pFoundRoutePoint = NULL;
320 m_FinishRouteOnKillFocus =
true;
322 m_pRolloverRouteSeg = NULL;
323 m_pRolloverTrackSeg = NULL;
324 m_bsectors_shown =
false;
326 m_bbrightdir =
false;
331 m_pos_image_user_day = NULL;
332 m_pos_image_user_dusk = NULL;
333 m_pos_image_user_night = NULL;
334 m_pos_image_user_grey_day = NULL;
335 m_pos_image_user_grey_dusk = NULL;
336 m_pos_image_user_grey_night = NULL;
339 m_rotation_speed = 0;
345 m_pos_image_user_yellow_day = NULL;
346 m_pos_image_user_yellow_dusk = NULL;
347 m_pos_image_user_yellow_night = NULL;
349 SetOwnShipState(SHIP_INVALID);
351 undo =
new Undo(
this);
357 m_focus_indicator_pix = 1;
359 m_pCurrentStack = NULL;
360 m_bpersistent_quilt =
false;
361 m_piano_ctx_menu = NULL;
363 m_NotificationsList = NULL;
364 m_notification_button = NULL;
366 g_ChartNotRenderScaleFactor = 2.0;
367 m_bShowScaleInStatusBar =
true;
370 m_bShowScaleInStatusBar =
false;
371 m_show_focus_bar =
true;
373 m_bShowOutlines =
false;
374 m_bDisplayGrid =
false;
375 m_bShowDepthUnits =
true;
376 m_encDisplayCategory = (int)STANDARD;
378 m_encShowLights =
true;
379 m_encShowAnchor =
true;
380 m_encShowDataQual =
false;
382 m_pQuilt =
new Quilt(
this);
387 g_PrintingInProgress =
false;
389#ifdef HAVE_WX_GESTURE_EVENTS
390 m_oldVPSScale = -1.0;
391 m_popupWanted =
false;
394 m_inLongPress =
false;
397 m_sw_left_down.Start();
398 m_sw_left_up.Start();
402 singleClickEventIsValid =
false;
411 pCursorPencil = NULL;
416 SetCursor(*pCursorArrow);
418 pPanTimer =
new wxTimer(
this, m_MouseDragging);
421 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
422 pMovementTimer->Stop();
424 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
425 pMovementStopTimer->Stop();
427 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
428 pRotDefTimer->Stop();
430 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
431 m_DoubleClickTimer->Stop();
433 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
434 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
435 m_chart_drag_inertia_active =
false;
437 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
438 m_animationActive =
false;
439 m_menuTimer.SetOwner(
this, MENU_TIMER);
440 m_tap_timer.SetOwner(
this, TAP_TIMER);
444 m_panx_target_final = m_pany_target_final = 0;
445 m_panx_target_now = m_pany_target_now = 0;
448 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
449 pCurTrackTimer->Stop();
450 m_curtrack_timer_msec = 10;
452 m_wheelzoom_stop_oneshot = 0;
453 m_last_wheel_dir = 0;
455 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
457 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
459 m_rollover_popup_timer_msec = 20;
461 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
463 m_b_rot_hidef =
true;
468 m_upMode = NORTH_UP_MODE;
469 m_bLookAhead =
false;
473 m_cs = GLOBAL_COLOR_SCHEME_DAY;
476 VPoint.view_scale_ppm = 1;
480 m_canvas_scale_factor = 1.;
482 m_canvas_width = 1000;
484 m_overzoomTextWidth = 0;
485 m_overzoomTextHeight = 0;
494 m_pEM_Fathoms = NULL;
496 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
498 m_pEM_OverZoom = NULL;
500 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
508 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
511 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
514 double factor_dusk = 0.5;
515 double factor_night = 0.25;
518 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
520 int rimg_width = m_os_image_red_day.GetWidth();
521 int rimg_height = m_os_image_red_day.GetHeight();
523 m_os_image_red_dusk = m_os_image_red_day.Copy();
524 m_os_image_red_night = m_os_image_red_day.Copy();
526 for (
int iy = 0; iy < rimg_height; iy++) {
527 for (
int ix = 0; ix < rimg_width; ix++) {
528 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
529 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
530 m_os_image_red_day.GetGreen(ix, iy),
531 m_os_image_red_day.GetBlue(ix, iy));
532 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
533 hsv.value = hsv.value * factor_dusk;
534 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
535 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
537 hsv = wxImage::RGBtoHSV(rgb);
538 hsv.value = hsv.value * factor_night;
539 nrgb = wxImage::HSVtoRGB(hsv);
540 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
546 m_os_image_grey_day =
547 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
549 int gimg_width = m_os_image_grey_day.GetWidth();
550 int gimg_height = m_os_image_grey_day.GetHeight();
552 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
553 m_os_image_grey_night = m_os_image_grey_day.Copy();
555 for (
int iy = 0; iy < gimg_height; iy++) {
556 for (
int ix = 0; ix < gimg_width; ix++) {
557 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
558 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
559 m_os_image_grey_day.GetGreen(ix, iy),
560 m_os_image_grey_day.GetBlue(ix, iy));
561 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
562 hsv.value = hsv.value * factor_dusk;
563 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
564 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
566 hsv = wxImage::RGBtoHSV(rgb);
567 hsv.value = hsv.value * factor_night;
568 nrgb = wxImage::HSVtoRGB(hsv);
569 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
575 m_os_image_yellow_day = m_os_image_red_day.Copy();
577 gimg_width = m_os_image_yellow_day.GetWidth();
578 gimg_height = m_os_image_yellow_day.GetHeight();
580 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
581 m_os_image_yellow_night = m_os_image_red_day.Copy();
583 for (
int iy = 0; iy < gimg_height; iy++) {
584 for (
int ix = 0; ix < gimg_width; ix++) {
585 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
586 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
587 m_os_image_yellow_day.GetGreen(ix, iy),
588 m_os_image_yellow_day.GetBlue(ix, iy));
589 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
590 hsv.hue += 60. / 360.;
591 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
592 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
594 hsv = wxImage::RGBtoHSV(rgb);
595 hsv.value = hsv.value * factor_dusk;
596 hsv.hue += 60. / 360.;
597 nrgb = wxImage::HSVtoRGB(hsv);
598 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
600 hsv = wxImage::RGBtoHSV(rgb);
601 hsv.hue += 60. / 360.;
602 hsv.value = hsv.value * factor_night;
603 nrgb = wxImage::HSVtoRGB(hsv);
604 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
610 m_pos_image_red = &m_os_image_red_day;
611 m_pos_image_yellow = &m_os_image_yellow_day;
612 m_pos_image_grey = &m_os_image_grey_day;
616 m_pBrightPopup = NULL;
619 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
624 m_Piano =
new Piano(
this);
626 m_bShowCompassWin =
true;
628 m_Compass->SetScaleFactor(g_compass_scalefactor);
629 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
631 if (IsPrimaryCanvas() && !g_disableNotifications) {
633 m_notification_button->SetScaleFactor(g_compass_scalefactor);
634 m_notification_button->Show(
true);
637 m_pianoFrozen =
false;
639 SetMinSize(wxSize(200, 200));
641 m_displayScale = 1.0;
642#if defined(__WXOSX__) || defined(__WXGTK3__)
644 m_displayScale = GetContentScaleFactor();
646 VPoint.SetPixelScale(m_displayScale);
648#ifdef HAVE_WX_GESTURE_EVENTS
651 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
652 wxLogError(
"Failed to enable touch events");
657 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
658 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
660 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
661 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
663 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
664 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
666 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
667 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
672 auto ¬eman = NotificationManager::GetInstance();
674 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
675 evt_notificationlist_change_listener.Listen(
676 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
677 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
678 if (m_NotificationsList && m_NotificationsList->IsShown()) {
679 m_NotificationsList->ReloadNotificationList();
685ChartCanvas::~ChartCanvas() {
686 delete pThumbDIBShow;
694 delete pCursorPencil;
698 delete pMovementTimer;
699 delete pMovementStopTimer;
700 delete pCurTrackTimer;
702 delete m_DoubleClickTimer;
704 delete m_pTrackRolloverWin;
705 delete m_pRouteRolloverWin;
706 delete m_pAISRolloverWin;
707 delete m_pBrightPopup;
713 m_dc_route.SelectObject(wxNullBitmap);
716 delete pWorldBackgroundChart;
717 delete pss_overlay_bmp;
721 delete m_pEM_Fathoms;
723 delete m_pEM_OverZoom;
728 delete m_pos_image_user_day;
729 delete m_pos_image_user_dusk;
730 delete m_pos_image_user_night;
731 delete m_pos_image_user_grey_day;
732 delete m_pos_image_user_grey_dusk;
733 delete m_pos_image_user_grey_night;
734 delete m_pos_image_user_yellow_day;
735 delete m_pos_image_user_yellow_dusk;
736 delete m_pos_image_user_yellow_night;
740 if (!g_bdisable_opengl) {
743#if wxCHECK_VERSION(2, 9, 0)
744 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
751 MUIBar *muiBar = m_muiBar;
755 delete m_pCurrentStack;
758 delete m_notification_button;
761void ChartCanvas::SetupGridFont() {
762 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
764 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
766 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
767 FALSE, wxString(
"Arial"));
770void ChartCanvas::RebuildCursors() {
776 delete pCursorPencil;
780 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
785 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
786 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
787 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
788 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
789 wxImage ICursorPencil =
790 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
791 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
793#if !defined(__WXMSW__) && !defined(__WXQT__)
794 ICursorLeft.ConvertAlphaToMask(128);
795 ICursorRight.ConvertAlphaToMask(128);
796 ICursorUp.ConvertAlphaToMask(128);
797 ICursorDown.ConvertAlphaToMask(128);
798 ICursorPencil.ConvertAlphaToMask(10);
799 ICursorCross.ConvertAlphaToMask(10);
802 if (ICursorLeft.Ok()) {
803 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
804 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
805 pCursorLeft =
new wxCursor(ICursorLeft);
807 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
809 if (ICursorRight.Ok()) {
810 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
811 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
812 pCursorRight =
new wxCursor(ICursorRight);
814 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
816 if (ICursorUp.Ok()) {
817 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
818 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
819 pCursorUp =
new wxCursor(ICursorUp);
821 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
823 if (ICursorDown.Ok()) {
824 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
825 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
826 pCursorDown =
new wxCursor(ICursorDown);
828 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
830 if (ICursorPencil.Ok()) {
831 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
832 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
833 pCursorPencil =
new wxCursor(ICursorPencil);
835 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
837 if (ICursorCross.Ok()) {
838 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
839 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
840 pCursorCross =
new wxCursor(ICursorCross);
842 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
844 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
845 pPlugIn_Cursor = NULL;
848void ChartCanvas::CanvasApplyLocale() {
849 CreateDepthUnitEmbossMaps(m_cs);
850 CreateOZEmbossMapData(m_cs);
853void ChartCanvas::SetupGlCanvas() {
856 if (!g_bdisable_opengl) {
858 wxLogMessage(
"Creating glChartCanvas");
863 if (IsPrimaryCanvas()) {
870 wxGLContext *pctx =
new wxGLContext(m_glcc);
871 m_glcc->SetContext(pctx);
875 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
877 m_glcc->SetContext(g_pGLcontext);
887 if (!g_bdisable_opengl) {
890 wxLogMessage(
"Creating glChartCanvas");
894 if (IsPrimaryCanvas()) {
895 qDebug() <<
"Creating Primary glChartCanvas";
903 wxGLContext *pctx =
new wxGLContext(m_glcc);
904 m_glcc->SetContext(pctx);
906 m_glcc->m_pParentCanvas =
this;
909 qDebug() <<
"Creating Secondary glChartCanvas";
916 top_frame::Get()->GetWxGlCanvas());
919 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
920 m_glcc->SetContext(pwxctx);
921 m_glcc->m_pParentCanvas =
this;
929void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
930 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
945 if (m_routeState && m_FinishRouteOnKillFocus)
946 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
948 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
952void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
953 m_routeFinishTimer.Stop();
957 top_frame::Get()->UpdateGlobalMenuItems(
this);
959 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
962void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
963 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
966#ifdef HAVE_WX_GESTURE_EVENTS
967void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
974 m_popupWanted =
true;
976 m_inLongPress = !g_bhide_context_menus;
979 m_menuPos =
event.GetPosition();
980 wxMouseEvent ev(wxEVT_LEFT_UP);
981 ev.m_x = m_menuPos.x;
982 ev.m_y = m_menuPos.y;
983 wxPostEvent(
this, ev);
987 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
988 ev_right_click.m_x = m_menuPos.x;
989 ev_right_click.m_y = m_menuPos.y;
990 MouseEvent(ev_right_click);
995void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
999void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1001void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1003void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1005 long dt = m_sw_left_up.Time() - m_sw_up_time;
1006 m_sw_up_time = m_sw_left_up.Time();
1017 wxPoint pos =
event.GetPosition();
1021 if (!m_popupWanted) {
1022 wxMouseEvent ev(wxEVT_LEFT_UP);
1029 m_popupWanted =
false;
1031 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1038void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1043 long dt = m_sw_left_down.Time() - m_sw_down_time;
1044 m_sw_down_time = m_sw_left_down.Time();
1068 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1070 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1071 m_lastTapPos.y - max_double_click_distance,
1072 max_double_click_distance * 2, max_double_click_distance * 2);
1075 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1081 m_lastTapPos =
event.GetPosition();
1082 m_tap_timer.StartOnce(
1086 if (m_tap_count == 2) {
1090 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1103void ChartCanvas::OnMotion(wxMouseEvent &event) {
1108 event.m_leftDown = m_leftdown;
1112void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1114 if (event.IsGestureEnd())
return;
1116 double factor =
event.GetZoomFactor();
1118 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1123 double wanted_factor = m_oldVPSScale / current_vps * factor;
1128 if (event.IsGestureStart()) {
1129 m_zoomStartPoint =
event.GetPosition();
1131 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1133 m_zoomStartPoint =
event.GetPosition();
1137void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1139void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1140 DoRotateCanvas(0.0);
1144void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1149void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1150 m_FinishRouteOnKillFocus =
false;
1151 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1152 m_FinishRouteOnKillFocus =
true;
1155void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1160 m_restore_dbindex = pcc->DBindex;
1162 if (pcc->GroupID < 0) pcc->GroupID = 0;
1167 m_groupIndex = pcc->GroupID;
1169 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1183 m_encDisplayCategory = pcc->nENCDisplayCategory;
1184 m_encShowDepth = pcc->bShowENCDepths;
1185 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1186 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1187 m_encShowLights = pcc->bShowENCLights;
1188 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1189 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1190 m_encShowDataQual = pcc->bShowENCDataQuality;
1194 m_upMode = NORTH_UP_MODE;
1196 m_upMode = COURSE_UP_MODE;
1198 m_upMode = HEAD_UP_MODE;
1202 m_singleChart = NULL;
1205void ChartCanvas::ApplyGlobalSettings() {
1208 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1209 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1211 if (m_notification_button) m_notification_button->UpdateStatus();
1214void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1215 bool groupOK = CheckGroup(m_groupIndex);
1218 SetGroupIndex(m_groupIndex,
true);
1222void ChartCanvas::SetShowGPS(
bool bshow) {
1223 if (m_bShowGPS != bshow) {
1226 m_Compass->SetScaleFactor(g_compass_scalefactor);
1227 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1232void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1233 m_bShowCompassWin = bshow;
1235 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1236 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1240int ChartCanvas::GetPianoHeight() {
1242 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1247void ChartCanvas::ConfigureChartBar() {
1250 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1251 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1253 if (GetQuiltMode()) {
1254 m_Piano->SetRoundedRectangles(
true);
1256 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1257 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1258 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1261void ChartCanvas::ShowTides(
bool bShow) {
1262 top_frame::Get()->LoadHarmonics();
1265 SetbShowTide(bShow);
1267 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1269 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1270 SetbShowTide(
false);
1271 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1274 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1275 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1286void ChartCanvas::ShowCurrents(
bool bShow) {
1287 top_frame::Get()->LoadHarmonics();
1290 SetbShowCurrent(bShow);
1291 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1293 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1294 SetbShowCurrent(
false);
1295 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1298 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1299 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1316void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1318void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1321 int new_index = index;
1324 bool bgroup_override =
false;
1325 int old_group_index = new_index;
1327 if (!CheckGroup(new_index)) {
1329 bgroup_override =
true;
1332 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1336 int current_chart_native_scale = GetCanvasChartNativeScale();
1339 m_groupIndex = new_index;
1345 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1349 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1353 g_sticky_chart = -1;
1357 UpdateCanvasOnGroupChange();
1360 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1362 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1365 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1366 double best_scale = GetBestStartScale(dbi_hint, vp);
1370 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1374 canvasChartsRefresh(dbi_hint);
1376 UpdateCanvasControlBar();
1378 if (!autoSwitch && bgroup_override) {
1380 wxString msg(_(
"Group \""));
1383 msg += pGroup->m_group_name;
1385 msg += _(
"\" is empty.");
1387 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1394 if (bgroup_override) {
1395 wxString msg(_(
"Group \""));
1398 msg += pGroup->m_group_name;
1400 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1402 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1406bool ChartCanvas::CheckGroup(
int igroup) {
1409 if (igroup == 0)
return true;
1416 if (pGroup->m_element_array.empty())
1420 for (
const auto &elem : pGroup->m_element_array) {
1421 for (
unsigned int ic = 0;
1422 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1423 auto &cte =
ChartData->GetChartTableEntry(ic);
1424 wxString chart_full_path(cte.GetpFullPath(), wxConvUTF8);
1426 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1431 for (
const auto &elem : pGroup->m_element_array) {
1432 const wxString &element_root = elem.m_element_name;
1433 wxString test_string =
"GSHH";
1434 if (element_root.Upper().Contains(test_string))
return true;
1440void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1443 AbstractPlatform::ShowBusySpinner();
1447 SetQuiltRefChart(-1);
1449 m_singleChart = NULL;
1455 if (!m_pCurrentStack) {
1457 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1460 if (-1 != dbi_hint) {
1461 if (GetQuiltMode()) {
1462 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1463 SetQuiltRefChart(dbi_hint);
1467 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1469 if (pTentative_Chart) {
1472 if (m_singleChart) m_singleChart->Deactivate();
1474 m_singleChart = pTentative_Chart;
1475 m_singleChart->Activate();
1477 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1478 GetpCurrentStack(), m_singleChart->GetFullPath());
1486 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1487 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1488 SetQuiltRefChart(selected_index);
1492 SetupCanvasQuiltMode();
1493 if (!GetQuiltMode() && m_singleChart == 0) {
1495 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1496 m_singleChart = pDummyChart;
1502 UpdateCanvasControlBar();
1503 UpdateGPSCompassStatusBox(
true);
1505 SetCursor(wxCURSOR_ARROW);
1507 AbstractPlatform::HideBusySpinner();
1510bool ChartCanvas::DoCanvasUpdate() {
1512 double vpLat, vpLon;
1513 bool blong_jump =
false;
1514 meters_to_shift = 0;
1517 bool bNewChart =
false;
1518 bool bNewView =
false;
1519 bool bCanvasChartAutoOpen =
true;
1521 bool bNewPiano =
false;
1522 bool bOpenSpecified;
1528 if (!GetVP().IsValid())
return false;
1529 if (bDBUpdateInProgress)
return false;
1534 if (m_chart_drag_inertia_active)
return false;
1535 if (m_animationActive)
return false;
1561 double dx = m_OSoffsetx;
1562 double dy = m_OSoffsety;
1566 if (GetUpMode() == NORTH_UP_MODE) {
1567 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1569 double offset_angle = atan2(d_north, d_east);
1570 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1571 double chart_angle = GetVPRotation();
1572 double target_angle = chart_angle + offset_angle;
1573 double d_east_mod = offset_distance * cos(target_angle);
1574 double d_north_mod = offset_distance * sin(target_angle);
1575 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1579 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1580 double cog_to_use =
gCog;
1582 (fabs(
gCog - gCog_gt) > 20)) {
1583 cog_to_use = gCog_gt;
1586 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1588 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1590 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1591 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1593 double pixel_delta_tent =
1594 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1596 double pixel_delta = 0;
1601 if (!std::isnan(
gSog)) {
1605 pixel_delta = pixel_delta_tent;
1608 meters_to_shift = 0;
1610 if (!std::isnan(
gCog)) {
1611 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1612 dir_to_shift = cog_to_use;
1613 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1619 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1633 if (GetQuiltMode()) {
1634 int current_db_index = -1;
1635 if (m_pCurrentStack)
1638 ->GetCurrentEntrydbIndex();
1646 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1648 if (m_pCurrentStack->nEntry) {
1649 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1651 SelectQuiltRefdbChart(new_dbIndex,
true);
1652 m_bautofind =
false;
1656 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1657 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1662 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1668 double proposed_scale_onscreen =
1671 int initial_db_index = m_restore_dbindex;
1672 if (initial_db_index < 0) {
1673 if (m_pCurrentStack->nEntry) {
1675 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1680 if (m_pCurrentStack->nEntry) {
1681 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1686 if (!IsChartQuiltableRef(initial_db_index)) {
1690 int stack_index = 0;
1692 if (stack_index >= 0) {
1693 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1694 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1695 if (IsChartQuiltableRef(test_db_index) &&
1697 ChartData->GetDBChartType(initial_db_index))) {
1698 initial_db_index = test_db_index;
1708 SetQuiltRefChart(initial_db_index);
1709 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1717 0, GetVPRotation());
1722 bool super_jump =
false;
1724 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1725 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1726 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1733 pLast_Ch = m_singleChart;
1734 ChartTypeEnum new_open_type;
1735 ChartFamilyEnum new_open_family;
1737 new_open_type = pLast_Ch->GetChartType();
1738 new_open_family = pLast_Ch->GetChartFamily();
1740 new_open_type = CHART_TYPE_KAP;
1741 new_open_family = CHART_FAMILY_RASTER;
1744 bOpenSpecified = m_bFirstAuto;
1747 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1750 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1752 if (NULL == pDummyChart) {
1758 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1760 m_singleChart = pDummyChart;
1765 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1767 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1770 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1771 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1778 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1784 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1789 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1792 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1797 if (NULL != m_singleChart)
1798 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1799 m_singleChart->GetFullPath());
1802 m_pCurrentStack->CurrentStackEntry = tEntry;
1812 if (bCanvasChartAutoOpen) {
1813 bool search_direction =
1815 int start_index = 0;
1819 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1820 (LastStack.nEntry == 0)) {
1821 search_direction =
true;
1822 start_index = m_pCurrentStack->nEntry - 1;
1826 if (bOpenSpecified) {
1827 if (m_restore_dbindex >= 0) {
1829 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
1830 std::vector<int> one_array;
1831 one_array.push_back(m_restore_dbindex);
1832 m_Piano->SetActiveKeyArray(one_array);
1833 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
1834 m_restore_dbindex = -1;
1838 search_direction =
false;
1839 start_index = m_restore_dbindex;
1840 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1843 new_open_type = CHART_TYPE_DONTCARE;
1848 pProposed =
ChartData->OpenStackChartConditional(
1849 m_pCurrentStack, start_index, search_direction, new_open_type,
1853 if (NULL == pProposed)
1854 pProposed =
ChartData->OpenStackChartConditional(
1855 m_pCurrentStack, start_index, search_direction,
1856 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1858 if (NULL == pProposed)
1859 pProposed =
ChartData->OpenStackChartConditional(
1860 m_pCurrentStack, start_index, search_direction,
1861 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1872 if (NULL == pProposed) {
1873 if (NULL == pDummyChart) {
1879 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1881 pProposed = pDummyChart;
1885 if (m_singleChart) m_singleChart->Deactivate();
1886 m_singleChart = pProposed;
1888 if (m_singleChart) {
1889 m_singleChart->Activate();
1890 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1891 m_pCurrentStack, m_singleChart->GetFullPath());
1896 if (NULL != m_singleChart) {
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,
1935 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 int stack_index = m_pCurrentStack->CurrentStackEntry;
2093 SelectQuiltRefdbChart(m_pCurrentStack->GetDBIndex(stack_index),
false);
2096 m_singleChart = NULL;
2099 AdjustQuiltRefChart();
2107 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2111 std::vector<int> empty_array;
2112 m_Piano->SetActiveKeyArray(empty_array);
2113 m_Piano->SetNoshowIndexArray(empty_array);
2114 m_Piano->SetEclipsedIndexArray(empty_array);
2117 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2118 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2119 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2120 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2122 m_Piano->SetRoundedRectangles(
false);
2128 if (!GetQuiltMode()) {
2133 if (m_bFollow ==
true) {
2141 if (!m_singleChart) {
2143 if (GetQuiltReferenceChartIndex() >= 0) {
2144 m_singleChart =
ChartData->OpenChartFromDB(
2145 GetQuiltReferenceChartIndex(), FULL_INIT);
2148 else if (m_restore_dbindex >= 0) {
2150 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
2156 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2164 int cur_max_scale = (int)1e8;
2166 ChartBase *pChart = GetFirstQuiltChart();
2170 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2172 if (pChart->GetNativeScale() < cur_max_scale) {
2173 Candidate_Chart = pChart;
2174 cur_max_scale = pChart->GetNativeScale();
2177 pChart = GetNextQuiltChart();
2180 m_singleChart = Candidate_Chart;
2184 if (NULL == m_singleChart) {
2185 m_singleChart =
ChartData->OpenStackChartConditional(
2186 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2187 CHART_FAMILY_DONTCARE);
2193 InvalidateAllQuiltPatchs();
2195 if (m_singleChart) {
2196 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2197 std::vector<int> one_array;
2198 one_array.push_back(dbi);
2199 m_Piano->SetActiveKeyArray(one_array);
2202 if (m_singleChart) {
2203 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2208 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2212bool ChartCanvas::IsTempMenuBarEnabled() {
2215 wxGetOsVersion(&major);
2223double ChartCanvas::GetCanvasRangeMeters() {
2225 GetSize(&width, &height);
2226 int minDimension = wxMin(width, height);
2229 range *= cos(GetVP().clat * PI / 180.);
2233void ChartCanvas::SetCanvasRangeMeters(
double range) {
2235 GetSize(&width, &height);
2236 int minDimension = wxMin(width, height);
2238 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2242bool ChartCanvas::SetUserOwnship() {
2246 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2247 double factor_dusk = 0.5;
2248 double factor_night = 0.25;
2250 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2251 m_pos_image_user_day =
new wxImage;
2252 *m_pos_image_user_day = pbmp->ConvertToImage();
2253 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2255 int gimg_width = m_pos_image_user_day->GetWidth();
2256 int gimg_height = m_pos_image_user_day->GetHeight();
2259 m_pos_image_user_dusk =
new wxImage;
2260 m_pos_image_user_night =
new wxImage;
2262 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2263 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2265 for (
int iy = 0; iy < gimg_height; iy++) {
2266 for (
int ix = 0; ix < gimg_width; ix++) {
2267 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2268 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2269 m_pos_image_user_day->GetGreen(ix, iy),
2270 m_pos_image_user_day->GetBlue(ix, iy));
2271 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2272 hsv.value = hsv.value * factor_dusk;
2273 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2274 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2277 hsv = wxImage::RGBtoHSV(rgb);
2278 hsv.value = hsv.value * factor_night;
2279 nrgb = wxImage::HSVtoRGB(hsv);
2280 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2287 m_pos_image_user_grey_day =
new wxImage;
2288 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2290 m_pos_image_user_grey_dusk =
new wxImage;
2291 m_pos_image_user_grey_night =
new wxImage;
2293 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2294 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2296 for (
int iy = 0; iy < gimg_height; iy++) {
2297 for (
int ix = 0; ix < gimg_width; ix++) {
2298 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2299 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2300 m_pos_image_user_grey_day->GetGreen(ix, iy),
2301 m_pos_image_user_grey_day->GetBlue(ix, iy));
2302 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2303 hsv.value = hsv.value * factor_dusk;
2304 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2305 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2308 hsv = wxImage::RGBtoHSV(rgb);
2309 hsv.value = hsv.value * factor_night;
2310 nrgb = wxImage::HSVtoRGB(hsv);
2311 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2318 m_pos_image_user_yellow_day =
new wxImage;
2319 m_pos_image_user_yellow_dusk =
new wxImage;
2320 m_pos_image_user_yellow_night =
new wxImage;
2322 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2323 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2324 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2326 for (
int iy = 0; iy < gimg_height; iy++) {
2327 for (
int ix = 0; ix < gimg_width; ix++) {
2328 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2329 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2330 m_pos_image_user_grey_day->GetGreen(ix, iy),
2331 m_pos_image_user_grey_day->GetBlue(ix, iy));
2335 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2336 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2337 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2339 hsv = wxImage::RGBtoHSV(rgb);
2340 hsv.value = hsv.value * factor_dusk;
2341 nrgb = wxImage::HSVtoRGB(hsv);
2342 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2344 hsv = wxImage::RGBtoHSV(rgb);
2345 hsv.value = hsv.value * factor_night;
2346 nrgb = wxImage::HSVtoRGB(hsv);
2347 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2359 m_display_size_mm = size;
2366 double horizontal = sd.x;
2370 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2371 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2375 ps52plib->SetPPMM(m_pix_per_mm);
2380 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2382 m_display_size_mm, sd.x, sd.y);
2388 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2391 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2394void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2396 wxString msg(event.m_string.c_str(), wxConvUTF8);
2398 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2399 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2402 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2404 compress_msg_array.RemoveAt(event.thread);
2405 compress_msg_array.Insert( msg, event.thread);
2408 compress_msg_array.Add(msg);
2411 wxString combined_msg;
2412 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2413 combined_msg += compress_msg_array[i];
2414 combined_msg +=
"\n";
2418 pprog->Update(pprog_count, combined_msg, &skip );
2419 pprog->SetSize(pprog_size);
2424void ChartCanvas::InvalidateGL() {
2425 if (!m_glcc)
return;
2427 if (g_bopengl) m_glcc->Invalidate();
2429 if (m_Compass) m_Compass->UpdateStatus(
true);
2432int ChartCanvas::GetCanvasChartNativeScale() {
2434 if (!VPoint.b_quilt) {
2435 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2437 ret = (int)m_pQuilt->GetRefNativeScale();
2442ChartBase *ChartCanvas::GetChartAtCursor() {
2444 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2445 target_chart = m_singleChart;
2446 else if (VPoint.b_quilt)
2447 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2449 target_chart = NULL;
2450 return target_chart;
2453ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2457 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2459 target_chart = NULL;
2460 return target_chart;
2463int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2464 int new_dbIndex = -1;
2465 if (!VPoint.b_quilt) {
2466 if (m_pCurrentStack) {
2467 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2468 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2470 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2481 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2484 for (
unsigned int is = 0; is < im; is++) {
2486 m_pQuilt->GetExtendedStackIndexArray()[is]);
2487 if ((m.Scale_ge(
scale)) &&
2488 (m_pQuilt->GetRefFamily() == m.GetChartFamily())) {
2489 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2496 if (new_dbIndex < 0) {
2497 for (
unsigned int is = 0; is < im; is++) {
2499 m_pQuilt->GetExtendedStackIndexArray()[is]);
2500 if (m.Scale_ge(
scale)) {
2501 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2512void ChartCanvas::EnablePaint(
bool b_enable) {
2513 m_b_paint_enable = b_enable;
2515 if (m_glcc) m_glcc->EnablePaint(b_enable);
2519bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2521void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2523std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2524 return m_pQuilt->GetQuiltIndexArray();
2528void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2529 VPoint.b_quilt = b_quilt;
2530 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2533bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2535int ChartCanvas::GetQuiltReferenceChartIndex() {
2536 return m_pQuilt->GetRefChartdbIndex();
2539void ChartCanvas::InvalidateAllQuiltPatchs() {
2540 m_pQuilt->InvalidateAllQuiltPatchs();
2543ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2544 return m_pQuilt->GetLargestScaleChart();
2547ChartBase *ChartCanvas::GetFirstQuiltChart() {
2548 return m_pQuilt->GetFirstChart();
2551ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2553int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2555void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2556 m_pQuilt->SetHiliteIndex(dbIndex);
2559void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2560 m_pQuilt->SetHiliteIndexArray(hilite_array);
2563void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2564 m_pQuilt->ClearHiliteIndexArray();
2567std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2569 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2572int ChartCanvas::GetQuiltRefChartdbIndex() {
2573 return m_pQuilt->GetRefChartdbIndex();
2576std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2577 return m_pQuilt->GetExtendedStackIndexArray();
2580std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2581 return m_pQuilt->GetFullscreenIndexArray();
2584std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2585 return m_pQuilt->GetEclipsedStackIndexArray();
2588void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2590double ChartCanvas::GetQuiltMaxErrorFactor() {
2591 return m_pQuilt->GetMaxErrorFactor();
2594bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2595 return m_pQuilt->IsChartQuiltableRef(db_index);
2599 double chartMaxScale =
2601 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2604void ChartCanvas::StartMeasureRoute() {
2605 if (!m_routeState) {
2606 if (m_bMeasure_Active) {
2608 m_pMeasureRoute = NULL;
2611 m_bMeasure_Active =
true;
2612 m_nMeasureState = 1;
2613 m_bDrawingRoute =
false;
2615 SetCursor(*pCursorPencil);
2620void ChartCanvas::CancelMeasureRoute() {
2621 m_bMeasure_Active =
false;
2622 m_nMeasureState = 0;
2623 m_bDrawingRoute =
false;
2626 m_pMeasureRoute = NULL;
2628 SetCursor(*pCursorArrow);
2631ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2633void ChartCanvas::SetVP(
ViewPort &vp) {
2644void ChartCanvas::TriggerDeferredFocus() {
2647 m_deferredFocusTimer.Start(20,
true);
2649#if defined(__WXGTK__) || defined(__WXOSX__)
2650 top_frame::Get()->Raise();
2660void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2665void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2666 if (SendKeyEventToPlugins(event))
2670 int key_char =
event.GetKeyCode();
2673 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2679 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2684 if (g_benable_rotate) {
2705void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2706 if (SendKeyEventToPlugins(event))
2710 bool b_handled =
false;
2712 m_modkeys =
event.GetModifiers();
2714 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2716#ifdef OCPN_ALT_MENUBAR
2722 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2724 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2725 if (!g_bTempShowMenuBar) {
2726 g_bTempShowMenuBar =
true;
2727 top_frame::Get()->ApplyGlobalSettings(
false);
2729 m_bMayToggleMenuBar =
false;
2735 if (event.GetKeyCode() != WXK_ALT) {
2736 m_bMayToggleMenuBar =
false;
2743 switch (event.GetKeyCode()) {
2750 event.GetPosition(&x, &y);
2751 m_FinishRouteOnKillFocus =
false;
2752 CallPopupMenu(x, y);
2753 m_FinishRouteOnKillFocus =
true;
2757 m_modkeys |= wxMOD_ALT;
2761 m_modkeys |= wxMOD_CONTROL;
2766 case WXK_RAW_CONTROL:
2767 m_modkeys |= wxMOD_RAW_CONTROL;
2772 if (m_modkeys == wxMOD_CONTROL)
2773 top_frame::Get()->DoStackDown(
this);
2775 StartTimedMovement();
2785 StartTimedMovement();
2793 if (m_modkeys == wxMOD_CONTROL)
2794 top_frame::Get()->DoStackUp(
this);
2796 StartTimedMovement();
2806 StartTimedMovement();
2814 if (event.ShiftDown()) {
2816 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2818 std::shared_ptr<HostApi> host_api;
2820 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2823 api_121->SelectChartFamily(m_canvasIndex,
2830 if (event.ShiftDown()) {
2832 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2834 std::shared_ptr<HostApi> host_api;
2836 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2839 api_121->SelectChartFamily(m_canvasIndex,
2842 SetShowENCText(!GetShowENCText());
2849 if (!m_bMeasure_Active) {
2850 if (event.ShiftDown())
2851 m_bMeasure_DistCircle =
true;
2853 m_bMeasure_DistCircle =
false;
2855 StartMeasureRoute();
2857 CancelMeasureRoute();
2859 SetCursor(*pCursorArrow);
2869 top_frame::Get()->ToggleColorScheme();
2870 top_frame::Get()->Raise();
2871 TriggerDeferredFocus();
2875 int mod = m_modkeys & wxMOD_SHIFT;
2876 if (mod != m_brightmod) {
2878 m_bbrightdir = !m_bbrightdir;
2881 if (!m_bbrightdir) {
2882 g_nbrightness -= 10;
2883 if (g_nbrightness <= MIN_BRIGHT) {
2884 g_nbrightness = MIN_BRIGHT;
2885 m_bbrightdir =
true;
2888 g_nbrightness += 10;
2889 if (g_nbrightness >= MAX_BRIGHT) {
2890 g_nbrightness = MAX_BRIGHT;
2891 m_bbrightdir =
false;
2895 SetScreenBrightness(g_nbrightness);
2896 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2899 top_frame::Get()->Raise();
2905 top_frame::Get()->DoStackDown(
this);
2909 top_frame::Get()->DoStackUp(
this);
2914 ToggleCanvasQuiltMode();
2920 top_frame::Get()->ToggleFullScreen();
2925 if (m_modkeys == wxMOD_ALT) {
2928 ToggleChartOutlines();
2934 top_frame::Get()->ActivateMOB();
2938 case WXK_NUMPAD_ADD:
2943 case WXK_NUMPAD_SUBTRACT:
2944 case WXK_PAGEDOWN: {
2945 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2950 if (m_bMeasure_Active) {
2951 if (m_nMeasureState > 2) {
2952 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2954 m_pMeasureRoute->GetnPoints();
2956 top_frame::Get()->RefreshAllCanvas();
2958 CancelMeasureRoute();
2959 StartMeasureRoute();
2967 if (event.GetKeyCode() < 128)
2969 int key_char =
event.GetKeyCode();
2973 if (!g_b_assume_azerty) {
2975 if (g_benable_rotate) {
3007 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3014 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3015 m_modkeys & wxMOD_RAW_CONTROL) {
3016 top_frame::Get()->ToggleFullScreen();
3021 if (event.ControlDown()) key_char -= 64;
3023 if (key_char >=
'0' && key_char <=
'9')
3024 SetGroupIndex(key_char -
'0');
3029 SetShowENCAnchor(!GetShowENCAnchor());
3035 top_frame::Get()->ToggleColorScheme();
3040 event.GetPosition(&x, &y);
3041 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3042 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3045 if (VPoint.b_quilt) {
3047 if (m_pQuilt->GetChartAtPix(
3052 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3054 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3059 if (m_singleChart) {
3060 ChartType = m_singleChart->GetChartType();
3061 ChartFam = m_singleChart->GetChartFamily();
3065 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3066 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3068 this, -1, ChartType, ChartFam,
3069 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3070 wxDefaultSize, wxSIMPLE_BORDER,
"");
3083 m_nmea_log->Raise();
3087 SetShowENCLights(!GetShowENCLights());
3093 if (event.ShiftDown())
3094 m_bMeasure_DistCircle =
true;
3096 m_bMeasure_DistCircle =
false;
3098 StartMeasureRoute();
3102 if (g_bInlandEcdis && ps52plib) {
3103 SetENCDisplayCategory((_DisCat)STANDARD);
3108 ToggleChartOutlines();
3112 ToggleCanvasQuiltMode();
3116 top_frame::Get()->ToggleTestPause();
3119 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3120 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3121 g_iNavAidRadarRingsNumberVisible = 1;
3122 else if (!g_bNavAidRadarRingsShown &&
3123 g_iNavAidRadarRingsNumberVisible == 1)
3124 g_iNavAidRadarRingsNumberVisible = 0;
3127 SetShowENCDepth(!m_encShowDepth);
3132 SetShowENCText(!GetShowENCText());
3137 SetShowENCDataQual(!GetShowENCDataQual());
3142 m_bShowNavobjects = !m_bShowNavobjects;
3157 if (g_bShowMenuBar ==
false) top_frame::Get()->ToggleChartBar(
this);
3162 if (event.ControlDown()) top_frame::Get()->DropMarker(
false);
3169 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3170 if ((indexActive + 1) <= r->GetnPoints()) {
3181 if (!g_bShowMenuBar) top_frame::Get()->DropMarker(
true);
3187 if (g_bSpaceDropMark) top_frame::Get()->DropMarker(
true);
3193 if (m_modkeys == wxMOD_CONTROL) top_frame::Get()->ActivateMOB();
3200 top_frame::Get()->DoSettings();
3204 parent_frame->Close();
3220 if (undo->AnythingToRedo()) {
3221 undo->RedoNextAction();
3228 if (event.ShiftDown()) {
3229 if (undo->AnythingToRedo()) {
3230 undo->RedoNextAction();
3235 if (undo->AnythingToUndo()) {
3236 undo->UndoLastAction();
3245 if (m_bMeasure_Active) {
3246 CancelMeasureRoute();
3248 SetCursor(*pCursorArrow);
3251 top_frame::Get()->RefreshAllCanvas();
3265 switch (gamma_state) {
3285 SetScreenBrightness(g_nbrightness);
3290 if (event.ControlDown()) {
3291 m_bShowCompassWin = !m_bShowCompassWin;
3292 SetShowGPSCompassWindow(m_bShowCompassWin);
3309void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3310 if (SendKeyEventToPlugins(event))
3314 switch (event.GetKeyCode()) {
3316 top_frame::Get()->SwitchKBFocus(
this);
3322 if (!m_pany) m_panspeed = 0;
3328 if (!m_panx) m_panspeed = 0;
3331 case WXK_NUMPAD_ADD:
3332 case WXK_NUMPAD_SUBTRACT:
3341 m_modkeys &= ~wxMOD_ALT;
3342#ifdef OCPN_ALT_MENUBAR
3347 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3348 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3349 top_frame::Get()->ApplyGlobalSettings(
false);
3351 m_bMayToggleMenuBar =
true;
3357 m_modkeys &= ~wxMOD_CONTROL;
3361 if (event.GetKeyCode() < 128)
3363 int key_char =
event.GetKeyCode();
3367 if (!g_b_assume_azerty) {
3382 m_rotation_speed = 0;
3400void ChartCanvas::ToggleChartOutlines() {
3401 m_bShowOutlines = !m_bShowOutlines;
3407 if (g_bopengl) InvalidateGL();
3411void ChartCanvas::ToggleLookahead() {
3412 m_bLookAhead = !m_bLookAhead;
3417void ChartCanvas::SetUpMode(
int mode) {
3420 if (mode != NORTH_UP_MODE) {
3423 if (!std::isnan(
gCog)) stuff =
gCog;
3426 auto cog_table = top_frame::Get()->GetCOGTable();
3427 for (
int i = 0; i <
g_COGAvgSec; i++) cog_table[i] = stuff;
3430 top_frame::Get()->StartCogTimer();
3432 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3433 SetVPRotation(GetVPSkew());
3438 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3439 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3441 UpdateGPSCompassStatusBox(
true);
3442 top_frame::Get()->DoChartUpdate();
3445bool ChartCanvas::DoCanvasCOGSet() {
3446 if (GetUpMode() == NORTH_UP_MODE)
return false;
3448 if (g_btenhertz) cog_use =
gCog;
3450 double rotation = 0;
3451 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3452 rotation = -
gHdt * PI / 180.;
3453 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3454 rotation = -cog_use * PI / 180.;
3456 SetVPRotation(rotation);
3460double easeOutCubic(
double t) {
3462 return 1.0 - pow(1.0 - t, 3.0);
3465void ChartCanvas::StartChartDragInertia() {
3466 m_bChartDragging =
false;
3469 m_chart_drag_inertia_time = 750;
3470 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3475 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3479 size_t length = m_drag_vec_t.size();
3480 for (
size_t i = 0; i < n_vel; i++) {
3481 xacc += m_drag_vec_x.at(length - 1 - i);
3482 yacc += m_drag_vec_y.at(length - 1 - i);
3483 tacc += m_drag_vec_t.at(length - 1 - i);
3486 if (tacc == 0)
return;
3488 double drag_velocity_x = xacc / tacc;
3489 double drag_velocity_y = yacc / tacc;
3495 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3497 m_chart_drag_velocity_x = drag_velocity_x;
3498 m_chart_drag_velocity_y = drag_velocity_y;
3500 m_chart_drag_inertia_active =
true;
3502 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3505void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3506 if (!m_chart_drag_inertia_active)
return;
3508 wxLongLong now = wxGetLocalTimeMillis();
3509 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3510 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3511 if (t > 1.0) t = 1.0;
3512 double e = 1.0 - easeOutCubic(t);
3515 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3517 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3519 m_last_elapsed = elapsed;
3523 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3524 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3525 double inertia_lat, inertia_lon;
3529 if (!IsOwnshipOnScreen()) {
3531 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3532 UpdateFollowButtonState();
3543 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3544 m_chart_drag_inertia_timer.Stop();
3547 m_target_lat = GetVP().
clat;
3548 m_target_lon = GetVP().
clon;
3549 m_pan_drag.x = m_pan_drag.y = 0;
3550 m_panx = m_pany = 0;
3551 m_chart_drag_inertia_active =
false;
3555 int target_redraw_interval = 40;
3556 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3560void ChartCanvas::StopMovement() {
3561 m_panx = m_pany = 0;
3564 m_rotation_speed = 0;
3567#if !defined(__WXGTK__) && !defined(__WXQT__)
3569 top_frame::Get()->Raise();
3578bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3580 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3582 if (!pMovementTimer->IsRunning()) {
3583 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3586 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3591 m_last_movement_time = wxDateTime::UNow();
3595void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3598 m_target_lat = target_lat;
3599 m_target_lon = target_lon;
3602 m_start_lat = GetVP().
clat;
3603 m_start_lon = GetVP().
clon;
3605 m_VPMovementTimer.Start(1,
true);
3606 m_timed_move_vp_active =
true;
3608 m_timedVP_step = nstep;
3611void ChartCanvas::DoTimedMovementVP() {
3612 if (!m_timed_move_vp_active)
return;
3613 if (m_stvpc++ > m_timedVP_step * 2) {
3620 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3635 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3636 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3638 m_run_lat = new_lat;
3639 m_run_lon = new_lon;
3644void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3646void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3648void ChartCanvas::StartTimedMovementTarget() {}
3650void ChartCanvas::DoTimedMovementTarget() {}
3652void ChartCanvas::StopMovementTarget() {}
3655void ChartCanvas::DoTimedMovement() {
3656 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3660 wxDateTime now = wxDateTime::UNow();
3662 if (m_last_movement_time.IsValid())
3663 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3665 m_last_movement_time = now;
3675 if (dt == 0) dt = 1;
3678 if (m_mustmove < 0) m_mustmove = 0;
3681 if (m_pan_drag.x || m_pan_drag.y) {
3683 m_pan_drag.x = m_pan_drag.y = 0;
3686 if (m_panx || m_pany) {
3687 const double slowpan = .1, maxpan = 2;
3688 if (m_modkeys == wxMOD_ALT)
3689 m_panspeed = slowpan;
3691 m_panspeed += (double)dt / 500;
3692 m_panspeed = wxMin(maxpan, m_panspeed);
3694 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3697 if (m_zoom_factor != 1) {
3698 double alpha = 400, beta = 1.5;
3699 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3701 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3703 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3708 if (zoom_factor > 1) {
3709 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3713 else if (zoom_factor < 1) {
3714 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3719 if (fabs(zoom_factor - 1) > 1e-4) {
3720 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3725 if (m_wheelzoom_stop_oneshot > 0) {
3726 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3727 m_wheelzoom_stop_oneshot = 0;
3732 if (zoom_factor > 1) {
3734 m_wheelzoom_stop_oneshot = 0;
3737 }
else if (zoom_factor < 1) {
3739 m_wheelzoom_stop_oneshot = 0;
3746 if (m_rotation_speed) {
3747 double speed = m_rotation_speed;
3748 if (m_modkeys == wxMOD_ALT) speed /= 10;
3749 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3753void ChartCanvas::SetColorScheme(ColorScheme cs) {
3758 case GLOBAL_COLOR_SCHEME_DAY:
3759 m_pos_image_red = &m_os_image_red_day;
3760 m_pos_image_grey = &m_os_image_grey_day;
3761 m_pos_image_yellow = &m_os_image_yellow_day;
3762 m_pos_image_user = m_pos_image_user_day;
3763 m_pos_image_user_grey = m_pos_image_user_grey_day;
3764 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3765 m_cTideBitmap = m_bmTideDay;
3766 m_cCurrentBitmap = m_bmCurrentDay;
3769 case GLOBAL_COLOR_SCHEME_DUSK:
3770 m_pos_image_red = &m_os_image_red_dusk;
3771 m_pos_image_grey = &m_os_image_grey_dusk;
3772 m_pos_image_yellow = &m_os_image_yellow_dusk;
3773 m_pos_image_user = m_pos_image_user_dusk;
3774 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3775 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3776 m_cTideBitmap = m_bmTideDusk;
3777 m_cCurrentBitmap = m_bmCurrentDusk;
3779 case GLOBAL_COLOR_SCHEME_NIGHT:
3780 m_pos_image_red = &m_os_image_red_night;
3781 m_pos_image_grey = &m_os_image_grey_night;
3782 m_pos_image_yellow = &m_os_image_yellow_night;
3783 m_pos_image_user = m_pos_image_user_night;
3784 m_pos_image_user_grey = m_pos_image_user_grey_night;
3785 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3786 m_cTideBitmap = m_bmTideNight;
3787 m_cCurrentBitmap = m_bmCurrentNight;
3790 m_pos_image_red = &m_os_image_red_day;
3791 m_pos_image_grey = &m_os_image_grey_day;
3792 m_pos_image_yellow = &m_os_image_yellow_day;
3793 m_pos_image_user = m_pos_image_user_day;
3794 m_pos_image_user_grey = m_pos_image_user_grey_day;
3795 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3796 m_cTideBitmap = m_bmTideDay;
3797 m_cCurrentBitmap = m_bmCurrentDay;
3801 CreateDepthUnitEmbossMaps(cs);
3802 CreateOZEmbossMapData(cs);
3805 m_fog_color = wxColor(
3809 case GLOBAL_COLOR_SCHEME_DUSK:
3812 case GLOBAL_COLOR_SCHEME_NIGHT:
3818 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3819 m_fog_color.Blue() * dim);
3823 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3824 SetBackgroundColour( wxColour(0,0,0) );
3826 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3829 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3831 SetBackgroundColour( wxNullColour );
3838 m_Piano->SetColorScheme(cs);
3840 m_Compass->SetColorScheme(cs);
3842 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3844 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3846 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3847 if (m_notification_button) {
3848 m_notification_button->SetColorScheme(cs);
3852 if (g_bopengl && m_glcc) {
3853 m_glcc->SetColorScheme(cs);
3859 m_brepaint_piano =
true;
3866wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3867 wxImage img = Bitmap.ConvertToImage();
3868 int sx = img.GetWidth();
3869 int sy = img.GetHeight();
3871 wxImage new_img(img);
3873 for (
int i = 0; i < sx; i++) {
3874 for (
int j = 0; j < sy; j++) {
3875 if (!img.IsTransparent(i, j)) {
3876 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3877 (
unsigned char)(img.GetGreen(i, j) * factor),
3878 (
unsigned char)(img.GetBlue(i, j) * factor));
3883 wxBitmap ret = wxBitmap(new_img);
3888void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3891 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3893 if (!m_pBrightPopup) {
3896 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3900 m_pBrightPopup->SetSize(x, y);
3901 m_pBrightPopup->Move(120, 120);
3904 int bmpsx = m_pBrightPopup->GetSize().x;
3905 int bmpsy = m_pBrightPopup->GetSize().y;
3907 wxBitmap bmp(bmpsx, bmpsx);
3908 wxMemoryDC mdc(bmp);
3910 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3911 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3912 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3913 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3916 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3918 mdc.SetFont(*pfont);
3921 if (brightness == max)
3923 else if (brightness == min)
3926 val.Printf(
"%3d", brightness);
3928 mdc.DrawText(val, 0, 0);
3930 mdc.SelectObject(wxNullBitmap);
3932 m_pBrightPopup->SetBitmap(bmp);
3933 m_pBrightPopup->Show();
3934 m_pBrightPopup->Refresh();
3937void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3938 m_b_rot_hidef =
true;
3942void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3945 bool b_need_refresh =
false;
3947 wxSize win_size = GetSize() * m_displayScale;
3951 bool showAISRollover =
false;
3953 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3957 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3958 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3961 showAISRollover =
true;
3963 if (NULL == m_pAISRolloverWin) {
3965 m_pAISRolloverWin->IsActive(
false);
3966 b_need_refresh =
true;
3967 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3968 m_AISRollover_MMSI != FoundAIS_MMSI) {
3974 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3975 m_pAISRolloverWin->IsActive(
false);
3976 m_AISRollover_MMSI = 0;
3981 m_AISRollover_MMSI = FoundAIS_MMSI;
3983 if (!m_pAISRolloverWin->IsActive()) {
3984 wxString s = ptarget->GetRolloverString();
3985 m_pAISRolloverWin->SetString(s);
3987 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3988 AIS_ROLLOVER, win_size);
3989 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3990 m_pAISRolloverWin->IsActive(
true);
3991 b_need_refresh =
true;
3995 m_AISRollover_MMSI = 0;
3996 showAISRollover =
false;
4001 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
4002 m_pAISRolloverWin->IsActive(
false);
4003 m_AISRollover_MMSI = 0;
4004 b_need_refresh =
true;
4009 bool showRouteRollover =
false;
4011 if (NULL == m_pRolloverRouteSeg) {
4015 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4016 SelectableItemList SelList =
pSelect->FindSelectionList(
4018 auto node = SelList.begin();
4019 while (node != SelList.end()) {
4024 if (pr && pr->IsVisible()) {
4025 m_pRolloverRouteSeg = pFindSel;
4026 showRouteRollover =
true;
4028 if (NULL == m_pRouteRolloverWin) {
4030 m_pRouteRolloverWin->IsActive(
false);
4033 if (!m_pRouteRolloverWin->IsActive()) {
4041 DistanceBearingMercator(
4042 segShow_point_b->m_lat, segShow_point_b->m_lon,
4043 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4045 if (!pr->m_bIsInLayer)
4046 s.Append(_(
"Route") +
": ");
4048 s.Append(_(
"Layer Route: "));
4050 if (pr->m_RouteNameString.IsEmpty())
4051 s.Append(_(
"(unnamed)"));
4053 s.Append(pr->m_RouteNameString);
4058 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4059 << segShow_point_b->GetName() <<
"\n";
4062 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4063 (
int)floor(brg + 0.5), 0x00B0);
4066 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4068 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4070 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4072 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4073 (
int)floor(varBrg + 0.5), 0x00B0);
4081 double shiptoEndLeg = 0.;
4082 bool validActive =
false;
4083 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4086 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4087 auto node = pr->pRoutePointList->begin();
4089 float dist_to_endleg = 0;
4092 for (++node; node != pr->pRoutePointList->end(); ++node) {
4099 if (prp->IsSame(segShow_point_a))
break;
4107 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4110 ->GetCurrentRngToActivePoint();
4119 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4124 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4125 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4127 << wxString(ttg_sec > SECONDS_PER_DAY
4128 ? ttg_span.Format(_(
"%Dd %H:%M"))
4129 : ttg_span.Format(_(
"%H:%M")));
4130 wxDateTime dtnow, eta;
4131 eta = dtnow.SetToCurrent().Add(ttg_span);
4132 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4133 << eta.Format(
" %d %H:%M");
4137 m_pRouteRolloverWin->SetString(s);
4139 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4140 LEG_ROLLOVER, win_size);
4141 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4142 m_pRouteRolloverWin->IsActive(
true);
4143 b_need_refresh =
true;
4144 showRouteRollover =
true;
4153 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4155 m_pRolloverRouteSeg))
4156 showRouteRollover =
false;
4157 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4158 showRouteRollover =
false;
4160 showRouteRollover =
true;
4164 if (m_routeState) showRouteRollover =
false;
4167 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4168 showRouteRollover =
false;
4170 if (m_pRouteRolloverWin &&
4171 !showRouteRollover) {
4172 m_pRouteRolloverWin->IsActive(
false);
4173 m_pRolloverRouteSeg = NULL;
4174 m_pRouteRolloverWin->Destroy();
4175 m_pRouteRolloverWin = NULL;
4176 b_need_refresh =
true;
4177 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4178 m_pRouteRolloverWin->IsActive(
true);
4179 b_need_refresh =
true;
4184 bool showTrackRollover =
false;
4186 if (NULL == m_pRolloverTrackSeg) {
4190 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4191 SelectableItemList SelList =
pSelect->FindSelectionList(
4194 auto node = SelList.begin();
4195 while (node != SelList.end()) {
4200 if (pt && pt->IsVisible()) {
4201 m_pRolloverTrackSeg = pFindSel;
4202 showTrackRollover =
true;
4204 if (NULL == m_pTrackRolloverWin) {
4206 m_pTrackRolloverWin->IsActive(
false);
4209 if (!m_pTrackRolloverWin->IsActive()) {
4217 DistanceBearingMercator(
4218 segShow_point_b->m_lat, segShow_point_b->m_lon,
4219 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4221 if (!pt->m_bIsInLayer)
4222 s.Append(_(
"Track") +
": ");
4224 s.Append(_(
"Layer Track: "));
4226 if (pt->GetName().IsEmpty())
4227 s.Append(_(
"(unnamed)"));
4229 s.Append(pt->GetName());
4230 double tlenght = pt->Length();
4232 if (pt->GetLastPoint()->GetTimeString() &&
4233 pt->GetPoint(0)->GetTimeString()) {
4234 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4235 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4236 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4237 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4238 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4239 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4240 << getUsrSpeedUnit();
4241 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4242 : ttime.Format(
" %H:%M"));
4246 if (g_bShowTrackPointTime &&
4247 strlen(segShow_point_b->GetTimeString())) {
4248 wxString stamp = segShow_point_b->GetTimeString();
4249 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4250 if (timestamp.IsValid()) {
4254 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4256 s <<
"\n" << _(
"Segment Created: ") << stamp;
4261 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4266 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4268 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4270 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4272 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4278 if (segShow_point_a->GetTimeString() &&
4279 segShow_point_b->GetTimeString()) {
4280 wxDateTime apoint = segShow_point_a->GetCreateTime();
4281 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4282 if (apoint.IsValid() && bpoint.IsValid()) {
4283 double segmentSpeed = toUsrSpeed(
4284 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4285 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4286 << getUsrSpeedUnit();
4290 m_pTrackRolloverWin->SetString(s);
4292 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4293 LEG_ROLLOVER, win_size);
4294 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4295 m_pTrackRolloverWin->IsActive(
true);
4296 b_need_refresh =
true;
4297 showTrackRollover =
true;
4306 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4308 m_pRolloverTrackSeg))
4309 showTrackRollover =
false;
4310 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4311 showTrackRollover =
false;
4313 showTrackRollover =
true;
4317 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4318 showTrackRollover =
false;
4321 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4322 showTrackRollover =
false;
4328 if (m_pTrackRolloverWin &&
4329 !showTrackRollover) {
4330 m_pTrackRolloverWin->IsActive(
false);
4331 m_pRolloverTrackSeg = NULL;
4332 m_pTrackRolloverWin->Destroy();
4333 m_pTrackRolloverWin = NULL;
4334 b_need_refresh =
true;
4335 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4336 m_pTrackRolloverWin->IsActive(
true);
4337 b_need_refresh =
true;
4340 if (b_need_refresh) Refresh();
4343void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4344 if ((GetShowENCLights() || m_bsectors_shown) &&
4345 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4346 extendedSectorLegs)) {
4347 if (!m_bsectors_shown) {
4349 m_bsectors_shown =
true;
4352 if (m_bsectors_shown) {
4354 m_bsectors_shown =
false;
4362#if defined(__WXGTK__) || defined(__WXQT__)
4367 double cursor_lat, cursor_lon;
4370 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4371 while (cursor_lon < -180.) cursor_lon += 360.;
4373 while (cursor_lon > 180.) cursor_lon -= 360.;
4375 SetCursorStatus(cursor_lat, cursor_lon);
4381void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4382 if (!top_frame::Get()->GetFrameStatusBar())
return;
4386 s1 += toSDMM(1, cursor_lat);
4388 s1 += toSDMM(2, cursor_lon);
4390 if (STAT_FIELD_CURSOR_LL >= 0)
4391 top_frame::Get()->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4393 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4398 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4399 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4400 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4402 wxString s = st + sm;
4415 if (g_bShowLiveETA) {
4418 float boatSpeedDefault = g_defaultBoatSpeed;
4423 if (!std::isnan(
gSog)) {
4425 if (boatSpeed < 0.5) {
4428 realTimeETA = dist / boatSpeed * 60;
4437 s << minutesToHoursDays(realTimeETA);
4442 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4443 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4445 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4450 top_frame::Get()->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4458wxString minutesToHoursDays(
float timeInMinutes) {
4461 if (timeInMinutes == 0) {
4466 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4467 s << wxString::Format(
"%d", (
int)timeInMinutes);
4472 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4475 hours = (int)timeInMinutes / 60;
4476 min = (int)timeInMinutes % 60;
4479 s << wxString::Format(
"%d", hours);
4482 s << wxString::Format(
"%d", hours);
4484 s << wxString::Format(
"%d", min);
4491 else if (timeInMinutes > 24 * 60) {
4494 days = (int)(timeInMinutes / 60) / 24;
4495 hours = (int)(timeInMinutes / 60) % 24;
4498 s << wxString::Format(
"%d", days);
4501 s << wxString::Format(
"%d", days);
4503 s << wxString::Format(
"%d", hours);
4515void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4523 wxPoint2DDouble *r) {
4528 double rlon, wxPoint2DDouble *r) {
4539 if (!g_bopengl && m_singleChart &&
4540 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4541 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4542 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4543 (m_singleChart->GetChartProjectionType() !=
4544 PROJECTION_TRANSVERSE_MERCATOR) &&
4545 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4546 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4547 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4561 Cur_BSB_Ch->SetVPRasterParms(vp);
4562 double rpixxd, rpixyd;
4563 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4589 if (std::isnan(p.m_x)) {
4590 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4594 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4595 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4597 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4616 if (!g_bopengl && m_singleChart &&
4617 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4618 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4619 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4620 (m_singleChart->GetChartProjectionType() !=
4621 PROJECTION_TRANSVERSE_MERCATOR) &&
4622 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4623 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4624 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4635 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4638 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4643 else if (slon > 180.)
4654 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4660 DoZoomCanvas(factor,
false);
4661 extendedSectorLegs.clear();
4666 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4669 if (StartTimedMovement(stoptimer)) {
4671 m_zoom_factor = factor;
4676 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4678 DoZoomCanvas(factor, can_zoom_to_cursor);
4681 extendedSectorLegs.clear();
4684void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4687 if (!m_pCurrentStack)
return;
4693 if (m_bzooming)
return;
4702 double proposed_scale_onscreen =
4705 bool b_do_zoom =
false;
4714 if (!VPoint.b_quilt) {
4717 if (!m_disable_adjust_on_zoom) {
4718 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4719 if (new_db_index >= 0)
4720 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4724 int current_ref_stack_index = -1;
4725 if (m_pCurrentStack->nEntry) {
4727 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4728 m_pQuilt->SetReferenceChart(trial_index);
4729 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4730 if (new_db_index >= 0)
4731 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4735 if (m_pCurrentStack)
4736 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4747 double min_allowed_scale =
4750 if (proposed_scale_onscreen < min_allowed_scale) {
4755 proposed_scale_onscreen = min_allowed_scale;
4759 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4762 }
else if (factor < 1) {
4767 bool b_smallest =
false;
4769 if (!VPoint.b_quilt) {
4774 LLBBox viewbox = VPoint.GetBBox();
4776 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4777 double max_allowed_scale;
4791 if (proposed_scale_onscreen > max_allowed_scale) {
4793 proposed_scale_onscreen = max_allowed_scale;
4798 if (!m_disable_adjust_on_zoom) {
4800 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4801 if (new_db_index >= 0)
4802 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4804 if (m_pCurrentStack)
4805 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4808 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4810 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4811 proposed_scale_onscreen =
4812 wxMin(proposed_scale_onscreen,
4818 m_absolute_min_scale_ppm)
4819 proposed_scale_onscreen =
4828 bool b_allow_ztc =
true;
4829 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4830 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4832 double brg, distance;
4833 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4836 meters_to_shift = distance * 1852;
4844 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4847 if (m_bFollow) DoCanvasUpdate();
4854void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4856 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4860void ChartCanvas::RotateCanvas(
double dir) {
4864 if (StartTimedMovement()) {
4866 m_rotation_speed = dir * 60;
4869 double speed = dir * 10;
4870 if (m_modkeys == wxMOD_ALT) speed /= 20;
4871 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4875void ChartCanvas::DoRotateCanvas(
double rotation) {
4876 while (rotation < 0) rotation += 2 * PI;
4877 while (rotation > 2 * PI) rotation -= 2 * PI;
4879 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4881 SetVPRotation(rotation);
4882 top_frame::Get()->UpdateRotationState(VPoint.
rotation);
4885void ChartCanvas::DoTiltCanvas(
double tilt) {
4886 while (tilt < 0) tilt = 0;
4887 while (tilt > .95) tilt = .95;
4889 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4895void ChartCanvas::TogglebFollow() {
4902void ChartCanvas::ClearbFollow() {
4905 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4907 UpdateFollowButtonState();
4911 top_frame::Get()->SetChartUpdatePeriod();
4914void ChartCanvas::SetbFollow() {
4917 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4918 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4926 p.m_x += m_OSoffsetx;
4927 p.m_y -= m_OSoffsety;
4936 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4937 UpdateFollowButtonState();
4939 if (!g_bSmoothRecenter) {
4943 top_frame::Get()->SetChartUpdatePeriod();
4946void ChartCanvas::UpdateFollowButtonState() {
4949 m_muiBar->SetFollowButtonState(0);
4952 m_muiBar->SetFollowButtonState(2);
4954 m_muiBar->SetFollowButtonState(1);
4960 androidSetFollowTool(0);
4963 androidSetFollowTool(2);
4965 androidSetFollowTool(1);
4972 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4973 if (pic->m_enabled && pic->m_init_state) {
4974 switch (pic->m_api_version) {
4977 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4988void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4989 if (g_bSmoothRecenter && !m_routeState) {
4990 if (StartSmoothJump(lat, lon, scale_ppm))
4994 double gcDist, gcBearingEnd;
4995 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4997 gcBearingEnd += 180;
4998 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
5001 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
5002 double new_lat = lat + (lat_offset / (1852 * 60));
5003 double new_lon = lon + (lon_offset / (1852 * 60));
5006 StartSmoothJump(lat, lon, scale_ppm);
5011 if (lon > 180.0) lon -= 360.0;
5017 if (!GetQuiltMode()) {
5019 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
5020 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
5024 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5025 AdjustQuiltRefChart();
5032 UpdateFollowButtonState();
5040bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5045 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5046 double distance_pixels = gcDist *
GetVPScale();
5047 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5053 m_startLat = m_vLat;
5054 m_startLon = m_vLon;
5059 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5060 m_endScale = scale_ppm;
5063 m_animationDuration = 600;
5064 m_animationStart = wxGetLocalTimeMillis();
5071 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5072 m_animationActive =
true;
5077void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5079 wxLongLong now = wxGetLocalTimeMillis();
5080 double elapsed = (now - m_animationStart).ToDouble();
5081 double t = elapsed / m_animationDuration.ToDouble();
5082 if (t > 1.0) t = 1.0;
5085 double e = easeOutCubic(t);
5088 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5089 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5090 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5095 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5101 m_animationActive =
false;
5102 UpdateFollowButtonState();
5111 extendedSectorLegs.clear();
5120 if (iters++ > 5)
return false;
5121 if (!std::isnan(dlat))
break;
5124 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5130 else if (dlat < -90)
5133 if (dlon > 360.) dlon -= 360.;
5134 if (dlon < -360.) dlon += 360.;
5149 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5153 if (VPoint.b_quilt) {
5154 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5155 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5159 double tweak_scale_ppm =
5165 if (new_ref_dbIndex == -1) {
5166#pragma GCC diagnostic push
5167#pragma GCC diagnostic ignored "-Warray-bounds"
5174 int trial_index = -1;
5175 if (m_pCurrentStack->nEntry) {
5177 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5180 if (trial_index < 0) {
5181 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5182 if (full_screen_array.size())
5183 trial_index = full_screen_array[full_screen_array.size() - 1];
5186 if (trial_index >= 0) {
5187 m_pQuilt->SetReferenceChart(trial_index);
5192#pragma GCC diagnostic pop
5199 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5201 double offset_angle = atan2(offy, offx);
5202 double offset_distance = sqrt((offy * offy) + (offx * offx));
5203 double chart_angle = GetVPRotation();
5204 double target_angle = chart_angle - offset_angle;
5205 double d_east_mod = offset_distance * cos(target_angle);
5206 double d_north_mod = offset_distance * sin(target_angle);
5211 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5212 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5214 UpdateFollowButtonState();
5220 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5225bool ChartCanvas::IsOwnshipOnScreen() {
5228 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5229 ((r.y > 0) && r.y < GetCanvasHeight()))
5235void ChartCanvas::ReloadVP(
bool b_adjust) {
5236 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5238 LoadVP(VPoint, b_adjust);
5241void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5243 if (g_bopengl && m_glcc) {
5244 m_glcc->Invalidate();
5245 if (m_glcc->GetSize() != GetSize()) {
5246 m_glcc->SetSize(GetSize());
5251 m_cache_vp.Invalidate();
5252 m_bm_cache_vp.Invalidate();
5255 VPoint.Invalidate();
5257 if (m_pQuilt) m_pQuilt->Invalidate();
5266 vp.m_projection_type, b_adjust);
5269void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5270 m_pQuilt->SetReferenceChart(dbIndex);
5271 VPoint.Invalidate();
5272 m_pQuilt->Invalidate();
5275double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5277 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5284int ChartCanvas::AdjustQuiltRefChart() {
5289 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5291 double min_ref_scale =
5292 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5293 double max_ref_scale =
5294 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5297 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5298 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5299 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5301 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5304 int target_stack_index = wxNOT_FOUND;
5306 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5307 if (index == m_pQuilt->GetRefChartdbIndex()) {
5308 target_stack_index = il;
5313 if (wxNOT_FOUND == target_stack_index)
5314 target_stack_index = 0;
5316 int ref_family = pc->GetChartFamily();
5317 int extended_array_count =
5318 m_pQuilt->GetExtendedStackIndexArray().size();
5319 while ((!brender_ok) &&
5320 ((
int)target_stack_index < (extended_array_count - 1))) {
5321 target_stack_index++;
5323 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5325 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5326 IsChartQuiltableRef(test_db_index)) {
5329 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5331 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5338 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5339 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5340 IsChartQuiltableRef(new_db_index)) {
5341 m_pQuilt->SetReferenceChart(new_db_index);
5344 ret = m_pQuilt->GetRefChartdbIndex();
5346 ret = m_pQuilt->GetRefChartdbIndex();
5349 ret = m_pQuilt->GetRefChartdbIndex();
5358void ChartCanvas::UpdateCanvasOnGroupChange() {
5359 delete m_pCurrentStack;
5371bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5372 double latNE,
double lonNE) {
5374 double latc = (latSW + latNE) / 2.0;
5375 double lonc = (lonSW + lonNE) / 2.0;
5378 double ne_easting, ne_northing;
5379 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5381 double sw_easting, sw_northing;
5382 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5384 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5391 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5394bool ChartCanvas::SetVPProjection(
int projection) {
5400 double prev_true_scale_ppm = m_true_scale_ppm;
5405 m_absolute_min_scale_ppm));
5413bool ChartCanvas::SetVPRotation(
double angle) {
5415 VPoint.
skew, angle);
5418 double skew,
double rotation,
int projection,
5419 bool b_adjust,
bool b_refresh) {
5425 if (VPoint.IsValid()) {
5426 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5427 (fabs(VPoint.
skew - skew) < 1e-9) &&
5428 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5429 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5430 (VPoint.m_projection_type == projection ||
5431 projection == PROJECTION_UNKNOWN))
5434 if (VPoint.m_projection_type != projection)
5435 VPoint.InvalidateTransformCache();
5445 if (projection != PROJECTION_UNKNOWN)
5446 VPoint.SetProjectionType(projection);
5447 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5448 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5451 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5452 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5453 if (VPoint.
clat > 89.5)
5455 else if (VPoint.
clat < -89.5)
5456 VPoint.
clat = -89.5;
5461 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5462 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5474 bool bwasValid = VPoint.IsValid();
5479 m_cache_vp.Invalidate();
5484 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5488 if (top_frame::Get()->GetCanvasIndexUnderMouse() == m_canvasIndex) {
5489 int mouseX = mouse_x;
5490 int mouseY = mouse_y;
5491 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5493 double lat_mouse, lon_mouse;
5501 if (!VPoint.b_quilt && m_singleChart) {
5506 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5510 if ((!m_cache_vp.IsValid()) ||
5515 wxPoint cp_last, cp_this;
5519 if (cp_last != cp_this) {
5525 if (m_pCurrentStack) {
5527 int current_db_index;
5529 m_pCurrentStack->GetCurrentEntrydbIndex();
5531 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5533 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5536 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5540 if (VPoint.b_quilt) {
5544 m_pQuilt->InvalidateAllQuiltPatchs();
5548 if (!m_pCurrentStack)
return false;
5550 int current_db_index;
5552 m_pCurrentStack->GetCurrentEntrydbIndex();
5554 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5555 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5558 int current_ref_stack_index = -1;
5559 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5560 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5561 current_ref_stack_index = i;
5564 if (g_bFullScreenQuilt) {
5565 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5569 bool b_needNewRef =
false;
5572 if ((-1 == current_ref_stack_index) &&
5573 (m_pQuilt->GetRefChartdbIndex() >= 0))
5574 b_needNewRef =
true;
5581 bool renderable =
true;
5583 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5584 if (referenceChart) {
5585 double chartMaxScale = referenceChart->GetNormalScaleMax(
5587 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5589 if (!renderable) b_needNewRef =
true;
5592 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5594 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5595 int target_scale = cte_ref.GetScale();
5596 int target_type = cte_ref.GetChartType();
5597 int candidate_stack_index;
5604 candidate_stack_index = 0;
5605 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5607 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)) {
5613 bool renderable =
true;
5615 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5616 if (tentative_referenceChart) {
5617 double chartMaxScale =
5618 tentative_referenceChart->GetNormalScaleMax(
5620 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5623 if (renderable)
break;
5626 candidate_stack_index++;
5631 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5632 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5633 while (candidate_stack_index >= 0) {
5634 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5638 int candidate_scale = cte_candidate.GetScale();
5639 int candidate_type = cte_candidate.GetChartType();
5641 if ((candidate_scale <= target_scale) &&
5642 (candidate_type == target_type))
5645 candidate_stack_index--;
5650 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5651 (candidate_stack_index < 0))
5652 candidate_stack_index = 0;
5654 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5656 m_pQuilt->SetReferenceChart(new_ref_index);
5662 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5667 bool renderable =
true;
5669 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5670 if (referenceChart) {
5671 double chartMaxScale = referenceChart->GetNormalScaleMax(
5673 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5674 proj =
ChartData->GetDBChartProj(ref_db_index);
5676 proj = PROJECTION_MERCATOR;
5678 VPoint.b_MercatorProjectionOverride =
5679 (m_pQuilt->GetnCharts() == 0 || !renderable);
5681 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5683 VPoint.SetProjectionType(proj);
5688 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5693 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5713 m_pQuilt->Invalidate();
5730 if (b_refresh) Refresh(
false);
5737 }
else if (!g_bopengl) {
5738 OcpnProjType projection = PROJECTION_UNKNOWN;
5741 projection = m_singleChart->GetChartProjectionType();
5742 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5743 VPoint.SetProjectionType(projection);
5747 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5748 m_cache_vp.Invalidate();
5752 UpdateCanvasControlBar();
5756 if (VPoint.GetBBox().GetValid()) {
5759 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5768 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5771 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5778 wxPoint2DDouble r, r1;
5780 double delta_check =
5784 double check_point = wxMin(89., VPoint.
clat);
5786 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5789 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5790 VPoint.
clon, 0, &rhumbDist);
5795 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5796 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5798 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5802 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5808 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5810 if (m_true_scale_ppm)
5811 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5816 double round_factor = 1000.;
5820 round_factor = 100.;
5822 round_factor = 1000.;
5825 double retina_coef = 1;
5829 retina_coef = GetContentScaleFactor();
5840 double true_scale_display =
5841 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5846 if (m_displayed_scale_factor > 10.0)
5847 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5848 m_displayed_scale_factor);
5849 else if (m_displayed_scale_factor > 1.0)
5850 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5851 m_displayed_scale_factor);
5852 else if (m_displayed_scale_factor > 0.1) {
5853 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5854 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5855 }
else if (m_displayed_scale_factor > 0.01) {
5856 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5857 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5860 "%s %4.0f (---)", _(
"Scale"),
5861 true_scale_display);
5864 m_scaleValue = true_scale_display;
5866 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5868 if (m_bShowScaleInStatusBar && top_frame::Get()->GetStatusBar() &&
5869 (top_frame::Get()->GetStatusBar()->GetFieldsCount() >
5870 STAT_FIELD_SCALE)) {
5872 bool b_noshow =
false;
5876 wxClientDC dc(top_frame::Get()->GetStatusBar());
5878 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5879 dc.SetFont(*templateFont);
5880 dc.GetTextExtent(text, &w, &h);
5885 top_frame::Get()->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE,
5887 if (w && w > rect.width) {
5888 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5892 dc.GetTextExtent(text, &w, &h);
5894 if (w && w > rect.width) {
5900 if (!b_noshow) top_frame::Get()->SetStatusText(text, STAT_FIELD_SCALE);
5905 m_vLat = VPoint.
clat;
5906 m_vLon = VPoint.
clon;
5920static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5924static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5925 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5927wxColour ChartCanvas::PredColor() {
5930 if (SHIP_NORMAL == m_ownship_state)
5931 return GetGlobalColor(
"URED");
5933 else if (SHIP_LOWACCURACY == m_ownship_state)
5934 return GetGlobalColor(
"YELO1");
5936 return GetGlobalColor(
"NODTA");
5939wxColour ChartCanvas::ShipColor() {
5943 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5945 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5947 return GetGlobalColor(
"URED");
5950void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5951 wxPoint2DDouble lShipMidPoint) {
5952 dc.SetPen(wxPen(PredColor(), 2));
5954 if (SHIP_NORMAL == m_ownship_state)
5955 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5957 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5959 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5960 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5962 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5964 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5965 lShipMidPoint.m_y + 12);
5968void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5969 wxPoint GPSOffsetPixels,
5970 wxPoint2DDouble lGPSPoint) {
5975 float ref_dim = m_display_size_mm / 24;
5976 ref_dim = wxMin(ref_dim, 12);
5977 ref_dim = wxMax(ref_dim, 6);
5980 cPred.Set(g_cog_predictor_color);
5981 if (cPred == wxNullColour) cPred = PredColor();
5988 double nominal_line_width_pix = wxMax(
5990 floor(m_pix_per_mm / 2));
5994 if (nominal_line_width_pix > g_cog_predictor_width)
5995 g_cog_predictor_width = nominal_line_width_pix;
5998 wxPoint lPredPoint, lHeadPoint;
6000 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6001 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6003 double pred_lat, pred_lon;
6004 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
6005 &pred_lat, &pred_lon);
6016 float ndelta_pix = 10.;
6017 double hdg_pred_lat, hdg_pred_lon;
6018 bool b_render_hdt =
false;
6019 if (!std::isnan(
gHdt)) {
6021 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
6024 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
6025 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
6026 if (dist > ndelta_pix ) {
6027 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
6028 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6033 wxPoint lShipMidPoint;
6034 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6035 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6036 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6037 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6039 if (lpp >= img_height / 2) {
6040 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6041 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6042 !std::isnan(
gSog)) {
6044 float dash_length = ref_dim;
6045 wxDash dash_long[2];
6047 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6048 g_cog_predictor_width);
6049 dash_long[1] = dash_long[0] / 2.0;
6053 if (dash_length > 250.) {
6054 dash_long[0] = 250. / g_cog_predictor_width;
6055 dash_long[1] = dash_long[0] / 2;
6058 wxPen ppPen2(cPred, g_cog_predictor_width,
6059 (wxPenStyle)g_cog_predictor_style);
6060 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6061 ppPen2.SetDashes(2, dash_long);
6064 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6065 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6067 if (g_cog_predictor_width > 1) {
6068 float line_width = g_cog_predictor_width / 3.;
6070 wxDash dash_long3[2];
6071 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6072 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6074 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6075 (wxPenStyle)g_cog_predictor_style);
6076 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6077 ppPen3.SetDashes(2, dash_long3);
6079 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6080 lGPSPoint.m_y + GPSOffsetPixels.y,
6081 lPredPoint.x + GPSOffsetPixels.x,
6082 lPredPoint.y + GPSOffsetPixels.y);
6085 if (g_cog_predictor_endmarker) {
6087 double png_pred_icon_scale_factor = .4;
6088 if (g_ShipScaleFactorExp > 1.0)
6089 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6090 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6094 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6095 (
float)(lPredPoint.x - lShipMidPoint.x));
6096 cog_rad += (float)PI;
6098 for (
int i = 0; i < 4; i++) {
6100 double pxa = (double)(s_png_pred_icon[j]);
6101 double pya = (double)(s_png_pred_icon[j + 1]);
6103 pya *= png_pred_icon_scale_factor;
6104 pxa *= png_pred_icon_scale_factor;
6106 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6107 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6109 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6110 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6114 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6117 dc.SetBrush(wxBrush(cPred));
6119 dc.StrokePolygon(4, icon);
6126 float hdt_dash_length = ref_dim * 0.4;
6128 cPred.Set(g_ownship_HDTpredictor_color);
6129 if (cPred == wxNullColour) cPred = PredColor();
6131 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6132 : g_cog_predictor_width * 0.8);
6133 wxDash dash_short[2];
6135 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6138 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6141 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6142 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6143 ppPen2.SetDashes(2, dash_short);
6147 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6148 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6150 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6152 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6154 if (g_ownship_HDTpredictor_endmarker) {
6155 double nominal_circle_size_pixels = wxMax(
6156 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6159 if (g_ShipScaleFactorExp > 1.0)
6160 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6162 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6163 lHeadPoint.y + GPSOffsetPixels.y,
6164 nominal_circle_size_pixels / 2);
6169 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6170 double factor = 1.00;
6171 if (g_pNavAidRadarRingsStepUnits == 1)
6173 else if (g_pNavAidRadarRingsStepUnits == 2) {
6174 if (std::isnan(
gSog))
6179 factor *= g_fNavAidRadarRingsStep;
6183 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6186 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6187 pow((
double)(lGPSPoint.m_y - r.y), 2));
6188 int pix_radius = (int)lpp;
6190 wxColor rangeringcolour =
6191 user_colors::GetDimColor(g_colourOwnshipRangeRingsColour);
6193 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6196 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6198 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6199 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6204void ChartCanvas::ResetGlGridFont() { GetglCanvas()->ResetGridFont(); }
6205bool ChartCanvas::CanAccelerateGlPanning() {
6206 return GetglCanvas()->CanAcceleratePanning();
6208void ChartCanvas::SetupGlCompression() { GetglCanvas()->SetupCompression(); }
6211void ChartCanvas::ResetGlGridFont() {}
6212bool ChartCanvas::CanAccelerateGlPanning() {
return false; }
6213void ChartCanvas::SetupGlCompression() {}
6216void ChartCanvas::ComputeShipScaleFactor(
6217 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6218 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6219 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6220 float screenResolution = m_pix_per_mm;
6223 double ship_bow_lat, ship_bow_lon;
6224 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6225 &ship_bow_lat, &ship_bow_lon);
6226 wxPoint lShipBowPoint;
6227 wxPoint2DDouble b_point =
6231 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6232 powf((
float)(b_point.m_y - a_point.m_y), 2));
6235 float shipLength_mm = shipLength_px / screenResolution;
6238 float ownship_min_mm = g_n_ownship_min_mm;
6239 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6242 float hdt_ant = icon_hdt + 180.;
6243 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6244 float dx = g_n_gps_antenna_offset_x / 1852.;
6245 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6253 if (shipLength_mm < ownship_min_mm) {
6254 dy /= shipLength_mm / ownship_min_mm;
6255 dx /= shipLength_mm / ownship_min_mm;
6258 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6260 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6261 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6267 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6268 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6270 float scale_factor = shipLength_px / ownShipLength;
6273 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6276 scale_factor = wxMax(scale_factor, scale_factor_min);
6278 scale_factor_y = scale_factor;
6279 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6280 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6283void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6284 if (!GetVP().IsValid())
return;
6286 wxPoint GPSOffsetPixels(0, 0);
6287 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6290 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6291 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6295 lShipMidPoint = lGPSPoint;
6299 float icon_hdt = pCog;
6300 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6303 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6307 double osd_head_lat, osd_head_lon;
6308 wxPoint osd_head_point;
6310 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6315 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6316 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6317 icon_rad += (float)PI;
6319 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6323 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6327 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6328 if (GetVP().chart_scale >
6331 ShipDrawLargeScale(dc, lShipMidPoint);
6337 if (m_pos_image_user)
6338 pos_image = m_pos_image_user->Copy();
6339 else if (SHIP_NORMAL == m_ownship_state)
6340 pos_image = m_pos_image_red->Copy();
6341 if (SHIP_LOWACCURACY == m_ownship_state)
6342 pos_image = m_pos_image_yellow->Copy();
6343 else if (SHIP_NORMAL != m_ownship_state)
6344 pos_image = m_pos_image_grey->Copy();
6347 if (m_pos_image_user) {
6348 pos_image = m_pos_image_user->Copy();
6350 if (SHIP_LOWACCURACY == m_ownship_state)
6351 pos_image = m_pos_image_user_yellow->Copy();
6352 else if (SHIP_NORMAL != m_ownship_state)
6353 pos_image = m_pos_image_user_grey->Copy();
6356 img_height = pos_image.GetHeight();
6358 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6359 g_OwnShipIconType > 0)
6361 int ownShipWidth = 22;
6362 int ownShipLength = 84;
6363 if (g_OwnShipIconType == 1) {
6364 ownShipWidth = pos_image.GetWidth();
6365 ownShipLength = pos_image.GetHeight();
6368 float scale_factor_x, scale_factor_y;
6369 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6370 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6371 scale_factor_x, scale_factor_y);
6373 if (g_OwnShipIconType == 1) {
6374 pos_image.Rescale(ownShipWidth * scale_factor_x,
6375 ownShipLength * scale_factor_y,
6376 wxIMAGE_QUALITY_HIGH);
6377 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6379 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6382 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6383 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6384 if (rot_image.GetAlpha(ip, jp) > 64)
6385 rot_image.SetAlpha(ip, jp, 255);
6387 wxBitmap os_bm(rot_image);
6389 int w = os_bm.GetWidth();
6390 int h = os_bm.GetHeight();
6393 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6394 lShipMidPoint.m_y - h / 2,
true);
6397 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6398 lShipMidPoint.m_y - h / 2);
6399 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6400 lShipMidPoint.m_y - h / 2 + h);
6403 else if (g_OwnShipIconType == 2) {
6404 wxPoint ownship_icon[10];
6406 for (
int i = 0; i < 10; i++) {
6408 float pxa = (float)(s_ownship_icon[j]);
6409 float pya = (float)(s_ownship_icon[j + 1]);
6410 pya *= scale_factor_y;
6411 pxa *= scale_factor_x;
6413 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6414 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6416 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6417 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6420 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6422 dc.SetBrush(wxBrush(ShipColor()));
6424 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6427 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6429 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6433 img_height = ownShipLength * scale_factor_y;
6437 if (m_pos_image_user) circle_rad = 1;
6439 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6440 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6441 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6444 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6446 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6449 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6450 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6451 if (rot_image.GetAlpha(ip, jp) > 64)
6452 rot_image.SetAlpha(ip, jp, 255);
6454 wxBitmap os_bm(rot_image);
6456 if (g_ShipScaleFactorExp > 1) {
6457 wxImage scaled_image = os_bm.ConvertToImage();
6458 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6460 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6461 scaled_image.GetHeight() * factor,
6462 wxIMAGE_QUALITY_HIGH));
6464 int w = os_bm.GetWidth();
6465 int h = os_bm.GetHeight();
6468 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6469 lShipMidPoint.m_y - h / 2,
true);
6473 if (m_pos_image_user) circle_rad = 1;
6475 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6476 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6477 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6480 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6481 lShipMidPoint.m_y - h / 2);
6482 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6483 lShipMidPoint.m_y - h / 2 + h);
6488 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6501void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6502 float &MinorSpacing) {
6507 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6508 {.000001f, 45.0f, 15.0f},
6509 {.0002f, 30.0f, 10.0f},
6510 {.0003f, 10.0f, 2.0f},
6511 {.0008f, 5.0f, 1.0f},
6512 {.001f, 2.0f, 30.0f / 60.0f},
6513 {.003f, 1.0f, 20.0f / 60.0f},
6514 {.006f, 0.5f, 10.0f / 60.0f},
6515 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6516 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6517 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6518 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6519 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6520 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6521 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6522 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6525 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6526 if (view_scale_ppm < lltab[tabi][0])
break;
6527 MajorSpacing = lltab[tabi][1];
6528 MinorSpacing = lltab[tabi][2];
6542wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6543 int deg = (int)fabs(latlon);
6544 float min = fabs((fabs(latlon) - deg) * 60.0);
6554 }
else if (latlon < 0.0) {
6566 if (spacing >= 1.0) {
6567 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6568 }
else if (spacing >= (1.0 / 60.0)) {
6569 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6571 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6588void ChartCanvas::GridDraw(
ocpnDC &dc) {
6589 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6591 double nlat, elon, slat, wlon;
6594 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6596 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6598 if (!m_pgridFont) SetupGridFont();
6599 dc.SetFont(*m_pgridFont);
6600 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6603 h = m_canvas_height;
6614 dlon = dlon + 360.0;
6617 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6620 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6623 while (lat < nlat) {
6626 CalcGridText(lat, gridlatMajor,
true);
6628 dc.
DrawLine(0, r.y, w, r.y,
false);
6629 dc.DrawText(st, 0, r.y);
6630 lat = lat + gridlatMajor;
6632 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6636 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6639 while (lat < nlat) {
6642 dc.
DrawLine(0, r.y, 10, r.y,
false);
6643 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6644 lat = lat + gridlatMinor;
6648 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6651 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6654 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6656 wxString st = CalcGridText(lon, gridlonMajor,
false);
6658 dc.
DrawLine(r.x, 0, r.x, h,
false);
6659 dc.DrawText(st, r.x, 0);
6660 lon = lon + gridlonMajor;
6665 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6669 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6671 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6674 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6675 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6676 lon = lon + gridlonMinor;
6683void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6685 double blat, blon, tlat, tlon;
6688 int x_origin = m_bDisplayGrid ? 60 : 20;
6689 int y_origin = m_canvas_height - 50;
6695 if (GetVP().chart_scale > 80000)
6699 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6700 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6705 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6706 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6710 double rotation = -VPoint.
rotation;
6712 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6714 int l1 = (y_origin - r.y) / count;
6716 for (
int i = 0; i < count; i++) {
6723 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6726 double blat, blon, tlat, tlon;
6733 int y_origin = m_canvas_height - chartbar_height - 5;
6737 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6744 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6749 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6750 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6754 float places = floor(logdist), rem = logdist - places;
6755 dist = pow(10, places);
6762 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6763 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6764 double rotation = -VPoint.
rotation;
6770 int l1 = r.x - x_origin;
6772 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6777 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6778 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6779 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6781 if (!m_pgridFont) SetupGridFont();
6782 dc.SetFont(*m_pgridFont);
6783 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6785 dc.GetTextExtent(s, &w, &h);
6791 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6795void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6800 double ra_max = 40.;
6802 wxPen pen_save = dc.GetPen();
6804 wxDateTime now = wxDateTime::Now();
6810 x0 = x1 = x + radius;
6815 while (angle < 360.) {
6816 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6819 if (angle > 360.) angle = 360.;
6821 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6829 x1 = (int)(x + cos(angle * PI / 180.) * r);
6830 y1 = (int)(y + sin(angle * PI / 180.) * r);
6840 dc.
DrawLine(x + radius, y, x1, y1);
6842 dc.SetPen(pen_save);
6845static bool bAnchorSoundPlaying =
false;
6847static void onAnchorSoundFinished(
void *ptr) {
6848 o_sound::g_anchorwatch_sound->UnLoad();
6849 bAnchorSoundPlaying =
false;
6852void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6853 using namespace o_sound;
6855 bool play_sound =
false;
6857 if (AnchorAlertOn1) {
6858 wxPoint TargetPoint;
6861 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6862 TargetPoint.y, 100);
6866 AnchorAlertOn1 =
false;
6869 if (AnchorAlertOn2) {
6870 wxPoint TargetPoint;
6873 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6874 TargetPoint.y, 100);
6878 AnchorAlertOn2 =
false;
6881 if (!bAnchorSoundPlaying) {
6882 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6883 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6884 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6885 if (g_anchorwatch_sound->IsOk()) {
6886 bAnchorSoundPlaying =
true;
6887 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6888 g_anchorwatch_sound->Play();
6894void ChartCanvas::UpdateShips() {
6897 wxClientDC dc(
this);
6900 if (!dc.IsOk() || dc.GetSize().x < 1 || dc.GetSize().y < 1)
return;
6902 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6903 if (!test_bitmap.IsOk())
return;
6905 wxMemoryDC temp_dc(test_bitmap);
6907 temp_dc.ResetBoundingBox();
6908 temp_dc.DestroyClippingRegion();
6909 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6920 ocpndc.CalcBoundingBox(px.x, px.y);
6925 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6926 temp_dc.MaxY() - temp_dc.MinY());
6928 wxRect own_ship_update_rect = ship_draw_rect;
6930 if (!own_ship_update_rect.IsEmpty()) {
6933 own_ship_update_rect.Union(ship_draw_last_rect);
6934 own_ship_update_rect.Inflate(2);
6937 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6939 ship_draw_last_rect = ship_draw_rect;
6941 temp_dc.SelectObject(wxNullBitmap);
6944void ChartCanvas::UpdateAlerts() {
6949 wxClientDC dc(
this);
6953 dc.GetSize(&sx, &sy);
6956 wxBitmap test_bitmap(sx, sy, -1);
6960 temp_dc.SelectObject(test_bitmap);
6962 temp_dc.ResetBoundingBox();
6963 temp_dc.DestroyClippingRegion();
6964 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6971 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6972 temp_dc.MaxX() - temp_dc.MinX(),
6973 temp_dc.MaxY() - temp_dc.MinY());
6975 if (!alert_rect.IsEmpty())
6976 alert_rect.Inflate(2);
6978 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6981 wxRect alert_update_rect = alert_draw_rect;
6982 alert_update_rect.Union(alert_rect);
6985 RefreshRect(alert_update_rect,
false);
6989 alert_draw_rect = alert_rect;
6991 temp_dc.SelectObject(wxNullBitmap);
6994void ChartCanvas::UpdateAIS() {
7000 wxClientDC dc(
this);
7004 dc.GetSize(&sx, &sy);
7012 if (
g_pAIS->GetTargetList().size() > 10) {
7013 ais_rect = wxRect(0, 0, sx, sy);
7016 wxBitmap test_bitmap(sx, sy, -1);
7020 temp_dc.SelectObject(test_bitmap);
7022 temp_dc.ResetBoundingBox();
7023 temp_dc.DestroyClippingRegion();
7024 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
7028 AISDraw(ocpndc, GetVP(),
this);
7029 AISDrawAreaNotices(ocpndc, GetVP(),
this);
7033 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
7034 temp_dc.MaxY() - temp_dc.MinY());
7036 if (!ais_rect.IsEmpty())
7037 ais_rect.Inflate(2);
7039 temp_dc.SelectObject(wxNullBitmap);
7042 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7045 wxRect ais_update_rect = ais_draw_rect;
7046 ais_update_rect.Union(ais_rect);
7049 RefreshRect(ais_update_rect,
false);
7053 ais_draw_rect = ais_rect;
7056void ChartCanvas::ToggleCPAWarn() {
7057 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7063 g_bTCPA_Max =
false;
7067 if (STAT_FIELD_SCALE >= 4 && top_frame::Get()->GetStatusBar()) {
7068 top_frame::Get()->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7070 if (!g_AisFirstTimeUse) {
7071 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7072 _(
"CPA") +
" " + mess, 4, 4);
7077void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7079void ChartCanvas::OnSize(wxSizeEvent &event) {
7080 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7082 GetClientSize(&m_canvas_width, &m_canvas_height);
7086 m_displayScale = GetContentScaleFactor();
7090 m_canvas_width *= m_displayScale;
7091 m_canvas_height *= m_displayScale;
7104 m_absolute_min_scale_ppm =
7106 (1.2 * WGS84_semimajor_axis_meters * PI);
7109 top_frame::Get()->ProcessCanvasResize();
7119 SetMUIBarPosition();
7120 UpdateFollowButtonState();
7121 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7125 xr_margin = m_canvas_width * 95 / 100;
7126 xl_margin = m_canvas_width * 5 / 100;
7127 yt_margin = m_canvas_height * 5 / 100;
7128 yb_margin = m_canvas_height * 95 / 100;
7131 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7136 m_brepaint_piano =
true;
7139 m_dc_route.SelectObject(wxNullBitmap);
7142 m_dc_route.SelectObject(*proute_bm);
7156 m_glcc->OnSize(event);
7165void ChartCanvas::ProcessNewGUIScale() {
7173void ChartCanvas::CreateMUIBar() {
7174 if (g_useMUI && !m_muiBar) {
7175 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7176 m_muiBar->SetColorScheme(m_cs);
7177 m_muiBarHOSize = m_muiBar->m_size;
7185 SetMUIBarPosition();
7186 UpdateFollowButtonState();
7187 m_muiBar->UpdateDynamicValues();
7188 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7192void ChartCanvas::SetMUIBarPosition() {
7196 int pianoWidth = GetClientSize().x * 0.6f;
7201 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7202 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7204 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7205 m_muiBar->SetColorScheme(m_cs);
7209 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7210 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7212 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7213 m_muiBar->SetColorScheme(m_cs);
7217 m_muiBar->SetBestPosition();
7221void ChartCanvas::DestroyMuiBar() {
7228void ChartCanvas::ShowCompositeInfoWindow(
7229 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7231 if (NULL == m_pCIWin) {
7236 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7239 s = _(
"Composite of ");
7242 s1.Printf(
"%d ", n_charts);
7250 s1.Printf(_(
"Chart scale"));
7253 s2.Printf(
"1:%d\n",
scale);
7257 s1 = _(
"Zoom in for more information");
7261 int char_width = s1.Length();
7262 int char_height = 3;
7264 if (g_bChartBarEx) {
7267 for (
int i : index_vector) {
7269 wxString path = cte.GetFullSystemPath();
7273 char_width = wxMax(char_width, path.Length());
7274 if (j++ >= 9)
break;
7277 s +=
" .\n .\n .\n";
7286 m_pCIWin->SetString(s);
7288 m_pCIWin->FitToChars(char_width, char_height);
7291 p.x = x / GetContentScaleFactor();
7292 if ((p.x + m_pCIWin->GetWinSize().x) >
7293 (m_canvas_width / GetContentScaleFactor()))
7294 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7295 m_pCIWin->GetWinSize().x) /
7298 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7299 4 - m_pCIWin->GetWinSize().y;
7301 m_pCIWin->dbIndex = 0;
7302 m_pCIWin->chart_scale = 0;
7303 m_pCIWin->SetPosition(p);
7304 m_pCIWin->SetBitmap();
7305 m_pCIWin->Refresh();
7309 HideChartInfoWindow();
7313void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7315 if (NULL == m_pCIWin) {
7320 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7329 dbIndex, FULL_INIT);
7331 int char_width, char_height;
7332 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7333 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7335 m_pCIWin->SetString(s);
7336 m_pCIWin->FitToChars(char_width, char_height);
7339 p.x = x / GetContentScaleFactor();
7340 if ((p.x + m_pCIWin->GetWinSize().x) >
7341 (m_canvas_width / GetContentScaleFactor()))
7342 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7343 m_pCIWin->GetWinSize().x) /
7346 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7347 4 - m_pCIWin->GetWinSize().y;
7349 m_pCIWin->dbIndex = dbIndex;
7350 m_pCIWin->SetPosition(p);
7351 m_pCIWin->SetBitmap();
7352 m_pCIWin->Refresh();
7356 HideChartInfoWindow();
7360void ChartCanvas::HideChartInfoWindow() {
7363 m_pCIWin->Destroy();
7367 androidForceFullRepaint();
7372void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7373 wxMouseEvent ev(wxEVT_MOTION);
7376 ev.m_leftDown = mouse_leftisdown;
7378 wxEvtHandler *evthp = GetEventHandler();
7380 ::wxPostEvent(evthp, ev);
7383void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7384 if ((m_panx_target_final - m_panx_target_now) ||
7385 (m_pany_target_final - m_pany_target_now)) {
7386 DoTimedMovementTarget();
7391void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7393bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7395 if (m_disable_edge_pan)
return false;
7398 int pan_margin = m_canvas_width * margin / 100;
7399 int pan_timer_set = 200;
7400 double pan_delta = GetVP().
pix_width * delta / 100;
7404 if (x > m_canvas_width - pan_margin) {
7409 else if (x < pan_margin) {
7414 if (y < pan_margin) {
7419 else if (y > m_canvas_height - pan_margin) {
7428 wxMouseState state = ::wxGetMouseState();
7429#if wxCHECK_VERSION(3, 0, 0)
7430 if (!state.LeftIsDown())
7432 if (!state.LeftDown())
7437 if ((bft) && !pPanTimer->IsRunning()) {
7439 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7445 if ((!bft) && pPanTimer->IsRunning()) {
7455void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7456 bool setBeingEdited) {
7457 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7458 m_pRoutePointEditTarget = NULL;
7459 m_pFoundPoint = NULL;
7462 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7463 SelectableItemList SelList =
pSelect->FindSelectionList(
7473 bool brp_viz =
false;
7474 if (m_pEditRouteArray) {
7475 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7476 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7477 if (pr->IsVisible()) {
7483 brp_viz = frp->IsVisible();
7487 if (m_pEditRouteArray)
7489 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7490 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7493 m_bRouteEditing = setBeingEdited;
7496 frp->m_bRPIsBeingEdited = setBeingEdited;
7497 m_bMarkEditing = setBeingEdited;
7500 m_pRoutePointEditTarget = frp;
7501 m_pFoundPoint = pFind;
7506std::shared_ptr<HostApi121::PiPointContext>
7507ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7521 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7522 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7523 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7524 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7525 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7529 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7532 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7537 int FoundAIS_MMSI = 0;
7539 FoundAIS_MMSI = pFindAIS->GetUserData();
7542 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7543 seltype |= SELTYPE_AISTARGET;
7549 Route *SelectedRoute = NULL;
7555 Route *pSelectedActiveRoute = NULL;
7556 Route *pSelectedVizRoute = NULL;
7559 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7560 SelectableItemList SelList =
7561 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7569 bool brp_viz =
false;
7571 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7573 if (pr->IsVisible()) {
7578 if (!brp_viz && prp->IsShared())
7580 brp_viz = prp->IsVisible();
7583 brp_viz = prp->IsVisible();
7585 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7591 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7594 pSelectedActiveRoute = pr;
7595 pFoundActiveRoutePoint = prp;
7600 if (NULL == pSelectedVizRoute) {
7601 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7603 if (pr->IsVisible()) {
7604 pSelectedVizRoute = pr;
7605 pFoundVizRoutePoint = prp;
7611 delete proute_array;
7616 if (pFoundActiveRoutePoint) {
7617 FoundRoutePoint = pFoundActiveRoutePoint;
7618 SelectedRoute = pSelectedActiveRoute;
7619 }
else if (pFoundVizRoutePoint) {
7620 FoundRoutePoint = pFoundVizRoutePoint;
7621 SelectedRoute = pSelectedVizRoute;
7624 FoundRoutePoint = pFirstVizPoint;
7626 if (SelectedRoute) {
7627 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7628 }
else if (FoundRoutePoint) {
7629 seltype |= SELTYPE_MARKPOINT;
7634 if (m_pFoundRoutePoint) {
7638 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7639 RefreshRect(wp_rect,
true);
7648 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7649 SelectableItemList SelList =
7650 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7652 if (NULL == SelectedRoute)
7657 if (pr->IsVisible()) {
7664 if (SelectedRoute) {
7665 if (NULL == FoundRoutePoint)
7666 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7669 seltype |= SELTYPE_ROUTESEGMENT;
7673 if (pFindTrackSeg) {
7674 m_pSelectedTrack = NULL;
7675 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7676 SelectableItemList SelList =
7677 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7682 if (pt->IsVisible()) {
7683 m_pSelectedTrack = pt;
7687 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7690 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7693 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7694 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7695 rstruct->object_ident =
"";
7697 if (seltype == SELTYPE_AISTARGET) {
7698 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7700 val.Printf(
"%d", FoundAIS_MMSI);
7701 rstruct->object_ident = val.ToStdString();
7702 }
else if (seltype & SELTYPE_MARKPOINT) {
7703 if (FoundRoutePoint) {
7704 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7705 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7707 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7708 if (SelectedRoute) {
7709 rstruct->object_type =
7710 HostApi121::PiContextObjectType::kObjectRoutesegment;
7711 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7713 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7714 if (m_pSelectedTrack) {
7715 rstruct->object_type =
7716 HostApi121::PiContextObjectType::kObjectTracksegment;
7717 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7724void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7725 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7726 singleClickEventIsValid =
false;
7727 m_DoubleClickTimer->Stop();
7732bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7733 if (!m_bChartDragging && !m_bDrawingRoute) {
7738 if (m_Compass && m_Compass->IsShown()) {
7740 bool isInCompass = logicalRect.Contains(event.GetPosition());
7741 if (isInCompass || m_mouseWasInCompass) {
7742 if (m_Compass->MouseEvent(event)) {
7743 cursor_region = CENTER;
7744 if (!g_btouch) SetCanvasCursor(event);
7745 m_mouseWasInCompass = isInCompass;
7749 m_mouseWasInCompass = isInCompass;
7752 if (m_notification_button && m_notification_button->IsShown()) {
7754 bool isinButton = logicalRect.Contains(event.GetPosition());
7756 SetCursor(*pCursorArrow);
7757 if (event.LeftDown()) HandleNotificationMouseClick();
7762 if (MouseEventToolbar(event))
return true;
7764 if (MouseEventChartBar(event))
return true;
7766 if (MouseEventMUIBar(event))
return true;
7768 if (MouseEventIENCBar(event))
return true;
7773void ChartCanvas::HandleNotificationMouseClick() {
7774 if (!m_NotificationsList) {
7778 m_NotificationsList->RecalculateSize();
7779 m_NotificationsList->Hide();
7782 if (m_NotificationsList->IsShown()) {
7783 m_NotificationsList->Hide();
7785 m_NotificationsList->RecalculateSize();
7786 m_NotificationsList->ReloadNotificationList();
7787 m_NotificationsList->Show();
7790bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7791 if (!g_bShowChartBar)
return false;
7793 if (!m_Piano->MouseEvent(event))
return false;
7795 cursor_region = CENTER;
7796 if (!g_btouch) SetCanvasCursor(event);
7800bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7801 if (!IsPrimaryCanvas())
return false;
7810 cursor_region = CENTER;
7811 if (!g_btouch) SetCanvasCursor(event);
7815bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7816 if (!IsPrimaryCanvas())
return false;
7829bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7831 if (!m_muiBar->MouseEvent(event))
return false;
7834 cursor_region = CENTER;
7835 if (!g_btouch) SetCanvasCursor(event);
7847 event.GetPosition(&x, &y);
7849 x *= m_displayScale;
7850 y *= m_displayScale;
7852 m_MouseDragging =
event.Dragging();
7858 if (event.Dragging()) {
7859 if ((x == mouse_x) && (y == mouse_y))
return true;
7865 mouse_leftisdown =
event.LeftDown();
7869 cursor_region = CENTER;
7873 if (m_Compass && m_Compass->IsShown() &&
7874 m_Compass->
GetRect().Contains(event.GetPosition())) {
7875 cursor_region = CENTER;
7876 }
else if (x > xr_margin) {
7877 cursor_region = MID_RIGHT;
7878 }
else if (x < xl_margin) {
7879 cursor_region = MID_LEFT;
7880 }
else if (y > yb_margin - chartbar_height &&
7881 y < m_canvas_height - chartbar_height) {
7882 cursor_region = MID_TOP;
7883 }
else if (y < yt_margin) {
7884 cursor_region = MID_BOT;
7886 cursor_region = CENTER;
7889 if (!g_btouch) SetCanvasCursor(event);
7893 leftIsDown =
event.LeftDown();
7896 if (event.LeftDown()) {
7897 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7900 g_bTempShowMenuBar =
false;
7901 top_frame::Get()->ApplyGlobalSettings(
false);
7909 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7910 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7914 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7915 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7918 event.SetEventObject(
this);
7919 if (SendMouseEventToPlugins(event))
7926 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7927 StartChartDragInertia();
7930 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7931 !singleClickEventIsValid) {
7933 if (m_DoubleClickTimer->IsRunning()) {
7934 m_DoubleClickTimer->Stop();
7939 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7940 singleClickEvent = event;
7941 singleClickEventIsValid =
true;
7950 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7951 if (g_click_stop > 0) {
7959 if (GetUpMode() == COURSE_UP_MODE) {
7960 m_b_rot_hidef =
false;
7961 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7963 pRotDefTimer->Stop();
7966 bool bRoll = !g_btouch;
7971 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7972 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7973 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7974 m_RolloverPopupTimer.Start(
7978 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7982 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7991#if !defined(__WXGTK__) && !defined(__WXQT__)
7999 if ((x >= 0) && (y >= 0))
8004 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
8005 wxPoint p = ClientToScreen(wxPoint(x, y));
8011 if (m_routeState >= 2) {
8014 m_bDrawingRoute =
true;
8016 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8021 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
8024 m_bDrawingRoute =
true;
8026 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8039#if defined(__WXMAC__) || defined(__ANDROID__)
8043 wxClientDC cdc(GetParent());
8055 if (m_pSelectedRoute) {
8057 m_pSelectedRoute->DeSelectRoute();
8059 if (g_bopengl && m_glcc) {
8064 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8067 if (m_pFoundRoutePoint) {
8075 if (g_btouch && m_pRoutePointEditTarget) {
8078 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8082 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8083 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8084 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8085 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8086 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8090 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8093 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8099 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8102 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8103 seltype |= SELTYPE_AISTARGET;
8108 m_pFoundRoutePoint = NULL;
8113 Route *pSelectedActiveRoute = NULL;
8114 Route *pSelectedVizRoute = NULL;
8117 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8118 SelectableItemList SelList =
8119 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8127 bool brp_viz =
false;
8129 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8131 if (pr->IsVisible()) {
8136 if (!brp_viz && prp->IsShared())
8138 brp_viz = prp->IsVisible();
8141 brp_viz = prp->IsVisible();
8143 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8148 m_pSelectedRoute = NULL;
8150 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8153 pSelectedActiveRoute = pr;
8154 pFoundActiveRoutePoint = prp;
8159 if (NULL == pSelectedVizRoute) {
8160 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8162 if (pr->IsVisible()) {
8163 pSelectedVizRoute = pr;
8164 pFoundVizRoutePoint = prp;
8170 delete proute_array;
8175 if (pFoundActiveRoutePoint) {
8176 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8177 m_pSelectedRoute = pSelectedActiveRoute;
8178 }
else if (pFoundVizRoutePoint) {
8179 m_pFoundRoutePoint = pFoundVizRoutePoint;
8180 m_pSelectedRoute = pSelectedVizRoute;
8183 m_pFoundRoutePoint = pFirstVizPoint;
8185 if (m_pSelectedRoute) {
8186 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8187 }
else if (m_pFoundRoutePoint) {
8188 seltype |= SELTYPE_MARKPOINT;
8192 if (m_pFoundRoutePoint) {
8196 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8197 RefreshRect(wp_rect,
true);
8205 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8206 SelectableItemList SelList =
8207 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8209 if (NULL == m_pSelectedRoute)
8214 if (pr->IsVisible()) {
8215 m_pSelectedRoute = pr;
8221 if (m_pSelectedRoute) {
8222 if (NULL == m_pFoundRoutePoint)
8223 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8228 if (g_bopengl && m_glcc) {
8233 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8235 seltype |= SELTYPE_ROUTESEGMENT;
8239 if (pFindTrackSeg) {
8240 m_pSelectedTrack = NULL;
8241 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8242 SelectableItemList SelList =
8243 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8248 if (pt->IsVisible()) {
8249 m_pSelectedTrack = pt;
8253 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8259 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8260 seltype |= SELTYPE_CURRENTPOINT;
8263 else if (pFindTide) {
8264 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8265 seltype |= SELTYPE_TIDEPOINT;
8270 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8275IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8285 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8286 SelectableItemList SelList =
8287 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8290 pFind = *SelList.begin();
8291 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8293 auto node = SelList.begin();
8294 if (SelList.size() > 1) {
8295 for (++node; node != SelList.end(); ++node) {
8298 if (pIDX_candidate->
IDX_type ==
'c') {
8299 pIDX_best_candidate = pIDX_candidate;
8304 pFind = *SelList.begin();
8305 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8308 return pIDX_best_candidate;
8310void ChartCanvas::CallPopupMenu(
int x,
int y) {
8314 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8322 if (SELTYPE_CURRENTPOINT == seltype) {
8328 if (SELTYPE_TIDEPOINT == seltype) {
8334 InvokeCanvasMenu(x, y, seltype);
8337 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8341 m_pSelectedRoute = NULL;
8343 if (m_pFoundRoutePoint) {
8344 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8347 m_pFoundRoutePoint = NULL;
8353bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8361 event.GetPosition(&x, &y);
8367 SelectRadius = g_Platform->GetSelectRadiusPix() /
8368 (m_true_scale_ppm * 1852 * 60);
8375 if (event.LeftDClick() && (cursor_region == CENTER)) {
8376 m_DoubleClickTimer->Start();
8377 singleClickEventIsValid =
false;
8383 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8386 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8389 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8390 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8391 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8397 SelectableItemList rpSelList =
8398 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8399 bool b_onRPtarget =
false;
8402 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8403 b_onRPtarget =
true;
8411 std::unique_ptr<HostApi> host_api =
GetHostApi();
8412 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8414 if (m_pRoutePointEditTarget) {
8416 if ((api_121->GetContextMenuMask() &
8417 api_121->kContextMenuDisableWaypoint))
8419 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8425 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8428 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8429 m_pRoutePointEditTarget = NULL;
8430 RefreshRect(wp_rect,
true);
8434 auto node = rpSelList.begin();
8435 if (node != rpSelList.end()) {
8439 wxArrayPtrVoid *proute_array =
8444 bool brp_viz =
false;
8446 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8448 if (pr->IsVisible()) {
8453 delete proute_array;
8457 brp_viz = frp->IsVisible();
8459 brp_viz = frp->IsVisible();
8462 if ((api_121->GetContextMenuMask() &
8463 api_121->kContextMenuDisableWaypoint))
8466 ShowMarkPropertiesDialog(frp);
8475 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8477 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8480 if (pr->IsVisible()) {
8481 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8486 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8488 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8491 if (pt->IsVisible()) {
8492 ShowTrackPropertiesDialog(pt);
8501 if (m_bShowCurrent) {
8503 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8505 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8507 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8508 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8510 if (pic->m_enabled && pic->m_init_state &&
8511 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8514 if (m_pIDXCandidate) {
8515 info.point_type = CURRENT_STATION;
8519 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8520 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8524 if (plugin) plugin->OnTideCurrentClick(info);
8539 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8541 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8543 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8544 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8546 if (pic->m_enabled && pic->m_init_state &&
8547 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8550 if (m_pIDXCandidate) {
8551 info.point_type = TIDE_STATION;
8555 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8556 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8560 if (plugin) plugin->OnTideCurrentClick(info);
8575 ShowObjectQueryWindow(x, y, zlat, zlon);
8580 if (event.LeftDown()) {
8596 bool appending =
false;
8597 bool inserting =
false;
8600 SetCursor(*pCursorPencil);
8604 m_bRouteEditing =
true;
8606 if (m_routeState == 1) {
8607 m_pMouseRoute =
new Route();
8608 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8618 double nearby_radius_meters =
8619 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8622 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8623 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8624 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8625 wxArrayPtrVoid *proute_array =
8630 bool brp_viz =
false;
8632 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8634 if (pr->IsVisible()) {
8639 delete proute_array;
8641 pNearbyPoint->IsShared())
8644 pNearbyPoint->IsVisible();
8646 brp_viz = pNearbyPoint->IsVisible();
8649 wxString msg = _(
"Use nearby waypoint?");
8651 const bool noname(pNearbyPoint->GetName() ==
"");
8654 _(
"Use nearby nameless waypoint and name it M with"
8655 " a unique number?");
8658 m_FinishRouteOnKillFocus =
false;
8660 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8661 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8662 m_FinishRouteOnKillFocus =
true;
8663 if (dlg_return == wxID_YES) {
8665 if (m_pMouseRoute) {
8666 int last_wp_num = m_pMouseRoute->GetnPoints();
8668 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8669 wxString wp_name = wxString::Format(
8670 "M%002i-%s", last_wp_num + 1, guid_short);
8671 pNearbyPoint->SetName(wp_name);
8673 pNearbyPoint->SetName(
"WPXX");
8675 pMousePoint = pNearbyPoint;
8678 if (m_routeState > 1)
8679 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8680 Undo_HasParent, NULL);
8683 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8684 bool procede =
false;
8688 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8694 m_FinishRouteOnKillFocus =
false;
8700 _(
"Insert first part of this route in the new route?");
8701 if (tail->GetIndexOf(pMousePoint) ==
8704 dmsg = _(
"Insert this route in the new route?");
8706 if (tail->GetIndexOf(pMousePoint) > 0) {
8707 dlg_return = OCPNMessageBox(
8708 this, dmsg, _(
"OpenCPN Route Create"),
8709 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8710 m_FinishRouteOnKillFocus =
true;
8712 if (dlg_return == wxID_YES) {
8719 _(
"Append last part of this route to the new route?");
8720 if (tail->GetIndexOf(pMousePoint) == 1)
8722 "Append this route to the new route?");
8727 if (tail->GetLastPoint() != pMousePoint) {
8728 dlg_return = OCPNMessageBox(
8729 this, dmsg, _(
"OpenCPN Route Create"),
8730 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8731 m_FinishRouteOnKillFocus =
true;
8733 if (dlg_return == wxID_YES) {
8744 if (!FindRouteContainingWaypoint(pMousePoint))
8745 pMousePoint->SetShared(
true);
8750 if (NULL == pMousePoint) {
8751 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8753 pMousePoint->SetNameShown(
false);
8757 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8759 if (m_routeState > 1)
8760 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8761 Undo_IsOrphanded, NULL);
8764 if (m_pMouseRoute) {
8765 if (m_routeState == 1) {
8767 m_pMouseRoute->AddPoint(pMousePoint);
8770 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8771 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8772 &rhumbBearing, &rhumbDist);
8773 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8774 rlat, &gcDist, &gcBearing, NULL);
8775 double gcDistNM = gcDist / 1852.0;
8778 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8779 pow(rhumbDist - gcDistNM - 1, 0.5);
8782 msg << _(
"For this leg the Great Circle route is ")
8784 << _(
" shorter than rhumbline.\n\n")
8785 << _(
"Would you like include the Great Circle routing points "
8788 m_FinishRouteOnKillFocus =
false;
8789 m_disable_edge_pan =
true;
8792 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8793 wxYES_NO | wxNO_DEFAULT);
8795 m_disable_edge_pan =
false;
8796 m_FinishRouteOnKillFocus =
true;
8798 if (answer == wxID_YES) {
8800 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8801 wxRealPoint gcCoord;
8803 for (
int i = 1; i <= segmentCount; i++) {
8804 double fraction = (double)i * (1.0 / (
double)segmentCount);
8805 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8806 gcDist * fraction, gcBearing,
8807 &gcCoord.x, &gcCoord.y, NULL);
8809 if (i < segmentCount) {
8810 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8812 gcPoint->SetNameShown(
false);
8814 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8816 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8819 gcPoint = pMousePoint;
8822 m_pMouseRoute->AddPoint(gcPoint);
8823 pSelect->AddSelectableRouteSegment(
8824 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8825 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8826 prevGcPoint = gcPoint;
8829 undo->CancelUndoableAction(
true);
8832 m_pMouseRoute->AddPoint(pMousePoint);
8833 pSelect->AddSelectableRouteSegment(
8834 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8835 pMousePoint, m_pMouseRoute);
8836 undo->AfterUndoableAction(m_pMouseRoute);
8840 m_pMouseRoute->AddPoint(pMousePoint);
8841 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8842 rlon, m_prev_pMousePoint,
8843 pMousePoint, m_pMouseRoute);
8844 undo->AfterUndoableAction(m_pMouseRoute);
8850 m_prev_pMousePoint = pMousePoint;
8858 int connect = tail->GetIndexOf(pMousePoint);
8863 int length = tail->GetnPoints();
8868 start = connect + 1;
8874 m_pMouseRoute->RemovePoint(m_pMouseRoute->GetLastPoint());
8876 for (i = start; i <= stop; i++) {
8877 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8880 m_pMouseRoute->GetnPoints();
8882 top_frame::Get()->RefreshAllCanvas();
8886 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8888 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8889 m_pMouseRoute->FinalizeForRendering();
8891 top_frame::Get()->RefreshAllCanvas();
8895 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8897 SetCursor(*pCursorPencil);
8899 if (!m_pMeasureRoute) {
8900 m_pMeasureRoute =
new Route();
8904 if (m_nMeasureState == 1) {
8911 wxEmptyString, wxEmptyString);
8913 pMousePoint->SetShowWaypointRangeRings(
false);
8915 m_pMeasureRoute->AddPoint(pMousePoint);
8919 m_prev_pMousePoint = pMousePoint;
8923 top_frame::Get()->RefreshAllCanvas();
8928 FindRoutePointsAtCursor(SelectRadius,
true);
8932 m_last_touch_down_pos =
event.GetPosition();
8934 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8942 if (ret)
return true;
8945 if (event.Dragging()) {
8948 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8950 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8952 SelectableItemList SelList =
pSelect->FindSelectionList(
8956 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8961 if (m_pRoutePointEditTarget &&
8962 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8964 SelectableItemList SelList =
pSelect->FindSelectionList(
8968 if (m_pRoutePointEditTarget == frp) {
8969 m_bIsInRadius =
true;
8974 if (!m_dragoffsetSet) {
8976 .PresetDragOffset(
this, mouse_x, mouse_y);
8977 m_dragoffsetSet =
true;
8982 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8983 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8986 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8988 DraggingAllowed =
false;
8990 if (m_pRoutePointEditTarget &&
8991 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8992 DraggingAllowed =
false;
8994 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8996 if (DraggingAllowed) {
8997 if (!undo->InUndoableAction()) {
8998 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8999 Undo_NeedsCopy, m_pFoundPoint);
9005 if (!g_bopengl && m_pEditRouteArray) {
9006 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9007 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9014 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9015 pre_rect.Union(route_rect);
9023 if (CheckEdgePan(x, y,
true, 5, 2))
9031 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9033 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9034 m_pRoutePointEditTarget,
9035 SELTYPE_DRAGHANDLE);
9036 m_pFoundPoint->m_slat =
9037 m_pRoutePointEditTarget->m_lat;
9038 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9040 m_pRoutePointEditTarget->m_lat =
9042 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9043 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9044 m_pFoundPoint->m_slat =
9046 m_pFoundPoint->m_slon = new_cursor_lon;
9062 if (m_pEditRouteArray) {
9063 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9065 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9068 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9069 post_rect.Union(route_rect);
9075 pre_rect.Union(post_rect);
9076 RefreshRect(pre_rect,
false);
9078 top_frame::Get()->RefreshCanvasOther(
this);
9079 m_bRoutePoinDragging =
true;
9084 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9085 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9088 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9090 DraggingAllowed =
false;
9092 if (m_pRoutePointEditTarget &&
9093 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9094 DraggingAllowed =
false;
9096 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9098 if (DraggingAllowed) {
9099 if (!undo->InUndoableAction()) {
9100 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9101 Undo_NeedsCopy, m_pFoundPoint);
9115 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9121 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9122 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9123 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9124 (
int)(lppmax - (pre_rect.height / 2)));
9132 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9135 m_pRoutePointEditTarget,
9136 SELTYPE_DRAGHANDLE);
9137 m_pFoundPoint->m_slat =
9138 m_pRoutePointEditTarget->m_lat;
9139 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9141 m_pRoutePointEditTarget->m_lat =
9144 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9157 if (!g_btouch) InvalidateGL();
9163 .CalculateDCRect(m_dc_route,
this, &post_rect);
9164 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9165 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9166 (
int)(lppmax - (post_rect.height / 2)));
9169 pre_rect.Union(post_rect);
9170 RefreshRect(pre_rect,
false);
9172 top_frame::Get()->RefreshCanvasOther(
this);
9173 m_bRoutePoinDragging =
true;
9175 ret = g_btouch ? m_bRoutePoinDragging :
true;
9178 if (ret)
return true;
9181 if (event.LeftUp()) {
9182 bool b_startedit_route =
false;
9183 m_dragoffsetSet =
false;
9186 m_bChartDragging =
false;
9187 m_bIsInRadius =
false;
9194 int dx = x - m_touchdownPos.x;
9195 int dy = y - m_touchdownPos.y;
9196 int dist2 = dx * dx + dy * dy;
9197 bool wasPan = (dist2 > 20 * 20);
9204 m_bedge_pan =
false;
9209 bool appending =
false;
9210 bool inserting =
false;
9216 if (m_pRoutePointEditTarget) {
9222 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9223 RefreshRect(wp_rect,
true);
9225 m_pRoutePointEditTarget = NULL;
9227 m_bRouteEditing =
true;
9229 if (m_routeState == 1) {
9230 m_pMouseRoute =
new Route();
9231 m_pMouseRoute->SetHiLite(50);
9235 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9242 double nearby_radius_meters =
9243 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9246 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9247 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9248 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9251 m_FinishRouteOnKillFocus =
9253 dlg_return = OCPNMessageBox(
9254 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9255 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9256 m_FinishRouteOnKillFocus =
true;
9258 dlg_return = wxID_YES;
9260 if (dlg_return == wxID_YES) {
9261 pMousePoint = pNearbyPoint;
9264 if (m_routeState > 1)
9265 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9266 Undo_HasParent, NULL);
9267 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9269 bool procede =
false;
9273 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9279 m_FinishRouteOnKillFocus =
false;
9280 if (m_routeState == 1) {
9284 _(
"Insert first part of this route in the new route?");
9285 if (tail->GetIndexOf(pMousePoint) ==
9288 dmsg = _(
"Insert this route in the new route?");
9290 if (tail->GetIndexOf(pMousePoint) != 1) {
9292 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9293 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9294 m_FinishRouteOnKillFocus =
true;
9296 if (dlg_return == wxID_YES) {
9303 _(
"Append last part of this route to the new route?");
9304 if (tail->GetIndexOf(pMousePoint) == 1)
9306 "Append this route to the new route?");
9310 if (tail->GetLastPoint() != pMousePoint) {
9312 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9313 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9314 m_FinishRouteOnKillFocus =
true;
9316 if (dlg_return == wxID_YES) {
9327 if (!FindRouteContainingWaypoint(pMousePoint))
9328 pMousePoint->SetShared(
true);
9332 if (NULL == pMousePoint) {
9333 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9335 pMousePoint->SetNameShown(
false);
9337 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9339 if (m_routeState > 1)
9340 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9341 Undo_IsOrphanded, NULL);
9344 if (m_routeState == 1) {
9346 m_pMouseRoute->AddPoint(pMousePoint);
9347 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9351 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9352 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9353 &rhumbBearing, &rhumbDist);
9354 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9355 &gcDist, &gcBearing, NULL);
9356 double gcDistNM = gcDist / 1852.0;
9359 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9360 pow(rhumbDist - gcDistNM - 1, 0.5);
9363 msg << _(
"For this leg the Great Circle route is ")
9365 << _(
" shorter than rhumbline.\n\n")
9366 << _(
"Would you like include the Great Circle routing points "
9370 m_FinishRouteOnKillFocus =
false;
9371 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9372 wxYES_NO | wxNO_DEFAULT);
9373 m_FinishRouteOnKillFocus =
true;
9375 int answer = wxID_NO;
9378 if (answer == wxID_YES) {
9380 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9381 wxRealPoint gcCoord;
9383 for (
int i = 1; i <= segmentCount; i++) {
9384 double fraction = (double)i * (1.0 / (
double)segmentCount);
9385 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9386 gcDist * fraction, gcBearing,
9387 &gcCoord.x, &gcCoord.y, NULL);
9389 if (i < segmentCount) {
9390 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9392 gcPoint->SetNameShown(
false);
9393 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9396 gcPoint = pMousePoint;
9399 m_pMouseRoute->AddPoint(gcPoint);
9400 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9402 pSelect->AddSelectableRouteSegment(
9403 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9404 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9405 prevGcPoint = gcPoint;
9408 undo->CancelUndoableAction(
true);
9411 m_pMouseRoute->AddPoint(pMousePoint);
9412 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9413 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9414 rlon, m_prev_pMousePoint,
9415 pMousePoint, m_pMouseRoute);
9416 undo->AfterUndoableAction(m_pMouseRoute);
9420 m_pMouseRoute->AddPoint(pMousePoint);
9421 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9423 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9424 rlon, m_prev_pMousePoint,
9425 pMousePoint, m_pMouseRoute);
9426 undo->AfterUndoableAction(m_pMouseRoute);
9432 m_prev_pMousePoint = pMousePoint;
9439 int connect = tail->GetIndexOf(pMousePoint);
9444 int length = tail->GetnPoints();
9449 start = connect + 1;
9454 m_pMouseRoute->RemovePoint(
9458 for (i = start; i <= stop; i++) {
9459 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9462 m_pMouseRoute->GetnPoints();
9464 top_frame::Get()->RefreshAllCanvas();
9468 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9470 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9471 m_pMouseRoute->FinalizeForRendering();
9476 }
else if (m_bMeasure_Active && m_nMeasureState)
9479 m_bedge_pan =
false;
9485 int mdx = x - m_touchdownPos.x;
9486 int mdy = y - m_touchdownPos.y;
9487 if (mdx * mdx + mdy * mdy > 20 * 20)
return false;
9490 if (m_nMeasureState == 1) {
9491 m_pMeasureRoute =
new Route();
9497 if (m_pMeasureRoute) {
9500 wxEmptyString, wxEmptyString);
9503 m_pMeasureRoute->AddPoint(pMousePoint);
9507 m_prev_pMousePoint = pMousePoint;
9509 m_pMeasureRoute->GetnPoints();
9513 CancelMeasureRoute();
9519 bool bSelectAllowed =
true;
9521 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9523 bSelectAllowed =
false;
9527 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9528 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9529 significant_drag) ||
9530 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9531 significant_drag)) {
9532 bSelectAllowed =
false;
9540 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9542 if (bSelectAllowed) {
9543 bool b_was_editing_mark = m_bMarkEditing;
9544 bool b_was_editing_route = m_bRouteEditing;
9545 FindRoutePointsAtCursor(SelectRadius,
9551 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9552 m_pRoutePointEditTarget = NULL;
9554 if (!b_was_editing_route) {
9555 if (m_pEditRouteArray) {
9556 b_startedit_route =
true;
9560 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9561 m_pTrackRolloverWin->IsActive(
false);
9563 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9564 m_pRouteRolloverWin->IsActive(
false);
9568 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9570 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9578 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9579 pre_rect.Union(route_rect);
9582 RefreshRect(pre_rect,
true);
9585 b_startedit_route =
false;
9589 if (m_pRoutePointEditTarget) {
9590 if (b_was_editing_mark ||
9591 b_was_editing_route) {
9592 if (m_lastRoutePointEditTarget) {
9596 .EnableDragHandle(
false);
9597 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9598 SELTYPE_DRAGHANDLE);
9602 if (m_pRoutePointEditTarget) {
9605 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9606 wxPoint2DDouble dragHandlePoint =
9608 .GetDragHandlePoint(
this);
9610 dragHandlePoint.m_y, dragHandlePoint.m_x,
9611 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9614 if (m_lastRoutePointEditTarget) {
9618 .EnableDragHandle(
false);
9619 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9620 SELTYPE_DRAGHANDLE);
9623 wxArrayPtrVoid *lastEditRouteArray =
9625 m_lastRoutePointEditTarget);
9626 if (lastEditRouteArray) {
9627 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9629 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9634 delete lastEditRouteArray;
9645 if (m_lastRoutePointEditTarget) {
9648 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9649 RefreshRect(wp_rect,
true);
9652 if (m_pRoutePointEditTarget) {
9655 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9656 RefreshRect(wp_rect,
true);
9664 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9665 bool b_start_rollover =
false;
9669 if (pFind) b_start_rollover =
true;
9672 if (!b_start_rollover && !b_startedit_route) {
9673 SelectableItemList SelList =
pSelect->FindSelectionList(
9677 if (pr && pr->IsVisible()) {
9678 b_start_rollover =
true;
9684 if (!b_start_rollover && !b_startedit_route) {
9685 SelectableItemList SelList =
pSelect->FindSelectionList(
9689 if (tr && tr->IsVisible()) {
9690 b_start_rollover =
true;
9696 if (b_start_rollover)
9697 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9701 bool appending =
false;
9702 bool inserting =
false;
9704 if (m_bRouteEditing ) {
9706 if (m_pRoutePointEditTarget) {
9712 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9713 double nearby_radius_meters =
9714 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9715 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9716 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9717 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9719 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9723 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9725 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9729 std::find(list->begin(), list->end(), pNearbyPoint);
9730 if (pos != list->end()) {
9742 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9747 OCPNMessageBox(
this,
9748 _(
"Replace this RoutePoint by the nearby "
9750 _(
"OpenCPN RoutePoint change"),
9751 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9752 if (dlg_return == wxID_YES) {
9757 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9760 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9762 if (tail && current && (tail != current)) {
9764 connect = tail->GetIndexOf(pNearbyPoint);
9765 int index_current_route =
9766 current->GetIndexOf(m_pRoutePointEditTarget);
9767 index_last = current->GetIndexOf(current->GetLastPoint());
9768 dlg_return1 = wxID_NO;
9770 index_current_route) {
9772 if (connect != tail->GetnPoints()) {
9775 _(
"Last part of route to be appended to dragged "
9779 _(
"Full route to be appended to dragged route?");
9781 dlg_return1 = OCPNMessageBox(
9782 this, dmsg, _(
"OpenCPN Route Create"),
9783 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9784 if (dlg_return1 == wxID_YES) {
9788 }
else if (index_current_route ==
9793 _(
"First part of route to be inserted into dragged "
9795 if (connect == tail->GetnPoints())
9797 "Full route to be inserted into dragged route?");
9799 dlg_return1 = OCPNMessageBox(
9800 this, dmsg, _(
"OpenCPN Route Create"),
9801 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9802 if (dlg_return1 == wxID_YES) {
9809 if (m_pRoutePointEditTarget->IsShared()) {
9811 dlg_return = OCPNMessageBox(
9813 _(
"Do you really want to delete and replace this "
9815 "\n" + _(
"which has been created manually?"),
9816 (
"OpenCPN RoutePoint warning"),
9817 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9820 if (dlg_return == wxID_YES) {
9821 pMousePoint = pNearbyPoint;
9823 pMousePoint->SetShared(
true);
9833 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9835 if (m_pEditRouteArray) {
9836 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9838 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9843 auto pos = std::find(list->begin(), list->end(),
9844 m_pRoutePointEditTarget);
9846 pSelect->DeleteAllSelectableRoutePoints(pr);
9847 pSelect->DeleteAllSelectableRouteSegments(pr);
9850 pos = std::find(list->begin(), list->end(),
9851 m_pRoutePointEditTarget);
9854 pSelect->AddAllSelectableRouteSegments(pr);
9855 pSelect->AddAllSelectableRoutePoints(pr);
9857 pr->FinalizeForRendering();
9858 pr->UpdateSegmentDistances();
9859 if (m_bRoutePoinDragging) {
9861 NavObj_dB::GetInstance().UpdateRoute(pr);
9869 if (m_pEditRouteArray) {
9870 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9872 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9891 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9898 delete m_pRoutePointEditTarget;
9899 m_lastRoutePointEditTarget = NULL;
9900 m_pRoutePointEditTarget = NULL;
9901 undo->AfterUndoableAction(pMousePoint);
9902 undo->InvalidateUndo();
9907 else if (m_bMarkEditing) {
9908 if (m_pRoutePointEditTarget)
9909 if (m_bRoutePoinDragging) {
9911 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9915 if (m_pRoutePointEditTarget)
9916 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9918 if (!m_pRoutePointEditTarget) {
9919 delete m_pEditRouteArray;
9920 m_pEditRouteArray = NULL;
9921 m_bRouteEditing =
false;
9923 m_bRoutePoinDragging =
false;
9930 int length = tail->GetnPoints();
9931 for (
int i = connect + 1; i <= length; i++) {
9932 current->AddPointAndSegment(tail->GetPoint(i),
false);
9935 top_frame::Get()->RefreshAllCanvas();
9938 current->FinalizeForRendering();
9944 pSelect->DeleteAllSelectableRoutePoints(current);
9945 pSelect->DeleteAllSelectableRouteSegments(current);
9946 for (
int i = 1; i < connect; i++) {
9947 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9949 pSelect->AddAllSelectableRouteSegments(current);
9950 pSelect->AddAllSelectableRoutePoints(current);
9951 current->FinalizeForRendering();
9958 if (m_pEditRouteArray) {
9959 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9960 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9973 if (m_bRouteEditing) {
9976 bool appending =
false;
9977 bool inserting =
false;
9980 if (m_pRoutePointEditTarget) {
9981 m_pRoutePointEditTarget->
m_bBlink =
false;
9985 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9986 double nearby_radius_meters =
9987 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9988 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9989 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9990 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9992 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9993 bool duplicate =
false;
9995 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9997 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10001 std::find(list->begin(), list->end(), pNearbyPoint);
10002 if (pos != list->end()) {
10014 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
10019 OCPNMessageBox(
this,
10020 _(
"Replace this RoutePoint by the nearby "
10022 _(
"OpenCPN RoutePoint change"),
10023 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10024 if (dlg_return == wxID_YES) {
10028 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
10031 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
10033 if (tail && current && (tail != current)) {
10035 connect = tail->GetIndexOf(pNearbyPoint);
10036 int index_current_route =
10037 current->GetIndexOf(m_pRoutePointEditTarget);
10038 index_last = current->GetIndexOf(current->GetLastPoint());
10039 dlg_return1 = wxID_NO;
10041 index_current_route) {
10043 if (connect != tail->GetnPoints()) {
10046 _(
"Last part of route to be appended to dragged "
10050 _(
"Full route to be appended to dragged route?");
10052 dlg_return1 = OCPNMessageBox(
10053 this, dmsg, _(
"OpenCPN Route Create"),
10054 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10055 if (dlg_return1 == wxID_YES) {
10059 }
else if (index_current_route ==
10061 if (connect != 1) {
10064 _(
"First part of route to be inserted into dragged "
10066 if (connect == tail->GetnPoints())
10068 "Full route to be inserted into dragged route?");
10070 dlg_return1 = OCPNMessageBox(
10071 this, dmsg, _(
"OpenCPN Route Create"),
10072 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10073 if (dlg_return1 == wxID_YES) {
10080 if (m_pRoutePointEditTarget->IsShared()) {
10081 dlg_return = wxID_NO;
10082 dlg_return = OCPNMessageBox(
10084 _(
"Do you really want to delete and replace this "
10086 "\n" + _(
"which has been created manually?"),
10087 (
"OpenCPN RoutePoint warning"),
10088 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10091 if (dlg_return == wxID_YES) {
10092 pMousePoint = pNearbyPoint;
10094 pMousePoint->SetShared(
true);
10104 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10106 if (m_pEditRouteArray) {
10107 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10109 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10113 auto pos = std::find(list->begin(), list->end(),
10114 m_pRoutePointEditTarget);
10116 pSelect->DeleteAllSelectableRoutePoints(pr);
10117 pSelect->DeleteAllSelectableRouteSegments(pr);
10120 pos = std::find(list->begin(), list->end(),
10121 m_pRoutePointEditTarget);
10122 if (pos != list->end()) list->erase(pos);
10125 pSelect->AddAllSelectableRouteSegments(pr);
10126 pSelect->AddAllSelectableRoutePoints(pr);
10128 pr->FinalizeForRendering();
10129 pr->UpdateSegmentDistances();
10132 if (m_bRoutePoinDragging) {
10137 NavObj_dB::GetInstance().UpdateRoutePoint(
10138 m_pRoutePointEditTarget);
10140 NavObj_dB::GetInstance().UpdateRoute(pr);
10152 int length = tail->GetnPoints();
10153 for (
int i = connect + 1; i <= length; i++) {
10154 current->AddPointAndSegment(tail->GetPoint(i),
false);
10158 top_frame::Get()->RefreshAllCanvas();
10161 current->FinalizeForRendering();
10167 pSelect->DeleteAllSelectableRoutePoints(current);
10168 pSelect->DeleteAllSelectableRouteSegments(current);
10169 for (
int i = 1; i < connect; i++) {
10170 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10172 pSelect->AddAllSelectableRouteSegments(current);
10173 pSelect->AddAllSelectableRoutePoints(current);
10174 current->FinalizeForRendering();
10181 if (m_pEditRouteArray) {
10182 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10184 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10196 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10203 delete m_pRoutePointEditTarget;
10204 m_lastRoutePointEditTarget = NULL;
10205 undo->AfterUndoableAction(pMousePoint);
10206 undo->InvalidateUndo();
10211 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10214 delete m_pEditRouteArray;
10215 m_pEditRouteArray = NULL;
10219 m_bRouteEditing =
false;
10220 m_pRoutePointEditTarget = NULL;
10226 else if (m_bMarkEditing) {
10227 if (m_pRoutePointEditTarget) {
10228 if (m_bRoutePoinDragging) {
10230 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10232 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10237 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10239 RefreshRect(wp_rect,
true);
10242 m_pRoutePointEditTarget = NULL;
10243 m_bMarkEditing =
false;
10248 else if (leftIsDown) {
10249 leftIsDown =
false;
10253 if (!m_bChartDragging && !m_bMeasure_Active) {
10255 m_bChartDragging =
false;
10259 m_bRoutePoinDragging =
false;
10262 if (ret)
return true;
10265 if (event.RightDown()) {
10276 m_FinishRouteOnKillFocus =
false;
10277 CallPopupMenu(mx, my);
10278 m_FinishRouteOnKillFocus =
true;
10288 if (event.ShiftDown()) {
10292 event.GetPosition(&x, &y);
10294 x *= m_displayScale;
10295 y *= m_displayScale;
10301 int wheel_dir =
event.GetWheelRotation();
10304 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10305 wheel_dir = wheel_dir > 0 ? 1 : -1;
10307 double factor = g_mouse_zoom_sensitivity;
10308 if (wheel_dir < 0) factor = 1 / factor;
10311 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10312 if (wheel_dir == m_last_wheel_dir) {
10313 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10318 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10319 m_wheelstopwatch.Start(0);
10324 m_last_wheel_dir = wheel_dir;
10329 if (event.LeftDown()) {
10335 last_drag.x = x, last_drag.y = y;
10336 m_touchdownPos = wxPoint(x, y);
10337 panleftIsDown =
true;
10340 if (event.LeftUp()) {
10341 if (panleftIsDown) {
10343 panleftIsDown =
false;
10346 if (!m_bChartDragging && !m_bMeasure_Active) {
10347 switch (cursor_region) {
10369 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10374 m_bChartDragging =
false;
10380 if (event.Dragging() && event.LeftIsDown()) {
10396 if (g_btouch && !m_inPinch) {
10397 struct timespec now;
10398 clock_gettime(CLOCK_MONOTONIC, &now);
10399 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10401 bool trigger_hold =
false;
10402 if (
false == m_bChartDragging) {
10403 if (m_DragTrigger < 0) {
10406 m_DragTriggerStartTime = tnow;
10407 trigger_hold =
true;
10409 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10410 m_DragTrigger = -1;
10415 if (trigger_hold)
return true;
10417 if (
false == m_bChartDragging) {
10420 last_drag.x = x - 1, last_drag.y = y - 1;
10421 m_bChartDragging =
true;
10422 m_chart_drag_total_time = 0;
10423 m_chart_drag_total_x = 0;
10424 m_chart_drag_total_y = 0;
10425 m_inertia_last_drag_x = x;
10426 m_inertia_last_drag_y = y;
10427 m_drag_vec_x.clear();
10428 m_drag_vec_y.clear();
10429 m_drag_vec_t.clear();
10430 m_last_drag_time = tnow;
10434 uint64_t delta_t = tnow - m_last_drag_time;
10435 double delta_tf = delta_t / 1e9;
10437 m_chart_drag_total_time += delta_tf;
10438 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10439 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10441 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10442 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10443 m_drag_vec_t.push_back(delta_tf);
10445 m_inertia_last_drag_x = x;
10446 m_inertia_last_drag_y = y;
10447 m_last_drag_time = tnow;
10449 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10450 m_bChartDragging =
true;
10451 StartTimedMovement();
10452 m_pan_drag.x += last_drag.x - x;
10453 m_pan_drag.y += last_drag.y - y;
10454 last_drag.x = x, last_drag.y = y;
10456 }
else if (!g_btouch) {
10457 if ((last_drag.x != x) || (last_drag.y != y)) {
10458 if (!m_routeState) {
10461 m_bChartDragging =
true;
10462 StartTimedMovement();
10463 m_pan_drag.x += last_drag.x - x;
10464 m_pan_drag.y += last_drag.y - y;
10465 last_drag.x = x, last_drag.y = y;
10472 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10474 m_DoubleClickTimer->Start();
10475 singleClickEventIsValid =
false;
10483void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10484 if (MouseEventOverlayWindows(event))
return;
10488 bool nm = MouseEventProcessObjects(event);
10492void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10495 wxCursor *ptarget_cursor = pCursorArrow;
10496 if (!pPlugIn_Cursor) {
10497 ptarget_cursor = pCursorArrow;
10498 if ((!m_routeState) &&
10499 (!m_bMeasure_Active) ) {
10500 if (cursor_region == MID_RIGHT) {
10501 ptarget_cursor = pCursorRight;
10502 }
else if (cursor_region == MID_LEFT) {
10503 ptarget_cursor = pCursorLeft;
10504 }
else if (cursor_region == MID_TOP) {
10505 ptarget_cursor = pCursorDown;
10506 }
else if (cursor_region == MID_BOT) {
10507 ptarget_cursor = pCursorUp;
10509 ptarget_cursor = pCursorArrow;
10511 }
else if (m_bMeasure_Active ||
10513 ptarget_cursor = pCursorPencil;
10515 ptarget_cursor = pPlugIn_Cursor;
10518 SetCursor(*ptarget_cursor);
10521void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10522 SetCursor(*pCursorArrow);
10525void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10529 wxArrayString files;
10531 ChartBase *target_chart = GetChartAtCursor();
10532 if (target_chart) {
10533 file.Assign(target_chart->GetFullPath());
10534 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10535 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10538 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10540 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10541 unsigned int im = stackIndexArray.size();
10542 int scale = 2147483647;
10543 if (VPoint.b_quilt && im > 0) {
10544 for (
unsigned int is = 0; is < im; is++) {
10545 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10546 CHART_TYPE_MBTILES) {
10547 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10549 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10550 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10552 .Contains(lat, lon)) {
10553 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10556 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10557 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10565 std::vector<Ais8_001_22 *> area_notices;
10567 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10570 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10571 auto target_data = target.second;
10572 if (!target_data->area_notices.empty()) {
10573 for (
auto &ani : target_data->area_notices) {
10578 for (Ais8_001_22_SubAreaList::iterator sa =
10579 area_notice.sub_areas.begin();
10580 sa != area_notice.sub_areas.end(); ++sa) {
10581 switch (sa->shape) {
10582 case AIS8_001_22_SHAPE_CIRCLE: {
10583 wxPoint target_point;
10585 bbox.Expand(target_point);
10586 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10589 case AIS8_001_22_SHAPE_RECT: {
10590 wxPoint target_point;
10592 bbox.Expand(target_point);
10593 if (sa->e_dim_m > sa->n_dim_m)
10594 bbox.EnLarge(sa->e_dim_m * vp_scale);
10596 bbox.EnLarge(sa->n_dim_m * vp_scale);
10599 case AIS8_001_22_SHAPE_POLYGON:
10600 case AIS8_001_22_SHAPE_POLYLINE: {
10601 for (
int i = 0; i < 4; ++i) {
10602 double lat = sa->latitude;
10603 double lon = sa->longitude;
10604 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10606 wxPoint target_point;
10608 bbox.Expand(target_point);
10612 case AIS8_001_22_SHAPE_SECTOR: {
10613 double lat1 = sa->latitude;
10614 double lon1 = sa->longitude;
10616 wxPoint target_point;
10618 bbox.Expand(target_point);
10619 for (
int i = 0; i < 18; ++i) {
10622 sa->left_bound_deg +
10623 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10624 sa->radius_m / 1852.0, &lat, &lon);
10626 bbox.Expand(target_point);
10628 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10631 bbox.Expand(target_point);
10637 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10638 area_notices.push_back(&area_notice);
10645 if (target_chart || !area_notices.empty() || file.HasName()) {
10647 int sel_rad_pix = 5;
10648 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10653 SetCursor(wxCURSOR_WAIT);
10654 bool lightsVis = m_encShowLights;
10655 if (!lightsVis) SetShowENCLights(
true);
10658 ListOfObjRazRules *rule_list = NULL;
10659 ListOfPI_S57Obj *pi_rule_list = NULL;
10662 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10663 else if (target_plugin_chart)
10664 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10665 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10667 ListOfObjRazRules *overlay_rule_list = NULL;
10668 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10671 if (CHs57_Overlay) {
10672 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10673 zlat, zlon, SelectRadius, &GetVP());
10676 if (!lightsVis) SetShowENCLights(
false);
10679 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10680 wxString face = dFont->GetFaceName();
10684 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10685 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10689 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10697 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10698 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10701 int points = dFont->GetPointSize();
10703 int points = dFont->GetPointSize() + 1;
10707 for (
int i = -2; i < 5; i++) {
10708 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10712 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10714 if (overlay_rule_list && CHs57_Overlay) {
10715 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10716 objText <<
"<hr noshade>";
10719 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10720 an != area_notices.end(); ++an) {
10721 objText <<
"<b>AIS Area Notice:</b> ";
10722 objText << ais8_001_22_notice_names[(*an)->notice_type];
10723 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10724 (*an)->sub_areas.begin();
10725 sa != (*an)->sub_areas.end(); ++sa)
10726 if (!sa->text.empty()) objText << sa->text;
10727 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10728 objText <<
"<hr noshade>";
10732 objText << Chs57->CreateObjDescriptions(rule_list);
10733 else if (target_plugin_chart)
10734 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10737 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10740 wxString AddFiles, filenameOK;
10742 if (!target_plugin_chart) {
10745 AddFiles = wxString::Format(
10746 "<hr noshade><br><b>Additional info files attached to: </b> "
10748 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10750 file.GetFullName());
10752 file.Assign(file.GetPath(),
"");
10753 wxDir dir(file.GetFullPath());
10755 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10757 file.Assign(dir.GetNameWithSep().append(filename));
10758 wxString FormatString =
10759 "<td valign=top><font size=-2><a "
10760 "href=\"%s\">%s</a></font></td>";
10761 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10762 filenameOK = file.GetFullPath();
10764 if (3 * ((
int)filecount / 3) == filecount)
10765 FormatString.Prepend(
"<tr>");
10767 FormatString.Prepend(
10768 "<td>  </td>");
10771 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10772 file.GetFullName());
10775 cont = dir.GetNext(&filename);
10777 objText << AddFiles <<
"</table>";
10779 objText <<
"</font>";
10780 objText <<
"</body></html>";
10782 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10786 if ((!Chs57 && filecount == 1)) {
10788 wxHtmlLinkInfo hli(filenameOK);
10789 wxHtmlLinkEvent hle(1, hli);
10793 if (rule_list) rule_list->Clear();
10796 if (overlay_rule_list) overlay_rule_list->Clear();
10797 delete overlay_rule_list;
10799 if (pi_rule_list) pi_rule_list->Clear();
10800 delete pi_rule_list;
10802 SetCursor(wxCURSOR_ARROW);
10806void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10815 wxSize canvas_size = GetSize();
10822 wxPoint canvas_pos = GetPosition();
10825 bool newFit =
false;
10826 if (canvas_size.x < fitted_size.x) {
10827 fitted_size.x = canvas_size.x - 40;
10828 if (canvas_size.y < fitted_size.y)
10829 fitted_size.y -= 40;
10831 if (canvas_size.y < fitted_size.y) {
10832 fitted_size.y = canvas_size.y - 40;
10833 if (canvas_size.x < fitted_size.x)
10834 fitted_size.x -= 40;
10845 wxString title_base = _(
"Mark Properties");
10847 title_base = _(
"Waypoint Properties");
10852 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10864void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10874 if (g_bresponsive) {
10875 wxSize canvas_size = GetSize();
10876 wxPoint canvas_pos = GetPosition();
10880 if (canvas_size.x < fitted_size.x) {
10881 fitted_size.x = canvas_size.x;
10882 if (canvas_size.y < fitted_size.y)
10883 fitted_size.y -= 20;
10885 if (canvas_size.y < fitted_size.y) {
10886 fitted_size.y = canvas_size.y;
10887 if (canvas_size.x < fitted_size.x)
10888 fitted_size.x -= 20;
10897 wxPoint xxp = ClientToScreen(canvas_pos);
10908void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10920void pupHandler_PasteWaypoint() {
10923 int pasteBuffer = kml.ParsePasteBuffer();
10924 RoutePoint *pasted = kml.GetParsedRoutePoint();
10925 if (!pasted)
return;
10927 double nearby_radius_meters =
10928 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10930 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10931 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10933 int answer = wxID_NO;
10937 "There is an existing waypoint at the same location as the one you are "
10938 "pasting. Would you like to merge the pasted data with it?\n\n");
10939 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10940 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10941 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10944 if (answer == wxID_YES) {
10945 nearPoint->SetName(pasted->GetName());
10951 if (answer == wxID_NO) {
10954 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10957 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10966 top_frame::Get()->InvalidateAllGL();
10967 top_frame::Get()->RefreshAllCanvas(
false);
10970void pupHandler_PasteRoute() {
10973 int pasteBuffer = kml.ParsePasteBuffer();
10974 Route *pasted = kml.GetParsedRoute();
10975 if (!pasted)
return;
10977 double nearby_radius_meters =
10978 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10984 bool mergepoints =
false;
10985 bool createNewRoute =
true;
10986 int existingWaypointCounter = 0;
10988 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10989 curPoint = pasted->GetPoint(i);
10990 nearPoint = pWayPointMan->GetNearbyWaypoint(
10991 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10993 mergepoints =
true;
10994 existingWaypointCounter++;
11002 int answer = wxID_NO;
11006 "There are existing waypoints at the same location as some of the ones "
11007 "you are pasting. Would you like to just merge the pasted data into "
11009 msg << _(
"Answering 'No' will create all new waypoints for this route.");
11010 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
11011 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
11013 if (answer == wxID_CANCEL) {
11020 if (mergepoints && answer == wxID_YES &&
11021 existingWaypointCounter == pasted->GetnPoints()) {
11024 createNewRoute =
false;
11030 Route *newRoute = 0;
11033 if (createNewRoute) {
11034 newRoute =
new Route();
11038 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11039 curPoint = pasted->GetPoint(i);
11042 newPoint = pWayPointMan->GetNearbyWaypoint(
11043 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11044 newPoint->SetName(curPoint->GetName());
11047 if (createNewRoute) newRoute->AddPoint(newPoint);
11053 newPoint->SetIconName(
"circle");
11056 newPoint->SetShared(
false);
11058 newRoute->AddPoint(newPoint);
11059 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11062 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11065 if (i > 1 && createNewRoute)
11066 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11067 curPoint->m_lat, curPoint->m_lon,
11068 prevPoint, newPoint, newRoute);
11069 prevPoint = newPoint;
11072 if (createNewRoute) {
11075 NavObj_dB::GetInstance().InsertRoute(newRoute);
11085 top_frame::Get()->InvalidateAllGL();
11086 top_frame::Get()->RefreshAllCanvas(
false);
11092void pupHandler_PasteTrack() {
11095 int pasteBuffer = kml.ParsePasteBuffer();
11096 Track *pasted = kml.GetParsedTrack();
11097 if (!pasted)
return;
11105 newTrack->SetName(pasted->GetName());
11107 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11108 curPoint = pasted->GetPoint(i);
11112 wxDateTime now = wxDateTime::Now();
11115 newTrack->AddPoint(newPoint);
11118 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11119 newPoint->m_lat, newPoint->m_lon,
11120 prevPoint, newPoint, newTrack);
11122 prevPoint = newPoint;
11127 NavObj_dB::GetInstance().InsertTrack(newTrack);
11129 top_frame::Get()->InvalidateAllGL();
11130 top_frame::Get()->RefreshAllCanvas(
false);
11133bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11136 v[
"CursorPosition_x"] = x;
11137 v[
"CursorPosition_y"] = y;
11140 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11141 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11142 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11147 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11149 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11152#define SELTYPE_UNKNOWN 0x0001
11153#define SELTYPE_ROUTEPOINT 0x0002
11154#define SELTYPE_ROUTESEGMENT 0x0004
11155#define SELTYPE_TIDEPOINT 0x0008
11156#define SELTYPE_CURRENTPOINT 0x0010
11157#define SELTYPE_ROUTECREATE 0x0020
11158#define SELTYPE_AISTARGET 0x0040
11159#define SELTYPE_MARKPOINT 0x0080
11160#define SELTYPE_TRACKSEGMENT 0x0100
11161#define SELTYPE_DRAGHANDLE 0x0200
11164 if (g_bhide_context_menus)
return true;
11166 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11167 m_pIDXCandidate, m_nmea_log);
11170 wxEVT_COMMAND_MENU_SELECTED,
11171 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11177 if (m_inLongPress) {
11178 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11179 m_inLongPress =
false;
11183 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11186 wxEVT_COMMAND_MENU_SELECTED,
11187 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11189 delete m_canvasMenu;
11190 m_canvasMenu = NULL;
11200void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11203 if (m_canvasMenu) {
11204 m_canvasMenu->PopupMenuHandler(event);
11209void ChartCanvas::StartRoute() {
11211 if (g_brouteCreating)
return;
11215 g_brouteCreating =
true;
11217 m_bDrawingRoute =
false;
11218 SetCursor(*pCursorPencil);
11220 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11222 HideGlobalToolbar();
11225 androidSetRouteAnnunciator(
true);
11229wxString ChartCanvas::FinishRoute() {
11231 m_prev_pMousePoint = NULL;
11232 m_bDrawingRoute =
false;
11234 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11237 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11239 androidSetRouteAnnunciator(
false);
11242 SetCursor(*pCursorArrow);
11244 if (m_pMouseRoute) {
11245 if (m_bAppendingRoute) {
11247 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11249 if (m_pMouseRoute->GetnPoints() > 1) {
11251 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11254 m_pMouseRoute = NULL;
11257 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11269 m_bAppendingRoute =
false;
11270 m_pMouseRoute = NULL;
11272 m_pSelectedRoute = NULL;
11274 undo->InvalidateUndo();
11275 top_frame::Get()->RefreshAllCanvas(
true);
11279 ShowGlobalToolbar();
11281 g_brouteCreating =
false;
11286void ChartCanvas::HideGlobalToolbar() {
11287 if (m_canvasIndex == 0) {
11288 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11292void ChartCanvas::ShowGlobalToolbar() {
11293 if (m_canvasIndex == 0) {
11294 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11298void ChartCanvas::ShowAISTargetList() {
11299 if (NULL == g_pAISTargetList) {
11303 g_pAISTargetList->UpdateAISTargetList();
11306void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11307 if (!m_bShowOutlines)
return;
11311 int nEntry =
ChartData->GetChartTableEntries();
11313 for (
int i = 0; i < nEntry; i++) {
11317 bool b_group_draw =
false;
11318 if (m_groupIndex > 0) {
11319 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11320 int index = pt->GetGroupArray()[ig];
11321 if (m_groupIndex == index) {
11322 b_group_draw =
true;
11327 b_group_draw =
true;
11329 if (b_group_draw) RenderChartOutline(dc, i, vp);
11335 if (VPoint.b_quilt) {
11336 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11337 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11341 }
else if (m_singleChart &&
11342 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11346 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11349 if (zoom_factor > 8.0) {
11350 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11353 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11357 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11361void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11363 if (g_bopengl && m_glcc) {
11365 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11370 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11371 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11374 float plylat, plylon;
11375 float plylat1, plylon1;
11377 int pixx, pixy, pixx1, pixy1;
11380 ChartData->GetDBBoundingBox(dbIndex, box);
11384 if (box.GetLonRange() == 360)
return;
11386 double lon_bias = 0;
11388 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11390 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11392 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11393 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11395 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11396 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11399 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11402 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11403 if (0 == nAuxPlyEntries)
11407 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11408 plylon += lon_bias;
11414 for (
int i = 0; i < nPly - 1; i++) {
11415 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11416 plylon1 += lon_bias;
11422 int pixxs1 = pixx1;
11423 int pixys1 = pixy1;
11425 bool b_skip =
false;
11429 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11430 pow((
double)(pixy1 - pixy), 2)) /
11436 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11441 if (fabs(dist - distgc) > 10000. * 1852.)
11447 ClipResult res = cohen_sutherland_line_clip_i(
11449 if (res != Invisible && !b_skip)
11450 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11458 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11459 plylon1 += lon_bias;
11465 ClipResult res = cohen_sutherland_line_clip_i(
11467 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11474 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11475 for (
int j = 0; j < nAuxPlyEntries; j++) {
11477 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11482 for (
int i = 0; i < nAuxPly - 1; i++) {
11483 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11489 int pixxs1 = pixx1;
11490 int pixys1 = pixy1;
11492 bool b_skip =
false;
11496 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11497 ((pixy1 - pixy) * (pixy1 - pixy))) /
11502 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11507 if (fabs(dist - distgc) > 10000. * 1852.)
11513 ClipResult res = cohen_sutherland_line_clip_i(
11515 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11523 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11528 ClipResult res = cohen_sutherland_line_clip_i(
11530 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11535static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11536 const wxArrayString &legend) {
11537 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11539 int pointsize = dFont->GetPointSize();
11543 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11544 false, dFont->GetFaceName());
11546 dc.SetFont(*psRLI_font);
11553 int hilite_offset = 3;
11555 for (wxString line : legend) {
11558 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11560 dc.GetTextExtent(line, &wl, &hl);
11569 xp = ref_point.x - w;
11571 yp += hilite_offset;
11573 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11575 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11576 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11578 for (wxString line : legend) {
11579 dc.DrawText(line, xp, yp);
11584void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11585 if (!g_bAllowShipToActive)
return;
11591 wxPoint2DDouble pa, pb;
11598 if (rt->
m_width != wxPENSTYLE_INVALID)
11600 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11601 g_shipToActiveStyle, 5)];
11602 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11604 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11607 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11610 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11613 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11614 (
int)pb.m_y, GetVP(),
true);
11618#ifdef USE_ANDROID_GLES2
11619 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11621 if (style != wxPENSTYLE_SOLID) {
11622 if (glChartCanvas::dash_map.find(style) !=
11623 glChartCanvas::dash_map.end()) {
11624 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11628 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11631 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11632 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11638void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11640 if (m_routeState >= 2) route = m_pMouseRoute;
11641 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11642 route = m_pMeasureRoute;
11644 if (!route)
return;
11652 int np = route->GetnPoints();
11654 if (g_btouch && (np > 1)) np--;
11656 render_lat = rp.m_lat;
11657 render_lon = rp.m_lon;
11660 double rhumbBearing, rhumbDist;
11662 &rhumbBearing, &rhumbDist);
11663 double brg = rhumbBearing;
11664 double dist = rhumbDist;
11668 double gcBearing, gcBearing2, gcDist;
11669 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11672 double gcDistm = gcDist / 1852.0;
11675 rhumbBearing = 90.;
11677 wxPoint destPoint, lastPoint;
11680 int milesDiff = rhumbDist - gcDistm;
11681 if (milesDiff > 1) {
11692 for (
int i = 1; i <= milesDiff; i++) {
11693 double p = (double)i * (1.0 / (
double)milesDiff);
11695 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11696 &pLon, &pLat, &gcBearing2);
11698 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11700 lastPoint = destPoint;
11703 if (r_rband.x && r_rband.y) {
11704 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11706 if (m_bMeasure_DistCircle) {
11707 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11708 powf((
float)(r_rband.y - lastPoint.y), 2));
11711 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11712 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11718 wxString routeInfo;
11719 wxArrayString infoArray;
11722 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11728 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11730 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11731 (
int)varBrg, 0x00B0);
11734 infoArray.Add(routeInfo);
11740 routeInfo <<
"Reverse: ";
11742 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11743 (
int)(brg + 180.) % 360, 0x00B0);
11745 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11746 (
int)(varBrg + 180.) % 360, 0x00B0);
11747 infoArray.Add(routeInfo);
11753 s0.Append(_(
"Route") +
": ");
11755 s0.Append(_(
"Layer Route: "));
11758 if (!g_btouch) disp_length += dist;
11764 RouteLegInfo(dc, r_rband, infoArray);
11766 m_brepaint_piano =
true;
11769void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11770 if (!m_bShowVisibleSectors)
return;
11772 if (g_bDeferredInitDone) {
11774 double rhumbBearing, rhumbDist;
11775 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11776 &rhumbBearing, &rhumbDist);
11778 if (rhumbDist > 0.05)
11780 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11781 m_sectorlegsVisible);
11782 m_sector_glat =
gLat;
11783 m_sector_glon =
gLon;
11785 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11789void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11797void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11798 if (!ps52plib)
return;
11800 if (VPoint.b_quilt) {
11801 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11803 if (m_pQuilt->IsQuiltVector()) {
11804 if (ps52plib->GetStateHash() != m_s52StateHash) {
11806 m_s52StateHash = ps52plib->GetStateHash();
11810 if (ps52plib->GetStateHash() != m_s52StateHash) {
11812 m_s52StateHash = ps52plib->GetStateHash();
11817 bool bSendPlibState =
true;
11818 if (VPoint.b_quilt) {
11819 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11822 if (bSendPlibState) {
11824 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11825 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11826 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11827 v[
"OpenCPN Version Date"] = VERSION_DATE;
11828 v[
"OpenCPN Version Full"] = VERSION_FULL;
11831 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11832 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11833 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11834 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11835 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11836 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11837 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11841 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11842 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11846 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11847 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11848 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11849 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11850 ps52plib->m_bShowS57ImportantTextOnly;
11851 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11852 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11853 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11854 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11855 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11858 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11859 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11860 v[
"OpenCPN Scale Factor Exp"] =
11861 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11868 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11869 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11870 g_lastS52PLIBPluginMessage = out;
11877 wxPaintDC dc(
this);
11887 if (!m_b_paint_enable) {
11895 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11897 if (m_glcc && g_bopengl) {
11898 if (!s_in_update) {
11908 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11910 wxRegion ru = GetUpdateRegion();
11912 int rx, ry, rwidth, rheight;
11913 ru.GetBox(rx, ry, rwidth, rheight);
11915#ifdef ocpnUSE_DIBSECTION
11918 wxMemoryDC temp_dc;
11926 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11927 height += m_Piano->GetHeight();
11929 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11933 int thumbx, thumby, thumbsx, thumbsy;
11934 pthumbwin->GetPosition(&thumbx, &thumby);
11935 pthumbwin->GetSize(&thumbsx, &thumbsy);
11936 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11939 rgn_chart.Subtract(rgn_thumbwin);
11940 ru.Subtract(rgn_thumbwin);
11946 wxRegion rgn_blit = ru;
11947 if (g_bShowChartBar) {
11948 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11949 GetClientSize().x, m_Piano->GetHeight());
11952 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11953 if (style->chartStatusWindowTransparent)
11954 m_brepaint_piano =
true;
11956 ru.Subtract(chart_bar_rect);
11960 if (m_Compass && m_Compass->IsShown()) {
11961 wxRect compassRect = m_Compass->
GetRect();
11962 if (ru.Contains(compassRect) != wxOutRegion) {
11963 ru.Subtract(compassRect);
11967 if (m_notification_button) {
11968 wxRect noteRect = m_notification_button->
GetRect();
11969 if (ru.Contains(noteRect) != wxOutRegion) {
11970 ru.Subtract(noteRect);
11975 bool b_newview =
true;
11980 m_cache_vp.IsValid()) {
11986 bool b_rcache_ok =
false;
11987 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11988 b_rcache_ok = !b_newview;
11991 if (VPoint.b_MercatorProjectionOverride)
11992 VPoint.SetProjectionType(PROJECTION_MERCATOR);
12006 if (b_rcache_ok) chart_get_region.Clear();
12009 if (VPoint.b_quilt)
12011 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
12013 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
12018 AbstractPlatform::ShowBusySpinner();
12022 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
12023 (m_working_bm.GetHeight() != svp.
pix_height))
12027 if (fabs(VPoint.
rotation) < 0.01) {
12028 bool b_save =
true;
12033 m_cache_vp.Invalidate();
12047 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12052 int dy = c_new.y - c_old.y;
12053 int dx = c_new.x - c_old.x;
12058 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12062 temp_dc.SelectObject(m_working_bm);
12064 wxMemoryDC cache_dc;
12065 cache_dc.SelectObject(m_cached_chart_bm);
12069 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12072 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12078 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12081 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12089 update_region.Union(
12092 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12097 update_region.Union(
12100 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12104 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12106 cache_dc.SelectObject(wxNullBitmap);
12110 temp_dc.SelectObject(m_cached_chart_bm);
12113 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12117 temp_dc.SelectObject(m_working_bm);
12118 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12123 temp_dc.SelectObject(m_cached_chart_bm);
12128 temp_dc.SelectObject(m_working_bm);
12129 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12142 wxMemoryDC scratch_dc_0;
12143 scratch_dc_0.SelectObject(m_cached_chart_bm);
12146 scratch_dc_0.SelectObject(wxNullBitmap);
12155 temp_dc.SelectObject(m_working_bm);
12158 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12159 chart_get_all_region);
12162 AbstractPlatform::HideBusySpinner();
12168 if (!m_singleChart) {
12169 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12174 if (!chart_get_region.IsEmpty()) {
12175 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12179 if (temp_dc.IsOk()) {
12184 if (!VPoint.b_quilt) {
12187 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12188 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12195 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12196 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12199 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12201 temp_dc.DestroyClippingRegion();
12206 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12208 if (!backgroundRegion.IsEmpty()) {
12214 wxColour water = pWorldBackgroundChart->water;
12215 if (water.IsOk()) {
12216 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12217 temp_dc.SetBrush(wxBrush(water));
12219 while (upd.HaveRects()) {
12220 wxRect rect = upd.GetRect();
12221 temp_dc.DrawRectangle(rect);
12226 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12227 temp_dc.SetDeviceClippingRegion(*clip_region);
12228 delete clip_region;
12232 SetVPRotation(VPoint.
skew);
12241 wxMemoryDC *pChartDC = &temp_dc;
12242 wxMemoryDC rotd_dc;
12244 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12246 if (!b_rcache_ok) {
12248 wxMemoryDC tbase_dc;
12250 tbase_dc.SelectObject(bm_base);
12252 tbase_dc.SelectObject(wxNullBitmap);
12254 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12257 wxImage base_image;
12258 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12266 bool b_rot_ok =
false;
12267 if (base_image.IsOk()) {
12270 m_b_rot_hidef =
false;
12274 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12275 m_b_rot_hidef, &m_roffset);
12280 rot_vp.IsValid() && (ri.IsOk())) {
12287 m_prot_bm =
new wxBitmap(ri);
12290 m_roffset.x += VPoint.rv_rect.x;
12291 m_roffset.y += VPoint.rv_rect.y;
12294 if (m_prot_bm && m_prot_bm->IsOk()) {
12295 rotd_dc.SelectObject(*m_prot_bm);
12296 pChartDC = &rotd_dc;
12298 pChartDC = &temp_dc;
12299 m_roffset = wxPoint(0, 0);
12302 pChartDC = &temp_dc;
12303 m_roffset = wxPoint(0, 0);
12306 wxPoint offset = m_roffset;
12309 m_cache_vp = VPoint;
12312 wxMemoryDC mscratch_dc;
12313 mscratch_dc.SelectObject(*pscratch_bm);
12315 mscratch_dc.ResetBoundingBox();
12316 mscratch_dc.DestroyClippingRegion();
12317 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12320 wxRegionIterator upd(rgn_blit);
12322 wxRect rect = upd.GetRect();
12324 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12325 rect.x - offset.x, rect.y - offset.y);
12331 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12332 if (
this == wxWindow::FindFocus()) {
12335 wxColour colour = GetGlobalColor(
"BLUE4");
12336 mscratch_dc.SetPen(wxPen(colour));
12337 mscratch_dc.SetBrush(wxBrush(colour));
12339 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12340 mscratch_dc.DrawRectangle(activeRect);
12345 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12346 unsigned int im = stackIndexArray.size();
12347 if (VPoint.b_quilt && im > 0) {
12348 std::vector<int> tiles_to_show;
12349 for (
unsigned int is = 0; is < im; is++) {
12351 ChartData->GetChartTableEntry(stackIndexArray[is]);
12352 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12355 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12356 tiles_to_show.push_back(stackIndexArray[is]);
12360 if (tiles_to_show.size())
12361 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12367 ocpnDC scratch_dc(mscratch_dc);
12368 RenderAlertMessage(mscratch_dc, GetVP());
12374#ifdef ocpnUSE_DIBSECTION
12379 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12380 q_dc.SelectObject(qbm);
12383 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12386 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12387 q_dc.SetBrush(qbr);
12388 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12391 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12394 q_dc.SelectObject(wxNullBitmap);
12403 if( VPoint.b_quilt ) {
12404 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12405 ChartBase *chart = m_pQuilt->GetRefChart();
12406 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12411 ChPI->ClearPLIBTextList();
12414 ps52plib->ClearTextList();
12418 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12420 wxColor maskBackground = wxColour(1,0,0);
12421 t_dc.SelectObject( qbm );
12422 t_dc.SetBackground(wxBrush(maskBackground));
12426 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12429 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12430 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12433 wxRegionIterator upd_final( ru );
12434 while( upd_final ) {
12435 wxRect rect = upd_final.GetRect();
12436 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12440 t_dc.SelectObject( wxNullBitmap );
12446 if (VPoint.b_quilt) {
12447 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12448 ChartBase *chart = m_pQuilt->GetRefChart();
12449 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12453 ChPI->ClearPLIBTextList();
12455 if (ps52plib) ps52plib->ClearTextList();
12460 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12462 if (g_bShowChartBar && m_Piano) {
12463 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12464 GetVP().pix_width, m_Piano->GetHeight());
12467 if (!style->chartStatusWindowTransparent)
12468 chart_all_text_region.Subtract(chart_bar_rect);
12471 if (m_Compass && m_Compass->IsShown()) {
12472 wxRect compassRect = m_Compass->
GetRect();
12473 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12474 chart_all_text_region.Subtract(compassRect);
12478 mscratch_dc.DestroyClippingRegion();
12480 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12481 chart_all_text_region);
12487 ocpnDC scratch_dc(mscratch_dc);
12488 DrawOverlayObjects(scratch_dc, ru);
12491 wxRegionIterator upd_final(rgn_blit);
12492 while (upd_final) {
12493 wxRect rect = upd_final.GetRect();
12494 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12501 temp_dc.SelectObject(wxNullBitmap);
12503 mscratch_dc.SelectObject(wxNullBitmap);
12505 dc.DestroyClippingRegion();
12510void ChartCanvas::PaintCleanup() {
12512 if (m_inPinch)
return;
12523 m_bTCupdate =
false;
12527 WarpPointer(warp_x, warp_y);
12534 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12535 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12539wxColour GetErrorGraphicColor(
double val)
12558 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12559 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12560 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12561 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12562 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12563 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12564 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12565 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12566 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12567 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12568 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12569 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12570 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12571 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12572 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12573 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12574 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12575 else if( val >= 48) c.Set(
"#410000");
12580void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12583 gr_image.InitAlpha();
12585 double maxval = -10000;
12586 double minval = 10000;
12603 maxval = wxMax(maxval, (glat - rlat));
12604 minval = wxMin(minval, (glat - rlat));
12621 double f = ((glat - rlat)-minval)/(maxval - minval);
12623 double dy = (f * 40);
12625 wxColour c = GetErrorGraphicColor(dy);
12626 unsigned char r = c.Red();
12627 unsigned char g = c.Green();
12628 unsigned char b = c.Blue();
12630 gr_image.SetRGB(j, i, r,g,b);
12631 if((glat - rlat )!= 0)
12632 gr_image.SetAlpha(j, i, 128);
12634 gr_image.SetAlpha(j, i, 255);
12641 wxBitmap *pbm =
new wxBitmap(gr_image);
12642 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12643 pbm->SetMask(gr_mask);
12645 pmdc->DrawBitmap(*pbm, 0,0);
12653void ChartCanvas::CancelMouseRoute() {
12655 m_pMouseRoute = NULL;
12656 m_bDrawingRoute =
false;
12659int ChartCanvas::GetNextContextMenuId() {
12660 return CanvasMenuHandler::GetNextContextMenuId();
12663bool ChartCanvas::SetCursor(
const wxCursor &c) {
12665 if (g_bopengl && m_glcc)
12666 return m_glcc->SetCursor(c);
12669 return wxWindow::SetCursor(c);
12672void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12673 if (g_bquiting)
return;
12683 if (!m_RolloverPopupTimer.IsRunning() &&
12684 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12685 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12686 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12687 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12690 if (m_glcc && g_bopengl) {
12693 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12695 m_glcc->Refresh(eraseBackground,
12712 if (m_pCIWin && m_pCIWin->IsShown()) {
12714 m_pCIWin->Refresh(
false);
12722 wxWindow::Refresh(eraseBackground, rect);
12725void ChartCanvas::Update() {
12726 if (m_glcc && g_bopengl) {
12731 wxWindow::Update();
12735 if (!pemboss)
return;
12736 int x = pemboss->x, y = pemboss->y;
12737 const double factor = 200;
12739 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12740 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12741 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12744 wxMemoryDC snip_dc;
12745 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12746 snip_dc.SelectObject(snip_bmp);
12748 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12749 snip_dc.SelectObject(wxNullBitmap);
12751 wxImage snip_img = snip_bmp.ConvertToImage();
12754 unsigned char *pdata = snip_img.GetData();
12756 for (
int y = 0; y < pemboss->height; y++) {
12757 int map_index = (y * pemboss->width);
12758 for (
int x = 0; x < pemboss->width; x++) {
12759 double val = (pemboss->pmap[map_index] * factor) / 256.;
12761 int nred = (int)((*pdata) + val);
12762 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12763 *pdata++ = (
unsigned char)nred;
12765 int ngreen = (int)((*pdata) + val);
12766 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12767 *pdata++ = (
unsigned char)ngreen;
12769 int nblue = (int)((*pdata) + val);
12770 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12771 *pdata++ = (
unsigned char)nblue;
12779 wxBitmap emb_bmp(snip_img);
12782 wxMemoryDC result_dc;
12783 result_dc.SelectObject(emb_bmp);
12786 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12788 result_dc.SelectObject(wxNullBitmap);
12794 if (GetQuiltMode()) {
12796 int refIndex = GetQuiltRefChartdbIndex();
12797 if (refIndex >= 0) {
12799 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12800 if (current_type == CHART_TYPE_MBTILES) {
12801 ChartBase *pChart = m_pQuilt->GetRefChart();
12804 zoom_factor = ptc->GetZoomFactor();
12809 if (zoom_factor <= 3.9)
return NULL;
12811 if (m_singleChart) {
12812 if (zoom_factor <= 3.9)
return NULL;
12817 if (m_pEM_OverZoom) {
12818 m_pEM_OverZoom->x = 4;
12819 m_pEM_OverZoom->y = 0;
12821 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12822 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12825 return m_pEM_OverZoom;
12828void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12841 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12842 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12846 AISDrawAreaNotices(dc, GetVP(),
this);
12848 wxDC *pdc = dc.GetDC();
12850 pdc->DestroyClippingRegion();
12851 wxDCClipper(*pdc, ru);
12854 if (m_bShowNavobjects) {
12855 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12856 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12857 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12858 DrawAnchorWatchPoints(dc);
12860 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12861 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12864 AISDraw(dc, GetVP(),
this);
12868 RenderVisibleSectorLights(dc);
12870 RenderAllChartOutlines(dc, GetVP());
12871 RenderRouteLegs(dc);
12872 RenderShipToActive(dc,
false);
12874 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12876 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12880 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12881 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12884 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12889 RebuildTideSelectList(GetVP().GetBBox());
12890 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12893 if (m_bShowCurrent) {
12894 RebuildCurrentSelectList(GetVP().GetBBox());
12895 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12898 if (!g_PrintingInProgress) {
12899 if (IsPrimaryCanvas()) {
12903 if (IsPrimaryCanvas()) {
12907 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12909 if (m_pTrackRolloverWin) {
12910 m_pTrackRolloverWin->Draw(dc);
12911 m_brepaint_piano =
true;
12914 if (m_pRouteRolloverWin) {
12915 m_pRouteRolloverWin->Draw(dc);
12916 m_brepaint_piano =
true;
12919 if (m_pAISRolloverWin) {
12920 m_pAISRolloverWin->Draw(dc);
12921 m_brepaint_piano =
true;
12923 if (m_brepaint_piano && g_bShowChartBar) {
12924 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12927 if (m_Compass) m_Compass->Paint(dc);
12929 if (!g_CanvasHideNotificationIcon) {
12930 if (IsPrimaryCanvas()) {
12931 auto ¬eman = NotificationManager::GetInstance();
12932 if (m_notification_button) {
12933 if (noteman.GetNotificationCount()) {
12934 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12935 if (m_notification_button->UpdateStatus()) Refresh();
12936 m_notification_button->Show(
true);
12937 m_notification_button->Paint(dc);
12939 m_notification_button->Show(
false);
12946 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12952 if (!m_bShowDepthUnits)
return NULL;
12954 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12956 if (GetQuiltMode()) {
12957 wxString s = m_pQuilt->GetQuiltDepthUnit();
12960 depth_unit_type = DEPTH_UNIT_FEET;
12961 else if (s.StartsWith(
"FATHOMS"))
12962 depth_unit_type = DEPTH_UNIT_FATHOMS;
12963 else if (s.StartsWith(
"METERS"))
12964 depth_unit_type = DEPTH_UNIT_METERS;
12965 else if (s.StartsWith(
"METRES"))
12966 depth_unit_type = DEPTH_UNIT_METERS;
12967 else if (s.StartsWith(
"METRIC"))
12968 depth_unit_type = DEPTH_UNIT_METERS;
12969 else if (s.StartsWith(
"METER"))
12970 depth_unit_type = DEPTH_UNIT_METERS;
12973 if (m_singleChart) {
12974 depth_unit_type = m_singleChart->GetDepthUnitType();
12975 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12976 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12981 switch (depth_unit_type) {
12982 case DEPTH_UNIT_FEET:
12985 case DEPTH_UNIT_METERS:
12986 ped = m_pEM_Meters;
12988 case DEPTH_UNIT_FATHOMS:
12989 ped = m_pEM_Fathoms;
12995 ped->x = (GetVP().
pix_width - ped->width);
12997 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12998 wxRect r = m_Compass->
GetRect();
12999 ped->y = r.y + r.height;
13006void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
13009 if (style->embossFont == wxEmptyString) {
13010 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13012 font.SetPointSize(60);
13013 font.SetWeight(wxFONTWEIGHT_BOLD);
13015 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13016 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13018 int emboss_width = 500;
13019 int emboss_height = 200;
13023 delete m_pEM_Meters;
13024 delete m_pEM_Fathoms;
13028 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
13030 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
13032 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
13035#define OVERZOOM_TEXT _("OverZoom")
13037void ChartCanvas::SetOverzoomFont() {
13042 if (style->embossFont == wxEmptyString) {
13043 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13045 font.SetPointSize(40);
13046 font.SetWeight(wxFONTWEIGHT_BOLD);
13048 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13049 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13051 wxClientDC dc(
this);
13053 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13055 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13056 font.SetPointSize(font.GetPointSize() - 1);
13058 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13060 m_overzoomFont = font;
13061 m_overzoomTextWidth = w;
13062 m_overzoomTextHeight = h;
13065void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13066 delete m_pEM_OverZoom;
13068 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13070 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13071 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13074emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13075 int height,
const wxString &str,
13080 wxBitmap bmp(width, height, -1);
13083 wxMemoryDC temp_dc;
13084 temp_dc.SelectObject(bmp);
13087 temp_dc.SetBackground(*wxWHITE_BRUSH);
13088 temp_dc.SetTextBackground(*wxWHITE);
13089 temp_dc.SetTextForeground(*wxBLACK);
13093 temp_dc.SetFont(font);
13096 temp_dc.GetTextExtent(str, &str_w, &str_h);
13098 temp_dc.DrawText(str, 1, 1);
13101 temp_dc.SelectObject(wxNullBitmap);
13104 wxImage img = bmp.ConvertToImage();
13106 int image_width = str_w * 105 / 100;
13107 int image_height = str_h * 105 / 100;
13108 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13109 wxMin(image_height, img.GetHeight()));
13110 wxImage imgs = img.GetSubImage(r);
13114 case GLOBAL_COLOR_SCHEME_DAY:
13118 case GLOBAL_COLOR_SCHEME_DUSK:
13121 case GLOBAL_COLOR_SCHEME_NIGHT:
13128 const int w = imgs.GetWidth();
13129 const int h = imgs.GetHeight();
13130 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13135 for (
int y = 1; y < h - 1; y++) {
13136 for (
int x = 1; x < w - 1; x++) {
13138 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13139 val = (int)(val * val_factor);
13140 index = (y * w) + x;
13153void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13154 Track *active_track = NULL;
13157 active_track = pTrackDraw;
13161 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13164 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13167void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13168 Track *active_track = NULL;
13171 active_track = pTrackDraw;
13175 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13178void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13179 Route *active_route = NULL;
13181 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13182 active_route = pRouteDraw;
13187 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13192 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13195void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13196 Route *active_route = NULL;
13199 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13200 active_route = pRouteDraw;
13204 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13207void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13208 if (!pWayPointMan)
return;
13210 auto node = pWayPointMan->GetWaypointList()->begin();
13212 while (node != pWayPointMan->GetWaypointList()->end()) {
13221 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13225 if (pWP->GetShowWaypointRangeRings() &&
13226 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13227 double factor = 1.00;
13228 if (pWP->GetWaypointRangeRingsStepUnits() ==
13230 factor = 1 / 1.852;
13232 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13233 pWP->GetWaypointRangeRingsStep() / 60.;
13237 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13238 pWP->m_lat + radius, pWP->m_lon + radius);
13239 if (!BltBBox.IntersectOut(radar_box)) {
13250void ChartCanvas::DrawBlinkObjects() {
13252 wxRect update_rect;
13254 if (!pWayPointMan)
return;
13256 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13263 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13266void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13271 wxPoint lAnchorPoint1, lAnchorPoint2;
13285 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13286 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13288 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13289 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13290 dc.SetBrush(*ppBrush);
13294 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13299 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13304 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13309 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13314double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13317 wxPoint lAnchorPoint;
13320 double tlat1, tlon1;
13322 if (pAnchorWatchPoint) {
13323 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13325 dabs = fabs(d1 / 1852.);
13326 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13331 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13332 pow((
double)(lAnchorPoint.y - r1.y), 2));
13335 if (d1 < 0) lpp = -lpp;
13343void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13346 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13348 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13354 if ((type ==
't') || (type ==
'T')) {
13355 if (BBox.Contains(lat, lon)) {
13357 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13363void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13366 wxDateTime this_now = gTimeSource;
13367 bool cur_time = !gTimeSource.IsValid();
13368 if (cur_time) this_now = wxDateTime::Now();
13369 time_t t_this_now = this_now.GetTicks();
13371 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13373 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13374 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13375 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13376 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13378 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13379 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13380 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13381 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13382 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13383 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13385 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13386 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13387 int font_size = wxMax(10, dFont->GetPointSize());
13390 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13391 false, dFont->GetFaceName());
13393 dc.SetPen(*pblack_pen);
13394 dc.SetBrush(*pgreen_brush);
13398 case GLOBAL_COLOR_SCHEME_DAY:
13401 case GLOBAL_COLOR_SCHEME_DUSK:
13404 case GLOBAL_COLOR_SCHEME_NIGHT:
13405 bm = m_bmTideNight;
13412 int bmw = bm.GetWidth();
13413 int bmh = bm.GetHeight();
13415 float scale_factor = 1.0;
13419 float icon_pixelRefDim = 45;
13424 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13426 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13428 scale_factor *= pix_factor;
13435 scale_factor *= user_scale_factor;
13436 scale_factor *= GetContentScaleFactor();
13439 double marge = 0.05;
13440 std::vector<LLBBox> drawn_boxes;
13441 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13445 if ((type ==
't') || (type ==
'T'))
13450 if (BBox.ContainsMarge(lat, lon, marge)) {
13452 if (GetVP().chart_scale < 500000) {
13453 bool bdrawn =
false;
13454 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13455 if (drawn_boxes[i].Contains(lat, lon)) {
13460 if (bdrawn)
continue;
13463 this_box.Set(lat, lon, lat, lon);
13464 this_box.EnLarge(.005);
13465 drawn_boxes.push_back(this_box);
13471 if (GetVP().chart_scale > 500000) {
13472 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13476 dc.SetFont(*plabelFont);
13488 if (
ptcmgr->GetTideFlowSens(
13489 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13493 ptcmgr->GetHightOrLowTide(
13494 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13495 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13507 if (tctime > t_this_now)
13508 ptcmgr->GetHightOrLowTide(
13509 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13510 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13514 ptcmgr->GetHightOrLowTide(
13515 t_this_now, FORWARD_TEN_MINUTES_STEP,
13516 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13530 int width = (int)(12 * scale_factor + 0.5);
13531 int height = (int)(45 * scale_factor + 0.5);
13532 int linew = wxMax(1, (
int)(scale_factor));
13533 int xDraw = r.x - (width / 2);
13534 int yDraw = r.y - (height / 2);
13537 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13538 int hs = (httime > lttime) ? -4 : 4;
13539 hs *= (int)(scale_factor + 0.5);
13540 if (ts > 0.995 || ts < 0.005) hs = 0;
13541 int ht_y = (int)(height * ts);
13544 pblack_pen->SetWidth(linew);
13545 dc.SetPen(*pblack_pen);
13546 dc.SetBrush(*pyelo_brush);
13547 dc.DrawRectangle(xDraw, yDraw, width, height);
13551 dc.SetPen(*pblue_pen);
13552 dc.SetBrush(*pblue_brush);
13553 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13554 (width - (4 * linew)), height - ht_y);
13560 arrow[0].x = xDraw + 2 * linew;
13561 arrow[1].x = xDraw + width / 2;
13562 arrow[2].x = xDraw + width - 2 * linew;
13563 pyelo_pen->SetWidth(linew);
13564 pblue_pen->SetWidth(linew);
13565 if (ts > 0.35 || ts < 0.15)
13567 hl = (int)(height * 0.25) + yDraw;
13569 arrow[1].y = hl + hs;
13572 dc.SetPen(*pyelo_pen);
13574 dc.SetPen(*pblue_pen);
13575 dc.DrawLines(3, arrow);
13577 if (ts > 0.60 || ts < 0.40)
13579 hl = (int)(height * 0.5) + yDraw;
13581 arrow[1].y = hl + hs;
13584 dc.SetPen(*pyelo_pen);
13586 dc.SetPen(*pblue_pen);
13587 dc.DrawLines(3, arrow);
13589 if (ts < 0.65 || ts > 0.85)
13591 hl = (int)(height * 0.75) + yDraw;
13593 arrow[1].y = hl + hs;
13596 dc.SetPen(*pyelo_pen);
13598 dc.SetPen(*pblue_pen);
13599 dc.DrawLines(3, arrow);
13603 s.Printf(
"%3.1f", nowlev);
13605 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13607 dc.GetTextExtent(s, &wx1, NULL);
13609 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13624void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13627 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13629 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13635 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13636 if ((BBox.Contains(lat, lon))) {
13638 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13644void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13647 float tcvalue, dir;
13651 double lon_last = 0.;
13652 double lat_last = 0.;
13654 double marge = 0.2;
13655 bool cur_time = !gTimeSource.IsValid();
13657 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13658 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13660 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13662 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13663 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13664 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13665 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13666 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13667 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13668 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13669 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13671 double skew_angle = GetVPRotation();
13673 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13674 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13675 int font_size = wxMax(10, dFont->GetPointSize());
13678 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13679 false, dFont->GetFaceName());
13681 float scale_factor = 1.0;
13687 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13689 float nominal_icon_size_pixels = 15;
13690 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13692 scale_factor *= pix_factor;
13699 scale_factor *= user_scale_factor;
13701 scale_factor *= GetContentScaleFactor();
13704 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13710 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13711 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13716 int dd = (int)(5.0 * scale_factor + 0.5);
13727 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13728 dc.SetPen(*pblack_pen);
13729 dc.SetBrush(*porange_brush);
13730 dc.DrawPolygon(4, d);
13733 dc.SetBrush(*pblack_brush);
13734 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13738 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13752 double a1 = fabs(tcvalue) * 10.;
13754 a1 = wxMax(1.0, a1);
13755 double a2 = log10(a1);
13757 float cscale = scale_factor * a2 * 0.3;
13759 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13760 dc.SetPen(*porange_pen);
13761 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13765 if (bDrawCurrentValues) {
13766 dc.SetFont(*pTCFont);
13767 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13768 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13794 if (!pvIDX)
return;
13799 if (pCwin && pCwin->IsShown()) {
13807 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13822 pCwin =
new TCWin(
this, x, y, pvIDX);
13840#define NUM_CURRENT_ARROW_POINTS 9
13841static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13842 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13843 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13844 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13846void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13848 if (
scale > 1e-2) {
13849 float sin_rot = sin(rot_angle * PI / 180.);
13850 float cos_rot = cos(rot_angle * PI / 180.);
13854 float xt = CurrentArrowArray[0].x;
13855 float yt = CurrentArrowArray[0].y;
13857 float xp = (xt * cos_rot) - (yt * sin_rot);
13858 float yp = (xt * sin_rot) + (yt * cos_rot);
13859 int x1 = (int)(xp *
scale);
13860 int y1 = (int)(yp *
scale);
13863 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13864 xt = CurrentArrowArray[ip].x;
13865 yt = CurrentArrowArray[ip].y;
13867 float xp = (xt * cos_rot) - (yt * sin_rot);
13868 float yp = (xt * sin_rot) + (yt * cos_rot);
13869 int x2 = (int)(xp *
scale);
13870 int y2 = (int)(yp *
scale);
13872 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13880wxString ChartCanvas::FindValidUploadPort() {
13883 if (!g_uploadConnection.IsEmpty() &&
13884 g_uploadConnection.StartsWith(
"Serial")) {
13885 port = g_uploadConnection;
13891 for (
auto *cp : TheConnectionParams()) {
13892 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13893 port <<
"Serial:" << cp->Port;
13899void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13902 if (NULL == g_pais_query_dialog_active) {
13903 int pos_x = g_ais_query_dialog_x;
13904 int pos_y = g_ais_query_dialog_y;
13906 if (g_pais_query_dialog_active) {
13907 g_pais_query_dialog_active->Destroy();
13913 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13914 wxPoint(pos_x, pos_y));
13916 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13917 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13918 g_pais_query_dialog_active->SetMMSI(mmsi);
13919 g_pais_query_dialog_active->UpdateText();
13920 wxSize sz = g_pais_query_dialog_active->GetSize();
13922 bool b_reset_pos =
false;
13927 RECT frame_title_rect;
13928 frame_title_rect.left = pos_x;
13929 frame_title_rect.top = pos_y;
13930 frame_title_rect.right = pos_x + sz.x;
13931 frame_title_rect.bottom = pos_y + 30;
13933 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13934 b_reset_pos =
true;
13939 wxRect window_title_rect;
13940 window_title_rect.x = pos_x;
13941 window_title_rect.y = pos_y;
13942 window_title_rect.width = sz.x;
13943 window_title_rect.height = 30;
13945 wxRect ClientRect = wxGetClientDisplayRect();
13946 ClientRect.Deflate(
13948 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13952 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13955 g_pais_query_dialog_active->SetMMSI(mmsi);
13956 g_pais_query_dialog_active->UpdateText();
13959 g_pais_query_dialog_active->Show();
13962void ChartCanvas::ToggleCanvasQuiltMode() {
13963 bool cur_mode = GetQuiltMode();
13965 if (!GetQuiltMode())
13966 SetQuiltMode(
true);
13967 else if (GetQuiltMode()) {
13968 SetQuiltMode(
false);
13969 g_sticky_chart = GetQuiltReferenceChartIndex();
13972 if (cur_mode != GetQuiltMode()) {
13973 SetupCanvasQuiltMode();
13982 if (ps52plib) ps52plib->GenerateStateHash();
13984 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13985 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13988void ChartCanvas::DoCanvasStackDelta(
int direction) {
13989 if (!GetQuiltMode()) {
13990 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13991 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13992 if ((current_stack_index + direction) < 0)
return;
13994 if (m_bpersistent_quilt ) {
13996 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13998 if (IsChartQuiltableRef(new_dbIndex)) {
13999 ToggleCanvasQuiltMode();
14000 SelectQuiltRefdbChart(new_dbIndex);
14001 m_bpersistent_quilt =
false;
14004 SelectChartFromStack(current_stack_index + direction);
14007 std::vector<int> piano_chart_index_array =
14008 GetQuiltExtendedStackdbIndexArray();
14009 int refdb = GetQuiltRefChartdbIndex();
14012 int current_index = -1;
14013 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14014 if (refdb == piano_chart_index_array[i]) {
14019 if (current_index == -1)
return;
14022 int target_family = ctet.GetChartFamily();
14024 int new_index = -1;
14025 int check_index = current_index + direction;
14026 bool found =
false;
14027 int check_dbIndex = -1;
14028 int new_dbIndex = -1;
14032 (
unsigned int)check_index < piano_chart_index_array.size() &&
14033 (check_index >= 0)) {
14034 check_dbIndex = piano_chart_index_array[check_index];
14036 if (target_family == cte.GetChartFamily()) {
14038 new_index = check_index;
14039 new_dbIndex = check_dbIndex;
14043 check_index += direction;
14046 if (!found)
return;
14048 if (!IsChartQuiltableRef(new_dbIndex)) {
14049 ToggleCanvasQuiltMode();
14050 SelectdbChart(new_dbIndex);
14051 m_bpersistent_quilt =
true;
14053 SelectQuiltRefChart(new_index);
14058 top_frame::Get()->UpdateGlobalMenuItems();
14059 SetQuiltChartHiLiteIndex(-1);
14070void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14073 switch (event.GetId()) {
14085 DoCanvasStackDelta(1);
14090 DoCanvasStackDelta(-1);
14100 ShowCurrents(!GetbShowCurrent());
14107 ShowTides(!GetbShowTide());
14114 if (0 == m_routeState) {
14121 androidSetRouteAnnunciator(m_routeState == 1);
14127 SetAISCanvasDisplayStyle(-1);
14139void ChartCanvas::SetShowAIS(
bool show) {
14141 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14142 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14145void ChartCanvas::SetAttenAIS(
bool show) {
14146 m_bShowAISScaled = show;
14147 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14148 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14151void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14154 bool bShowAIS_Array[3] = {
true,
true,
false};
14155 bool bShowScaled_Array[3] = {
false,
true,
true};
14156 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14157 _(
"Attenuate less critical AIS targets"),
14158 _(
"Hide AIS Targets")};
14159 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14161 int AIS_Toolbar_Switch = 0;
14162 if (StyleIndx == -1) {
14164 for (
int i = 1; i < ArraySize; i++) {
14165 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14166 (bShowScaled_Array[i] == m_bShowAISScaled))
14167 AIS_Toolbar_Switch = i;
14169 AIS_Toolbar_Switch++;
14170 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14171 AIS_Toolbar_Switch++;
14174 AIS_Toolbar_Switch = StyleIndx;
14177 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14179 int AIS_Toolbar_Switch_Next =
14180 AIS_Toolbar_Switch + 1;
14181 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14182 AIS_Toolbar_Switch_Next++;
14183 if (AIS_Toolbar_Switch_Next >= ArraySize)
14184 AIS_Toolbar_Switch_Next = 0;
14187 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14188 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14191void ChartCanvas::TouchAISToolActive() {}
14193void ChartCanvas::UpdateAISTBTool() {}
14201void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14203 bool b_update =
false;
14204 int cc1_edge_comp = 2;
14205 wxRect rect = m_Compass->
GetRect();
14206 wxSize parent_size = GetSize();
14208 parent_size *= m_displayScale;
14212 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14213 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14214 wxRect compass_rect(compass_pt, rect.GetSize());
14216 m_Compass->Move(compass_pt);
14218 if (m_Compass && m_Compass->IsShown())
14219 m_Compass->UpdateStatus(b_force_new | b_update);
14221 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14222 scaler = wxMax(scaler, 1.0);
14223 wxPoint note_point = wxPoint(
14224 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14225 if (m_notification_button) {
14226 m_notification_button->Move(note_point);
14227 m_notification_button->UpdateStatus();
14230 if (b_force_new | b_update) Refresh();
14233void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14234 ChartTypeEnum New_Type,
14235 ChartFamilyEnum New_Family) {
14236 if (!GetpCurrentStack())
return;
14239 if (index < GetpCurrentStack()->nEntry) {
14242 pTentative_Chart =
ChartData->OpenStackChartConditional(
14243 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14245 if (pTentative_Chart) {
14246 if (m_singleChart) m_singleChart->Deactivate();
14248 m_singleChart = pTentative_Chart;
14249 m_singleChart->Activate();
14251 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14252 GetpCurrentStack(), m_singleChart->GetFullPath());
14265 double best_scale_ppm = GetBestVPScale(m_singleChart);
14266 double rotation = GetVPRotation();
14267 double oldskew = GetVPSkew();
14268 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14270 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14271 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14272 if (fabs(newskew) > 0.0001) rotation = newskew;
14275 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14277 UpdateGPSCompassStatusBox(
true);
14281 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14282 if (idx < 0)
return;
14284 std::vector<int> piano_active_chart_index_array;
14285 piano_active_chart_index_array.push_back(
14286 GetpCurrentStack()->GetCurrentEntrydbIndex());
14287 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14290void ChartCanvas::SelectdbChart(
int dbindex) {
14291 if (!GetpCurrentStack())
return;
14294 if (dbindex >= 0) {
14297 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14299 if (pTentative_Chart) {
14300 if (m_singleChart) m_singleChart->Deactivate();
14302 m_singleChart = pTentative_Chart;
14303 m_singleChart->Activate();
14305 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14306 GetpCurrentStack(), m_singleChart->GetFullPath());
14319 double best_scale_ppm = GetBestVPScale(m_singleChart);
14323 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14333void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14336 if (!GetQuiltMode()) {
14337 if (GetpCurrentStack()) {
14338 int stack_index = -1;
14339 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14340 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14341 if (check_dbIndex < 0)
continue;
14343 ChartData->GetChartTableEntry(check_dbIndex);
14344 if (type == cte.GetChartType()) {
14347 }
else if (family == cte.GetChartFamily()) {
14353 if (stack_index >= 0) {
14354 SelectChartFromStack(stack_index);
14358 int sel_dbIndex = -1;
14359 std::vector<int> piano_chart_index_array =
14360 GetQuiltExtendedStackdbIndexArray();
14361 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14362 int check_dbIndex = piano_chart_index_array[i];
14364 if (type == cte.GetChartType()) {
14365 if (IsChartQuiltableRef(check_dbIndex)) {
14366 sel_dbIndex = check_dbIndex;
14369 }
else if (family == cte.GetChartFamily()) {
14370 if (IsChartQuiltableRef(check_dbIndex)) {
14371 sel_dbIndex = check_dbIndex;
14377 if (sel_dbIndex >= 0) {
14378 SelectQuiltRefdbChart(sel_dbIndex,
false);
14380 AdjustQuiltRefChart();
14387 SetQuiltChartHiLiteIndex(-1);
14392bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14393 return std::find(m_tile_yesshow_index_array.begin(),
14394 m_tile_yesshow_index_array.end(),
14395 index) != m_tile_yesshow_index_array.end();
14398bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14399 return std::find(m_tile_noshow_index_array.begin(),
14400 m_tile_noshow_index_array.end(),
14401 index) != m_tile_noshow_index_array.end();
14404void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14405 if (std::find(m_tile_noshow_index_array.begin(),
14406 m_tile_noshow_index_array.end(),
14407 index) == m_tile_noshow_index_array.end()) {
14408 m_tile_noshow_index_array.push_back(index);
14418void ChartCanvas::HandlePianoClick(
14419 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14422 if (!m_pCurrentStack)
return;
14438 double distance = 25000;
14439 int closest_index = -1;
14440 for (
int chart_index : selected_dbIndex_array) {
14442 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14443 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14446 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14447 if (test_distance < distance) {
14448 distance = test_distance;
14449 closest_index = chart_index;
14453 int selected_dbIndex = selected_dbIndex_array[0];
14454 if (closest_index >= 0) selected_dbIndex = closest_index;
14456 if (!GetQuiltMode()) {
14457 if (m_bpersistent_quilt ) {
14458 if (IsChartQuiltableRef(selected_dbIndex)) {
14459 ToggleCanvasQuiltMode();
14460 SelectQuiltRefdbChart(selected_dbIndex);
14461 m_bpersistent_quilt =
false;
14463 SelectChartFromStack(selected_index);
14466 SelectChartFromStack(selected_index);
14467 g_sticky_chart = selected_dbIndex;
14471 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14475 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14476 bool bfound =
false;
14477 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14478 if (m_tile_noshow_index_array[i] ==
14479 selected_dbIndex) {
14480 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14487 m_tile_noshow_index_array.push_back(selected_dbIndex);
14491 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14492 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14496 if (IsChartQuiltableRef(selected_dbIndex)) {
14502 bool set_scale =
false;
14503 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14504 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14510 SelectQuiltRefdbChart(selected_dbIndex,
true);
14512 SelectQuiltRefdbChart(selected_dbIndex,
false);
14517 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14519 double proposed_scale_onscreen =
14522 if (g_bPreserveScaleOnX) {
14523 proposed_scale_onscreen =
14524 wxMin(proposed_scale_onscreen,
14526 GetCanvasWidth()));
14528 proposed_scale_onscreen =
14529 wxMin(proposed_scale_onscreen,
14531 GetCanvasWidth()));
14533 proposed_scale_onscreen =
14534 wxMax(proposed_scale_onscreen,
14543 ToggleCanvasQuiltMode();
14544 SelectdbChart(selected_dbIndex);
14545 m_bpersistent_quilt =
true;
14550 SetQuiltChartHiLiteIndex(-1);
14552 top_frame::Get()->UpdateGlobalMenuItems();
14553 HideChartInfoWindow();
14558void ChartCanvas::HandlePianoRClick(
14559 int x,
int y,
int selected_index,
14560 const std::vector<int> &selected_dbIndex_array) {
14563 if (!GetpCurrentStack())
return;
14565 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14566 UpdateCanvasControlBar();
14568 SetQuiltChartHiLiteIndex(-1);
14571void ChartCanvas::HandlePianoRollover(
14572 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14573 int n_charts,
int scale) {
14576 if (!GetpCurrentStack())
return;
14581 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14583 if (!GetQuiltMode()) {
14584 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14587 std::vector<int> piano_chart_index_array;
14588 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14589 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14590 if ((GetpCurrentStack()->nEntry > 1) ||
14591 (piano_chart_index_array.size() >= 1)) {
14592 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14594 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14596 }
else if (GetpCurrentStack()->nEntry == 1) {
14598 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14599 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14600 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14602 }
else if ((-1 == selected_index) &&
14603 (0 == selected_dbIndex_array.size())) {
14604 ShowChartInfoWindow(key_location.x, -1);
14608 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14610 if ((GetpCurrentStack()->nEntry > 1) ||
14611 (piano_chart_index_array.size() >= 1)) {
14613 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14614 selected_dbIndex_array);
14615 else if (n_charts == 1)
14616 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14618 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14625void ChartCanvas::ClearPianoRollover() {
14626 ClearQuiltChartHiLiteIndexArray();
14627 ShowChartInfoWindow(0, -1);
14628 std::vector<int> vec;
14629 ShowCompositeInfoWindow(0, 0, 0, vec);
14633void ChartCanvas::UpdateCanvasControlBar() {
14634 if (m_pianoFrozen)
return;
14636 if (!GetpCurrentStack())
return;
14638 if (!g_bShowChartBar)
return;
14641 int sel_family = -1;
14643 std::vector<int> piano_chart_index_array;
14644 std::vector<int> empty_piano_chart_index_array;
14646 wxString old_hash = m_Piano->GetStoredHash();
14648 if (GetQuiltMode()) {
14649 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14650 GetQuiltFullScreendbIndexArray());
14652 std::vector<int> piano_active_chart_index_array =
14653 GetQuiltCandidatedbIndexArray();
14654 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14656 std::vector<int> piano_eclipsed_chart_index_array =
14657 GetQuiltEclipsedStackdbIndexArray();
14658 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14660 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14661 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14663 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14664 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14666 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14667 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14670 if (m_singleChart) {
14671 sel_type = m_singleChart->GetChartType();
14672 sel_family = m_singleChart->GetChartFamily();
14677 std::vector<int> piano_skew_chart_index_array;
14678 std::vector<int> piano_tmerc_chart_index_array;
14679 std::vector<int> piano_poly_chart_index_array;
14681 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14683 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14684 double skew_norm = ctei.GetChartSkew();
14685 if (skew_norm > 180.) skew_norm -= 360.;
14687 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14688 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14691 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14692 if (fabs(skew_norm) > 1.)
14693 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14695 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14696 }
else if (fabs(skew_norm) > 1.)
14697 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14699 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14700 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14701 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14703 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14704 if (new_hash != old_hash) {
14705 m_Piano->FormatKeys();
14706 HideChartInfoWindow();
14707 m_Piano->ResetRollover();
14708 SetQuiltChartHiLiteIndex(-1);
14709 m_brepaint_piano =
true;
14715 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14717 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14718 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14719 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14720 if (e == CHART_FAMILY_RASTER) mask |= 1;
14721 if (e == CHART_FAMILY_VECTOR) {
14722 if (t == CHART_TYPE_CM93COMP)
14729 wxString s_indicated;
14730 if (sel_type == CHART_TYPE_CM93COMP)
14731 s_indicated =
"cm93";
14733 if (sel_family == CHART_FAMILY_RASTER)
14734 s_indicated =
"raster";
14735 else if (sel_family == CHART_FAMILY_VECTOR)
14736 s_indicated =
"vector";
14739 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14742void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14744void ChartCanvas::PianoPopupMenu(
14745 int x,
int y,
int selected_index,
14746 const std::vector<int> &selected_dbIndex_array) {
14747 if (!GetpCurrentStack())
return;
14750 if (!GetQuiltMode())
return;
14752 m_piano_ctx_menu =
new wxMenu();
14754 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14764 menu_selected_dbIndex = selected_dbIndex_array[0];
14765 menu_selected_index = selected_index;
14768 bool b_is_in_noshow =
false;
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 b_is_in_noshow =
true;
14778 if (b_is_in_noshow) {
14779 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14780 _(
"Show This Chart"));
14781 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14782 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14783 }
else if (GetpCurrentStack()->nEntry > 1) {
14784 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14785 _(
"Hide This Chart"));
14786 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14787 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14791 wxPoint pos = wxPoint(x, y - 30);
14794 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14795 PopupMenu(m_piano_ctx_menu, pos);
14797 delete m_piano_ctx_menu;
14798 m_piano_ctx_menu = NULL;
14800 HideChartInfoWindow();
14801 m_Piano->ResetRollover();
14803 SetQuiltChartHiLiteIndex(-1);
14804 ClearQuiltChartHiLiteIndexArray();
14809void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14810 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14811 if (m_quilt_noshow_index_array[i] ==
14812 menu_selected_dbIndex)
14814 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14820void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14821 if (!GetpCurrentStack())
return;
14824 RemoveChartFromQuilt(menu_selected_dbIndex);
14828 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14829 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14831 int i = menu_selected_index + 1;
14832 bool b_success =
false;
14833 while (i < GetpCurrentStack()->nEntry - 1) {
14834 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14835 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14836 SelectQuiltRefChart(i);
14846 i = menu_selected_index - 1;
14848 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14849 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14850 SelectQuiltRefChart(i);
14860void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14862 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14863 if (m_quilt_noshow_index_array[i] ==
14866 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14871 m_quilt_noshow_index_array.push_back(dbIndex);
14874bool ChartCanvas::UpdateS52State() {
14875 bool retval =
false;
14878 ps52plib->SetShowS57Text(m_encShowText);
14879 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14880 ps52plib->m_bShowSoundg = m_encShowDepth;
14881 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14882 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14885 if (!m_encShowLights)
14886 ps52plib->AddObjNoshow(
"LIGHTS");
14888 ps52plib->RemoveObjNoshow(
"LIGHTS");
14889 ps52plib->SetLightsOff(!m_encShowLights);
14890 ps52plib->m_bExtendLightSectors =
true;
14893 ps52plib->SetAnchorOn(m_encShowAnchor);
14894 ps52plib->SetQualityOfData(m_encShowDataQual);
14900void ChartCanvas::SetShowENCDataQual(
bool show) {
14901 m_encShowDataQual = show;
14902 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14903 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14905 m_s52StateHash = 0;
14908void ChartCanvas::SetShowENCText(
bool show) {
14909 m_encShowText = show;
14910 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14911 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14913 m_s52StateHash = 0;
14916void ChartCanvas::SetENCDisplayCategory(
int category) {
14917 m_encDisplayCategory = category;
14918 m_s52StateHash = 0;
14921void ChartCanvas::SetShowENCDepth(
bool show) {
14922 m_encShowDepth = show;
14923 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14924 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14926 m_s52StateHash = 0;
14929void ChartCanvas::SetShowENCLightDesc(
bool show) {
14930 m_encShowLightDesc = show;
14931 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14932 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14934 m_s52StateHash = 0;
14937void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14938 m_encShowBuoyLabels = show;
14939 m_s52StateHash = 0;
14942void ChartCanvas::SetShowENCLights(
bool show) {
14943 m_encShowLights = show;
14944 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14945 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14947 m_s52StateHash = 0;
14950void ChartCanvas::SetShowENCAnchor(
bool show) {
14951 m_encShowAnchor = show;
14952 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14953 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14955 m_s52StateHash = 0;
14958wxRect ChartCanvas::GetMUIBarRect() {
14961 rv = m_muiBar->GetRect();
14967void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14968 if (!GetAlertString().IsEmpty()) {
14969 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14970 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14972 dc.SetFont(*pfont);
14973 dc.SetPen(*wxTRANSPARENT_PEN);
14975 dc.SetBrush(wxColour(243, 229, 47));
14977 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14981 wxRect sbr = GetScaleBarRect();
14982 int xp = sbr.x + sbr.width + 10;
14983 int yp = (sbr.y + sbr.height) - h;
14985 int wdraw = w + 10;
14986 dc.DrawRectangle(xp, yp, wdraw, h);
14987 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14988 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14998#define BRIGHT_XCALIB
14999#define __OPCPN_USEICC__
15002#ifdef __OPCPN_USEICC__
15003int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15004 double co_green,
double co_blue);
15006wxString temp_file_name;
15010class ocpnCurtain:
public wxDialog
15012 DECLARE_CLASS( ocpnCurtain )
15013 DECLARE_EVENT_TABLE()
15016 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
15018 bool ProcessEvent(wxEvent& event);
15022IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
15024BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
15027ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
15029 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
15032ocpnCurtain::~ocpnCurtain()
15036bool ocpnCurtain::ProcessEvent(wxEvent& event)
15038 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
15039 return GetParent()->GetEventHandler()->ProcessEvent(event);
15044#include <windows.h>
15047typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15048typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15049SetDeviceGammaRamp_ptr_type
15050 g_pSetDeviceGammaRamp;
15051GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15053WORD *g_pSavedGammaMap;
15057int InitScreenBrightness() {
15060 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15064 if (NULL == hGDI32DLL) {
15065 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15067 if (NULL != hGDI32DLL) {
15069 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15070 hGDI32DLL,
"SetDeviceGammaRamp");
15071 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15072 hGDI32DLL,
"GetDeviceGammaRamp");
15075 if ((NULL == g_pSetDeviceGammaRamp) ||
15076 (NULL == g_pGetDeviceGammaRamp)) {
15077 FreeLibrary(hGDI32DLL);
15086 if (!g_pSavedGammaMap) {
15087 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15090 bbr = g_pGetDeviceGammaRamp(
15091 hDC, g_pSavedGammaMap);
15092 ReleaseDC(NULL, hDC);
15097 wxRegKey *pRegKey =
new wxRegKey(
15098 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15099 "NT\\CurrentVersion\\ICM");
15100 if (!pRegKey->Exists()) pRegKey->Create();
15101 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15103 g_brightness_init =
true;
15109 if (NULL == g_pcurtain) {
15110 if (top_frame::Get()->CanSetTransparent()) {
15112 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15113 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15114 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15115 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15122 g_pcurtain->Hide();
15124 HWND hWnd = GetHwndOf(g_pcurtain);
15125 SetWindowLong(hWnd, GWL_EXSTYLE,
15126 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15127 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15128 g_pcurtain->SetTransparent(0);
15130 g_pcurtain->Maximize();
15131 g_pcurtain->Show();
15134 g_pcurtain->Enable();
15135 g_pcurtain->Disable();
15137 top_frame::Get()->Disable();
15138 top_frame::Get()->Enable();
15142 g_brightness_init =
true;
15148 wxString cmd(
"xcalib -version");
15150 wxArrayString output;
15151 long r = wxExecute(cmd, output);
15154 " External application \"xcalib\" not found. Screen brightness "
15157 g_brightness_init =
true;
15162int RestoreScreenBrightness() {
15165 if (g_pSavedGammaMap) {
15166 HDC hDC = GetDC(NULL);
15167 g_pSetDeviceGammaRamp(hDC,
15169 ReleaseDC(NULL, hDC);
15171 free(g_pSavedGammaMap);
15172 g_pSavedGammaMap = NULL;
15176 g_pcurtain->Close();
15177 g_pcurtain->Destroy();
15181 g_brightness_init =
false;
15186#ifdef BRIGHT_XCALIB
15187 if (g_brightness_init) {
15189 cmd =
"xcalib -clear";
15190 wxExecute(cmd, wxEXEC_ASYNC);
15191 g_brightness_init =
false;
15201int SetScreenBrightness(
int brightness) {
15208 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15210 g_pcurtain->Close();
15211 g_pcurtain->Destroy();
15215 InitScreenBrightness();
15217 if (NULL == hGDI32DLL) {
15219 wchar_t wdll_name[80];
15220 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15221 LPCWSTR cstr = wdll_name;
15223 hGDI32DLL = LoadLibrary(cstr);
15225 if (NULL != hGDI32DLL) {
15227 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15228 hGDI32DLL,
"SetDeviceGammaRamp");
15229 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15230 hGDI32DLL,
"GetDeviceGammaRamp");
15233 if ((NULL == g_pSetDeviceGammaRamp) ||
15234 (NULL == g_pGetDeviceGammaRamp)) {
15235 FreeLibrary(hGDI32DLL);
15242 HDC hDC = GetDC(NULL);
15253 int increment = brightness * 256 / 100;
15256 WORD GammaTable[3][256];
15259 for (
int i = 0; i < 256; i++) {
15260 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15261 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15262 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15264 table_val += increment;
15266 if (table_val > 65535) table_val = 65535;
15269 g_pSetDeviceGammaRamp(hDC, GammaTable);
15270 ReleaseDC(NULL, hDC);
15277 if (g_pSavedGammaMap) {
15278 HDC hDC = GetDC(NULL);
15279 g_pSetDeviceGammaRamp(hDC,
15281 ReleaseDC(NULL, hDC);
15284 if (brightness < 100) {
15285 if (NULL == g_pcurtain) InitScreenBrightness();
15288 int sbrite = wxMax(1, brightness);
15289 sbrite = wxMin(100, sbrite);
15291 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15295 g_pcurtain->Close();
15296 g_pcurtain->Destroy();
15306#ifdef BRIGHT_XCALIB
15308 if (!g_brightness_init) {
15309 last_brightness = 100;
15310 g_brightness_init =
true;
15311 temp_file_name = wxFileName::CreateTempFileName(
"");
15312 InitScreenBrightness();
15315#ifdef __OPCPN_USEICC__
15318 if (!CreateSimpleICCProfileFile(
15319 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15320 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15321 wxString cmd(
"xcalib ");
15322 cmd += temp_file_name;
15324 wxExecute(cmd, wxEXEC_ASYNC);
15333 if (brightness > last_brightness) {
15335 cmd =
"xcalib -clear";
15336 wxExecute(cmd, wxEXEC_ASYNC);
15338 ::wxMilliSleep(10);
15340 int brite_adj = wxMax(1, brightness);
15341 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15342 wxExecute(cmd, wxEXEC_ASYNC);
15344 int brite_adj = wxMax(1, brightness);
15345 int factor = (brite_adj * 100) / last_brightness;
15346 factor = wxMax(1, factor);
15348 cmd.Printf(
"xcalib -co %2d -a", factor);
15349 wxExecute(cmd, wxEXEC_ASYNC);
15354 last_brightness = brightness;
15361#ifdef __OPCPN_USEICC__
15363#define MLUT_TAG 0x6d4c5554L
15364#define VCGT_TAG 0x76636774L
15366int GetIntEndian(
unsigned char *s) {
15371 p = (
unsigned char *)&ret;
15374 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15376 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15381unsigned short GetShortEndian(
unsigned char *s) {
15382 unsigned short ret;
15386 p = (
unsigned char *)&ret;
15389 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15391 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15397int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15398 double co_green,
double co_blue) {
15402 fp = fopen(file_name,
"wb");
15403 if (!fp)
return -1;
15409 for (
int i = 0; i < 128; i++) header[i] = 0;
15411 fwrite(header, 128, 1, fp);
15415 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15416 fwrite(&numTags, 1, 4, fp);
15418 int tagName0 = VCGT_TAG;
15419 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15420 fwrite(&tagName, 1, 4, fp);
15422 int tagOffset0 = 128 + 4 *
sizeof(int);
15423 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15424 fwrite(&tagOffset, 1, 4, fp);
15427 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15428 fwrite(&tagSize, 1, 4, fp);
15430 fwrite(&tagName, 1, 4, fp);
15432 fwrite(&tagName, 1, 4, fp);
15437 int gammatype0 = 0;
15438 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15439 fwrite(&gammatype, 1, 4, fp);
15441 int numChannels0 = 3;
15442 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15443 fwrite(&numChannels, 1, 2, fp);
15445 int numEntries0 = 256;
15446 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15447 fwrite(&numEntries, 1, 2, fp);
15449 int entrySize0 = 1;
15450 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15451 fwrite(&entrySize, 1, 2, fp);
15453 unsigned char ramp[256];
15456 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15457 fwrite(ramp, 256, 1, fp);
15460 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15461 fwrite(ramp, 256, 1, fp);
15464 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15465 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.