35#include <wx/graphics.h>
36#include <wx/clipbrd.h>
37#include <wx/aui/aui.h>
41#include "o_sound/o_sound.h"
48#include "model/geodesic.h"
54#include "model/nav_object_database.h"
116#include "tide_time.h"
123#include "user_colors.h"
125#include "s57_ocpn_utils.h"
128#include "androidUTIL.h"
138#include <wx/msw/msvcrt.h>
147#define printf printf2
149int __cdecl printf2(
const char *format, ...) {
153 va_start(argptr, format);
154 int ret = vsnprintf(str,
sizeof(str), format, argptr);
156 OutputDebugStringA(str);
161#if defined(__MSVC__) && (_MSC_VER < 1700)
162#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
168#define OCPN_ALT_MENUBAR 1
175static bool g_bSmoothRecenter =
true;
176static bool bDrawCurrentValues;
197static bool mouse_leftisdown;
198static bool g_brouteCreating;
199static int r_gamma_mult;
200static int g_gamma_mult;
201static int b_gamma_mult;
202static int gamma_state;
203static bool g_brightness_init;
204static int last_brightness;
205static wxGLContext *g_pGLcontext;
208static wxDialog *g_pcurtain;
210static wxString g_lastS52PLIBPluginMessage;
213#define MAX_BRIGHT 100
220EVT_ACTIVATE(ChartCanvas::OnActivate)
221EVT_SIZE(ChartCanvas::OnSize)
222#ifndef HAVE_WX_GESTURE_EVENTS
223EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
225EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
226EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
227EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
228EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
229EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
230EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
231EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
232EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
233EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
234EVT_KEY_UP(ChartCanvas::OnKeyUp)
235EVT_CHAR(ChartCanvas::OnKeyChar)
236EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
237EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
238EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
239EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
240EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
241EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
242EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
243EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
244EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
245EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
252 m_nmea_log(nmea_log) {
253 parent_frame = frame;
254 m_canvasIndex = canvasIndex;
258 SetBackgroundColour(wxColour(0, 0, 0));
259 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
263 m_bDrawingRoute =
false;
264 m_bRouteEditing =
false;
265 m_bMarkEditing =
false;
266 m_bRoutePoinDragging =
false;
267 m_bIsInRadius =
false;
268 m_bMayToggleMenuBar =
true;
271 m_bShowNavobjects =
true;
273 m_bAppendingRoute =
false;
274 pThumbDIBShow = NULL;
275 m_bShowCurrent =
false;
277 bShowingCurrent =
false;
281 m_b_paint_enable =
true;
284 pss_overlay_bmp = NULL;
285 pss_overlay_mask = NULL;
286 m_bChartDragging =
false;
287 m_bMeasure_Active =
false;
288 m_bMeasure_DistCircle =
false;
289 m_pMeasureRoute = NULL;
290 m_pTrackRolloverWin = NULL;
291 m_pRouteRolloverWin = NULL;
292 m_pAISRolloverWin = NULL;
294 m_disable_edge_pan =
false;
295 m_dragoffsetSet =
false;
299 m_singleChart = NULL;
300 m_upMode = NORTH_UP_MODE;
302 m_bShowAISScaled =
false;
303 m_timed_move_vp_active =
false;
305 m_disable_adjust_on_zoom =
false;
312 m_pSelectedRoute = NULL;
313 m_pSelectedTrack = NULL;
314 m_pRoutePointEditTarget = NULL;
315 m_pFoundPoint = NULL;
316 m_pMouseRoute = NULL;
317 m_prev_pMousePoint = NULL;
318 m_pEditRouteArray = NULL;
319 m_pFoundRoutePoint = NULL;
320 m_FinishRouteOnKillFocus =
true;
322 m_pRolloverRouteSeg = NULL;
323 m_pRolloverTrackSeg = NULL;
324 m_bsectors_shown =
false;
326 m_bbrightdir =
false;
331 m_pos_image_user_day = NULL;
332 m_pos_image_user_dusk = NULL;
333 m_pos_image_user_night = NULL;
334 m_pos_image_user_grey_day = NULL;
335 m_pos_image_user_grey_dusk = NULL;
336 m_pos_image_user_grey_night = NULL;
339 m_rotation_speed = 0;
345 m_pos_image_user_yellow_day = NULL;
346 m_pos_image_user_yellow_dusk = NULL;
347 m_pos_image_user_yellow_night = NULL;
349 SetOwnShipState(SHIP_INVALID);
351 undo =
new Undo(
this);
357 m_focus_indicator_pix = 1;
359 m_pCurrentStack = NULL;
360 m_bpersistent_quilt =
false;
361 m_piano_ctx_menu = NULL;
363 m_NotificationsList = NULL;
364 m_notification_button = NULL;
366 g_ChartNotRenderScaleFactor = 2.0;
367 m_bShowScaleInStatusBar =
true;
370 m_bShowScaleInStatusBar =
false;
371 m_show_focus_bar =
true;
373 m_bShowOutlines =
false;
374 m_bDisplayGrid =
false;
375 m_bShowDepthUnits =
true;
376 m_encDisplayCategory = (int)STANDARD;
378 m_encShowLights =
true;
379 m_encShowAnchor =
true;
380 m_encShowDataQual =
false;
382 m_pQuilt =
new Quilt(
this);
387 g_PrintingInProgress =
false;
389#ifdef HAVE_WX_GESTURE_EVENTS
390 m_oldVPSScale = -1.0;
391 m_popupWanted =
false;
394 m_inLongPress =
false;
397 m_sw_left_down.Start();
398 m_sw_left_up.Start();
402 singleClickEventIsValid =
false;
411 pCursorPencil = NULL;
416 SetCursor(*pCursorArrow);
418 pPanTimer =
new wxTimer(
this, m_MouseDragging);
421 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
422 pMovementTimer->Stop();
424 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
425 pMovementStopTimer->Stop();
427 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
428 pRotDefTimer->Stop();
430 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
431 m_DoubleClickTimer->Stop();
433 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
434 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
435 m_chart_drag_inertia_active =
false;
437 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
438 m_animationActive =
false;
439 m_menuTimer.SetOwner(
this, MENU_TIMER);
440 m_tap_timer.SetOwner(
this, TAP_TIMER);
444 m_panx_target_final = m_pany_target_final = 0;
445 m_panx_target_now = m_pany_target_now = 0;
448 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
449 pCurTrackTimer->Stop();
450 m_curtrack_timer_msec = 10;
452 m_wheelzoom_stop_oneshot = 0;
453 m_last_wheel_dir = 0;
455 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
457 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
459 m_rollover_popup_timer_msec = 20;
461 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
463 m_b_rot_hidef =
true;
468 m_upMode = NORTH_UP_MODE;
469 m_bLookAhead =
false;
473 m_cs = GLOBAL_COLOR_SCHEME_DAY;
476 VPoint.view_scale_ppm = 1;
480 m_canvas_scale_factor = 1.;
482 m_canvas_width = 1000;
484 m_overzoomTextWidth = 0;
485 m_overzoomTextHeight = 0;
494 m_pEM_Fathoms = NULL;
496 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
498 m_pEM_OverZoom = NULL;
500 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
508 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
511 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
514 double factor_dusk = 0.5;
515 double factor_night = 0.25;
518 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
520 int rimg_width = m_os_image_red_day.GetWidth();
521 int rimg_height = m_os_image_red_day.GetHeight();
523 m_os_image_red_dusk = m_os_image_red_day.Copy();
524 m_os_image_red_night = m_os_image_red_day.Copy();
526 for (
int iy = 0; iy < rimg_height; iy++) {
527 for (
int ix = 0; ix < rimg_width; ix++) {
528 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
529 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
530 m_os_image_red_day.GetGreen(ix, iy),
531 m_os_image_red_day.GetBlue(ix, iy));
532 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
533 hsv.value = hsv.value * factor_dusk;
534 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
535 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
537 hsv = wxImage::RGBtoHSV(rgb);
538 hsv.value = hsv.value * factor_night;
539 nrgb = wxImage::HSVtoRGB(hsv);
540 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
546 m_os_image_grey_day =
547 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
549 int gimg_width = m_os_image_grey_day.GetWidth();
550 int gimg_height = m_os_image_grey_day.GetHeight();
552 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
553 m_os_image_grey_night = m_os_image_grey_day.Copy();
555 for (
int iy = 0; iy < gimg_height; iy++) {
556 for (
int ix = 0; ix < gimg_width; ix++) {
557 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
558 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
559 m_os_image_grey_day.GetGreen(ix, iy),
560 m_os_image_grey_day.GetBlue(ix, iy));
561 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
562 hsv.value = hsv.value * factor_dusk;
563 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
564 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
566 hsv = wxImage::RGBtoHSV(rgb);
567 hsv.value = hsv.value * factor_night;
568 nrgb = wxImage::HSVtoRGB(hsv);
569 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
575 m_os_image_yellow_day = m_os_image_red_day.Copy();
577 gimg_width = m_os_image_yellow_day.GetWidth();
578 gimg_height = m_os_image_yellow_day.GetHeight();
580 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
581 m_os_image_yellow_night = m_os_image_red_day.Copy();
583 for (
int iy = 0; iy < gimg_height; iy++) {
584 for (
int ix = 0; ix < gimg_width; ix++) {
585 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
586 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
587 m_os_image_yellow_day.GetGreen(ix, iy),
588 m_os_image_yellow_day.GetBlue(ix, iy));
589 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
590 hsv.hue += 60. / 360.;
591 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
592 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
594 hsv = wxImage::RGBtoHSV(rgb);
595 hsv.value = hsv.value * factor_dusk;
596 hsv.hue += 60. / 360.;
597 nrgb = wxImage::HSVtoRGB(hsv);
598 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
600 hsv = wxImage::RGBtoHSV(rgb);
601 hsv.hue += 60. / 360.;
602 hsv.value = hsv.value * factor_night;
603 nrgb = wxImage::HSVtoRGB(hsv);
604 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
610 m_pos_image_red = &m_os_image_red_day;
611 m_pos_image_yellow = &m_os_image_yellow_day;
612 m_pos_image_grey = &m_os_image_grey_day;
616 m_pBrightPopup = NULL;
619 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
624 m_Piano =
new Piano(
this);
626 m_bShowCompassWin =
false;
628 m_Compass->SetScaleFactor(g_compass_scalefactor);
629 m_Compass->Show(
false);
631 if (IsPrimaryCanvas() && !g_disableNotifications) {
633 m_notification_button->SetScaleFactor(g_compass_scalefactor);
634 m_notification_button->Show(
true);
637 m_pianoFrozen =
false;
639 SetMinSize(wxSize(200, 200));
641 m_displayScale = 1.0;
642#if defined(__WXOSX__) || defined(__WXGTK3__)
644 m_displayScale = GetContentScaleFactor();
646 VPoint.SetPixelScale(m_displayScale);
648#ifdef HAVE_WX_GESTURE_EVENTS
651 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
652 wxLogError(
"Failed to enable touch events");
657 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
658 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
660 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
661 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
663 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
664 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
666 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
667 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
672 auto ¬eman = NotificationManager::GetInstance();
674 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
675 evt_notificationlist_change_listener.Listen(
676 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
677 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
678 if (m_NotificationsList && m_NotificationsList->IsShown()) {
679 m_NotificationsList->ReloadNotificationList();
685ChartCanvas::~ChartCanvas() {
686 delete pThumbDIBShow;
694 delete pCursorPencil;
698 delete pMovementTimer;
699 delete pMovementStopTimer;
700 delete pCurTrackTimer;
702 delete m_DoubleClickTimer;
704 delete m_pTrackRolloverWin;
705 delete m_pRouteRolloverWin;
706 delete m_pAISRolloverWin;
707 delete m_pBrightPopup;
713 m_dc_route.SelectObject(wxNullBitmap);
716 delete pWorldBackgroundChart;
717 delete pss_overlay_bmp;
721 delete m_pEM_Fathoms;
723 delete m_pEM_OverZoom;
728 delete m_pos_image_user_day;
729 delete m_pos_image_user_dusk;
730 delete m_pos_image_user_night;
731 delete m_pos_image_user_grey_day;
732 delete m_pos_image_user_grey_dusk;
733 delete m_pos_image_user_grey_night;
734 delete m_pos_image_user_yellow_day;
735 delete m_pos_image_user_yellow_dusk;
736 delete m_pos_image_user_yellow_night;
740 if (!g_bdisable_opengl) {
743#if wxCHECK_VERSION(2, 9, 0)
744 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
751 MUIBar *muiBar = m_muiBar;
755 delete m_pCurrentStack;
758 delete m_notification_button;
761void ChartCanvas::SetupGridFont() {
762 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
764 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
766 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
767 FALSE, wxString(
"Arial"));
770void ChartCanvas::RebuildCursors() {
776 delete pCursorPencil;
780 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
785 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
786 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
787 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
788 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
789 wxImage ICursorPencil =
790 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
791 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
793#if !defined(__WXMSW__) && !defined(__WXQT__)
794 ICursorLeft.ConvertAlphaToMask(128);
795 ICursorRight.ConvertAlphaToMask(128);
796 ICursorUp.ConvertAlphaToMask(128);
797 ICursorDown.ConvertAlphaToMask(128);
798 ICursorPencil.ConvertAlphaToMask(10);
799 ICursorCross.ConvertAlphaToMask(10);
802 if (ICursorLeft.Ok()) {
803 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
804 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
805 pCursorLeft =
new wxCursor(ICursorLeft);
807 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
809 if (ICursorRight.Ok()) {
810 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
811 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
812 pCursorRight =
new wxCursor(ICursorRight);
814 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
816 if (ICursorUp.Ok()) {
817 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
818 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
819 pCursorUp =
new wxCursor(ICursorUp);
821 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
823 if (ICursorDown.Ok()) {
824 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
825 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
826 pCursorDown =
new wxCursor(ICursorDown);
828 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
830 if (ICursorPencil.Ok()) {
831 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
832 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
833 pCursorPencil =
new wxCursor(ICursorPencil);
835 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
837 if (ICursorCross.Ok()) {
838 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
839 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
840 pCursorCross =
new wxCursor(ICursorCross);
842 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
844 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
845 pPlugIn_Cursor = NULL;
848void ChartCanvas::CanvasApplyLocale() {
849 CreateDepthUnitEmbossMaps(m_cs);
850 CreateOZEmbossMapData(m_cs);
853void ChartCanvas::SetupGlCanvas() {
856 if (!g_bdisable_opengl) {
858 wxLogMessage(
"Creating glChartCanvas");
863 if (IsPrimaryCanvas()) {
870 wxGLContext *pctx =
new wxGLContext(m_glcc);
871 m_glcc->SetContext(pctx);
875 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
877 m_glcc->SetContext(g_pGLcontext);
887 if (!g_bdisable_opengl) {
890 wxLogMessage(
"Creating glChartCanvas");
894 if (IsPrimaryCanvas()) {
895 qDebug() <<
"Creating Primary glChartCanvas";
903 wxGLContext *pctx =
new wxGLContext(m_glcc);
904 m_glcc->SetContext(pctx);
906 m_glcc->m_pParentCanvas =
this;
909 qDebug() <<
"Creating Secondary glChartCanvas";
916 top_frame::Get()->GetWxGlCanvas());
919 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
920 m_glcc->SetContext(pwxctx);
921 m_glcc->m_pParentCanvas =
this;
929void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
930 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
945 if (m_routeState && m_FinishRouteOnKillFocus)
946 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
948 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
952void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
953 m_routeFinishTimer.Stop();
957 top_frame::Get()->UpdateGlobalMenuItems(
this);
959 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
962void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
963 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
966#ifdef HAVE_WX_GESTURE_EVENTS
967void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
974 m_popupWanted =
true;
976 m_inLongPress = !g_bhide_context_menus;
979 m_menuPos =
event.GetPosition();
980 wxMouseEvent ev(wxEVT_LEFT_UP);
981 ev.m_x = m_menuPos.x;
982 ev.m_y = m_menuPos.y;
983 wxPostEvent(
this, ev);
987 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
988 ev_right_click.m_x = m_menuPos.x;
989 ev_right_click.m_y = m_menuPos.y;
990 MouseEvent(ev_right_click);
995void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
999void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1001void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1003void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1005 long dt = m_sw_left_up.Time() - m_sw_up_time;
1006 m_sw_up_time = m_sw_left_up.Time();
1017 wxPoint pos =
event.GetPosition();
1021 if (!m_popupWanted) {
1022 wxMouseEvent ev(wxEVT_LEFT_UP);
1029 m_popupWanted =
false;
1031 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1038void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1043 long dt = m_sw_left_down.Time() - m_sw_down_time;
1044 m_sw_down_time = m_sw_left_down.Time();
1068 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1070 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1071 m_lastTapPos.y - max_double_click_distance,
1072 max_double_click_distance * 2, max_double_click_distance * 2);
1075 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1081 m_lastTapPos =
event.GetPosition();
1082 m_tap_timer.StartOnce(
1086 if (m_tap_count == 2) {
1090 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1103void ChartCanvas::OnMotion(wxMouseEvent &event) {
1108 event.m_leftDown = m_leftdown;
1112void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1114 if (event.IsGestureEnd())
return;
1116 double factor =
event.GetZoomFactor();
1118 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1123 double wanted_factor = m_oldVPSScale / current_vps * factor;
1128 if (event.IsGestureStart()) {
1129 m_zoomStartPoint =
event.GetPosition();
1131 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1133 m_zoomStartPoint =
event.GetPosition();
1137void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1139void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1140 DoRotateCanvas(0.0);
1144void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1149void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1150 m_FinishRouteOnKillFocus =
false;
1151 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1152 m_FinishRouteOnKillFocus =
true;
1155void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1160 m_restore_dbindex = pcc->DBindex;
1162 if (pcc->GroupID < 0) pcc->GroupID = 0;
1167 m_groupIndex = pcc->GroupID;
1169 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1181 SetbEnableBasemapTile((pcc->bEnableBasemapTile));
1185 m_encDisplayCategory = pcc->nENCDisplayCategory;
1186 m_encShowDepth = pcc->bShowENCDepths;
1187 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1188 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1189 m_encShowLights = pcc->bShowENCLights;
1190 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1191 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1192 m_encShowDataQual = pcc->bShowENCDataQuality;
1196 m_upMode = NORTH_UP_MODE;
1198 m_upMode = COURSE_UP_MODE;
1200 m_upMode = HEAD_UP_MODE;
1204 m_singleChart = NULL;
1207void ChartCanvas::ApplyGlobalSettings() {
1210 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1211 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1213 if (m_notification_button) m_notification_button->UpdateStatus();
1216void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1217 bool groupOK = CheckGroup(m_groupIndex);
1220 SetGroupIndex(m_groupIndex,
true);
1224void ChartCanvas::SetShowGPS(
bool bshow) {
1225 if (m_bShowGPS != bshow) {
1228 m_Compass->SetScaleFactor(g_compass_scalefactor);
1229 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1234void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1235 m_bShowCompassWin = bshow;
1237 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1238 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1242int ChartCanvas::GetPianoHeight() {
1244 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1249void ChartCanvas::ConfigureChartBar() {
1252 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1253 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1255 if (GetQuiltMode()) {
1256 m_Piano->SetRoundedRectangles(
true);
1258 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1259 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1260 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1263void ChartCanvas::ShowTides(
bool bShow) {
1264 top_frame::Get()->LoadHarmonics();
1267 SetbShowTide(bShow);
1269 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1271 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1272 SetbShowTide(
false);
1273 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1276 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1277 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1288void ChartCanvas::ShowCurrents(
bool bShow) {
1289 top_frame::Get()->LoadHarmonics();
1292 SetbShowCurrent(bShow);
1293 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1295 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1296 SetbShowCurrent(
false);
1297 top_frame::Get()->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1300 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1301 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1318void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1320void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1323 int new_index = index;
1326 bool bgroup_override =
false;
1327 int old_group_index = new_index;
1329 if (!CheckGroup(new_index)) {
1331 bgroup_override =
true;
1334 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1338 int current_chart_native_scale = GetCanvasChartNativeScale();
1341 m_groupIndex = new_index;
1347 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1351 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1355 g_sticky_chart = -1;
1359 UpdateCanvasOnGroupChange();
1362 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1364 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1367 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1368 double best_scale = GetBestStartScale(dbi_hint, vp);
1372 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1376 canvasChartsRefresh(dbi_hint);
1378 UpdateCanvasControlBar();
1380 if (!autoSwitch && bgroup_override) {
1382 wxString msg(_(
"Group \""));
1385 msg += pGroup->m_group_name;
1387 msg += _(
"\" is empty.");
1389 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1396 if (bgroup_override) {
1397 wxString msg(_(
"Group \""));
1400 msg += pGroup->m_group_name;
1402 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1404 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1408bool ChartCanvas::CheckGroup(
int igroup) {
1411 if (igroup == 0)
return true;
1418 if (pGroup->m_element_array.empty())
1422 for (
const auto &elem : pGroup->m_element_array) {
1423 for (
unsigned int ic = 0;
1424 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1425 auto &cte =
ChartData->GetChartTableEntry(ic);
1426 wxString chart_full_path(cte.GetpFullPath(), wxConvUTF8);
1428 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1433 for (
const auto &elem : pGroup->m_element_array) {
1434 const wxString &element_root = elem.m_element_name;
1435 wxString test_string =
"GSHH";
1436 if (element_root.Upper().Contains(test_string))
return true;
1442void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1445 AbstractPlatform::ShowBusySpinner();
1449 SetQuiltRefChart(-1);
1451 m_singleChart = NULL;
1457 if (!m_pCurrentStack) {
1459 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1462 if (-1 != dbi_hint) {
1463 if (GetQuiltMode()) {
1464 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1465 SetQuiltRefChart(dbi_hint);
1469 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1471 if (pTentative_Chart) {
1474 if (m_singleChart) m_singleChart->Deactivate();
1476 m_singleChart = pTentative_Chart;
1477 m_singleChart->Activate();
1479 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1480 GetpCurrentStack(), m_singleChart->GetFullPath());
1488 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1489 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1490 SetQuiltRefChart(selected_index);
1494 SetupCanvasQuiltMode();
1495 if (!GetQuiltMode() && m_singleChart == 0) {
1497 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1498 m_singleChart = pDummyChart;
1504 UpdateCanvasControlBar();
1505 UpdateGPSCompassStatusBox(
true);
1507 SetCursor(wxCURSOR_ARROW);
1509 AbstractPlatform::HideBusySpinner();
1512bool ChartCanvas::DoCanvasUpdate() {
1514 double vpLat, vpLon;
1515 bool blong_jump =
false;
1516 meters_to_shift = 0;
1519 bool bNewChart =
false;
1520 bool bNewView =
false;
1521 bool bCanvasChartAutoOpen =
true;
1523 bool bNewPiano =
false;
1524 bool bOpenSpecified;
1530 if (!GetVP().IsValid())
return false;
1531 if (bDBUpdateInProgress)
return false;
1536 if (m_chart_drag_inertia_active)
return false;
1537 if (m_animationActive)
return false;
1563 double dx = m_OSoffsetx;
1564 double dy = m_OSoffsety;
1568 if (GetUpMode() == NORTH_UP_MODE) {
1569 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1571 double offset_angle = atan2(d_north, d_east);
1572 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1573 double chart_angle = GetVPRotation();
1574 double target_angle = chart_angle + offset_angle;
1575 double d_east_mod = offset_distance * cos(target_angle);
1576 double d_north_mod = offset_distance * sin(target_angle);
1577 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1581 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1582 double cog_to_use =
gCog;
1584 (fabs(
gCog - gCog_gt) > 20)) {
1585 cog_to_use = gCog_gt;
1588 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1590 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1592 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1593 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1595 double pixel_delta_tent =
1596 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1598 double pixel_delta = 0;
1603 if (!std::isnan(
gSog)) {
1607 pixel_delta = pixel_delta_tent;
1610 meters_to_shift = 0;
1612 if (!std::isnan(
gCog)) {
1613 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1614 dir_to_shift = cog_to_use;
1615 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1621 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1635 if (GetQuiltMode()) {
1636 int current_db_index = -1;
1637 if (m_pCurrentStack)
1640 ->GetCurrentEntrydbIndex();
1648 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1650 if (m_pCurrentStack->nEntry) {
1651 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1653 SelectQuiltRefdbChart(new_dbIndex,
true);
1654 m_bautofind =
false;
1658 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1659 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1664 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1670 double proposed_scale_onscreen =
1673 int initial_db_index = m_restore_dbindex;
1674 if (initial_db_index < 0) {
1675 if (m_pCurrentStack->nEntry) {
1677 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1682 if (m_pCurrentStack->nEntry) {
1683 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1688 if (!IsChartQuiltableRef(initial_db_index)) {
1692 int stack_index = 0;
1694 if (stack_index >= 0) {
1695 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1696 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1697 if (IsChartQuiltableRef(test_db_index) &&
1699 ChartData->GetDBChartType(initial_db_index))) {
1700 initial_db_index = test_db_index;
1710 SetQuiltRefChart(initial_db_index);
1711 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1719 0, GetVPRotation());
1724 bool super_jump =
false;
1726 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1727 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1728 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1735 pLast_Ch = m_singleChart;
1736 ChartTypeEnum new_open_type;
1737 ChartFamilyEnum new_open_family;
1739 new_open_type = pLast_Ch->GetChartType();
1740 new_open_family = pLast_Ch->GetChartFamily();
1742 new_open_type = CHART_TYPE_KAP;
1743 new_open_family = CHART_FAMILY_RASTER;
1746 bOpenSpecified = m_bFirstAuto;
1749 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1752 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1754 if (NULL == pDummyChart) {
1760 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1762 m_singleChart = pDummyChart;
1767 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1769 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1772 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1773 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1780 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1786 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1791 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1794 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1799 if (NULL != m_singleChart)
1800 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1801 m_singleChart->GetFullPath());
1804 m_pCurrentStack->CurrentStackEntry = tEntry;
1814 if (bCanvasChartAutoOpen) {
1815 bool search_direction =
1817 int start_index = 0;
1821 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1822 (LastStack.nEntry == 0)) {
1823 search_direction =
true;
1824 start_index = m_pCurrentStack->nEntry - 1;
1828 if (bOpenSpecified) {
1829 if (m_restore_dbindex >= 0) {
1831 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
1832 std::vector<int> one_array;
1833 one_array.push_back(m_restore_dbindex);
1834 m_Piano->SetActiveKeyArray(one_array);
1835 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
1836 m_restore_dbindex = -1;
1840 search_direction =
false;
1841 start_index = m_restore_dbindex;
1842 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1845 new_open_type = CHART_TYPE_DONTCARE;
1850 pProposed =
ChartData->OpenStackChartConditional(
1851 m_pCurrentStack, start_index, search_direction, new_open_type,
1855 if (NULL == pProposed)
1856 pProposed =
ChartData->OpenStackChartConditional(
1857 m_pCurrentStack, start_index, search_direction,
1858 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1860 if (NULL == pProposed)
1861 pProposed =
ChartData->OpenStackChartConditional(
1862 m_pCurrentStack, start_index, search_direction,
1863 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1874 if (NULL == pProposed) {
1875 if (NULL == pDummyChart) {
1881 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1883 pProposed = pDummyChart;
1887 if (m_singleChart) m_singleChart->Deactivate();
1888 m_singleChart = pProposed;
1890 if (m_singleChart) {
1891 m_singleChart->Activate();
1892 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1893 m_pCurrentStack, m_singleChart->GetFullPath());
1898 if (NULL != m_singleChart) {
1902 double proposed_scale_onscreen;
1905 double new_scale_ppm =
1906 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1914 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1915 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1916 double equivalent_vp_scale =
1918 double new_scale_ppm =
1919 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1924 proposed_scale_onscreen =
1925 wxMin(proposed_scale_onscreen,
1928 proposed_scale_onscreen =
1929 wxMax(proposed_scale_onscreen,
1937 m_singleChart->GetChartSkew() * PI / 180.,
1945 if ((m_bFollow) && m_singleChart)
1947 m_singleChart->GetChartSkew() * PI / 180.,
1956 m_bFirstAuto =
false;
1960 if (bNewChart && !bNewView) Refresh(
false);
1965 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1968 return bNewChart | bNewView;
1971void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1972 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1974 SetQuiltRefChart(db_index);
1979 double best_scale_ppm = GetBestVPScale(pc);
1983 SetQuiltRefChart(-1);
1985 SetQuiltRefChart(-1);
1988void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1989 std::vector<int> piano_chart_index_array =
1990 GetQuiltExtendedStackdbIndexArray();
1991 int current_db_index = piano_chart_index_array[selected_index];
1993 SelectQuiltRefdbChart(current_db_index);
1996double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
2000 if ((g_bPreserveScaleOnX) ||
2001 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2007 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2008 double equivalent_vp_scale =
2010 double new_scale_ppm =
2011 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2018 double max_underzoom_multiplier = 2.0;
2019 if (GetVP().b_quilt) {
2020 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2021 pchart->GetChartType(),
2022 pchart->GetChartFamily());
2023 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2026 proposed_scale_onscreen = wxMin(
2027 proposed_scale_onscreen,
2029 max_underzoom_multiplier);
2032 proposed_scale_onscreen =
2033 wxMax(proposed_scale_onscreen,
2041void ChartCanvas::SetupCanvasQuiltMode() {
2046 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2050 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2051 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2052 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2053 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2055 m_Piano->SetRoundedRectangles(
true);
2058 int target_new_dbindex = -1;
2059 if (m_pCurrentStack) {
2060 target_new_dbindex =
2061 GetQuiltReferenceChartIndex();
2063 if (-1 != target_new_dbindex) {
2064 if (!IsChartQuiltableRef(target_new_dbindex)) {
2065 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2066 int type =
ChartData->GetDBChartType(target_new_dbindex);
2069 int stack_index = m_pCurrentStack->CurrentStackEntry;
2071 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2072 (stack_index >= 0)) {
2073 int proj_tent =
ChartData->GetDBChartProj(
2074 m_pCurrentStack->GetDBIndex(stack_index));
2075 int type_tent =
ChartData->GetDBChartType(
2076 m_pCurrentStack->GetDBIndex(stack_index));
2078 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2079 if ((proj == proj_tent) && (type_tent == type)) {
2080 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2090 if (IsChartQuiltableRef(target_new_dbindex))
2091 SelectQuiltRefdbChart(target_new_dbindex,
2094 int stack_index = m_pCurrentStack->CurrentStackEntry;
2095 SelectQuiltRefdbChart(m_pCurrentStack->GetDBIndex(stack_index),
false);
2098 m_singleChart = NULL;
2101 AdjustQuiltRefChart();
2109 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2113 std::vector<int> empty_array;
2114 m_Piano->SetActiveKeyArray(empty_array);
2115 m_Piano->SetNoshowIndexArray(empty_array);
2116 m_Piano->SetEclipsedIndexArray(empty_array);
2119 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2120 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2121 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2122 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2124 m_Piano->SetRoundedRectangles(
false);
2130 if (!GetQuiltMode()) {
2135 if (m_bFollow ==
true) {
2143 if (!m_singleChart) {
2145 if (GetQuiltReferenceChartIndex() >= 0) {
2146 m_singleChart =
ChartData->OpenChartFromDB(
2147 GetQuiltReferenceChartIndex(), FULL_INIT);
2150 else if (m_restore_dbindex >= 0) {
2152 ChartData->OpenChartFromDB(m_restore_dbindex, FULL_INIT);
2158 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2166 int cur_max_scale = (int)1e8;
2168 ChartBase *pChart = GetFirstQuiltChart();
2172 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2174 if (pChart->GetNativeScale() < cur_max_scale) {
2175 Candidate_Chart = pChart;
2176 cur_max_scale = pChart->GetNativeScale();
2179 pChart = GetNextQuiltChart();
2182 m_singleChart = Candidate_Chart;
2186 if (NULL == m_singleChart) {
2187 m_singleChart =
ChartData->OpenStackChartConditional(
2188 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2189 CHART_FAMILY_DONTCARE);
2195 InvalidateAllQuiltPatchs();
2197 if (m_singleChart) {
2198 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2199 std::vector<int> one_array;
2200 one_array.push_back(dbi);
2201 m_Piano->SetActiveKeyArray(one_array);
2204 if (m_singleChart) {
2205 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2210 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2214bool ChartCanvas::IsTempMenuBarEnabled() {
2217 wxGetOsVersion(&major);
2225double ChartCanvas::GetCanvasRangeMeters() {
2227 GetSize(&width, &height);
2228 int minDimension = wxMin(width, height);
2231 range *= cos(GetVP().clat * PI / 180.);
2235void ChartCanvas::SetCanvasRangeMeters(
double range) {
2237 GetSize(&width, &height);
2238 int minDimension = wxMin(width, height);
2240 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2244bool ChartCanvas::SetUserOwnship() {
2248 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2249 double factor_dusk = 0.5;
2250 double factor_night = 0.25;
2252 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2253 m_pos_image_user_day =
new wxImage;
2254 *m_pos_image_user_day = pbmp->ConvertToImage();
2255 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2257 int gimg_width = m_pos_image_user_day->GetWidth();
2258 int gimg_height = m_pos_image_user_day->GetHeight();
2261 m_pos_image_user_dusk =
new wxImage;
2262 m_pos_image_user_night =
new wxImage;
2264 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2265 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2267 for (
int iy = 0; iy < gimg_height; iy++) {
2268 for (
int ix = 0; ix < gimg_width; ix++) {
2269 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2270 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2271 m_pos_image_user_day->GetGreen(ix, iy),
2272 m_pos_image_user_day->GetBlue(ix, iy));
2273 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2274 hsv.value = hsv.value * factor_dusk;
2275 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2276 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2279 hsv = wxImage::RGBtoHSV(rgb);
2280 hsv.value = hsv.value * factor_night;
2281 nrgb = wxImage::HSVtoRGB(hsv);
2282 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2289 m_pos_image_user_grey_day =
new wxImage;
2290 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2292 m_pos_image_user_grey_dusk =
new wxImage;
2293 m_pos_image_user_grey_night =
new wxImage;
2295 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2296 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2298 for (
int iy = 0; iy < gimg_height; iy++) {
2299 for (
int ix = 0; ix < gimg_width; ix++) {
2300 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2301 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2302 m_pos_image_user_grey_day->GetGreen(ix, iy),
2303 m_pos_image_user_grey_day->GetBlue(ix, iy));
2304 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2305 hsv.value = hsv.value * factor_dusk;
2306 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2307 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2310 hsv = wxImage::RGBtoHSV(rgb);
2311 hsv.value = hsv.value * factor_night;
2312 nrgb = wxImage::HSVtoRGB(hsv);
2313 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2320 m_pos_image_user_yellow_day =
new wxImage;
2321 m_pos_image_user_yellow_dusk =
new wxImage;
2322 m_pos_image_user_yellow_night =
new wxImage;
2324 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2325 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2326 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2328 for (
int iy = 0; iy < gimg_height; iy++) {
2329 for (
int ix = 0; ix < gimg_width; ix++) {
2330 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2331 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2332 m_pos_image_user_grey_day->GetGreen(ix, iy),
2333 m_pos_image_user_grey_day->GetBlue(ix, iy));
2337 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2338 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2339 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2341 hsv = wxImage::RGBtoHSV(rgb);
2342 hsv.value = hsv.value * factor_dusk;
2343 nrgb = wxImage::HSVtoRGB(hsv);
2344 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2346 hsv = wxImage::RGBtoHSV(rgb);
2347 hsv.value = hsv.value * factor_night;
2348 nrgb = wxImage::HSVtoRGB(hsv);
2349 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2361 m_display_size_mm = size;
2368 double horizontal = sd.x;
2372 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2373 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2377 ps52plib->SetPPMM(m_pix_per_mm);
2382 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2384 m_display_size_mm, sd.x, sd.y);
2390 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2393 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2396void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2398 wxString msg(event.m_string.c_str(), wxConvUTF8);
2400 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2401 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2404 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2406 compress_msg_array.RemoveAt(event.thread);
2407 compress_msg_array.Insert( msg, event.thread);
2410 compress_msg_array.Add(msg);
2413 wxString combined_msg;
2414 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2415 combined_msg += compress_msg_array[i];
2416 combined_msg +=
"\n";
2420 pprog->Update(pprog_count, combined_msg, &skip );
2421 pprog->SetSize(pprog_size);
2426void ChartCanvas::InvalidateGL() {
2427 if (!m_glcc)
return;
2429 if (g_bopengl) m_glcc->Invalidate();
2431 if (m_Compass) m_Compass->UpdateStatus(
true);
2434int ChartCanvas::GetCanvasChartNativeScale() {
2436 if (!VPoint.b_quilt) {
2437 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2439 ret = (int)m_pQuilt->GetRefNativeScale();
2444ChartBase *ChartCanvas::GetChartAtCursor() {
2446 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2447 target_chart = m_singleChart;
2448 else if (VPoint.b_quilt)
2449 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2451 target_chart = NULL;
2452 return target_chart;
2455ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2459 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2461 target_chart = NULL;
2462 return target_chart;
2465int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2466 int new_dbIndex = -1;
2467 if (!VPoint.b_quilt) {
2468 if (m_pCurrentStack) {
2469 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2470 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2472 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2483 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2486 for (
unsigned int is = 0; is < im; is++) {
2488 m_pQuilt->GetExtendedStackIndexArray()[is]);
2489 if ((m.Scale_ge(
scale)) &&
2490 (m_pQuilt->GetRefFamily() == m.GetChartFamily())) {
2491 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2498 if (new_dbIndex < 0) {
2499 for (
unsigned int is = 0; is < im; is++) {
2501 m_pQuilt->GetExtendedStackIndexArray()[is]);
2502 if (m.Scale_ge(
scale)) {
2503 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2514void ChartCanvas::EnablePaint(
bool b_enable) {
2515 m_b_paint_enable = b_enable;
2517 if (m_glcc) m_glcc->EnablePaint(b_enable);
2521bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2523void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2525std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2526 return m_pQuilt->GetQuiltIndexArray();
2530void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2531 VPoint.b_quilt = b_quilt;
2532 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2535bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2537int ChartCanvas::GetQuiltReferenceChartIndex() {
2538 return m_pQuilt->GetRefChartdbIndex();
2541void ChartCanvas::InvalidateAllQuiltPatchs() {
2542 m_pQuilt->InvalidateAllQuiltPatchs();
2545ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2546 return m_pQuilt->GetLargestScaleChart();
2549ChartBase *ChartCanvas::GetFirstQuiltChart() {
2550 return m_pQuilt->GetFirstChart();
2553ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2555int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2557void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2558 m_pQuilt->SetHiliteIndex(dbIndex);
2561void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2562 m_pQuilt->SetHiliteIndexArray(hilite_array);
2565void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2566 m_pQuilt->ClearHiliteIndexArray();
2569std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2571 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2574int ChartCanvas::GetQuiltRefChartdbIndex() {
2575 return m_pQuilt->GetRefChartdbIndex();
2578std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2579 return m_pQuilt->GetExtendedStackIndexArray();
2582std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2583 return m_pQuilt->GetFullscreenIndexArray();
2586std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2587 return m_pQuilt->GetEclipsedStackIndexArray();
2590void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2592double ChartCanvas::GetQuiltMaxErrorFactor() {
2593 return m_pQuilt->GetMaxErrorFactor();
2596bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2597 return m_pQuilt->IsChartQuiltableRef(db_index);
2601 double chartMaxScale =
2603 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2606void ChartCanvas::StartMeasureRoute() {
2607 if (!m_routeState) {
2608 if (m_bMeasure_Active) {
2610 m_pMeasureRoute = NULL;
2613 m_bMeasure_Active =
true;
2614 m_nMeasureState = 1;
2615 m_bDrawingRoute =
false;
2617 SetCursor(*pCursorPencil);
2622void ChartCanvas::CancelMeasureRoute() {
2623 m_bMeasure_Active =
false;
2624 m_nMeasureState = 0;
2625 m_bDrawingRoute =
false;
2628 m_pMeasureRoute = NULL;
2630 SetCursor(*pCursorArrow);
2633ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2635void ChartCanvas::SetVP(
ViewPort &vp) {
2646void ChartCanvas::TriggerDeferredFocus() {
2649 m_deferredFocusTimer.Start(20,
true);
2651#if defined(__WXGTK__) || defined(__WXOSX__)
2652 top_frame::Get()->Raise();
2662void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2667void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2668 if (SendKeyEventToPlugins(event))
2672 int key_char =
event.GetKeyCode();
2675 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2681 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2686 if (g_benable_rotate) {
2707void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2708 if (SendKeyEventToPlugins(event))
2712 bool b_handled =
false;
2714 m_modkeys =
event.GetModifiers();
2716 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2718#ifdef OCPN_ALT_MENUBAR
2724 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2726 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2727 if (!g_bTempShowMenuBar) {
2728 g_bTempShowMenuBar =
true;
2729 top_frame::Get()->ApplyGlobalSettings(
false);
2731 m_bMayToggleMenuBar =
false;
2737 if (event.GetKeyCode() != WXK_ALT) {
2738 m_bMayToggleMenuBar =
false;
2745 switch (event.GetKeyCode()) {
2752 event.GetPosition(&x, &y);
2753 m_FinishRouteOnKillFocus =
false;
2754 CallPopupMenu(x, y);
2755 m_FinishRouteOnKillFocus =
true;
2759 m_modkeys |= wxMOD_ALT;
2763 m_modkeys |= wxMOD_CONTROL;
2768 case WXK_RAW_CONTROL:
2769 m_modkeys |= wxMOD_RAW_CONTROL;
2774 if (m_modkeys == wxMOD_CONTROL)
2775 top_frame::Get()->DoStackDown(
this);
2777 StartTimedMovement();
2787 StartTimedMovement();
2795 if (m_modkeys == wxMOD_CONTROL)
2796 top_frame::Get()->DoStackUp(
this);
2798 StartTimedMovement();
2808 StartTimedMovement();
2816 if (event.ShiftDown()) {
2818 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2820 std::shared_ptr<HostApi> host_api;
2822 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2825 api_121->SelectChartFamily(m_canvasIndex,
2832 if (event.ShiftDown()) {
2834 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2836 std::shared_ptr<HostApi> host_api;
2838 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2841 api_121->SelectChartFamily(m_canvasIndex,
2844 SetShowENCText(!GetShowENCText());
2851 if (!m_bMeasure_Active) {
2852 if (event.ShiftDown())
2853 m_bMeasure_DistCircle =
true;
2855 m_bMeasure_DistCircle =
false;
2857 StartMeasureRoute();
2859 CancelMeasureRoute();
2861 SetCursor(*pCursorArrow);
2871 top_frame::Get()->ToggleColorScheme();
2872 top_frame::Get()->Raise();
2873 TriggerDeferredFocus();
2877 int mod = m_modkeys & wxMOD_SHIFT;
2878 if (mod != m_brightmod) {
2880 m_bbrightdir = !m_bbrightdir;
2883 if (!m_bbrightdir) {
2884 g_nbrightness -= 10;
2885 if (g_nbrightness <= MIN_BRIGHT) {
2886 g_nbrightness = MIN_BRIGHT;
2887 m_bbrightdir =
true;
2890 g_nbrightness += 10;
2891 if (g_nbrightness >= MAX_BRIGHT) {
2892 g_nbrightness = MAX_BRIGHT;
2893 m_bbrightdir =
false;
2897 SetScreenBrightness(g_nbrightness);
2898 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2901 top_frame::Get()->Raise();
2907 top_frame::Get()->DoStackDown(
this);
2911 top_frame::Get()->DoStackUp(
this);
2916 ToggleCanvasQuiltMode();
2922 top_frame::Get()->ToggleFullScreen();
2927 if (m_modkeys == wxMOD_ALT) {
2930 ToggleChartOutlines();
2936 top_frame::Get()->ActivateMOB();
2940 case WXK_NUMPAD_ADD:
2945 case WXK_NUMPAD_SUBTRACT:
2946 case WXK_PAGEDOWN: {
2947 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2952 if (m_bMeasure_Active) {
2953 if (m_nMeasureState > 2) {
2954 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2956 m_pMeasureRoute->GetnPoints();
2958 top_frame::Get()->RefreshAllCanvas();
2960 CancelMeasureRoute();
2961 StartMeasureRoute();
2969 if (event.GetKeyCode() < 128)
2971 int key_char =
event.GetKeyCode();
2975 if (!g_b_assume_azerty) {
2977 if (g_benable_rotate) {
3009 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
3016 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
3017 m_modkeys & wxMOD_RAW_CONTROL) {
3018 top_frame::Get()->ToggleFullScreen();
3023 if (event.ControlDown()) key_char -= 64;
3025 if (key_char >=
'0' && key_char <=
'9')
3026 SetGroupIndex(key_char -
'0');
3031 SetShowENCAnchor(!GetShowENCAnchor());
3037 top_frame::Get()->ToggleColorScheme();
3042 event.GetPosition(&x, &y);
3043 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3044 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3047 if (VPoint.b_quilt) {
3049 if (m_pQuilt->GetChartAtPix(
3054 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3056 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3061 if (m_singleChart) {
3062 ChartType = m_singleChart->GetChartType();
3063 ChartFam = m_singleChart->GetChartFamily();
3067 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3068 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3070 this, -1, ChartType, ChartFam,
3071 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3072 wxDefaultSize, wxSIMPLE_BORDER,
"");
3085 m_nmea_log->Raise();
3089 SetShowENCLights(!GetShowENCLights());
3095 if (event.ShiftDown())
3096 m_bMeasure_DistCircle =
true;
3098 m_bMeasure_DistCircle =
false;
3100 StartMeasureRoute();
3104 if (g_bInlandEcdis && ps52plib) {
3105 SetENCDisplayCategory((_DisCat)STANDARD);
3110 ToggleChartOutlines();
3114 ToggleCanvasQuiltMode();
3118 top_frame::Get()->ToggleTestPause();
3121 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3122 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3123 g_iNavAidRadarRingsNumberVisible = 1;
3124 else if (!g_bNavAidRadarRingsShown &&
3125 g_iNavAidRadarRingsNumberVisible == 1)
3126 g_iNavAidRadarRingsNumberVisible = 0;
3129 SetShowENCDepth(!m_encShowDepth);
3134 SetShowENCText(!GetShowENCText());
3139 SetShowENCDataQual(!GetShowENCDataQual());
3144 m_bShowNavobjects = !m_bShowNavobjects;
3159 if (g_bShowMenuBar ==
false) top_frame::Get()->ToggleChartBar(
this);
3164 if (event.ControlDown()) top_frame::Get()->DropMarker(
false);
3171 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3172 if ((indexActive + 1) <= r->GetnPoints()) {
3183 if (!g_bShowMenuBar) top_frame::Get()->DropMarker(
true);
3189 if (g_bSpaceDropMark) top_frame::Get()->DropMarker(
true);
3195 if (m_modkeys == wxMOD_CONTROL) top_frame::Get()->ActivateMOB();
3202 top_frame::Get()->DoSettings();
3206 parent_frame->Close();
3222 if (undo->AnythingToRedo()) {
3223 undo->RedoNextAction();
3230 if (event.ShiftDown()) {
3231 if (undo->AnythingToRedo()) {
3232 undo->RedoNextAction();
3237 if (undo->AnythingToUndo()) {
3238 undo->UndoLastAction();
3247 if (m_bMeasure_Active) {
3248 CancelMeasureRoute();
3250 SetCursor(*pCursorArrow);
3253 top_frame::Get()->RefreshAllCanvas();
3267 switch (gamma_state) {
3287 SetScreenBrightness(g_nbrightness);
3292 if (event.ControlDown()) {
3293 m_bShowCompassWin = !m_bShowCompassWin;
3294 SetShowGPSCompassWindow(m_bShowCompassWin);
3311void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3312 if (SendKeyEventToPlugins(event))
3316 switch (event.GetKeyCode()) {
3318 top_frame::Get()->SwitchKBFocus(
this);
3324 if (!m_pany) m_panspeed = 0;
3330 if (!m_panx) m_panspeed = 0;
3333 case WXK_NUMPAD_ADD:
3334 case WXK_NUMPAD_SUBTRACT:
3343 m_modkeys &= ~wxMOD_ALT;
3344#ifdef OCPN_ALT_MENUBAR
3349 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3350 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3351 top_frame::Get()->ApplyGlobalSettings(
false);
3353 m_bMayToggleMenuBar =
true;
3359 m_modkeys &= ~wxMOD_CONTROL;
3363 if (event.GetKeyCode() < 128)
3365 int key_char =
event.GetKeyCode();
3369 if (!g_b_assume_azerty) {
3384 m_rotation_speed = 0;
3402void ChartCanvas::ToggleChartOutlines() {
3403 m_bShowOutlines = !m_bShowOutlines;
3409 if (g_bopengl) InvalidateGL();
3413void ChartCanvas::ToggleLookahead() {
3414 m_bLookAhead = !m_bLookAhead;
3419void ChartCanvas::SetUpMode(
int mode) {
3422 if (mode != NORTH_UP_MODE) {
3425 if (!std::isnan(
gCog)) stuff =
gCog;
3428 auto cog_table = top_frame::Get()->GetCOGTable();
3429 for (
int i = 0; i <
g_COGAvgSec; i++) cog_table[i] = stuff;
3432 top_frame::Get()->StartCogTimer();
3434 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3435 SetVPRotation(GetVPSkew());
3440 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3441 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3443 UpdateGPSCompassStatusBox(
true);
3444 top_frame::Get()->DoChartUpdate();
3447bool ChartCanvas::DoCanvasCOGSet() {
3448 if (GetUpMode() == NORTH_UP_MODE)
return false;
3450 if (g_btenhertz) cog_use =
gCog;
3452 double rotation = 0;
3453 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3454 rotation = -
gHdt * PI / 180.;
3455 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3456 rotation = -cog_use * PI / 180.;
3458 SetVPRotation(rotation);
3462double easeOutCubic(
double t) {
3464 return 1.0 - pow(1.0 - t, 3.0);
3467void ChartCanvas::StartChartDragInertia() {
3468 m_bChartDragging =
false;
3471 m_chart_drag_inertia_time = 750;
3472 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3477 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3481 size_t length = m_drag_vec_t.size();
3482 for (
size_t i = 0; i < n_vel; i++) {
3483 xacc += m_drag_vec_x.at(length - 1 - i);
3484 yacc += m_drag_vec_y.at(length - 1 - i);
3485 tacc += m_drag_vec_t.at(length - 1 - i);
3488 if (tacc == 0)
return;
3490 double drag_velocity_x = xacc / tacc;
3491 double drag_velocity_y = yacc / tacc;
3497 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3499 m_chart_drag_velocity_x = drag_velocity_x;
3500 m_chart_drag_velocity_y = drag_velocity_y;
3502 m_chart_drag_inertia_active =
true;
3504 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3507void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3508 if (!m_chart_drag_inertia_active)
return;
3510 wxLongLong now = wxGetLocalTimeMillis();
3511 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3512 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3513 if (t > 1.0) t = 1.0;
3514 double e = 1.0 - easeOutCubic(t);
3517 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3519 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3521 m_last_elapsed = elapsed;
3525 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3526 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3527 double inertia_lat, inertia_lon;
3531 if (!IsOwnshipOnScreen()) {
3533 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3534 UpdateFollowButtonState();
3545 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3546 m_chart_drag_inertia_timer.Stop();
3549 m_target_lat = GetVP().
clat;
3550 m_target_lon = GetVP().
clon;
3551 m_pan_drag.x = m_pan_drag.y = 0;
3552 m_panx = m_pany = 0;
3553 m_chart_drag_inertia_active =
false;
3557 int target_redraw_interval = 40;
3558 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3562void ChartCanvas::StopMovement() {
3563 m_panx = m_pany = 0;
3566 m_rotation_speed = 0;
3569#if !defined(__WXGTK__) && !defined(__WXQT__)
3571 top_frame::Get()->Raise();
3580bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3582 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3584 if (!pMovementTimer->IsRunning()) {
3585 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3588 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3593 m_last_movement_time = wxDateTime::UNow();
3597void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3600 m_target_lat = target_lat;
3601 m_target_lon = target_lon;
3604 m_start_lat = GetVP().
clat;
3605 m_start_lon = GetVP().
clon;
3607 m_VPMovementTimer.Start(1,
true);
3608 m_timed_move_vp_active =
true;
3610 m_timedVP_step = nstep;
3613void ChartCanvas::DoTimedMovementVP() {
3614 if (!m_timed_move_vp_active)
return;
3615 if (m_stvpc++ > m_timedVP_step * 2) {
3622 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3637 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3638 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3640 m_run_lat = new_lat;
3641 m_run_lon = new_lon;
3646void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3648void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3650void ChartCanvas::StartTimedMovementTarget() {}
3652void ChartCanvas::DoTimedMovementTarget() {}
3654void ChartCanvas::StopMovementTarget() {}
3657void ChartCanvas::DoTimedMovement() {
3658 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3662 wxDateTime now = wxDateTime::UNow();
3664 if (m_last_movement_time.IsValid())
3665 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3667 m_last_movement_time = now;
3677 if (dt == 0) dt = 1;
3680 if (m_mustmove < 0) m_mustmove = 0;
3683 if (m_pan_drag.x || m_pan_drag.y) {
3685 m_pan_drag.x = m_pan_drag.y = 0;
3688 if (m_panx || m_pany) {
3689 const double slowpan = .1, maxpan = 2;
3690 if (m_modkeys == wxMOD_ALT)
3691 m_panspeed = slowpan;
3693 m_panspeed += (double)dt / 500;
3694 m_panspeed = wxMin(maxpan, m_panspeed);
3696 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3699 if (m_zoom_factor != 1) {
3700 double alpha = 400, beta = 1.5;
3701 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3703 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3705 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3710 if (zoom_factor > 1) {
3711 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3715 else if (zoom_factor < 1) {
3716 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3721 if (fabs(zoom_factor - 1) > 1e-4) {
3722 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3727 if (m_wheelzoom_stop_oneshot > 0) {
3728 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3729 m_wheelzoom_stop_oneshot = 0;
3734 if (zoom_factor > 1) {
3736 m_wheelzoom_stop_oneshot = 0;
3739 }
else if (zoom_factor < 1) {
3741 m_wheelzoom_stop_oneshot = 0;
3748 if (m_rotation_speed) {
3749 double speed = m_rotation_speed;
3750 if (m_modkeys == wxMOD_ALT) speed /= 10;
3751 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3755void ChartCanvas::SetColorScheme(ColorScheme cs) {
3760 case GLOBAL_COLOR_SCHEME_DAY:
3761 m_pos_image_red = &m_os_image_red_day;
3762 m_pos_image_grey = &m_os_image_grey_day;
3763 m_pos_image_yellow = &m_os_image_yellow_day;
3764 m_pos_image_user = m_pos_image_user_day;
3765 m_pos_image_user_grey = m_pos_image_user_grey_day;
3766 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3767 m_cTideBitmap = m_bmTideDay;
3768 m_cCurrentBitmap = m_bmCurrentDay;
3771 case GLOBAL_COLOR_SCHEME_DUSK:
3772 m_pos_image_red = &m_os_image_red_dusk;
3773 m_pos_image_grey = &m_os_image_grey_dusk;
3774 m_pos_image_yellow = &m_os_image_yellow_dusk;
3775 m_pos_image_user = m_pos_image_user_dusk;
3776 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3777 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3778 m_cTideBitmap = m_bmTideDusk;
3779 m_cCurrentBitmap = m_bmCurrentDusk;
3781 case GLOBAL_COLOR_SCHEME_NIGHT:
3782 m_pos_image_red = &m_os_image_red_night;
3783 m_pos_image_grey = &m_os_image_grey_night;
3784 m_pos_image_yellow = &m_os_image_yellow_night;
3785 m_pos_image_user = m_pos_image_user_night;
3786 m_pos_image_user_grey = m_pos_image_user_grey_night;
3787 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3788 m_cTideBitmap = m_bmTideNight;
3789 m_cCurrentBitmap = m_bmCurrentNight;
3792 m_pos_image_red = &m_os_image_red_day;
3793 m_pos_image_grey = &m_os_image_grey_day;
3794 m_pos_image_yellow = &m_os_image_yellow_day;
3795 m_pos_image_user = m_pos_image_user_day;
3796 m_pos_image_user_grey = m_pos_image_user_grey_day;
3797 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3798 m_cTideBitmap = m_bmTideDay;
3799 m_cCurrentBitmap = m_bmCurrentDay;
3803 CreateDepthUnitEmbossMaps(cs);
3804 CreateOZEmbossMapData(cs);
3807 m_fog_color = wxColor(
3811 case GLOBAL_COLOR_SCHEME_DUSK:
3814 case GLOBAL_COLOR_SCHEME_NIGHT:
3820 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3821 m_fog_color.Blue() * dim);
3825 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3826 SetBackgroundColour( wxColour(0,0,0) );
3828 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3831 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3833 SetBackgroundColour( wxNullColour );
3840 m_Piano->SetColorScheme(cs);
3842 m_Compass->SetColorScheme(cs);
3844 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3846 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3848 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3849 if (m_notification_button) {
3850 m_notification_button->SetColorScheme(cs);
3854 if (g_bopengl && m_glcc) {
3855 m_glcc->SetColorScheme(cs);
3861 m_brepaint_piano =
true;
3868wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3869 wxImage img = Bitmap.ConvertToImage();
3870 int sx = img.GetWidth();
3871 int sy = img.GetHeight();
3873 wxImage new_img(img);
3875 for (
int i = 0; i < sx; i++) {
3876 for (
int j = 0; j < sy; j++) {
3877 if (!img.IsTransparent(i, j)) {
3878 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3879 (
unsigned char)(img.GetGreen(i, j) * factor),
3880 (
unsigned char)(img.GetBlue(i, j) * factor));
3885 wxBitmap ret = wxBitmap(new_img);
3890void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3893 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3895 if (!m_pBrightPopup) {
3898 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3902 m_pBrightPopup->SetSize(x, y);
3903 m_pBrightPopup->Move(120, 120);
3906 int bmpsx = m_pBrightPopup->GetSize().x;
3907 int bmpsy = m_pBrightPopup->GetSize().y;
3909 wxBitmap bmp(bmpsx, bmpsx);
3910 wxMemoryDC mdc(bmp);
3912 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3913 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3914 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3915 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3918 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3920 mdc.SetFont(*pfont);
3923 if (brightness == max)
3925 else if (brightness == min)
3928 val.Printf(
"%3d", brightness);
3930 mdc.DrawText(val, 0, 0);
3932 mdc.SelectObject(wxNullBitmap);
3934 m_pBrightPopup->SetBitmap(bmp);
3935 m_pBrightPopup->Show();
3936 m_pBrightPopup->Refresh();
3939void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3940 m_b_rot_hidef =
true;
3944void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3947 bool b_need_refresh =
false;
3949 wxSize win_size = GetSize() * m_displayScale;
3953 bool showAISRollover =
false;
3955 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3959 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3960 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3963 showAISRollover =
true;
3965 if (NULL == m_pAISRolloverWin) {
3967 m_pAISRolloverWin->IsActive(
false);
3968 b_need_refresh =
true;
3969 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3970 m_AISRollover_MMSI != FoundAIS_MMSI) {
3976 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3977 m_pAISRolloverWin->IsActive(
false);
3978 m_AISRollover_MMSI = 0;
3983 m_AISRollover_MMSI = FoundAIS_MMSI;
3985 if (!m_pAISRolloverWin->IsActive()) {
3986 wxString s = ptarget->GetRolloverString();
3987 m_pAISRolloverWin->SetString(s);
3989 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3990 AIS_ROLLOVER, win_size);
3991 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3992 m_pAISRolloverWin->IsActive(
true);
3993 b_need_refresh =
true;
3997 m_AISRollover_MMSI = 0;
3998 showAISRollover =
false;
4003 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
4004 m_pAISRolloverWin->IsActive(
false);
4005 m_AISRollover_MMSI = 0;
4006 b_need_refresh =
true;
4011 bool showRouteRollover =
false;
4013 if (NULL == m_pRolloverRouteSeg) {
4017 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4018 SelectableItemList SelList =
pSelect->FindSelectionList(
4020 auto node = SelList.begin();
4021 while (node != SelList.end()) {
4026 if (pr && pr->IsVisible()) {
4027 m_pRolloverRouteSeg = pFindSel;
4028 showRouteRollover =
true;
4030 if (NULL == m_pRouteRolloverWin) {
4032 m_pRouteRolloverWin->IsActive(
false);
4035 if (!m_pRouteRolloverWin->IsActive()) {
4043 DistanceBearingMercator(
4044 segShow_point_b->m_lat, segShow_point_b->m_lon,
4045 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4047 if (!pr->m_bIsInLayer)
4048 s.Append(_(
"Route") +
": ");
4050 s.Append(_(
"Layer Route: "));
4052 if (pr->m_RouteNameString.IsEmpty())
4053 s.Append(_(
"(unnamed)"));
4055 s.Append(pr->m_RouteNameString);
4060 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4061 << segShow_point_b->GetName() <<
"\n";
4064 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4065 (
int)floor(brg + 0.5), 0x00B0);
4068 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4070 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4072 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4074 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4075 (
int)floor(varBrg + 0.5), 0x00B0);
4083 double shiptoEndLeg = 0.;
4084 bool validActive =
false;
4085 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4088 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4089 auto node = pr->pRoutePointList->begin();
4091 float dist_to_endleg = 0;
4094 for (++node; node != pr->pRoutePointList->end(); ++node) {
4101 if (prp->IsSame(segShow_point_a))
break;
4109 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4112 ->GetCurrentRngToActivePoint();
4121 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4126 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4127 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4129 << wxString(ttg_sec > SECONDS_PER_DAY
4130 ? ttg_span.Format(_(
"%Dd %H:%M"))
4131 : ttg_span.Format(_(
"%H:%M")));
4132 wxDateTime dtnow, eta;
4133 eta = dtnow.SetToCurrent().Add(ttg_span);
4134 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4135 << eta.Format(
" %d %H:%M");
4139 m_pRouteRolloverWin->SetString(s);
4141 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4142 LEG_ROLLOVER, win_size);
4143 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4144 m_pRouteRolloverWin->IsActive(
true);
4145 b_need_refresh =
true;
4146 showRouteRollover =
true;
4155 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4157 m_pRolloverRouteSeg))
4158 showRouteRollover =
false;
4159 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4160 showRouteRollover =
false;
4162 showRouteRollover =
true;
4166 if (m_routeState) showRouteRollover =
false;
4169 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4170 showRouteRollover =
false;
4172 if (m_pRouteRolloverWin &&
4173 !showRouteRollover) {
4174 m_pRouteRolloverWin->IsActive(
false);
4175 m_pRolloverRouteSeg = NULL;
4176 m_pRouteRolloverWin->Destroy();
4177 m_pRouteRolloverWin = NULL;
4178 b_need_refresh =
true;
4179 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4180 m_pRouteRolloverWin->IsActive(
true);
4181 b_need_refresh =
true;
4186 bool showTrackRollover =
false;
4188 if (NULL == m_pRolloverTrackSeg) {
4192 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4193 SelectableItemList SelList =
pSelect->FindSelectionList(
4196 auto node = SelList.begin();
4197 while (node != SelList.end()) {
4202 if (pt && pt->IsVisible()) {
4203 m_pRolloverTrackSeg = pFindSel;
4204 showTrackRollover =
true;
4206 if (NULL == m_pTrackRolloverWin) {
4208 m_pTrackRolloverWin->IsActive(
false);
4211 if (!m_pTrackRolloverWin->IsActive()) {
4219 DistanceBearingMercator(
4220 segShow_point_b->m_lat, segShow_point_b->m_lon,
4221 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4223 if (!pt->m_bIsInLayer)
4224 s.Append(_(
"Track") +
": ");
4226 s.Append(_(
"Layer Track: "));
4228 if (pt->GetName().IsEmpty())
4229 s.Append(_(
"(unnamed)"));
4231 s.Append(pt->GetName());
4232 double tlenght = pt->Length();
4234 if (pt->GetLastPoint()->GetTimeString() &&
4235 pt->GetPoint(0)->GetTimeString()) {
4236 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4237 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4238 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4239 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4240 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4241 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4242 << getUsrSpeedUnit();
4243 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4244 : ttime.Format(
" %H:%M"));
4248 if (g_bShowTrackPointTime &&
4249 strlen(segShow_point_b->GetTimeString())) {
4250 wxString stamp = segShow_point_b->GetTimeString();
4251 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4252 if (timestamp.IsValid()) {
4256 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4258 s <<
"\n" << _(
"Segment Created: ") << stamp;
4263 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4268 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4270 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4272 top_frame::Get()->GetMag(brg, latAverage, lonAverage);
4274 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4280 if (segShow_point_a->GetTimeString() &&
4281 segShow_point_b->GetTimeString()) {
4282 wxDateTime apoint = segShow_point_a->GetCreateTime();
4283 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4284 if (apoint.IsValid() && bpoint.IsValid()) {
4285 double segmentSpeed = toUsrSpeed(
4286 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4287 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4288 << getUsrSpeedUnit();
4292 m_pTrackRolloverWin->SetString(s);
4294 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4295 LEG_ROLLOVER, win_size);
4296 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4297 m_pTrackRolloverWin->IsActive(
true);
4298 b_need_refresh =
true;
4299 showTrackRollover =
true;
4308 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4310 m_pRolloverTrackSeg))
4311 showTrackRollover =
false;
4312 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4313 showTrackRollover =
false;
4315 showTrackRollover =
true;
4319 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4320 showTrackRollover =
false;
4323 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4324 showTrackRollover =
false;
4330 if (m_pTrackRolloverWin &&
4331 !showTrackRollover) {
4332 m_pTrackRolloverWin->IsActive(
false);
4333 m_pRolloverTrackSeg = NULL;
4334 m_pTrackRolloverWin->Destroy();
4335 m_pTrackRolloverWin = NULL;
4336 b_need_refresh =
true;
4337 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4338 m_pTrackRolloverWin->IsActive(
true);
4339 b_need_refresh =
true;
4342 if (b_need_refresh) Refresh();
4345void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4346 if ((GetShowENCLights() || m_bsectors_shown) &&
4347 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4348 extendedSectorLegs)) {
4349 if (!m_bsectors_shown) {
4351 m_bsectors_shown =
true;
4354 if (m_bsectors_shown) {
4356 m_bsectors_shown =
false;
4364#if defined(__WXGTK__) || defined(__WXQT__)
4369 double cursor_lat, cursor_lon;
4372 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4373 while (cursor_lon < -180.) cursor_lon += 360.;
4375 while (cursor_lon > 180.) cursor_lon -= 360.;
4377 SetCursorStatus(cursor_lat, cursor_lon);
4383void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4384 if (!top_frame::Get()->GetFrameStatusBar())
return;
4388 s1 += toSDMM(1, cursor_lat);
4390 s1 += toSDMM(2, cursor_lon);
4392 if (STAT_FIELD_CURSOR_LL >= 0)
4393 top_frame::Get()->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4395 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4400 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4401 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4402 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4404 wxString s = st + sm;
4417 if (g_bShowLiveETA) {
4420 float boatSpeedDefault = g_defaultBoatSpeed;
4425 if (!std::isnan(
gSog)) {
4427 if (boatSpeed < 0.5) {
4430 realTimeETA = dist / boatSpeed * 60;
4439 s << minutesToHoursDays(realTimeETA);
4444 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4445 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4447 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4452 top_frame::Get()->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4460wxString minutesToHoursDays(
float timeInMinutes) {
4463 if (timeInMinutes == 0) {
4468 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4469 s << wxString::Format(
"%d", (
int)timeInMinutes);
4474 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4477 hours = (int)timeInMinutes / 60;
4478 min = (int)timeInMinutes % 60;
4481 s << wxString::Format(
"%d", hours);
4484 s << wxString::Format(
"%d", hours);
4486 s << wxString::Format(
"%d", min);
4493 else if (timeInMinutes > 24 * 60) {
4496 days = (int)(timeInMinutes / 60) / 24;
4497 hours = (int)(timeInMinutes / 60) % 24;
4500 s << wxString::Format(
"%d", days);
4503 s << wxString::Format(
"%d", days);
4505 s << wxString::Format(
"%d", hours);
4517void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4525 wxPoint2DDouble *r) {
4530 double rlon, wxPoint2DDouble *r) {
4541 if (!g_bopengl && m_singleChart &&
4542 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4543 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4544 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4545 (m_singleChart->GetChartProjectionType() !=
4546 PROJECTION_TRANSVERSE_MERCATOR) &&
4547 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4548 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4549 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4563 Cur_BSB_Ch->SetVPRasterParms(vp);
4564 double rpixxd, rpixyd;
4565 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4591 if (std::isnan(p.m_x)) {
4592 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4596 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4597 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4599 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4618 if (!g_bopengl && m_singleChart &&
4619 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4620 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4621 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4622 (m_singleChart->GetChartProjectionType() !=
4623 PROJECTION_TRANSVERSE_MERCATOR) &&
4624 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4625 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4626 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4637 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4640 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4645 else if (slon > 180.)
4656 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4662 DoZoomCanvas(factor,
false);
4663 extendedSectorLegs.clear();
4668 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4671 if (StartTimedMovement(stoptimer)) {
4673 m_zoom_factor = factor;
4678 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4680 DoZoomCanvas(factor, can_zoom_to_cursor);
4683 extendedSectorLegs.clear();
4686void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4689 if (!m_pCurrentStack)
return;
4695 if (m_bzooming)
return;
4704 double proposed_scale_onscreen =
4707 bool b_do_zoom =
false;
4716 if (!VPoint.b_quilt) {
4719 if (!m_disable_adjust_on_zoom) {
4720 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4721 if (new_db_index >= 0)
4722 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4726 int current_ref_stack_index = -1;
4727 if (m_pCurrentStack->nEntry) {
4729 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4730 m_pQuilt->SetReferenceChart(trial_index);
4731 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4732 if (new_db_index >= 0)
4733 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4737 if (m_pCurrentStack)
4738 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4749 double min_allowed_scale =
4752 if (proposed_scale_onscreen < min_allowed_scale) {
4757 proposed_scale_onscreen = min_allowed_scale;
4761 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4764 }
else if (factor < 1) {
4769 bool b_smallest =
false;
4771 if (!VPoint.b_quilt) {
4776 LLBBox viewbox = VPoint.GetBBox();
4778 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4779 double max_allowed_scale;
4793 if (proposed_scale_onscreen > max_allowed_scale) {
4795 proposed_scale_onscreen = max_allowed_scale;
4800 if (!m_disable_adjust_on_zoom) {
4802 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4803 if (new_db_index >= 0)
4804 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4806 if (m_pCurrentStack)
4807 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4810 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4812 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4813 proposed_scale_onscreen =
4814 wxMin(proposed_scale_onscreen,
4820 m_absolute_min_scale_ppm)
4821 proposed_scale_onscreen =
4830 bool b_allow_ztc =
true;
4831 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4832 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4834 double brg, distance;
4835 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4838 meters_to_shift = distance * 1852;
4846 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4849 if (m_bFollow) DoCanvasUpdate();
4856void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4858 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4862void ChartCanvas::RotateCanvas(
double dir) {
4866 if (StartTimedMovement()) {
4868 m_rotation_speed = dir * 60;
4871 double speed = dir * 10;
4872 if (m_modkeys == wxMOD_ALT) speed /= 20;
4873 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4877void ChartCanvas::DoRotateCanvas(
double rotation) {
4878 while (rotation < 0) rotation += 2 * PI;
4879 while (rotation > 2 * PI) rotation -= 2 * PI;
4881 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4883 SetVPRotation(rotation);
4884 top_frame::Get()->UpdateRotationState(VPoint.
rotation);
4887void ChartCanvas::DoTiltCanvas(
double tilt) {
4888 while (tilt < 0) tilt = 0;
4889 while (tilt > .95) tilt = .95;
4891 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4897void ChartCanvas::TogglebFollow() {
4904void ChartCanvas::ClearbFollow() {
4907 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4909 UpdateFollowButtonState();
4913 top_frame::Get()->SetChartUpdatePeriod();
4916void ChartCanvas::SetbFollow() {
4919 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4920 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4928 p.m_x += m_OSoffsetx;
4929 p.m_y -= m_OSoffsety;
4938 top_frame::Get()->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4939 UpdateFollowButtonState();
4941 if (!g_bSmoothRecenter) {
4945 top_frame::Get()->SetChartUpdatePeriod();
4948void ChartCanvas::UpdateFollowButtonState() {
4951 m_muiBar->SetFollowButtonState(0);
4954 m_muiBar->SetFollowButtonState(2);
4956 m_muiBar->SetFollowButtonState(1);
4962 androidSetFollowTool(0);
4965 androidSetFollowTool(2);
4967 androidSetFollowTool(1);
4974 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4975 if (pic->m_enabled && pic->m_init_state) {
4976 switch (pic->m_api_version) {
4979 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4990void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4991 if (g_bSmoothRecenter && !m_routeState) {
4992 if (StartSmoothJump(lat, lon, scale_ppm))
4996 double gcDist, gcBearingEnd;
4997 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4999 gcBearingEnd += 180;
5000 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
5003 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
5004 double new_lat = lat + (lat_offset / (1852 * 60));
5005 double new_lon = lon + (lon_offset / (1852 * 60));
5008 StartSmoothJump(lat, lon, scale_ppm);
5013 if (lon > 180.0) lon -= 360.0;
5019 if (!GetQuiltMode()) {
5021 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
5022 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
5026 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5027 AdjustQuiltRefChart();
5034 UpdateFollowButtonState();
5042bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5047 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5048 double distance_pixels = gcDist *
GetVPScale();
5049 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5055 m_startLat = m_vLat;
5056 m_startLon = m_vLon;
5061 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5062 m_endScale = scale_ppm;
5065 m_animationDuration = 600;
5066 m_animationStart = wxGetLocalTimeMillis();
5073 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5074 m_animationActive =
true;
5079void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5081 wxLongLong now = wxGetLocalTimeMillis();
5082 double elapsed = (now - m_animationStart).ToDouble();
5083 double t = elapsed / m_animationDuration.ToDouble();
5084 if (t > 1.0) t = 1.0;
5087 double e = easeOutCubic(t);
5090 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5091 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5092 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5097 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5103 m_animationActive =
false;
5104 UpdateFollowButtonState();
5113 extendedSectorLegs.clear();
5122 if (iters++ > 5)
return false;
5123 if (!std::isnan(dlat))
break;
5126 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5132 else if (dlat < -90)
5135 if (dlon > 360.) dlon -= 360.;
5136 if (dlon < -360.) dlon += 360.;
5151 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5155 if (VPoint.b_quilt) {
5156 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5157 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5161 double tweak_scale_ppm =
5167 if (new_ref_dbIndex == -1) {
5168#pragma GCC diagnostic push
5169#pragma GCC diagnostic ignored "-Warray-bounds"
5176 int trial_index = -1;
5177 if (m_pCurrentStack->nEntry) {
5179 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5182 if (trial_index < 0) {
5183 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5184 if (full_screen_array.size())
5185 trial_index = full_screen_array[full_screen_array.size() - 1];
5188 if (trial_index >= 0) {
5189 m_pQuilt->SetReferenceChart(trial_index);
5194#pragma GCC diagnostic pop
5201 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5203 double offset_angle = atan2(offy, offx);
5204 double offset_distance = sqrt((offy * offy) + (offx * offx));
5205 double chart_angle = GetVPRotation();
5206 double target_angle = chart_angle - offset_angle;
5207 double d_east_mod = offset_distance * cos(target_angle);
5208 double d_north_mod = offset_distance * sin(target_angle);
5213 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5214 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5216 UpdateFollowButtonState();
5222 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5227bool ChartCanvas::IsOwnshipOnScreen() {
5230 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5231 ((r.y > 0) && r.y < GetCanvasHeight()))
5237void ChartCanvas::ReloadVP(
bool b_adjust) {
5238 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5240 LoadVP(VPoint, b_adjust);
5243void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5245 if (g_bopengl && m_glcc) {
5246 m_glcc->Invalidate();
5247 if (m_glcc->GetSize() != GetSize()) {
5248 m_glcc->SetSize(GetSize());
5253 m_cache_vp.Invalidate();
5254 m_bm_cache_vp.Invalidate();
5257 VPoint.Invalidate();
5259 if (m_pQuilt) m_pQuilt->Invalidate();
5268 vp.m_projection_type, b_adjust);
5271void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5272 m_pQuilt->SetReferenceChart(dbIndex);
5273 VPoint.Invalidate();
5274 m_pQuilt->Invalidate();
5277double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5279 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5286int ChartCanvas::AdjustQuiltRefChart() {
5291 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5293 double min_ref_scale =
5294 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5295 double max_ref_scale =
5296 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5299 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5300 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5301 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5303 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5306 int target_stack_index = wxNOT_FOUND;
5308 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5309 if (index == m_pQuilt->GetRefChartdbIndex()) {
5310 target_stack_index = il;
5315 if (wxNOT_FOUND == target_stack_index)
5316 target_stack_index = 0;
5318 int ref_family = pc->GetChartFamily();
5319 int extended_array_count =
5320 m_pQuilt->GetExtendedStackIndexArray().size();
5321 while ((!brender_ok) &&
5322 ((
int)target_stack_index < (extended_array_count - 1))) {
5323 target_stack_index++;
5325 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5327 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5328 IsChartQuiltableRef(test_db_index)) {
5331 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5333 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5340 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5341 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5342 IsChartQuiltableRef(new_db_index)) {
5343 m_pQuilt->SetReferenceChart(new_db_index);
5346 ret = m_pQuilt->GetRefChartdbIndex();
5348 ret = m_pQuilt->GetRefChartdbIndex();
5351 ret = m_pQuilt->GetRefChartdbIndex();
5360void ChartCanvas::UpdateCanvasOnGroupChange() {
5361 delete m_pCurrentStack;
5373bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5374 double latNE,
double lonNE) {
5376 double latc = (latSW + latNE) / 2.0;
5377 double lonc = (lonSW + lonNE) / 2.0;
5380 double ne_easting, ne_northing;
5381 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5383 double sw_easting, sw_northing;
5384 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5386 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5393 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5396bool ChartCanvas::SetVPProjection(
int projection) {
5402 double prev_true_scale_ppm = m_true_scale_ppm;
5407 m_absolute_min_scale_ppm));
5415bool ChartCanvas::SetVPRotation(
double angle) {
5417 VPoint.
skew, angle);
5420 double skew,
double rotation,
int projection,
5421 bool b_adjust,
bool b_refresh) {
5427 if (VPoint.IsValid()) {
5428 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5429 (fabs(VPoint.
skew - skew) < 1e-9) &&
5430 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5431 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5432 (VPoint.m_projection_type == projection ||
5433 projection == PROJECTION_UNKNOWN))
5436 if (VPoint.m_projection_type != projection)
5437 VPoint.InvalidateTransformCache();
5447 if (projection != PROJECTION_UNKNOWN)
5448 VPoint.SetProjectionType(projection);
5449 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5450 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5453 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5454 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5455 if (VPoint.
clat > 89.5)
5457 else if (VPoint.
clat < -89.5)
5458 VPoint.
clat = -89.5;
5463 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5464 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5476 bool bwasValid = VPoint.IsValid();
5481 m_cache_vp.Invalidate();
5486 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5490 if (top_frame::Get()->GetCanvasIndexUnderMouse() == m_canvasIndex) {
5491 int mouseX = mouse_x;
5492 int mouseY = mouse_y;
5493 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5495 double lat_mouse, lon_mouse;
5503 if (!VPoint.b_quilt && m_singleChart) {
5508 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5512 if ((!m_cache_vp.IsValid()) ||
5517 wxPoint cp_last, cp_this;
5521 if (cp_last != cp_this) {
5527 if (m_pCurrentStack) {
5529 int current_db_index;
5531 m_pCurrentStack->GetCurrentEntrydbIndex();
5533 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5535 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5538 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5542 if (VPoint.b_quilt) {
5546 m_pQuilt->InvalidateAllQuiltPatchs();
5550 if (!m_pCurrentStack)
return false;
5552 int current_db_index;
5554 m_pCurrentStack->GetCurrentEntrydbIndex();
5556 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5557 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5560 int current_ref_stack_index = -1;
5561 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5562 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5563 current_ref_stack_index = i;
5566 if (g_bFullScreenQuilt) {
5567 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5571 bool b_needNewRef =
false;
5574 if ((-1 == current_ref_stack_index) &&
5575 (m_pQuilt->GetRefChartdbIndex() >= 0))
5576 b_needNewRef =
true;
5583 bool renderable =
true;
5585 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5586 if (referenceChart) {
5587 double chartMaxScale = referenceChart->GetNormalScaleMax(
5589 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5591 if (!renderable) b_needNewRef =
true;
5594 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5596 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5597 int target_scale = cte_ref.GetScale();
5598 int target_type = cte_ref.GetChartType();
5599 int candidate_stack_index;
5606 candidate_stack_index = 0;
5607 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5609 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5610 int candidate_scale = cte_candidate.GetScale();
5611 int candidate_type = cte_candidate.GetChartType();
5613 if ((candidate_scale >= target_scale) &&
5614 (candidate_type == target_type)) {
5615 bool renderable =
true;
5617 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5618 if (tentative_referenceChart) {
5619 double chartMaxScale =
5620 tentative_referenceChart->GetNormalScaleMax(
5622 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5625 if (renderable)
break;
5628 candidate_stack_index++;
5633 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5634 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5635 while (candidate_stack_index >= 0) {
5636 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5640 int candidate_scale = cte_candidate.GetScale();
5641 int candidate_type = cte_candidate.GetChartType();
5643 if ((candidate_scale <= target_scale) &&
5644 (candidate_type == target_type))
5647 candidate_stack_index--;
5652 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5653 (candidate_stack_index < 0))
5654 candidate_stack_index = 0;
5656 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5658 m_pQuilt->SetReferenceChart(new_ref_index);
5664 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5669 bool renderable =
true;
5671 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5672 if (referenceChart) {
5673 double chartMaxScale = referenceChart->GetNormalScaleMax(
5675 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5676 proj =
ChartData->GetDBChartProj(ref_db_index);
5678 proj = PROJECTION_MERCATOR;
5680 VPoint.b_MercatorProjectionOverride =
5681 (m_pQuilt->GetnCharts() == 0 || !renderable);
5683 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5685 VPoint.SetProjectionType(proj);
5690 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5695 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5715 m_pQuilt->Invalidate();
5732 if (b_refresh) Refresh(
false);
5739 }
else if (!g_bopengl) {
5740 OcpnProjType projection = PROJECTION_UNKNOWN;
5743 projection = m_singleChart->GetChartProjectionType();
5744 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5745 VPoint.SetProjectionType(projection);
5749 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5750 m_cache_vp.Invalidate();
5754 UpdateCanvasControlBar();
5758 if (VPoint.GetBBox().GetValid()) {
5761 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5770 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5773 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5780 wxPoint2DDouble r, r1;
5782 double delta_check =
5786 double check_point = wxMin(89., VPoint.
clat);
5788 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5791 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5792 VPoint.
clon, 0, &rhumbDist);
5797 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5798 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5800 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5804 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5810 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5812 if (m_true_scale_ppm)
5813 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5818 double round_factor = 1000.;
5822 round_factor = 100.;
5824 round_factor = 1000.;
5827 double retina_coef = 1;
5831 retina_coef = GetContentScaleFactor();
5842 double true_scale_display =
5843 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5848 if (m_displayed_scale_factor > 10.0)
5849 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5850 m_displayed_scale_factor);
5851 else if (m_displayed_scale_factor > 1.0)
5852 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5853 m_displayed_scale_factor);
5854 else if (m_displayed_scale_factor > 0.1) {
5855 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5856 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5857 }
else if (m_displayed_scale_factor > 0.01) {
5858 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5859 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5862 "%s %4.0f (---)", _(
"Scale"),
5863 true_scale_display);
5866 m_scaleValue = true_scale_display;
5868 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5870 if (m_bShowScaleInStatusBar && top_frame::Get()->GetStatusBar() &&
5871 (top_frame::Get()->GetStatusBar()->GetFieldsCount() >
5872 STAT_FIELD_SCALE)) {
5874 bool b_noshow =
false;
5878 wxClientDC dc(top_frame::Get()->GetStatusBar());
5880 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5881 dc.SetFont(*templateFont);
5882 dc.GetTextExtent(text, &w, &h);
5887 top_frame::Get()->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE,
5889 if (w && w > rect.width) {
5890 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5894 dc.GetTextExtent(text, &w, &h);
5896 if (w && w > rect.width) {
5902 if (!b_noshow) top_frame::Get()->SetStatusText(text, STAT_FIELD_SCALE);
5907 m_vLat = VPoint.
clat;
5908 m_vLon = VPoint.
clon;
5922static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5926static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5927 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5929wxColour ChartCanvas::PredColor() {
5932 if (SHIP_NORMAL == m_ownship_state)
5933 return GetGlobalColor(
"URED");
5935 else if (SHIP_LOWACCURACY == m_ownship_state)
5936 return GetGlobalColor(
"YELO1");
5938 return GetGlobalColor(
"NODTA");
5941wxColour ChartCanvas::ShipColor() {
5945 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5947 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5949 return GetGlobalColor(
"URED");
5952void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5953 wxPoint2DDouble lShipMidPoint) {
5954 dc.SetPen(wxPen(PredColor(), 2));
5956 if (SHIP_NORMAL == m_ownship_state)
5957 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5959 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5961 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5962 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5964 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5966 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5967 lShipMidPoint.m_y + 12);
5970void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5971 wxPoint GPSOffsetPixels,
5972 wxPoint2DDouble lGPSPoint) {
5977 float ref_dim = m_display_size_mm / 24;
5978 ref_dim = wxMin(ref_dim, 12);
5979 ref_dim = wxMax(ref_dim, 6);
5982 cPred.Set(g_cog_predictor_color);
5983 if (cPred == wxNullColour) cPred = PredColor();
5990 double nominal_line_width_pix = wxMax(
5992 floor(m_pix_per_mm / 2));
5996 if (nominal_line_width_pix > g_cog_predictor_width)
5997 g_cog_predictor_width = nominal_line_width_pix;
6000 wxPoint lPredPoint, lHeadPoint;
6002 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6003 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6005 double pred_lat, pred_lon;
6006 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
6007 &pred_lat, &pred_lon);
6018 float ndelta_pix = 10.;
6019 double hdg_pred_lat, hdg_pred_lon;
6020 bool b_render_hdt =
false;
6021 if (!std::isnan(
gHdt)) {
6023 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
6026 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
6027 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
6028 if (dist > ndelta_pix ) {
6029 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
6030 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
6035 wxPoint lShipMidPoint;
6036 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
6037 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
6038 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
6039 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6041 if (lpp >= img_height / 2) {
6042 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6043 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6044 !std::isnan(
gSog)) {
6046 float dash_length = ref_dim;
6047 wxDash dash_long[2];
6049 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6050 g_cog_predictor_width);
6051 dash_long[1] = dash_long[0] / 2.0;
6055 if (dash_length > 250.) {
6056 dash_long[0] = 250. / g_cog_predictor_width;
6057 dash_long[1] = dash_long[0] / 2;
6060 wxPen ppPen2(cPred, g_cog_predictor_width,
6061 (wxPenStyle)g_cog_predictor_style);
6062 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6063 ppPen2.SetDashes(2, dash_long);
6066 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6067 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6069 if (g_cog_predictor_width > 1) {
6070 float line_width = g_cog_predictor_width / 3.;
6072 wxDash dash_long3[2];
6073 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6074 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6076 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6077 (wxPenStyle)g_cog_predictor_style);
6078 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6079 ppPen3.SetDashes(2, dash_long3);
6081 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6082 lGPSPoint.m_y + GPSOffsetPixels.y,
6083 lPredPoint.x + GPSOffsetPixels.x,
6084 lPredPoint.y + GPSOffsetPixels.y);
6087 if (g_cog_predictor_endmarker) {
6089 double png_pred_icon_scale_factor = .4;
6090 if (g_ShipScaleFactorExp > 1.0)
6091 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6092 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6096 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6097 (
float)(lPredPoint.x - lShipMidPoint.x));
6098 cog_rad += (float)PI;
6100 for (
int i = 0; i < 4; i++) {
6102 double pxa = (double)(s_png_pred_icon[j]);
6103 double pya = (double)(s_png_pred_icon[j + 1]);
6105 pya *= png_pred_icon_scale_factor;
6106 pxa *= png_pred_icon_scale_factor;
6108 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6109 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6111 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6112 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6116 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6119 dc.SetBrush(wxBrush(cPred));
6121 dc.StrokePolygon(4, icon);
6128 float hdt_dash_length = ref_dim * 0.4;
6130 cPred.Set(g_ownship_HDTpredictor_color);
6131 if (cPred == wxNullColour) cPred = PredColor();
6133 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6134 : g_cog_predictor_width * 0.8);
6135 wxDash dash_short[2];
6137 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6140 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6143 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6144 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6145 ppPen2.SetDashes(2, dash_short);
6149 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6150 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6152 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6154 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6156 if (g_ownship_HDTpredictor_endmarker) {
6157 double nominal_circle_size_pixels = wxMax(
6158 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6161 if (g_ShipScaleFactorExp > 1.0)
6162 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6164 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6165 lHeadPoint.y + GPSOffsetPixels.y,
6166 nominal_circle_size_pixels / 2);
6171 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6172 double factor = 1.00;
6173 if (g_pNavAidRadarRingsStepUnits == 1)
6175 else if (g_pNavAidRadarRingsStepUnits == 2) {
6176 if (std::isnan(
gSog))
6181 factor *= g_fNavAidRadarRingsStep;
6185 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6188 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6189 pow((
double)(lGPSPoint.m_y - r.y), 2));
6190 int pix_radius = (int)lpp;
6192 wxColor rangeringcolour =
6193 user_colors::GetDimColor(g_colourOwnshipRangeRingsColour);
6195 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6198 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6200 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6201 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6206void ChartCanvas::ResetGlGridFont() { GetglCanvas()->ResetGridFont(); }
6207bool ChartCanvas::CanAccelerateGlPanning() {
6208 return GetglCanvas()->CanAcceleratePanning();
6210void ChartCanvas::SetupGlCompression() { GetglCanvas()->SetupCompression(); }
6213void ChartCanvas::ResetGlGridFont() {}
6214bool ChartCanvas::CanAccelerateGlPanning() {
return false; }
6215void ChartCanvas::SetupGlCompression() {}
6218void ChartCanvas::ComputeShipScaleFactor(
6219 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6220 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6221 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6222 float screenResolution = m_pix_per_mm;
6225 double ship_bow_lat, ship_bow_lon;
6226 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6227 &ship_bow_lat, &ship_bow_lon);
6228 wxPoint lShipBowPoint;
6229 wxPoint2DDouble b_point =
6233 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6234 powf((
float)(b_point.m_y - a_point.m_y), 2));
6237 float shipLength_mm = shipLength_px / screenResolution;
6240 float ownship_min_mm = g_n_ownship_min_mm;
6241 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6244 float hdt_ant = icon_hdt + 180.;
6245 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6246 float dx = g_n_gps_antenna_offset_x / 1852.;
6247 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6255 if (shipLength_mm < ownship_min_mm) {
6256 dy /= shipLength_mm / ownship_min_mm;
6257 dx /= shipLength_mm / ownship_min_mm;
6260 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6262 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6263 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6269 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6270 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6272 float scale_factor = shipLength_px / ownShipLength;
6275 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6278 scale_factor = wxMax(scale_factor, scale_factor_min);
6280 scale_factor_y = scale_factor;
6281 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6282 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6285void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6286 if (!GetVP().IsValid())
return;
6288 wxPoint GPSOffsetPixels(0, 0);
6289 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6292 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6293 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6297 lShipMidPoint = lGPSPoint;
6301 float icon_hdt = pCog;
6302 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6305 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6309 double osd_head_lat, osd_head_lon;
6310 wxPoint osd_head_point;
6312 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6317 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6318 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6319 icon_rad += (float)PI;
6321 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6325 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6329 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6330 if (GetVP().chart_scale >
6333 ShipDrawLargeScale(dc, lShipMidPoint);
6339 if (m_pos_image_user)
6340 pos_image = m_pos_image_user->Copy();
6341 else if (SHIP_NORMAL == m_ownship_state)
6342 pos_image = m_pos_image_red->Copy();
6343 if (SHIP_LOWACCURACY == m_ownship_state)
6344 pos_image = m_pos_image_yellow->Copy();
6345 else if (SHIP_NORMAL != m_ownship_state)
6346 pos_image = m_pos_image_grey->Copy();
6349 if (m_pos_image_user) {
6350 pos_image = m_pos_image_user->Copy();
6352 if (SHIP_LOWACCURACY == m_ownship_state)
6353 pos_image = m_pos_image_user_yellow->Copy();
6354 else if (SHIP_NORMAL != m_ownship_state)
6355 pos_image = m_pos_image_user_grey->Copy();
6358 img_height = pos_image.GetHeight();
6360 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6361 g_OwnShipIconType > 0)
6363 int ownShipWidth = 22;
6364 int ownShipLength = 84;
6365 if (g_OwnShipIconType == 1) {
6366 ownShipWidth = pos_image.GetWidth();
6367 ownShipLength = pos_image.GetHeight();
6370 float scale_factor_x, scale_factor_y;
6371 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6372 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6373 scale_factor_x, scale_factor_y);
6375 if (g_OwnShipIconType == 1) {
6376 pos_image.Rescale(ownShipWidth * scale_factor_x,
6377 ownShipLength * scale_factor_y,
6378 wxIMAGE_QUALITY_HIGH);
6379 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6381 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6384 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6385 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6386 if (rot_image.GetAlpha(ip, jp) > 64)
6387 rot_image.SetAlpha(ip, jp, 255);
6389 wxBitmap os_bm(rot_image);
6391 int w = os_bm.GetWidth();
6392 int h = os_bm.GetHeight();
6395 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6396 lShipMidPoint.m_y - h / 2,
true);
6399 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6400 lShipMidPoint.m_y - h / 2);
6401 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6402 lShipMidPoint.m_y - h / 2 + h);
6405 else if (g_OwnShipIconType == 2) {
6406 wxPoint ownship_icon[10];
6408 for (
int i = 0; i < 10; i++) {
6410 float pxa = (float)(s_ownship_icon[j]);
6411 float pya = (float)(s_ownship_icon[j + 1]);
6412 pya *= scale_factor_y;
6413 pxa *= scale_factor_x;
6415 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6416 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6418 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6419 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6422 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6424 dc.SetBrush(wxBrush(ShipColor()));
6426 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6429 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6431 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6435 img_height = ownShipLength * scale_factor_y;
6439 if (m_pos_image_user) circle_rad = 1;
6441 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6442 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6443 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6446 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6448 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6451 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6452 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6453 if (rot_image.GetAlpha(ip, jp) > 64)
6454 rot_image.SetAlpha(ip, jp, 255);
6456 wxBitmap os_bm(rot_image);
6458 if (g_ShipScaleFactorExp > 1) {
6459 wxImage scaled_image = os_bm.ConvertToImage();
6460 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6462 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6463 scaled_image.GetHeight() * factor,
6464 wxIMAGE_QUALITY_HIGH));
6466 int w = os_bm.GetWidth();
6467 int h = os_bm.GetHeight();
6470 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6471 lShipMidPoint.m_y - h / 2,
true);
6475 if (m_pos_image_user) circle_rad = 1;
6477 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6478 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6479 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6482 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6483 lShipMidPoint.m_y - h / 2);
6484 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6485 lShipMidPoint.m_y - h / 2 + h);
6490 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6503void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6504 float &MinorSpacing) {
6509 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6510 {.000001f, 45.0f, 15.0f},
6511 {.0002f, 30.0f, 10.0f},
6512 {.0003f, 10.0f, 2.0f},
6513 {.0008f, 5.0f, 1.0f},
6514 {.001f, 2.0f, 30.0f / 60.0f},
6515 {.003f, 1.0f, 20.0f / 60.0f},
6516 {.006f, 0.5f, 10.0f / 60.0f},
6517 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6518 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6519 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6520 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6521 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6522 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6523 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6524 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6527 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6528 if (view_scale_ppm < lltab[tabi][0])
break;
6529 MajorSpacing = lltab[tabi][1];
6530 MinorSpacing = lltab[tabi][2];
6544wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6545 int deg = (int)fabs(latlon);
6546 float min = fabs((fabs(latlon) - deg) * 60.0);
6556 }
else if (latlon < 0.0) {
6568 if (spacing >= 1.0) {
6569 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6570 }
else if (spacing >= (1.0 / 60.0)) {
6571 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6573 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6590void ChartCanvas::GridDraw(
ocpnDC &dc) {
6591 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6593 double nlat, elon, slat, wlon;
6596 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6598 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6600 if (!m_pgridFont) SetupGridFont();
6601 dc.SetFont(*m_pgridFont);
6602 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6605 h = m_canvas_height;
6616 dlon = dlon + 360.0;
6619 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6622 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6625 while (lat < nlat) {
6628 CalcGridText(lat, gridlatMajor,
true);
6630 dc.
DrawLine(0, r.y, w, r.y,
false);
6631 dc.DrawText(st, 0, r.y);
6632 lat = lat + gridlatMajor;
6634 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6638 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6641 while (lat < nlat) {
6644 dc.
DrawLine(0, r.y, 10, r.y,
false);
6645 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6646 lat = lat + gridlatMinor;
6650 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6653 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6656 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6658 wxString st = CalcGridText(lon, gridlonMajor,
false);
6660 dc.
DrawLine(r.x, 0, r.x, h,
false);
6661 dc.DrawText(st, r.x, 0);
6662 lon = lon + gridlonMajor;
6667 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6671 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6673 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6676 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6677 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6678 lon = lon + gridlonMinor;
6685void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6687 double blat, blon, tlat, tlon;
6690 int x_origin = m_bDisplayGrid ? 60 : 20;
6691 int y_origin = m_canvas_height - 50;
6697 if (GetVP().chart_scale > 80000)
6701 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6702 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6707 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6708 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6712 double rotation = -VPoint.
rotation;
6714 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6716 int l1 = (y_origin - r.y) / count;
6718 for (
int i = 0; i < count; i++) {
6725 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6728 double blat, blon, tlat, tlon;
6735 int y_origin = m_canvas_height - chartbar_height - 5;
6739 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6746 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6751 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6752 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6756 float places = floor(logdist), rem = logdist - places;
6757 dist = pow(10, places);
6764 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6765 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6766 double rotation = -VPoint.
rotation;
6772 int l1 = r.x - x_origin;
6774 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6779 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6780 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6781 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6783 if (!m_pgridFont) SetupGridFont();
6784 dc.SetFont(*m_pgridFont);
6785 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6787 dc.GetTextExtent(s, &w, &h);
6793 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6797void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6802 double ra_max = 40.;
6804 wxPen pen_save = dc.GetPen();
6806 wxDateTime now = wxDateTime::Now();
6812 x0 = x1 = x + radius;
6817 while (angle < 360.) {
6818 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6821 if (angle > 360.) angle = 360.;
6823 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6831 x1 = (int)(x + cos(angle * PI / 180.) * r);
6832 y1 = (int)(y + sin(angle * PI / 180.) * r);
6842 dc.
DrawLine(x + radius, y, x1, y1);
6844 dc.SetPen(pen_save);
6847static bool bAnchorSoundPlaying =
false;
6849static void onAnchorSoundFinished(
void *ptr) {
6850 o_sound::g_anchorwatch_sound->UnLoad();
6851 bAnchorSoundPlaying =
false;
6854void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6855 using namespace o_sound;
6857 bool play_sound =
false;
6859 if (AnchorAlertOn1) {
6860 wxPoint TargetPoint;
6863 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6864 TargetPoint.y, 100);
6868 AnchorAlertOn1 =
false;
6871 if (AnchorAlertOn2) {
6872 wxPoint TargetPoint;
6875 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6876 TargetPoint.y, 100);
6880 AnchorAlertOn2 =
false;
6883 if (!bAnchorSoundPlaying) {
6884 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6885 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6886 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6887 if (g_anchorwatch_sound->IsOk()) {
6888 bAnchorSoundPlaying =
true;
6889 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6890 g_anchorwatch_sound->Play();
6896void ChartCanvas::UpdateShips() {
6899 wxClientDC dc(
this);
6902 if (!dc.IsOk() || dc.GetSize().x < 1 || dc.GetSize().y < 1)
return;
6904 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6905 if (!test_bitmap.IsOk())
return;
6907 wxMemoryDC temp_dc(test_bitmap);
6909 temp_dc.ResetBoundingBox();
6910 temp_dc.DestroyClippingRegion();
6911 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6922 ocpndc.CalcBoundingBox(px.x, px.y);
6927 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6928 temp_dc.MaxY() - temp_dc.MinY());
6930 wxRect own_ship_update_rect = ship_draw_rect;
6932 if (!own_ship_update_rect.IsEmpty()) {
6935 own_ship_update_rect.Union(ship_draw_last_rect);
6936 own_ship_update_rect.Inflate(2);
6939 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6941 ship_draw_last_rect = ship_draw_rect;
6943 temp_dc.SelectObject(wxNullBitmap);
6946void ChartCanvas::UpdateAlerts() {
6951 wxClientDC dc(
this);
6955 dc.GetSize(&sx, &sy);
6958 wxBitmap test_bitmap(sx, sy, -1);
6962 temp_dc.SelectObject(test_bitmap);
6964 temp_dc.ResetBoundingBox();
6965 temp_dc.DestroyClippingRegion();
6966 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6973 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6974 temp_dc.MaxX() - temp_dc.MinX(),
6975 temp_dc.MaxY() - temp_dc.MinY());
6977 if (!alert_rect.IsEmpty())
6978 alert_rect.Inflate(2);
6980 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6983 wxRect alert_update_rect = alert_draw_rect;
6984 alert_update_rect.Union(alert_rect);
6987 RefreshRect(alert_update_rect,
false);
6991 alert_draw_rect = alert_rect;
6993 temp_dc.SelectObject(wxNullBitmap);
6996void ChartCanvas::UpdateAIS() {
7002 wxClientDC dc(
this);
7006 dc.GetSize(&sx, &sy);
7014 if (
g_pAIS->GetTargetList().size() > 10) {
7015 ais_rect = wxRect(0, 0, sx, sy);
7018 wxBitmap test_bitmap(sx, sy, -1);
7022 temp_dc.SelectObject(test_bitmap);
7024 temp_dc.ResetBoundingBox();
7025 temp_dc.DestroyClippingRegion();
7026 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
7030 AISDraw(ocpndc, GetVP(),
this);
7031 AISDrawAreaNotices(ocpndc, GetVP(),
this);
7035 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
7036 temp_dc.MaxY() - temp_dc.MinY());
7038 if (!ais_rect.IsEmpty())
7039 ais_rect.Inflate(2);
7041 temp_dc.SelectObject(wxNullBitmap);
7044 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
7047 wxRect ais_update_rect = ais_draw_rect;
7048 ais_update_rect.Union(ais_rect);
7051 RefreshRect(ais_update_rect,
false);
7055 ais_draw_rect = ais_rect;
7058void ChartCanvas::ToggleCPAWarn() {
7059 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7065 g_bTCPA_Max =
false;
7069 if (STAT_FIELD_SCALE >= 4 && top_frame::Get()->GetStatusBar()) {
7070 top_frame::Get()->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7072 if (!g_AisFirstTimeUse) {
7073 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7074 _(
"CPA") +
" " + mess, 4, 4);
7079void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7081void ChartCanvas::OnSize(wxSizeEvent &event) {
7082 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7084 GetClientSize(&m_canvas_width, &m_canvas_height);
7088 m_displayScale = GetContentScaleFactor();
7092 m_canvas_width *= m_displayScale;
7093 m_canvas_height *= m_displayScale;
7106 m_absolute_min_scale_ppm =
7108 (1.2 * WGS84_semimajor_axis_meters * PI);
7111 top_frame::Get()->ProcessCanvasResize();
7121 SetMUIBarPosition();
7122 UpdateFollowButtonState();
7123 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7127 xr_margin = m_canvas_width * 95 / 100;
7128 xl_margin = m_canvas_width * 5 / 100;
7129 yt_margin = m_canvas_height * 5 / 100;
7130 yb_margin = m_canvas_height * 95 / 100;
7133 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7138 m_brepaint_piano =
true;
7141 m_dc_route.SelectObject(wxNullBitmap);
7144 m_dc_route.SelectObject(*proute_bm);
7158 m_glcc->OnSize(event);
7167void ChartCanvas::ProcessNewGUIScale() {
7175void ChartCanvas::CreateMUIBar() {
7176 if (g_useMUI && !m_muiBar) {
7177 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7178 m_muiBar->SetColorScheme(m_cs);
7179 m_muiBarHOSize = m_muiBar->m_size;
7187 SetMUIBarPosition();
7188 UpdateFollowButtonState();
7189 m_muiBar->UpdateDynamicValues();
7190 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7194void ChartCanvas::SetMUIBarPosition() {
7198 int pianoWidth = GetClientSize().x * 0.6f;
7203 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7204 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7206 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7207 m_muiBar->SetColorScheme(m_cs);
7211 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7212 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7214 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7215 m_muiBar->SetColorScheme(m_cs);
7219 m_muiBar->SetBestPosition();
7223void ChartCanvas::DestroyMuiBar() {
7230void ChartCanvas::ShowCompositeInfoWindow(
7231 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7233 if (NULL == m_pCIWin) {
7238 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7241 s = _(
"Composite of ");
7244 s1.Printf(
"%d ", n_charts);
7252 s1.Printf(_(
"Chart scale"));
7255 s2.Printf(
"1:%d\n",
scale);
7259 s1 = _(
"Zoom in for more information");
7263 int char_width = s1.Length();
7264 int char_height = 3;
7266 if (g_bChartBarEx) {
7269 for (
int i : index_vector) {
7271 wxString path = cte.GetFullSystemPath();
7275 char_width = wxMax(char_width, path.Length());
7276 if (j++ >= 9)
break;
7279 s +=
" .\n .\n .\n";
7288 m_pCIWin->SetString(s);
7290 m_pCIWin->FitToChars(char_width, char_height);
7293 p.x = x / GetContentScaleFactor();
7294 if ((p.x + m_pCIWin->GetWinSize().x) >
7295 (m_canvas_width / GetContentScaleFactor()))
7296 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7297 m_pCIWin->GetWinSize().x) /
7300 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7301 4 - m_pCIWin->GetWinSize().y;
7303 m_pCIWin->dbIndex = 0;
7304 m_pCIWin->chart_scale = 0;
7305 m_pCIWin->SetPosition(p);
7306 m_pCIWin->SetBitmap();
7307 m_pCIWin->Refresh();
7311 HideChartInfoWindow();
7315void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7317 if (NULL == m_pCIWin) {
7322 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7331 dbIndex, FULL_INIT);
7333 int char_width, char_height;
7334 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7335 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7337 m_pCIWin->SetString(s);
7338 m_pCIWin->FitToChars(char_width, char_height);
7341 p.x = x / GetContentScaleFactor();
7342 if ((p.x + m_pCIWin->GetWinSize().x) >
7343 (m_canvas_width / GetContentScaleFactor()))
7344 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7345 m_pCIWin->GetWinSize().x) /
7348 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7349 4 - m_pCIWin->GetWinSize().y;
7351 m_pCIWin->dbIndex = dbIndex;
7352 m_pCIWin->SetPosition(p);
7353 m_pCIWin->SetBitmap();
7354 m_pCIWin->Refresh();
7358 HideChartInfoWindow();
7362void ChartCanvas::HideChartInfoWindow() {
7365 m_pCIWin->Destroy();
7369 androidForceFullRepaint();
7374void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7375 wxMouseEvent ev(wxEVT_MOTION);
7378 ev.m_leftDown = mouse_leftisdown;
7380 wxEvtHandler *evthp = GetEventHandler();
7382 ::wxPostEvent(evthp, ev);
7385void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7386 if ((m_panx_target_final - m_panx_target_now) ||
7387 (m_pany_target_final - m_pany_target_now)) {
7388 DoTimedMovementTarget();
7393void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7395bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7397 if (m_disable_edge_pan)
return false;
7400 int pan_margin = m_canvas_width * margin / 100;
7401 int pan_timer_set = 200;
7402 double pan_delta = GetVP().
pix_width * delta / 100;
7406 if (x > m_canvas_width - pan_margin) {
7411 else if (x < pan_margin) {
7416 if (y < pan_margin) {
7421 else if (y > m_canvas_height - pan_margin) {
7430 wxMouseState state = ::wxGetMouseState();
7431#if wxCHECK_VERSION(3, 0, 0)
7432 if (!state.LeftIsDown())
7434 if (!state.LeftDown())
7439 if ((bft) && !pPanTimer->IsRunning()) {
7441 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7447 if ((!bft) && pPanTimer->IsRunning()) {
7457void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7458 bool setBeingEdited) {
7459 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7460 m_pRoutePointEditTarget = NULL;
7461 m_pFoundPoint = NULL;
7464 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7465 SelectableItemList SelList =
pSelect->FindSelectionList(
7475 bool brp_viz =
false;
7476 if (m_pEditRouteArray) {
7477 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7478 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7479 if (pr->IsVisible()) {
7485 brp_viz = frp->IsVisible();
7489 if (m_pEditRouteArray)
7491 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7492 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7495 m_bRouteEditing = setBeingEdited;
7498 frp->m_bRPIsBeingEdited = setBeingEdited;
7499 m_bMarkEditing = setBeingEdited;
7502 m_pRoutePointEditTarget = frp;
7503 m_pFoundPoint = pFind;
7508std::shared_ptr<HostApi121::PiPointContext>
7509ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7523 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7524 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7525 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7526 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7527 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7531 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7534 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7539 int FoundAIS_MMSI = 0;
7541 FoundAIS_MMSI = pFindAIS->GetUserData();
7544 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7545 seltype |= SELTYPE_AISTARGET;
7551 Route *SelectedRoute = NULL;
7557 Route *pSelectedActiveRoute = NULL;
7558 Route *pSelectedVizRoute = NULL;
7561 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7562 SelectableItemList SelList =
7563 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7571 bool brp_viz =
false;
7573 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7575 if (pr->IsVisible()) {
7580 if (!brp_viz && prp->IsShared())
7582 brp_viz = prp->IsVisible();
7585 brp_viz = prp->IsVisible();
7587 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7593 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7596 pSelectedActiveRoute = pr;
7597 pFoundActiveRoutePoint = prp;
7602 if (NULL == pSelectedVizRoute) {
7603 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7605 if (pr->IsVisible()) {
7606 pSelectedVizRoute = pr;
7607 pFoundVizRoutePoint = prp;
7613 delete proute_array;
7618 if (pFoundActiveRoutePoint) {
7619 FoundRoutePoint = pFoundActiveRoutePoint;
7620 SelectedRoute = pSelectedActiveRoute;
7621 }
else if (pFoundVizRoutePoint) {
7622 FoundRoutePoint = pFoundVizRoutePoint;
7623 SelectedRoute = pSelectedVizRoute;
7626 FoundRoutePoint = pFirstVizPoint;
7628 if (SelectedRoute) {
7629 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7630 }
else if (FoundRoutePoint) {
7631 seltype |= SELTYPE_MARKPOINT;
7636 if (m_pFoundRoutePoint) {
7640 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7641 RefreshRect(wp_rect,
true);
7650 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7651 SelectableItemList SelList =
7652 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7654 if (NULL == SelectedRoute)
7659 if (pr->IsVisible()) {
7666 if (SelectedRoute) {
7667 if (NULL == FoundRoutePoint)
7668 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7671 seltype |= SELTYPE_ROUTESEGMENT;
7675 if (pFindTrackSeg) {
7676 m_pSelectedTrack = NULL;
7677 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7678 SelectableItemList SelList =
7679 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7684 if (pt->IsVisible()) {
7685 m_pSelectedTrack = pt;
7689 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7692 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7695 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7696 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7697 rstruct->object_ident =
"";
7699 if (seltype == SELTYPE_AISTARGET) {
7700 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7702 val.Printf(
"%d", FoundAIS_MMSI);
7703 rstruct->object_ident = val.ToStdString();
7704 }
else if (seltype & SELTYPE_MARKPOINT) {
7705 if (FoundRoutePoint) {
7706 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7707 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7709 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7710 if (SelectedRoute) {
7711 rstruct->object_type =
7712 HostApi121::PiContextObjectType::kObjectRoutesegment;
7713 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7715 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7716 if (m_pSelectedTrack) {
7717 rstruct->object_type =
7718 HostApi121::PiContextObjectType::kObjectTracksegment;
7719 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7726void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7727 if (singleClickEventIsValid) {
7728 const bool wasReplaying = m_isReplayingClickEvent;
7729 m_isReplayingClickEvent =
true;
7730 MouseEvent(singleClickEvent);
7731 m_isReplayingClickEvent = wasReplaying;
7734 singleClickEventIsValid =
false;
7735 m_DoubleClickTimer->Stop();
7740bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7741 if (!m_bChartDragging && !m_bDrawingRoute) {
7746 if (m_Compass && m_Compass->IsShown()) {
7748 bool isInCompass = logicalRect.Contains(event.GetPosition());
7749 if (isInCompass || m_mouseWasInCompass) {
7750 if (m_Compass->MouseEvent(event)) {
7751 cursor_region = CENTER;
7752 if (!g_btouch) SetCanvasCursor(event);
7753 m_mouseWasInCompass = isInCompass;
7757 m_mouseWasInCompass = isInCompass;
7760 if (m_notification_button && m_notification_button->IsShown()) {
7762 bool isinButton = logicalRect.Contains(event.GetPosition());
7764 SetCursor(*pCursorArrow);
7765 if (event.LeftDown()) HandleNotificationMouseClick();
7770 if (MouseEventToolbar(event))
return true;
7772 if (MouseEventChartBar(event))
return true;
7774 if (MouseEventMUIBar(event))
return true;
7776 if (MouseEventIENCBar(event))
return true;
7781void ChartCanvas::HandleNotificationMouseClick() {
7782 if (!m_NotificationsList) {
7786 m_NotificationsList->RecalculateSize();
7787 m_NotificationsList->Hide();
7790 if (m_NotificationsList->IsShown()) {
7791 m_NotificationsList->Hide();
7793 m_NotificationsList->RecalculateSize();
7794 m_NotificationsList->ReloadNotificationList();
7795 m_NotificationsList->Show();
7798bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7799 if (!g_bShowChartBar)
return false;
7801 if (!m_Piano->MouseEvent(event))
return false;
7803 cursor_region = CENTER;
7804 if (!g_btouch) SetCanvasCursor(event);
7808bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7809 if (!IsPrimaryCanvas())
return false;
7818 cursor_region = CENTER;
7819 if (!g_btouch) SetCanvasCursor(event);
7823bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7824 if (!IsPrimaryCanvas())
return false;
7837bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7839 if (!m_muiBar->MouseEvent(event))
return false;
7842 cursor_region = CENTER;
7843 if (!g_btouch) SetCanvasCursor(event);
7855 event.GetPosition(&x, &y);
7857 x *= m_displayScale;
7858 y *= m_displayScale;
7860 m_MouseDragging =
event.Dragging();
7866 if (event.Dragging()) {
7867 if ((x == mouse_x) && (y == mouse_y))
return true;
7873 mouse_leftisdown =
event.LeftDown();
7877 cursor_region = CENTER;
7881 if (m_Compass && m_Compass->IsShown() &&
7882 m_Compass->
GetRect().Contains(event.GetPosition())) {
7883 cursor_region = CENTER;
7884 }
else if (x > xr_margin) {
7885 cursor_region = MID_RIGHT;
7886 }
else if (x < xl_margin) {
7887 cursor_region = MID_LEFT;
7888 }
else if (y > yb_margin - chartbar_height &&
7889 y < m_canvas_height - chartbar_height) {
7890 cursor_region = MID_TOP;
7891 }
else if (y < yt_margin) {
7892 cursor_region = MID_BOT;
7894 cursor_region = CENTER;
7897 if (!g_btouch) SetCanvasCursor(event);
7901 leftIsDown =
event.LeftDown();
7904 if (event.LeftDown()) {
7905 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7908 g_bTempShowMenuBar =
false;
7909 top_frame::Get()->ApplyGlobalSettings(
false);
7917 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7918 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7923 if (!m_isReplayingClickEvent) {
7924 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7925 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7929 event.SetEventObject(
this);
7930 if (SendMouseEventToPlugins(event))
7937 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7938 StartChartDragInertia();
7941 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7942 !singleClickEventIsValid) {
7944 if (m_DoubleClickTimer->IsRunning()) {
7945 m_DoubleClickTimer->Stop();
7950 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7951 singleClickEvent = event;
7952 singleClickEventIsValid =
true;
7961 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7962 if (g_click_stop > 0) {
7970 if (GetUpMode() == COURSE_UP_MODE) {
7971 m_b_rot_hidef =
false;
7972 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7974 pRotDefTimer->Stop();
7977 bool bRoll = !g_btouch;
7982 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7983 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7984 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7985 m_RolloverPopupTimer.Start(
7989 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7993 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
8002#if !defined(__WXGTK__) && !defined(__WXQT__)
8010 if ((x >= 0) && (y >= 0))
8015 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
8016 wxPoint p = ClientToScreen(wxPoint(x, y));
8022 if (m_routeState >= 2) {
8025 m_bDrawingRoute =
true;
8027 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8032 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
8035 m_bDrawingRoute =
true;
8037 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8050#if defined(__WXMAC__) || defined(__ANDROID__)
8054 wxClientDC cdc(GetParent());
8066 if (m_pSelectedRoute) {
8068 m_pSelectedRoute->DeSelectRoute();
8070 if (g_bopengl && m_glcc) {
8075 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8078 if (m_pFoundRoutePoint) {
8086 if (g_btouch && m_pRoutePointEditTarget) {
8089 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8093 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8094 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8095 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8096 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8097 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8101 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8104 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8110 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8113 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8114 seltype |= SELTYPE_AISTARGET;
8119 m_pFoundRoutePoint = NULL;
8124 Route *pSelectedActiveRoute = NULL;
8125 Route *pSelectedVizRoute = NULL;
8128 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8129 SelectableItemList SelList =
8130 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8138 bool brp_viz =
false;
8140 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8142 if (pr->IsVisible()) {
8147 if (!brp_viz && prp->IsShared())
8149 brp_viz = prp->IsVisible();
8152 brp_viz = prp->IsVisible();
8154 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8159 m_pSelectedRoute = NULL;
8161 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8164 pSelectedActiveRoute = pr;
8165 pFoundActiveRoutePoint = prp;
8170 if (NULL == pSelectedVizRoute) {
8171 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8173 if (pr->IsVisible()) {
8174 pSelectedVizRoute = pr;
8175 pFoundVizRoutePoint = prp;
8181 delete proute_array;
8186 if (pFoundActiveRoutePoint) {
8187 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8188 m_pSelectedRoute = pSelectedActiveRoute;
8189 }
else if (pFoundVizRoutePoint) {
8190 m_pFoundRoutePoint = pFoundVizRoutePoint;
8191 m_pSelectedRoute = pSelectedVizRoute;
8194 m_pFoundRoutePoint = pFirstVizPoint;
8196 if (m_pSelectedRoute) {
8197 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8198 }
else if (m_pFoundRoutePoint) {
8199 seltype |= SELTYPE_MARKPOINT;
8203 if (m_pFoundRoutePoint) {
8207 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8208 RefreshRect(wp_rect,
true);
8216 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8217 SelectableItemList SelList =
8218 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8220 if (NULL == m_pSelectedRoute)
8225 if (pr->IsVisible()) {
8226 m_pSelectedRoute = pr;
8232 if (m_pSelectedRoute) {
8233 if (NULL == m_pFoundRoutePoint)
8234 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8239 if (g_bopengl && m_glcc) {
8244 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8246 seltype |= SELTYPE_ROUTESEGMENT;
8250 if (pFindTrackSeg) {
8251 m_pSelectedTrack = NULL;
8252 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8253 SelectableItemList SelList =
8254 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8259 if (pt->IsVisible()) {
8260 m_pSelectedTrack = pt;
8264 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8270 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8271 seltype |= SELTYPE_CURRENTPOINT;
8274 else if (pFindTide) {
8275 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8276 seltype |= SELTYPE_TIDEPOINT;
8281 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8286IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8296 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8297 SelectableItemList SelList =
8298 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8301 pFind = *SelList.begin();
8302 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8304 auto node = SelList.begin();
8305 if (SelList.size() > 1) {
8306 for (++node; node != SelList.end(); ++node) {
8309 if (pIDX_candidate->
IDX_type ==
'c') {
8310 pIDX_best_candidate = pIDX_candidate;
8315 pFind = *SelList.begin();
8316 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8319 return pIDX_best_candidate;
8321void ChartCanvas::CallPopupMenu(
int x,
int y) {
8325 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8333 if (SELTYPE_CURRENTPOINT == seltype) {
8339 if (SELTYPE_TIDEPOINT == seltype) {
8345 InvokeCanvasMenu(x, y, seltype);
8348 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8352 m_pSelectedRoute = NULL;
8354 if (m_pFoundRoutePoint) {
8355 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8358 m_pFoundRoutePoint = NULL;
8364bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8372 event.GetPosition(&x, &y);
8378 SelectRadius = g_Platform->GetSelectRadiusPix() /
8379 (m_true_scale_ppm * 1852 * 60);
8386 if (event.LeftDClick() && (cursor_region == CENTER)) {
8387 m_DoubleClickTimer->Start();
8388 singleClickEventIsValid =
false;
8394 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8397 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8400 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8401 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8402 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8408 SelectableItemList rpSelList =
8409 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8410 bool b_onRPtarget =
false;
8413 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8414 b_onRPtarget =
true;
8422 std::unique_ptr<HostApi> host_api =
GetHostApi();
8423 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8425 if (m_pRoutePointEditTarget) {
8427 if ((api_121->GetContextMenuMask() &
8428 api_121->kContextMenuDisableWaypoint))
8430 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8436 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8439 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8440 m_pRoutePointEditTarget = NULL;
8441 RefreshRect(wp_rect,
true);
8445 auto node = rpSelList.begin();
8446 if (node != rpSelList.end()) {
8450 wxArrayPtrVoid *proute_array =
8455 bool brp_viz =
false;
8457 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8459 if (pr->IsVisible()) {
8464 delete proute_array;
8468 brp_viz = frp->IsVisible();
8470 brp_viz = frp->IsVisible();
8473 if ((api_121->GetContextMenuMask() &
8474 api_121->kContextMenuDisableWaypoint))
8477 ShowMarkPropertiesDialog(frp);
8486 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8488 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8491 if (pr->IsVisible()) {
8492 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8497 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8499 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8502 if (pt->IsVisible()) {
8503 ShowTrackPropertiesDialog(pt);
8512 if (m_bShowCurrent) {
8514 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8516 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8518 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8519 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8521 if (pic->m_enabled && pic->m_init_state &&
8522 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8525 if (m_pIDXCandidate) {
8526 info.point_type = CURRENT_STATION;
8530 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8531 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8535 if (plugin) plugin->OnTideCurrentClick(info);
8550 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8552 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8554 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8555 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8557 if (pic->m_enabled && pic->m_init_state &&
8558 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8561 if (m_pIDXCandidate) {
8562 info.point_type = TIDE_STATION;
8566 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8567 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8571 if (plugin) plugin->OnTideCurrentClick(info);
8586 ShowObjectQueryWindow(x, y, zlat, zlon);
8591 if (event.LeftDown()) {
8607 bool appending =
false;
8608 bool inserting =
false;
8611 SetCursor(*pCursorPencil);
8615 m_bRouteEditing =
true;
8617 if (m_routeState == 1) {
8618 m_pMouseRoute =
new Route();
8619 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8629 double nearby_radius_meters =
8630 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8633 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8634 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8635 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8636 wxArrayPtrVoid *proute_array =
8641 bool brp_viz =
false;
8643 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8645 if (pr->IsVisible()) {
8650 delete proute_array;
8652 pNearbyPoint->IsShared())
8655 pNearbyPoint->IsVisible();
8657 brp_viz = pNearbyPoint->IsVisible();
8660 wxString msg = _(
"Use nearby waypoint?");
8662 const bool noname(pNearbyPoint->GetName() ==
"");
8665 _(
"Use nearby nameless waypoint and name it M with"
8666 " a unique number?");
8669 m_FinishRouteOnKillFocus =
false;
8671 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8672 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8673 m_FinishRouteOnKillFocus =
true;
8674 if (dlg_return == wxID_YES) {
8676 if (m_pMouseRoute) {
8677 int last_wp_num = m_pMouseRoute->GetnPoints();
8679 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8680 wxString wp_name = wxString::Format(
8681 "M%002i-%s", last_wp_num + 1, guid_short);
8682 pNearbyPoint->SetName(wp_name);
8684 pNearbyPoint->SetName(
"WPXX");
8686 pMousePoint = pNearbyPoint;
8689 if (m_routeState > 1)
8690 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8691 Undo_HasParent, NULL);
8694 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8695 bool procede =
false;
8699 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8705 m_FinishRouteOnKillFocus =
false;
8711 _(
"Insert first part of this route in the new route?");
8712 if (tail->GetIndexOf(pMousePoint) ==
8715 dmsg = _(
"Insert this route in the new route?");
8717 if (tail->GetIndexOf(pMousePoint) > 0) {
8718 dlg_return = OCPNMessageBox(
8719 this, dmsg, _(
"OpenCPN Route Create"),
8720 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8721 m_FinishRouteOnKillFocus =
true;
8723 if (dlg_return == wxID_YES) {
8730 _(
"Append last part of this route to the new route?");
8731 if (tail->GetIndexOf(pMousePoint) == 1)
8733 "Append this route to the new route?");
8738 if (tail->GetLastPoint() != pMousePoint) {
8739 dlg_return = OCPNMessageBox(
8740 this, dmsg, _(
"OpenCPN Route Create"),
8741 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8742 m_FinishRouteOnKillFocus =
true;
8744 if (dlg_return == wxID_YES) {
8755 if (!FindRouteContainingWaypoint(pMousePoint))
8756 pMousePoint->SetShared(
true);
8761 if (NULL == pMousePoint) {
8762 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8764 pMousePoint->SetNameShown(
false);
8768 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8770 if (m_routeState > 1)
8771 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8772 Undo_IsOrphanded, NULL);
8775 if (m_pMouseRoute) {
8776 if (m_routeState == 1) {
8778 m_pMouseRoute->AddPoint(pMousePoint);
8781 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8782 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8783 &rhumbBearing, &rhumbDist);
8784 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8785 rlat, &gcDist, &gcBearing, NULL);
8786 double gcDistNM = gcDist / 1852.0;
8789 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8790 pow(rhumbDist - gcDistNM - 1, 0.5);
8793 msg << _(
"For this leg the Great Circle route is ")
8795 << _(
" shorter than rhumbline.\n\n")
8796 << _(
"Would you like include the Great Circle routing points "
8799 m_FinishRouteOnKillFocus =
false;
8800 m_disable_edge_pan =
true;
8803 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8804 wxYES_NO | wxNO_DEFAULT);
8806 m_disable_edge_pan =
false;
8807 m_FinishRouteOnKillFocus =
true;
8809 if (answer == wxID_YES) {
8811 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8812 wxRealPoint gcCoord;
8814 for (
int i = 1; i <= segmentCount; i++) {
8815 double fraction = (double)i * (1.0 / (
double)segmentCount);
8816 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8817 gcDist * fraction, gcBearing,
8818 &gcCoord.x, &gcCoord.y, NULL);
8820 if (i < segmentCount) {
8821 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8823 gcPoint->SetNameShown(
false);
8825 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8827 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8830 gcPoint = pMousePoint;
8833 m_pMouseRoute->AddPoint(gcPoint);
8834 pSelect->AddSelectableRouteSegment(
8835 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8836 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8837 prevGcPoint = gcPoint;
8840 undo->CancelUndoableAction(
true);
8843 m_pMouseRoute->AddPoint(pMousePoint);
8844 pSelect->AddSelectableRouteSegment(
8845 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8846 pMousePoint, m_pMouseRoute);
8847 undo->AfterUndoableAction(m_pMouseRoute);
8851 m_pMouseRoute->AddPoint(pMousePoint);
8852 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8853 rlon, m_prev_pMousePoint,
8854 pMousePoint, m_pMouseRoute);
8855 undo->AfterUndoableAction(m_pMouseRoute);
8861 m_prev_pMousePoint = pMousePoint;
8869 int connect = tail->GetIndexOf(pMousePoint);
8874 int length = tail->GetnPoints();
8879 start = connect + 1;
8885 m_pMouseRoute->RemovePoint(m_pMouseRoute->GetLastPoint());
8887 for (i = start; i <= stop; i++) {
8888 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8891 m_pMouseRoute->GetnPoints();
8893 top_frame::Get()->RefreshAllCanvas();
8897 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8899 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8900 m_pMouseRoute->FinalizeForRendering();
8902 top_frame::Get()->RefreshAllCanvas();
8906 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8908 SetCursor(*pCursorPencil);
8910 if (!m_pMeasureRoute) {
8911 m_pMeasureRoute =
new Route();
8915 if (m_nMeasureState == 1) {
8922 wxEmptyString, wxEmptyString);
8924 pMousePoint->SetShowWaypointRangeRings(
false);
8926 m_pMeasureRoute->AddPoint(pMousePoint);
8930 m_prev_pMousePoint = pMousePoint;
8934 top_frame::Get()->RefreshAllCanvas();
8939 FindRoutePointsAtCursor(SelectRadius,
true);
8943 m_last_touch_down_pos =
event.GetPosition();
8945 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8953 if (ret)
return true;
8956 if (event.Dragging()) {
8959 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8961 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8963 SelectableItemList SelList =
pSelect->FindSelectionList(
8967 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8972 if (m_pRoutePointEditTarget &&
8973 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8975 SelectableItemList SelList =
pSelect->FindSelectionList(
8979 if (m_pRoutePointEditTarget == frp) {
8980 m_bIsInRadius =
true;
8985 if (!m_dragoffsetSet) {
8987 .PresetDragOffset(
this, mouse_x, mouse_y);
8988 m_dragoffsetSet =
true;
8993 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8994 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8997 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8999 DraggingAllowed =
false;
9001 if (m_pRoutePointEditTarget &&
9002 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9003 DraggingAllowed =
false;
9005 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9007 if (DraggingAllowed) {
9008 if (!undo->InUndoableAction()) {
9009 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9010 Undo_NeedsCopy, m_pFoundPoint);
9016 if (!g_bopengl && m_pEditRouteArray) {
9017 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9018 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9025 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9026 pre_rect.Union(route_rect);
9034 if (CheckEdgePan(x, y,
true, 5, 2))
9042 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9044 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9045 m_pRoutePointEditTarget,
9046 SELTYPE_DRAGHANDLE);
9047 m_pFoundPoint->m_slat =
9048 m_pRoutePointEditTarget->m_lat;
9049 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9051 m_pRoutePointEditTarget->m_lat =
9053 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9054 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9055 m_pFoundPoint->m_slat =
9057 m_pFoundPoint->m_slon = new_cursor_lon;
9073 if (m_pEditRouteArray) {
9074 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9076 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9079 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9080 post_rect.Union(route_rect);
9086 pre_rect.Union(post_rect);
9087 RefreshRect(pre_rect,
false);
9089 top_frame::Get()->RefreshCanvasOther(
this);
9090 m_bRoutePoinDragging =
true;
9095 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9096 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9099 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9101 DraggingAllowed =
false;
9103 if (m_pRoutePointEditTarget &&
9104 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9105 DraggingAllowed =
false;
9107 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9109 if (DraggingAllowed) {
9110 if (!undo->InUndoableAction()) {
9111 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9112 Undo_NeedsCopy, m_pFoundPoint);
9126 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9132 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9133 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9134 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9135 (
int)(lppmax - (pre_rect.height / 2)));
9143 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9146 m_pRoutePointEditTarget,
9147 SELTYPE_DRAGHANDLE);
9148 m_pFoundPoint->m_slat =
9149 m_pRoutePointEditTarget->m_lat;
9150 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9152 m_pRoutePointEditTarget->m_lat =
9155 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9168 if (!g_btouch) InvalidateGL();
9174 .CalculateDCRect(m_dc_route,
this, &post_rect);
9175 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9176 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9177 (
int)(lppmax - (post_rect.height / 2)));
9180 pre_rect.Union(post_rect);
9181 RefreshRect(pre_rect,
false);
9183 top_frame::Get()->RefreshCanvasOther(
this);
9184 m_bRoutePoinDragging =
true;
9186 ret = g_btouch ? m_bRoutePoinDragging :
true;
9189 if (ret)
return true;
9192 if (event.LeftUp()) {
9193 bool b_startedit_route =
false;
9194 m_dragoffsetSet =
false;
9197 m_bChartDragging =
false;
9198 m_bIsInRadius =
false;
9205 int dx = x - m_touchdownPos.x;
9206 int dy = y - m_touchdownPos.y;
9207 int dist2 = dx * dx + dy * dy;
9208 bool wasPan = (dist2 > 20 * 20);
9215 m_bedge_pan =
false;
9220 bool appending =
false;
9221 bool inserting =
false;
9227 if (m_pRoutePointEditTarget) {
9233 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9234 RefreshRect(wp_rect,
true);
9236 m_pRoutePointEditTarget = NULL;
9238 m_bRouteEditing =
true;
9240 if (m_routeState == 1) {
9241 m_pMouseRoute =
new Route();
9242 m_pMouseRoute->SetHiLite(50);
9246 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9253 double nearby_radius_meters =
9254 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9257 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9258 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9259 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9262 m_FinishRouteOnKillFocus =
9264 dlg_return = OCPNMessageBox(
9265 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9266 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9267 m_FinishRouteOnKillFocus =
true;
9269 dlg_return = wxID_YES;
9271 if (dlg_return == wxID_YES) {
9272 pMousePoint = pNearbyPoint;
9275 if (m_routeState > 1)
9276 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9277 Undo_HasParent, NULL);
9278 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9280 bool procede =
false;
9284 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9290 m_FinishRouteOnKillFocus =
false;
9291 if (m_routeState == 1) {
9295 _(
"Insert first part of this route in the new route?");
9296 if (tail->GetIndexOf(pMousePoint) ==
9299 dmsg = _(
"Insert this route in the new route?");
9301 if (tail->GetIndexOf(pMousePoint) != 1) {
9303 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9304 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9305 m_FinishRouteOnKillFocus =
true;
9307 if (dlg_return == wxID_YES) {
9314 _(
"Append last part of this route to the new route?");
9315 if (tail->GetIndexOf(pMousePoint) == 1)
9317 "Append this route to the new route?");
9321 if (tail->GetLastPoint() != pMousePoint) {
9323 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9324 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9325 m_FinishRouteOnKillFocus =
true;
9327 if (dlg_return == wxID_YES) {
9338 if (!FindRouteContainingWaypoint(pMousePoint))
9339 pMousePoint->SetShared(
true);
9343 if (NULL == pMousePoint) {
9344 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9346 pMousePoint->SetNameShown(
false);
9348 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9350 if (m_routeState > 1)
9351 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9352 Undo_IsOrphanded, NULL);
9355 if (m_routeState == 1) {
9357 m_pMouseRoute->AddPoint(pMousePoint);
9358 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9362 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9363 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9364 &rhumbBearing, &rhumbDist);
9365 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9366 &gcDist, &gcBearing, NULL);
9367 double gcDistNM = gcDist / 1852.0;
9370 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9371 pow(rhumbDist - gcDistNM - 1, 0.5);
9374 msg << _(
"For this leg the Great Circle route is ")
9376 << _(
" shorter than rhumbline.\n\n")
9377 << _(
"Would you like include the Great Circle routing points "
9381 m_FinishRouteOnKillFocus =
false;
9382 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9383 wxYES_NO | wxNO_DEFAULT);
9384 m_FinishRouteOnKillFocus =
true;
9386 int answer = wxID_NO;
9389 if (answer == wxID_YES) {
9391 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9392 wxRealPoint gcCoord;
9394 for (
int i = 1; i <= segmentCount; i++) {
9395 double fraction = (double)i * (1.0 / (
double)segmentCount);
9396 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9397 gcDist * fraction, gcBearing,
9398 &gcCoord.x, &gcCoord.y, NULL);
9400 if (i < segmentCount) {
9401 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9403 gcPoint->SetNameShown(
false);
9404 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9407 gcPoint = pMousePoint;
9410 m_pMouseRoute->AddPoint(gcPoint);
9411 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9413 pSelect->AddSelectableRouteSegment(
9414 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9415 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9416 prevGcPoint = gcPoint;
9419 undo->CancelUndoableAction(
true);
9422 m_pMouseRoute->AddPoint(pMousePoint);
9423 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9424 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9425 rlon, m_prev_pMousePoint,
9426 pMousePoint, m_pMouseRoute);
9427 undo->AfterUndoableAction(m_pMouseRoute);
9431 m_pMouseRoute->AddPoint(pMousePoint);
9432 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9434 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9435 rlon, m_prev_pMousePoint,
9436 pMousePoint, m_pMouseRoute);
9437 undo->AfterUndoableAction(m_pMouseRoute);
9443 m_prev_pMousePoint = pMousePoint;
9450 int connect = tail->GetIndexOf(pMousePoint);
9455 int length = tail->GetnPoints();
9460 start = connect + 1;
9465 m_pMouseRoute->RemovePoint(
9469 for (i = start; i <= stop; i++) {
9470 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9473 m_pMouseRoute->GetnPoints();
9475 top_frame::Get()->RefreshAllCanvas();
9479 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9481 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9482 m_pMouseRoute->FinalizeForRendering();
9487 }
else if (m_bMeasure_Active && m_nMeasureState)
9490 m_bedge_pan =
false;
9496 int mdx = x - m_touchdownPos.x;
9497 int mdy = y - m_touchdownPos.y;
9498 if (mdx * mdx + mdy * mdy > 20 * 20)
return false;
9501 if (m_nMeasureState == 1) {
9502 m_pMeasureRoute =
new Route();
9508 if (m_pMeasureRoute) {
9511 wxEmptyString, wxEmptyString);
9514 m_pMeasureRoute->AddPoint(pMousePoint);
9518 m_prev_pMousePoint = pMousePoint;
9520 m_pMeasureRoute->GetnPoints();
9524 CancelMeasureRoute();
9530 bool bSelectAllowed =
true;
9532 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9534 bSelectAllowed =
false;
9538 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9539 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9540 significant_drag) ||
9541 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9542 significant_drag)) {
9543 bSelectAllowed =
false;
9551 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9553 if (bSelectAllowed) {
9554 bool b_was_editing_mark = m_bMarkEditing;
9555 bool b_was_editing_route = m_bRouteEditing;
9556 FindRoutePointsAtCursor(SelectRadius,
9562 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9563 m_pRoutePointEditTarget = NULL;
9565 if (!b_was_editing_route) {
9566 if (m_pEditRouteArray) {
9567 b_startedit_route =
true;
9571 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9572 m_pTrackRolloverWin->IsActive(
false);
9574 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9575 m_pRouteRolloverWin->IsActive(
false);
9579 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9581 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9589 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9590 pre_rect.Union(route_rect);
9593 RefreshRect(pre_rect,
true);
9596 b_startedit_route =
false;
9600 if (m_pRoutePointEditTarget) {
9601 if (b_was_editing_mark ||
9602 b_was_editing_route) {
9603 if (m_lastRoutePointEditTarget) {
9607 .EnableDragHandle(
false);
9608 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9609 SELTYPE_DRAGHANDLE);
9613 if (m_pRoutePointEditTarget) {
9616 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9617 wxPoint2DDouble dragHandlePoint =
9619 .GetDragHandlePoint(
this);
9621 dragHandlePoint.m_y, dragHandlePoint.m_x,
9622 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9625 if (m_lastRoutePointEditTarget) {
9629 .EnableDragHandle(
false);
9630 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9631 SELTYPE_DRAGHANDLE);
9634 wxArrayPtrVoid *lastEditRouteArray =
9636 m_lastRoutePointEditTarget);
9637 if (lastEditRouteArray) {
9638 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9640 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9645 delete lastEditRouteArray;
9656 if (m_lastRoutePointEditTarget) {
9659 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9660 RefreshRect(wp_rect,
true);
9663 if (m_pRoutePointEditTarget) {
9666 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9667 RefreshRect(wp_rect,
true);
9675 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9676 bool b_start_rollover =
false;
9680 if (pFind) b_start_rollover =
true;
9683 if (!b_start_rollover && !b_startedit_route) {
9684 SelectableItemList SelList =
pSelect->FindSelectionList(
9688 if (pr && pr->IsVisible()) {
9689 b_start_rollover =
true;
9695 if (!b_start_rollover && !b_startedit_route) {
9696 SelectableItemList SelList =
pSelect->FindSelectionList(
9700 if (tr && tr->IsVisible()) {
9701 b_start_rollover =
true;
9707 if (b_start_rollover)
9708 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9712 bool appending =
false;
9713 bool inserting =
false;
9715 if (m_bRouteEditing ) {
9717 if (m_pRoutePointEditTarget) {
9723 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9724 double nearby_radius_meters =
9725 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9726 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9727 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9728 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9730 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9734 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9736 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9740 std::find(list->begin(), list->end(), pNearbyPoint);
9741 if (pos != list->end()) {
9753 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9758 OCPNMessageBox(
this,
9759 _(
"Replace this RoutePoint by the nearby "
9761 _(
"OpenCPN RoutePoint change"),
9762 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9763 if (dlg_return == wxID_YES) {
9768 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9771 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9773 if (tail && current && (tail != current)) {
9775 connect = tail->GetIndexOf(pNearbyPoint);
9776 int index_current_route =
9777 current->GetIndexOf(m_pRoutePointEditTarget);
9778 index_last = current->GetIndexOf(current->GetLastPoint());
9779 dlg_return1 = wxID_NO;
9781 index_current_route) {
9783 if (connect != tail->GetnPoints()) {
9786 _(
"Last part of route to be appended to dragged "
9790 _(
"Full route to be appended to dragged route?");
9792 dlg_return1 = OCPNMessageBox(
9793 this, dmsg, _(
"OpenCPN Route Create"),
9794 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9795 if (dlg_return1 == wxID_YES) {
9799 }
else if (index_current_route ==
9804 _(
"First part of route to be inserted into dragged "
9806 if (connect == tail->GetnPoints())
9808 "Full route to be inserted into dragged route?");
9810 dlg_return1 = OCPNMessageBox(
9811 this, dmsg, _(
"OpenCPN Route Create"),
9812 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9813 if (dlg_return1 == wxID_YES) {
9820 if (m_pRoutePointEditTarget->IsShared()) {
9822 dlg_return = OCPNMessageBox(
9824 _(
"Do you really want to delete and replace this "
9826 "\n" + _(
"which has been created manually?"),
9827 (
"OpenCPN RoutePoint warning"),
9828 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9831 if (dlg_return == wxID_YES) {
9832 pMousePoint = pNearbyPoint;
9834 pMousePoint->SetShared(
true);
9844 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9846 if (m_pEditRouteArray) {
9847 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9849 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9854 auto pos = std::find(list->begin(), list->end(),
9855 m_pRoutePointEditTarget);
9857 pSelect->DeleteAllSelectableRoutePoints(pr);
9858 pSelect->DeleteAllSelectableRouteSegments(pr);
9861 pos = std::find(list->begin(), list->end(),
9862 m_pRoutePointEditTarget);
9865 pSelect->AddAllSelectableRouteSegments(pr);
9866 pSelect->AddAllSelectableRoutePoints(pr);
9868 pr->FinalizeForRendering();
9869 pr->UpdateSegmentDistances();
9870 if (m_bRoutePoinDragging) {
9872 NavObj_dB::GetInstance().UpdateRoute(pr);
9880 if (m_pEditRouteArray) {
9881 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9883 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9902 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9909 delete m_pRoutePointEditTarget;
9910 m_lastRoutePointEditTarget = NULL;
9911 m_pRoutePointEditTarget = NULL;
9912 undo->AfterUndoableAction(pMousePoint);
9913 undo->InvalidateUndo();
9918 else if (m_bMarkEditing) {
9919 if (m_pRoutePointEditTarget)
9920 if (m_bRoutePoinDragging) {
9922 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9926 if (m_pRoutePointEditTarget)
9927 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9929 if (!m_pRoutePointEditTarget) {
9930 delete m_pEditRouteArray;
9931 m_pEditRouteArray = NULL;
9932 m_bRouteEditing =
false;
9934 m_bRoutePoinDragging =
false;
9941 int length = tail->GetnPoints();
9942 for (
int i = connect + 1; i <= length; i++) {
9943 current->AddPointAndSegment(tail->GetPoint(i),
false);
9946 top_frame::Get()->RefreshAllCanvas();
9949 current->FinalizeForRendering();
9955 pSelect->DeleteAllSelectableRoutePoints(current);
9956 pSelect->DeleteAllSelectableRouteSegments(current);
9957 for (
int i = 1; i < connect; i++) {
9958 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9960 pSelect->AddAllSelectableRouteSegments(current);
9961 pSelect->AddAllSelectableRoutePoints(current);
9962 current->FinalizeForRendering();
9969 if (m_pEditRouteArray) {
9970 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9971 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9984 if (m_bRouteEditing) {
9987 bool appending =
false;
9988 bool inserting =
false;
9991 if (m_pRoutePointEditTarget) {
9992 m_pRoutePointEditTarget->
m_bBlink =
false;
9996 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9997 double nearby_radius_meters =
9998 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9999 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
10000 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
10001 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
10003 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
10004 bool duplicate =
false;
10006 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10008 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10012 std::find(list->begin(), list->end(), pNearbyPoint);
10013 if (pos != list->end()) {
10025 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
10030 OCPNMessageBox(
this,
10031 _(
"Replace this RoutePoint by the nearby "
10033 _(
"OpenCPN RoutePoint change"),
10034 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10035 if (dlg_return == wxID_YES) {
10039 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
10042 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
10044 if (tail && current && (tail != current)) {
10046 connect = tail->GetIndexOf(pNearbyPoint);
10047 int index_current_route =
10048 current->GetIndexOf(m_pRoutePointEditTarget);
10049 index_last = current->GetIndexOf(current->GetLastPoint());
10050 dlg_return1 = wxID_NO;
10052 index_current_route) {
10054 if (connect != tail->GetnPoints()) {
10057 _(
"Last part of route to be appended to dragged "
10061 _(
"Full route to be appended to dragged route?");
10063 dlg_return1 = OCPNMessageBox(
10064 this, dmsg, _(
"OpenCPN Route Create"),
10065 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10066 if (dlg_return1 == wxID_YES) {
10070 }
else if (index_current_route ==
10072 if (connect != 1) {
10075 _(
"First part of route to be inserted into dragged "
10077 if (connect == tail->GetnPoints())
10079 "Full route to be inserted into dragged route?");
10081 dlg_return1 = OCPNMessageBox(
10082 this, dmsg, _(
"OpenCPN Route Create"),
10083 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10084 if (dlg_return1 == wxID_YES) {
10091 if (m_pRoutePointEditTarget->IsShared()) {
10092 dlg_return = wxID_NO;
10093 dlg_return = OCPNMessageBox(
10095 _(
"Do you really want to delete and replace this "
10097 "\n" + _(
"which has been created manually?"),
10098 (
"OpenCPN RoutePoint warning"),
10099 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10102 if (dlg_return == wxID_YES) {
10103 pMousePoint = pNearbyPoint;
10105 pMousePoint->SetShared(
true);
10115 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10117 if (m_pEditRouteArray) {
10118 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10120 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10124 auto pos = std::find(list->begin(), list->end(),
10125 m_pRoutePointEditTarget);
10127 pSelect->DeleteAllSelectableRoutePoints(pr);
10128 pSelect->DeleteAllSelectableRouteSegments(pr);
10131 pos = std::find(list->begin(), list->end(),
10132 m_pRoutePointEditTarget);
10133 if (pos != list->end()) list->erase(pos);
10136 pSelect->AddAllSelectableRouteSegments(pr);
10137 pSelect->AddAllSelectableRoutePoints(pr);
10139 pr->FinalizeForRendering();
10140 pr->UpdateSegmentDistances();
10143 if (m_bRoutePoinDragging) {
10148 NavObj_dB::GetInstance().UpdateRoutePoint(
10149 m_pRoutePointEditTarget);
10151 NavObj_dB::GetInstance().UpdateRoute(pr);
10163 int length = tail->GetnPoints();
10164 for (
int i = connect + 1; i <= length; i++) {
10165 current->AddPointAndSegment(tail->GetPoint(i),
false);
10169 top_frame::Get()->RefreshAllCanvas();
10172 current->FinalizeForRendering();
10178 pSelect->DeleteAllSelectableRoutePoints(current);
10179 pSelect->DeleteAllSelectableRouteSegments(current);
10180 for (
int i = 1; i < connect; i++) {
10181 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10183 pSelect->AddAllSelectableRouteSegments(current);
10184 pSelect->AddAllSelectableRoutePoints(current);
10185 current->FinalizeForRendering();
10192 if (m_pEditRouteArray) {
10193 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10195 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10207 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10214 delete m_pRoutePointEditTarget;
10215 m_lastRoutePointEditTarget = NULL;
10216 undo->AfterUndoableAction(pMousePoint);
10217 undo->InvalidateUndo();
10222 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10225 delete m_pEditRouteArray;
10226 m_pEditRouteArray = NULL;
10230 m_bRouteEditing =
false;
10231 m_pRoutePointEditTarget = NULL;
10237 else if (m_bMarkEditing) {
10238 if (m_pRoutePointEditTarget) {
10239 if (m_bRoutePoinDragging) {
10241 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10243 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10248 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10250 RefreshRect(wp_rect,
true);
10253 m_pRoutePointEditTarget = NULL;
10254 m_bMarkEditing =
false;
10259 else if (leftIsDown) {
10260 leftIsDown =
false;
10264 if (!m_bChartDragging && !m_bMeasure_Active) {
10266 m_bChartDragging =
false;
10270 m_bRoutePoinDragging =
false;
10273 if (ret)
return true;
10276 if (event.RightDown()) {
10287 m_FinishRouteOnKillFocus =
false;
10288 CallPopupMenu(mx, my);
10289 m_FinishRouteOnKillFocus =
true;
10299 if (event.ShiftDown()) {
10303 event.GetPosition(&x, &y);
10305 x *= m_displayScale;
10306 y *= m_displayScale;
10312 int wheel_dir =
event.GetWheelRotation();
10315 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10316 wheel_dir = wheel_dir > 0 ? 1 : -1;
10318 double factor = g_mouse_zoom_sensitivity;
10319 if (wheel_dir < 0) factor = 1 / factor;
10322 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10323 if (wheel_dir == m_last_wheel_dir) {
10324 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10329 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10330 m_wheelstopwatch.Start(0);
10335 m_last_wheel_dir = wheel_dir;
10340 if (event.LeftDown()) {
10346 last_drag.x = x, last_drag.y = y;
10347 m_touchdownPos = wxPoint(x, y);
10348 panleftIsDown =
true;
10351 if (event.LeftUp()) {
10352 if (panleftIsDown) {
10354 panleftIsDown =
false;
10357 if (!m_bChartDragging && !m_bMeasure_Active) {
10358 switch (cursor_region) {
10380 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10385 m_bChartDragging =
false;
10391 if (event.Dragging() && event.LeftIsDown()) {
10407 if (g_btouch && !m_inPinch) {
10408 struct timespec now;
10409 clock_gettime(CLOCK_MONOTONIC, &now);
10410 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10412 bool trigger_hold =
false;
10413 if (
false == m_bChartDragging) {
10414 if (m_DragTrigger < 0) {
10417 m_DragTriggerStartTime = tnow;
10418 trigger_hold =
true;
10420 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10421 m_DragTrigger = -1;
10426 if (trigger_hold)
return true;
10428 if (
false == m_bChartDragging) {
10431 last_drag.x = x - 1, last_drag.y = y - 1;
10432 m_bChartDragging =
true;
10433 m_chart_drag_total_time = 0;
10434 m_chart_drag_total_x = 0;
10435 m_chart_drag_total_y = 0;
10436 m_inertia_last_drag_x = x;
10437 m_inertia_last_drag_y = y;
10438 m_drag_vec_x.clear();
10439 m_drag_vec_y.clear();
10440 m_drag_vec_t.clear();
10441 m_last_drag_time = tnow;
10445 uint64_t delta_t = tnow - m_last_drag_time;
10446 double delta_tf = delta_t / 1e9;
10448 m_chart_drag_total_time += delta_tf;
10449 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10450 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10452 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10453 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10454 m_drag_vec_t.push_back(delta_tf);
10456 m_inertia_last_drag_x = x;
10457 m_inertia_last_drag_y = y;
10458 m_last_drag_time = tnow;
10460 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
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;
10467 }
else if (!g_btouch) {
10468 if ((last_drag.x != x) || (last_drag.y != y)) {
10469 if (!m_routeState) {
10472 m_bChartDragging =
true;
10473 StartTimedMovement();
10474 m_pan_drag.x += last_drag.x - x;
10475 m_pan_drag.y += last_drag.y - y;
10476 last_drag.x = x, last_drag.y = y;
10483 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10485 m_DoubleClickTimer->Start();
10486 singleClickEventIsValid =
false;
10494void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10495 if (MouseEventOverlayWindows(event))
return;
10499 bool nm = MouseEventProcessObjects(event);
10503void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10506 wxCursor *ptarget_cursor = pCursorArrow;
10507 if (!pPlugIn_Cursor) {
10508 ptarget_cursor = pCursorArrow;
10509 if ((!m_routeState) &&
10510 (!m_bMeasure_Active) ) {
10511 if (cursor_region == MID_RIGHT) {
10512 ptarget_cursor = pCursorRight;
10513 }
else if (cursor_region == MID_LEFT) {
10514 ptarget_cursor = pCursorLeft;
10515 }
else if (cursor_region == MID_TOP) {
10516 ptarget_cursor = pCursorDown;
10517 }
else if (cursor_region == MID_BOT) {
10518 ptarget_cursor = pCursorUp;
10520 ptarget_cursor = pCursorArrow;
10522 }
else if (m_bMeasure_Active ||
10524 ptarget_cursor = pCursorPencil;
10526 ptarget_cursor = pPlugIn_Cursor;
10529 SetCursor(*ptarget_cursor);
10532void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10533 SetCursor(*pCursorArrow);
10536void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10540 wxArrayString files;
10542 ChartBase *target_chart = GetChartAtCursor();
10543 if (target_chart) {
10544 file.Assign(target_chart->GetFullPath());
10545 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10546 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10549 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10551 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10552 unsigned int im = stackIndexArray.size();
10553 int scale = 2147483647;
10554 if (VPoint.b_quilt && im > 0) {
10555 for (
unsigned int is = 0; is < im; is++) {
10556 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10557 CHART_TYPE_MBTILES) {
10558 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10560 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10561 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10563 .Contains(lat, lon)) {
10564 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10567 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10568 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10576 std::vector<Ais8_001_22 *> area_notices;
10578 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10581 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10582 auto target_data = target.second;
10583 if (!target_data->area_notices.empty()) {
10584 for (
auto &ani : target_data->area_notices) {
10589 for (Ais8_001_22_SubAreaList::iterator sa =
10590 area_notice.sub_areas.begin();
10591 sa != area_notice.sub_areas.end(); ++sa) {
10592 switch (sa->shape) {
10593 case AIS8_001_22_SHAPE_CIRCLE: {
10594 wxPoint target_point;
10596 bbox.Expand(target_point);
10597 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10600 case AIS8_001_22_SHAPE_RECT: {
10601 wxPoint target_point;
10603 bbox.Expand(target_point);
10604 if (sa->e_dim_m > sa->n_dim_m)
10605 bbox.EnLarge(sa->e_dim_m * vp_scale);
10607 bbox.EnLarge(sa->n_dim_m * vp_scale);
10610 case AIS8_001_22_SHAPE_POLYGON:
10611 case AIS8_001_22_SHAPE_POLYLINE: {
10612 for (
int i = 0; i < 4; ++i) {
10613 double lat = sa->latitude;
10614 double lon = sa->longitude;
10615 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10617 wxPoint target_point;
10619 bbox.Expand(target_point);
10623 case AIS8_001_22_SHAPE_SECTOR: {
10624 double lat1 = sa->latitude;
10625 double lon1 = sa->longitude;
10627 wxPoint target_point;
10629 bbox.Expand(target_point);
10630 for (
int i = 0; i < 18; ++i) {
10633 sa->left_bound_deg +
10634 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10635 sa->radius_m / 1852.0, &lat, &lon);
10637 bbox.Expand(target_point);
10639 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10642 bbox.Expand(target_point);
10648 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10649 area_notices.push_back(&area_notice);
10656 if (target_chart || !area_notices.empty() || file.HasName()) {
10658 int sel_rad_pix = 5;
10659 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10664 SetCursor(wxCURSOR_WAIT);
10665 bool lightsVis = m_encShowLights;
10666 if (!lightsVis) SetShowENCLights(
true);
10669 ListOfObjRazRules *rule_list = NULL;
10670 ListOfPI_S57Obj *pi_rule_list = NULL;
10673 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10674 else if (target_plugin_chart)
10675 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10676 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10678 ListOfObjRazRules *overlay_rule_list = NULL;
10679 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10682 if (CHs57_Overlay) {
10683 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10684 zlat, zlon, SelectRadius, &GetVP());
10687 if (!lightsVis) SetShowENCLights(
false);
10690 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10691 wxString face = dFont->GetFaceName();
10695 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10696 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10700 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10708 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10709 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10712 int points = dFont->GetPointSize();
10714 int points = dFont->GetPointSize() + 1;
10718 for (
int i = -2; i < 5; i++) {
10719 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10723 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10725 if (overlay_rule_list && CHs57_Overlay) {
10726 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10727 objText <<
"<hr noshade>";
10730 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10731 an != area_notices.end(); ++an) {
10732 objText <<
"<b>AIS Area Notice:</b> ";
10733 objText << ais8_001_22_notice_names[(*an)->notice_type];
10734 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10735 (*an)->sub_areas.begin();
10736 sa != (*an)->sub_areas.end(); ++sa)
10737 if (!sa->text.empty()) objText << sa->text;
10738 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10739 objText <<
"<hr noshade>";
10743 objText << Chs57->CreateObjDescriptions(rule_list);
10744 else if (target_plugin_chart)
10745 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10748 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10751 wxString AddFiles, filenameOK;
10753 if (!target_plugin_chart) {
10756 AddFiles = wxString::Format(
10757 "<hr noshade><br><b>Additional info files attached to: </b> "
10759 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10761 file.GetFullName());
10763 file.Assign(file.GetPath(),
"");
10764 wxDir dir(file.GetFullPath());
10766 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10768 file.Assign(dir.GetNameWithSep().append(filename));
10769 wxString FormatString =
10770 "<td valign=top><font size=-2><a "
10771 "href=\"%s\">%s</a></font></td>";
10772 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10773 filenameOK = file.GetFullPath();
10775 if (3 * ((
int)filecount / 3) == filecount)
10776 FormatString.Prepend(
"<tr>");
10778 FormatString.Prepend(
10779 "<td>  </td>");
10782 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10783 file.GetFullName());
10786 cont = dir.GetNext(&filename);
10788 objText << AddFiles <<
"</table>";
10790 objText <<
"</font>";
10791 objText <<
"</body></html>";
10793 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10797 if ((!Chs57 && filecount == 1)) {
10799 wxHtmlLinkInfo hli(filenameOK);
10800 wxHtmlLinkEvent hle(1, hli);
10804 if (rule_list) rule_list->Clear();
10807 if (overlay_rule_list) overlay_rule_list->Clear();
10808 delete overlay_rule_list;
10810 if (pi_rule_list) pi_rule_list->Clear();
10811 delete pi_rule_list;
10813 SetCursor(wxCURSOR_ARROW);
10817void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10826 wxSize canvas_size = GetSize();
10833 wxPoint canvas_pos = GetPosition();
10836 bool newFit =
false;
10837 if (canvas_size.x < fitted_size.x) {
10838 fitted_size.x = canvas_size.x - 40;
10839 if (canvas_size.y < fitted_size.y)
10840 fitted_size.y -= 40;
10842 if (canvas_size.y < fitted_size.y) {
10843 fitted_size.y = canvas_size.y - 40;
10844 if (canvas_size.x < fitted_size.x)
10845 fitted_size.x -= 40;
10856 wxString title_base = _(
"Mark Properties");
10858 title_base = _(
"Waypoint Properties");
10863 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10875void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10885 if (g_bresponsive) {
10886 wxSize canvas_size = GetSize();
10887 wxPoint canvas_pos = GetPosition();
10891 if (canvas_size.x < fitted_size.x) {
10892 fitted_size.x = canvas_size.x;
10893 if (canvas_size.y < fitted_size.y)
10894 fitted_size.y -= 20;
10896 if (canvas_size.y < fitted_size.y) {
10897 fitted_size.y = canvas_size.y;
10898 if (canvas_size.x < fitted_size.x)
10899 fitted_size.x -= 20;
10908 wxPoint xxp = ClientToScreen(canvas_pos);
10919void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10931void pupHandler_PasteWaypoint() {
10934 int pasteBuffer = kml.ParsePasteBuffer();
10935 RoutePoint *pasted = kml.GetParsedRoutePoint();
10936 if (!pasted)
return;
10938 double nearby_radius_meters =
10939 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10941 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10942 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10944 int answer = wxID_NO;
10948 "There is an existing waypoint at the same location as the one you are "
10949 "pasting. Would you like to merge the pasted data with it?\n\n");
10950 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10951 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10952 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10955 if (answer == wxID_YES) {
10956 nearPoint->SetName(pasted->GetName());
10962 if (answer == wxID_NO) {
10965 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10968 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10977 top_frame::Get()->InvalidateAllGL();
10978 top_frame::Get()->RefreshAllCanvas(
false);
10981void pupHandler_PasteRoute() {
10984 int pasteBuffer = kml.ParsePasteBuffer();
10985 Route *pasted = kml.GetParsedRoute();
10986 if (!pasted)
return;
10988 double nearby_radius_meters =
10989 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10995 bool mergepoints =
false;
10996 bool createNewRoute =
true;
10997 int existingWaypointCounter = 0;
10999 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11000 curPoint = pasted->GetPoint(i);
11001 nearPoint = pWayPointMan->GetNearbyWaypoint(
11002 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11004 mergepoints =
true;
11005 existingWaypointCounter++;
11013 int answer = wxID_NO;
11017 "There are existing waypoints at the same location as some of the ones "
11018 "you are pasting. Would you like to just merge the pasted data into "
11020 msg << _(
"Answering 'No' will create all new waypoints for this route.");
11021 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
11022 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
11024 if (answer == wxID_CANCEL) {
11031 if (mergepoints && answer == wxID_YES &&
11032 existingWaypointCounter == pasted->GetnPoints()) {
11035 createNewRoute =
false;
11041 Route *newRoute = 0;
11044 if (createNewRoute) {
11045 newRoute =
new Route();
11049 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11050 curPoint = pasted->GetPoint(i);
11053 newPoint = pWayPointMan->GetNearbyWaypoint(
11054 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11055 newPoint->SetName(curPoint->GetName());
11058 if (createNewRoute) newRoute->AddPoint(newPoint);
11064 newPoint->SetIconName(
"circle");
11067 newPoint->SetShared(
false);
11069 newRoute->AddPoint(newPoint);
11070 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11073 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11076 if (i > 1 && createNewRoute)
11077 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11078 curPoint->m_lat, curPoint->m_lon,
11079 prevPoint, newPoint, newRoute);
11080 prevPoint = newPoint;
11083 if (createNewRoute) {
11086 NavObj_dB::GetInstance().InsertRoute(newRoute);
11096 top_frame::Get()->InvalidateAllGL();
11097 top_frame::Get()->RefreshAllCanvas(
false);
11103void pupHandler_PasteTrack() {
11106 int pasteBuffer = kml.ParsePasteBuffer();
11107 Track *pasted = kml.GetParsedTrack();
11108 if (!pasted)
return;
11116 newTrack->SetName(pasted->GetName());
11118 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11119 curPoint = pasted->GetPoint(i);
11123 wxDateTime now = wxDateTime::Now();
11126 newTrack->AddPoint(newPoint);
11129 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11130 newPoint->m_lat, newPoint->m_lon,
11131 prevPoint, newPoint, newTrack);
11133 prevPoint = newPoint;
11138 NavObj_dB::GetInstance().InsertTrack(newTrack);
11140 top_frame::Get()->InvalidateAllGL();
11141 top_frame::Get()->RefreshAllCanvas(
false);
11144bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11147 v[
"CursorPosition_x"] = x;
11148 v[
"CursorPosition_y"] = y;
11151 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11152 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11153 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11158 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11160 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11163#define SELTYPE_UNKNOWN 0x0001
11164#define SELTYPE_ROUTEPOINT 0x0002
11165#define SELTYPE_ROUTESEGMENT 0x0004
11166#define SELTYPE_TIDEPOINT 0x0008
11167#define SELTYPE_CURRENTPOINT 0x0010
11168#define SELTYPE_ROUTECREATE 0x0020
11169#define SELTYPE_AISTARGET 0x0040
11170#define SELTYPE_MARKPOINT 0x0080
11171#define SELTYPE_TRACKSEGMENT 0x0100
11172#define SELTYPE_DRAGHANDLE 0x0200
11175 if (g_bhide_context_menus)
return true;
11177 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11178 m_pIDXCandidate, m_nmea_log);
11181 wxEVT_COMMAND_MENU_SELECTED,
11182 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11188 if (m_inLongPress) {
11189 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11190 m_inLongPress =
false;
11194 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11197 wxEVT_COMMAND_MENU_SELECTED,
11198 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11200 delete m_canvasMenu;
11201 m_canvasMenu = NULL;
11211void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11214 if (m_canvasMenu) {
11215 m_canvasMenu->PopupMenuHandler(event);
11220void ChartCanvas::StartRoute() {
11222 if (g_brouteCreating)
return;
11226 g_brouteCreating =
true;
11228 m_bDrawingRoute =
false;
11229 SetCursor(*pCursorPencil);
11231 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11233 HideGlobalToolbar();
11236 androidSetRouteAnnunciator(
true);
11240wxString ChartCanvas::FinishRoute() {
11242 m_prev_pMousePoint = NULL;
11243 m_bDrawingRoute =
false;
11245 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11248 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11250 androidSetRouteAnnunciator(
false);
11253 SetCursor(*pCursorArrow);
11255 if (m_pMouseRoute) {
11256 if (m_bAppendingRoute) {
11258 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11260 if (m_pMouseRoute->GetnPoints() > 1) {
11262 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11265 m_pMouseRoute = NULL;
11268 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11280 m_bAppendingRoute =
false;
11281 m_pMouseRoute = NULL;
11283 m_pSelectedRoute = NULL;
11285 undo->InvalidateUndo();
11286 top_frame::Get()->RefreshAllCanvas(
true);
11290 ShowGlobalToolbar();
11292 g_brouteCreating =
false;
11297void ChartCanvas::HideGlobalToolbar() {
11298 if (m_canvasIndex == 0) {
11299 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11303void ChartCanvas::ShowGlobalToolbar() {
11304 if (m_canvasIndex == 0) {
11305 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11309void ChartCanvas::ShowAISTargetList() {
11310 if (NULL == g_pAISTargetList) {
11314 g_pAISTargetList->UpdateAISTargetList();
11317void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11318 if (!m_bShowOutlines)
return;
11322 int nEntry =
ChartData->GetChartTableEntries();
11324 for (
int i = 0; i < nEntry; i++) {
11328 bool b_group_draw =
false;
11329 if (m_groupIndex > 0) {
11330 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11331 int index = pt->GetGroupArray()[ig];
11332 if (m_groupIndex == index) {
11333 b_group_draw =
true;
11338 b_group_draw =
true;
11340 if (b_group_draw) RenderChartOutline(dc, i, vp);
11346 if (VPoint.b_quilt) {
11347 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11348 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11352 }
else if (m_singleChart &&
11353 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11357 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11360 if (zoom_factor > 8.0) {
11361 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11364 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11368 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11372void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11374 if (g_bopengl && m_glcc) {
11376 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11381 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11382 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11385 float plylat, plylon;
11386 float plylat1, plylon1;
11388 int pixx, pixy, pixx1, pixy1;
11391 ChartData->GetDBBoundingBox(dbIndex, box);
11395 if (box.GetLonRange() == 360)
return;
11397 double lon_bias = 0;
11399 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11401 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11403 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11404 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11406 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11407 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11410 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11413 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11414 if (0 == nAuxPlyEntries)
11418 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11419 plylon += lon_bias;
11425 for (
int i = 0; i < nPly - 1; i++) {
11426 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11427 plylon1 += lon_bias;
11433 int pixxs1 = pixx1;
11434 int pixys1 = pixy1;
11436 bool b_skip =
false;
11440 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11441 pow((
double)(pixy1 - pixy), 2)) /
11447 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11452 if (fabs(dist - distgc) > 10000. * 1852.)
11458 ClipResult res = cohen_sutherland_line_clip_i(
11460 if (res != Invisible && !b_skip)
11461 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11469 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11470 plylon1 += lon_bias;
11476 ClipResult res = cohen_sutherland_line_clip_i(
11478 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11485 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11486 for (
int j = 0; j < nAuxPlyEntries; j++) {
11488 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11493 for (
int i = 0; i < nAuxPly - 1; i++) {
11494 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11500 int pixxs1 = pixx1;
11501 int pixys1 = pixy1;
11503 bool b_skip =
false;
11507 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11508 ((pixy1 - pixy) * (pixy1 - pixy))) /
11513 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11518 if (fabs(dist - distgc) > 10000. * 1852.)
11524 ClipResult res = cohen_sutherland_line_clip_i(
11526 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11534 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11539 ClipResult res = cohen_sutherland_line_clip_i(
11541 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11546static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11547 const wxArrayString &legend) {
11548 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11550 int pointsize = dFont->GetPointSize();
11554 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11555 false, dFont->GetFaceName());
11557 dc.SetFont(*psRLI_font);
11564 int hilite_offset = 3;
11566 for (wxString line : legend) {
11569 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11571 dc.GetTextExtent(line, &wl, &hl);
11580 xp = ref_point.x - w;
11582 yp += hilite_offset;
11584 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11586 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11587 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11589 for (wxString line : legend) {
11590 dc.DrawText(line, xp, yp);
11595void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11596 if (!g_bAllowShipToActive)
return;
11602 wxPoint2DDouble pa, pb;
11609 if (rt->
m_width != wxPENSTYLE_INVALID)
11611 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11612 g_shipToActiveStyle, 5)];
11613 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11615 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11618 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11621 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11624 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11625 (
int)pb.m_y, GetVP(),
true);
11629#ifdef USE_ANDROID_GLES2
11630 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11632 if (style != wxPENSTYLE_SOLID) {
11633 if (glChartCanvas::dash_map.find(style) !=
11634 glChartCanvas::dash_map.end()) {
11635 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11639 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11642 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11643 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11649void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11651 if (m_routeState >= 2) route = m_pMouseRoute;
11652 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11653 route = m_pMeasureRoute;
11655 if (!route)
return;
11663 int np = route->GetnPoints();
11665 if (g_btouch && (np > 1)) np--;
11667 render_lat = rp.m_lat;
11668 render_lon = rp.m_lon;
11671 double rhumbBearing, rhumbDist;
11673 &rhumbBearing, &rhumbDist);
11674 double brg = rhumbBearing;
11675 double dist = rhumbDist;
11679 double gcBearing, gcBearing2, gcDist;
11680 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11683 double gcDistm = gcDist / 1852.0;
11686 rhumbBearing = 90.;
11688 wxPoint destPoint, lastPoint;
11691 int milesDiff = rhumbDist - gcDistm;
11692 if (milesDiff > 1) {
11703 for (
int i = 1; i <= milesDiff; i++) {
11704 double p = (double)i * (1.0 / (
double)milesDiff);
11706 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11707 &pLon, &pLat, &gcBearing2);
11709 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11711 lastPoint = destPoint;
11714 if (r_rband.x && r_rband.y) {
11715 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11717 if (m_bMeasure_DistCircle) {
11718 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11719 powf((
float)(r_rband.y - lastPoint.y), 2));
11722 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11723 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11729 wxString routeInfo;
11730 wxArrayString infoArray;
11733 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11739 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11741 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11742 (
int)varBrg, 0x00B0);
11745 infoArray.Add(routeInfo);
11751 routeInfo <<
"Reverse: ";
11753 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11754 (
int)(brg + 180.) % 360, 0x00B0);
11756 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11757 (
int)(varBrg + 180.) % 360, 0x00B0);
11758 infoArray.Add(routeInfo);
11764 s0.Append(_(
"Route") +
": ");
11766 s0.Append(_(
"Layer Route: "));
11769 if (!g_btouch) disp_length += dist;
11775 RouteLegInfo(dc, r_rband, infoArray);
11777 m_brepaint_piano =
true;
11780void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11781 if (!m_bShowVisibleSectors)
return;
11783 if (g_bDeferredInitDone) {
11785 double rhumbBearing, rhumbDist;
11786 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11787 &rhumbBearing, &rhumbDist);
11789 if (rhumbDist > 0.05)
11791 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11792 m_sectorlegsVisible);
11793 m_sector_glat =
gLat;
11794 m_sector_glon =
gLon;
11796 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11800void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11808void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11809 if (!ps52plib)
return;
11811 if (VPoint.b_quilt) {
11812 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11814 if (m_pQuilt->IsQuiltVector()) {
11815 if (ps52plib->GetStateHash() != m_s52StateHash) {
11817 m_s52StateHash = ps52plib->GetStateHash();
11821 if (ps52plib->GetStateHash() != m_s52StateHash) {
11823 m_s52StateHash = ps52plib->GetStateHash();
11828 bool bSendPlibState =
true;
11829 if (VPoint.b_quilt) {
11830 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11833 if (bSendPlibState) {
11835 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11836 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11837 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11838 v[
"OpenCPN Version Date"] = VERSION_DATE;
11839 v[
"OpenCPN Version Full"] = VERSION_FULL;
11842 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11843 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11844 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11845 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11846 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11847 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11848 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11852 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11853 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11857 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11858 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11859 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11860 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11861 ps52plib->m_bShowS57ImportantTextOnly;
11862 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11863 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11864 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11865 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11866 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11869 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11870 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11871 v[
"OpenCPN Scale Factor Exp"] =
11872 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11879 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11880 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11881 g_lastS52PLIBPluginMessage = out;
11888 wxPaintDC dc(
this);
11898 if (!m_b_paint_enable) {
11906 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11908 if (m_glcc && g_bopengl) {
11909 if (!s_in_update) {
11919 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11921 wxRegion ru = GetUpdateRegion();
11923 int rx, ry, rwidth, rheight;
11924 ru.GetBox(rx, ry, rwidth, rheight);
11926#ifdef ocpnUSE_DIBSECTION
11929 wxMemoryDC temp_dc;
11937 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11938 height += m_Piano->GetHeight();
11940 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11944 int thumbx, thumby, thumbsx, thumbsy;
11945 pthumbwin->GetPosition(&thumbx, &thumby);
11946 pthumbwin->GetSize(&thumbsx, &thumbsy);
11947 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11950 rgn_chart.Subtract(rgn_thumbwin);
11951 ru.Subtract(rgn_thumbwin);
11957 wxRegion rgn_blit = ru;
11958 if (g_bShowChartBar) {
11959 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11960 GetClientSize().x, m_Piano->GetHeight());
11963 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11964 if (style->chartStatusWindowTransparent)
11965 m_brepaint_piano =
true;
11967 ru.Subtract(chart_bar_rect);
11971 if (m_Compass && m_Compass->IsShown()) {
11972 wxRect compassRect = m_Compass->
GetRect();
11973 if (ru.Contains(compassRect) != wxOutRegion) {
11974 ru.Subtract(compassRect);
11978 if (m_notification_button) {
11979 wxRect noteRect = m_notification_button->
GetRect();
11980 if (ru.Contains(noteRect) != wxOutRegion) {
11981 ru.Subtract(noteRect);
11986 bool b_newview =
true;
11991 m_cache_vp.IsValid()) {
11997 bool b_rcache_ok =
false;
11998 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11999 b_rcache_ok = !b_newview;
12002 if (VPoint.b_MercatorProjectionOverride)
12003 VPoint.SetProjectionType(PROJECTION_MERCATOR);
12017 if (b_rcache_ok) chart_get_region.Clear();
12020 if (VPoint.b_quilt)
12022 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
12024 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
12029 AbstractPlatform::ShowBusySpinner();
12033 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
12034 (m_working_bm.GetHeight() != svp.
pix_height))
12038 if (fabs(VPoint.
rotation) < 0.01) {
12039 bool b_save =
true;
12044 m_cache_vp.Invalidate();
12058 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12063 int dy = c_new.y - c_old.y;
12064 int dx = c_new.x - c_old.x;
12069 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12073 temp_dc.SelectObject(m_working_bm);
12075 wxMemoryDC cache_dc;
12076 cache_dc.SelectObject(m_cached_chart_bm);
12080 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12083 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12089 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12092 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12100 update_region.Union(
12103 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12108 update_region.Union(
12111 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12115 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12117 cache_dc.SelectObject(wxNullBitmap);
12121 temp_dc.SelectObject(m_cached_chart_bm);
12124 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12128 temp_dc.SelectObject(m_working_bm);
12129 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12134 temp_dc.SelectObject(m_cached_chart_bm);
12139 temp_dc.SelectObject(m_working_bm);
12140 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12153 wxMemoryDC scratch_dc_0;
12154 scratch_dc_0.SelectObject(m_cached_chart_bm);
12157 scratch_dc_0.SelectObject(wxNullBitmap);
12166 temp_dc.SelectObject(m_working_bm);
12169 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12170 chart_get_all_region);
12173 AbstractPlatform::HideBusySpinner();
12179 if (!m_singleChart) {
12180 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12185 if (!chart_get_region.IsEmpty()) {
12186 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12190 if (temp_dc.IsOk()) {
12195 if (!VPoint.b_quilt) {
12198 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12199 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12206 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12207 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12210 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12212 temp_dc.DestroyClippingRegion();
12217 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12219 if (!backgroundRegion.IsEmpty()) {
12225 wxColour water = pWorldBackgroundChart->water;
12226 if (water.IsOk()) {
12227 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12228 temp_dc.SetBrush(wxBrush(water));
12230 while (upd.HaveRects()) {
12231 wxRect rect = upd.GetRect();
12232 temp_dc.DrawRectangle(rect);
12237 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12238 temp_dc.SetDeviceClippingRegion(*clip_region);
12239 delete clip_region;
12243 SetVPRotation(VPoint.
skew);
12252 wxMemoryDC *pChartDC = &temp_dc;
12253 wxMemoryDC rotd_dc;
12255 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12257 if (!b_rcache_ok) {
12259 wxMemoryDC tbase_dc;
12261 tbase_dc.SelectObject(bm_base);
12263 tbase_dc.SelectObject(wxNullBitmap);
12265 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12268 wxImage base_image;
12269 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12277 bool b_rot_ok =
false;
12278 if (base_image.IsOk()) {
12281 m_b_rot_hidef =
false;
12285 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12286 m_b_rot_hidef, &m_roffset);
12291 rot_vp.IsValid() && (ri.IsOk())) {
12298 m_prot_bm =
new wxBitmap(ri);
12301 m_roffset.x += VPoint.rv_rect.x;
12302 m_roffset.y += VPoint.rv_rect.y;
12305 if (m_prot_bm && m_prot_bm->IsOk()) {
12306 rotd_dc.SelectObject(*m_prot_bm);
12307 pChartDC = &rotd_dc;
12309 pChartDC = &temp_dc;
12310 m_roffset = wxPoint(0, 0);
12313 pChartDC = &temp_dc;
12314 m_roffset = wxPoint(0, 0);
12317 wxPoint offset = m_roffset;
12320 m_cache_vp = VPoint;
12323 wxMemoryDC mscratch_dc;
12324 mscratch_dc.SelectObject(*pscratch_bm);
12326 mscratch_dc.ResetBoundingBox();
12327 mscratch_dc.DestroyClippingRegion();
12328 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12331 wxRegionIterator upd(rgn_blit);
12333 wxRect rect = upd.GetRect();
12335 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12336 rect.x - offset.x, rect.y - offset.y);
12342 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12343 if (
this == wxWindow::FindFocus()) {
12346 wxColour colour = GetGlobalColor(
"BLUE4");
12347 mscratch_dc.SetPen(wxPen(colour));
12348 mscratch_dc.SetBrush(wxBrush(colour));
12350 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12351 mscratch_dc.DrawRectangle(activeRect);
12356 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12357 unsigned int im = stackIndexArray.size();
12358 if (VPoint.b_quilt && im > 0) {
12359 std::vector<int> tiles_to_show;
12360 for (
unsigned int is = 0; is < im; is++) {
12362 ChartData->GetChartTableEntry(stackIndexArray[is]);
12363 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12366 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12367 tiles_to_show.push_back(stackIndexArray[is]);
12371 if (tiles_to_show.size())
12372 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12378 ocpnDC scratch_dc(mscratch_dc);
12379 RenderAlertMessage(mscratch_dc, GetVP());
12385#ifdef ocpnUSE_DIBSECTION
12390 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12391 q_dc.SelectObject(qbm);
12394 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12397 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12398 q_dc.SetBrush(qbr);
12399 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12402 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12405 q_dc.SelectObject(wxNullBitmap);
12414 if( VPoint.b_quilt ) {
12415 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12416 ChartBase *chart = m_pQuilt->GetRefChart();
12417 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12422 ChPI->ClearPLIBTextList();
12425 ps52plib->ClearTextList();
12429 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12431 wxColor maskBackground = wxColour(1,0,0);
12432 t_dc.SelectObject( qbm );
12433 t_dc.SetBackground(wxBrush(maskBackground));
12437 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12440 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12441 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12444 wxRegionIterator upd_final( ru );
12445 while( upd_final ) {
12446 wxRect rect = upd_final.GetRect();
12447 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12451 t_dc.SelectObject( wxNullBitmap );
12457 if (VPoint.b_quilt) {
12458 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12459 ChartBase *chart = m_pQuilt->GetRefChart();
12460 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12464 ChPI->ClearPLIBTextList();
12466 if (ps52plib) ps52plib->ClearTextList();
12471 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12473 if (g_bShowChartBar && m_Piano) {
12474 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12475 GetVP().pix_width, m_Piano->GetHeight());
12478 if (!style->chartStatusWindowTransparent)
12479 chart_all_text_region.Subtract(chart_bar_rect);
12482 if (m_Compass && m_Compass->IsShown()) {
12483 wxRect compassRect = m_Compass->
GetRect();
12484 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12485 chart_all_text_region.Subtract(compassRect);
12489 mscratch_dc.DestroyClippingRegion();
12491 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12492 chart_all_text_region);
12498 ocpnDC scratch_dc(mscratch_dc);
12499 DrawOverlayObjects(scratch_dc, ru);
12502 wxRegionIterator upd_final(rgn_blit);
12503 while (upd_final) {
12504 wxRect rect = upd_final.GetRect();
12505 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12512 temp_dc.SelectObject(wxNullBitmap);
12514 mscratch_dc.SelectObject(wxNullBitmap);
12516 dc.DestroyClippingRegion();
12521void ChartCanvas::PaintCleanup() {
12523 if (m_inPinch)
return;
12534 m_bTCupdate =
false;
12538 WarpPointer(warp_x, warp_y);
12545 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12546 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12550wxColour GetErrorGraphicColor(
double val)
12569 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12570 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12571 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12572 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12573 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12574 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12575 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12576 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12577 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12578 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12579 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12580 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12581 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12582 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12583 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12584 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12585 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12586 else if( val >= 48) c.Set(
"#410000");
12591void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12594 gr_image.InitAlpha();
12596 double maxval = -10000;
12597 double minval = 10000;
12614 maxval = wxMax(maxval, (glat - rlat));
12615 minval = wxMin(minval, (glat - rlat));
12632 double f = ((glat - rlat)-minval)/(maxval - minval);
12634 double dy = (f * 40);
12636 wxColour c = GetErrorGraphicColor(dy);
12637 unsigned char r = c.Red();
12638 unsigned char g = c.Green();
12639 unsigned char b = c.Blue();
12641 gr_image.SetRGB(j, i, r,g,b);
12642 if((glat - rlat )!= 0)
12643 gr_image.SetAlpha(j, i, 128);
12645 gr_image.SetAlpha(j, i, 255);
12652 wxBitmap *pbm =
new wxBitmap(gr_image);
12653 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12654 pbm->SetMask(gr_mask);
12656 pmdc->DrawBitmap(*pbm, 0,0);
12664void ChartCanvas::CancelMouseRoute() {
12666 m_pMouseRoute = NULL;
12667 m_bDrawingRoute =
false;
12670int ChartCanvas::GetNextContextMenuId() {
12671 return CanvasMenuHandler::GetNextContextMenuId();
12674bool ChartCanvas::SetCursor(
const wxCursor &c) {
12676 if (g_bopengl && m_glcc)
12677 return m_glcc->SetCursor(c);
12680 return wxWindow::SetCursor(c);
12683void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12684 if (g_bquiting)
return;
12694 if (!m_RolloverPopupTimer.IsRunning() &&
12695 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12696 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12697 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12698 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12701 if (m_glcc && g_bopengl) {
12704 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12706 m_glcc->Refresh(eraseBackground,
12723 if (m_pCIWin && m_pCIWin->IsShown()) {
12725 m_pCIWin->Refresh(
false);
12733 wxWindow::Refresh(eraseBackground, rect);
12736void ChartCanvas::Update() {
12737 if (m_glcc && g_bopengl) {
12742 wxWindow::Update();
12746 if (!pemboss)
return;
12747 int x = pemboss->x, y = pemboss->y;
12748 const double factor = 200;
12750 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12751 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12752 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12755 wxMemoryDC snip_dc;
12756 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12757 snip_dc.SelectObject(snip_bmp);
12759 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12760 snip_dc.SelectObject(wxNullBitmap);
12762 wxImage snip_img = snip_bmp.ConvertToImage();
12765 unsigned char *pdata = snip_img.GetData();
12767 for (
int y = 0; y < pemboss->height; y++) {
12768 int map_index = (y * pemboss->width);
12769 for (
int x = 0; x < pemboss->width; x++) {
12770 double val = (pemboss->pmap[map_index] * factor) / 256.;
12772 int nred = (int)((*pdata) + val);
12773 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12774 *pdata++ = (
unsigned char)nred;
12776 int ngreen = (int)((*pdata) + val);
12777 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12778 *pdata++ = (
unsigned char)ngreen;
12780 int nblue = (int)((*pdata) + val);
12781 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12782 *pdata++ = (
unsigned char)nblue;
12790 wxBitmap emb_bmp(snip_img);
12793 wxMemoryDC result_dc;
12794 result_dc.SelectObject(emb_bmp);
12797 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12799 result_dc.SelectObject(wxNullBitmap);
12805 if (GetQuiltMode()) {
12807 int refIndex = GetQuiltRefChartdbIndex();
12808 if (refIndex >= 0) {
12810 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12811 if (current_type == CHART_TYPE_MBTILES) {
12812 ChartBase *pChart = m_pQuilt->GetRefChart();
12815 zoom_factor = ptc->GetZoomFactor();
12820 if (zoom_factor <= 3.9)
return NULL;
12822 if (m_singleChart) {
12823 if (zoom_factor <= 3.9)
return NULL;
12828 if (m_pEM_OverZoom) {
12829 m_pEM_OverZoom->x = 4;
12830 m_pEM_OverZoom->y = 0;
12832 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12833 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12836 return m_pEM_OverZoom;
12839void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12852 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12853 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12857 AISDrawAreaNotices(dc, GetVP(),
this);
12859 wxDC *pdc = dc.GetDC();
12861 pdc->DestroyClippingRegion();
12862 wxDCClipper(*pdc, ru);
12865 if (m_bShowNavobjects) {
12866 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12867 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12868 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12869 DrawAnchorWatchPoints(dc);
12871 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12872 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12875 AISDraw(dc, GetVP(),
this);
12879 RenderVisibleSectorLights(dc);
12881 RenderAllChartOutlines(dc, GetVP());
12882 RenderRouteLegs(dc);
12883 RenderShipToActive(dc,
false);
12885 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12887 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12891 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12892 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12895 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12900 RebuildTideSelectList(GetVP().GetBBox());
12901 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12904 if (m_bShowCurrent) {
12905 RebuildCurrentSelectList(GetVP().GetBBox());
12906 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12909 if (!g_PrintingInProgress) {
12910 if (IsPrimaryCanvas()) {
12914 if (IsPrimaryCanvas()) {
12918 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12920 if (m_pTrackRolloverWin) {
12921 m_pTrackRolloverWin->Draw(dc);
12922 m_brepaint_piano =
true;
12925 if (m_pRouteRolloverWin) {
12926 m_pRouteRolloverWin->Draw(dc);
12927 m_brepaint_piano =
true;
12930 if (m_pAISRolloverWin) {
12931 m_pAISRolloverWin->Draw(dc);
12932 m_brepaint_piano =
true;
12934 if (m_brepaint_piano && g_bShowChartBar) {
12935 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12938 if (m_Compass) m_Compass->Paint(dc);
12940 if (!g_CanvasHideNotificationIcon) {
12941 if (IsPrimaryCanvas()) {
12942 auto ¬eman = NotificationManager::GetInstance();
12943 if (m_notification_button) {
12944 if (noteman.GetNotificationCount()) {
12945 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12946 if (m_notification_button->UpdateStatus()) Refresh();
12947 m_notification_button->Show(
true);
12948 m_notification_button->Paint(dc);
12950 m_notification_button->Show(
false);
12957 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12963 if (!m_bShowDepthUnits)
return NULL;
12965 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12967 if (GetQuiltMode()) {
12968 wxString s = m_pQuilt->GetQuiltDepthUnit();
12971 depth_unit_type = DEPTH_UNIT_FEET;
12972 else if (s.StartsWith(
"FATHOMS"))
12973 depth_unit_type = DEPTH_UNIT_FATHOMS;
12974 else if (s.StartsWith(
"METERS"))
12975 depth_unit_type = DEPTH_UNIT_METERS;
12976 else if (s.StartsWith(
"METRES"))
12977 depth_unit_type = DEPTH_UNIT_METERS;
12978 else if (s.StartsWith(
"METRIC"))
12979 depth_unit_type = DEPTH_UNIT_METERS;
12980 else if (s.StartsWith(
"METER"))
12981 depth_unit_type = DEPTH_UNIT_METERS;
12984 if (m_singleChart) {
12985 depth_unit_type = m_singleChart->GetDepthUnitType();
12986 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12987 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12992 switch (depth_unit_type) {
12993 case DEPTH_UNIT_FEET:
12996 case DEPTH_UNIT_METERS:
12997 ped = m_pEM_Meters;
12999 case DEPTH_UNIT_FATHOMS:
13000 ped = m_pEM_Fathoms;
13006 ped->x = (GetVP().
pix_width - ped->width);
13008 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
13009 wxRect r = m_Compass->
GetRect();
13010 ped->y = r.y + r.height;
13017void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
13020 if (style->embossFont == wxEmptyString) {
13021 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13023 font.SetPointSize(60);
13024 font.SetWeight(wxFONTWEIGHT_BOLD);
13026 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13027 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13029 int emboss_width = 500;
13030 int emboss_height = 200;
13034 delete m_pEM_Meters;
13035 delete m_pEM_Fathoms;
13039 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
13041 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
13043 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
13046#define OVERZOOM_TEXT _("OverZoom")
13048void ChartCanvas::SetOverzoomFont() {
13053 if (style->embossFont == wxEmptyString) {
13054 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13056 font.SetPointSize(40);
13057 font.SetWeight(wxFONTWEIGHT_BOLD);
13059 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13060 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13062 wxClientDC dc(
this);
13064 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13066 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13067 font.SetPointSize(font.GetPointSize() - 1);
13069 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13071 m_overzoomFont = font;
13072 m_overzoomTextWidth = w;
13073 m_overzoomTextHeight = h;
13076void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13077 delete m_pEM_OverZoom;
13079 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13081 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13082 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13085emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13086 int height,
const wxString &str,
13091 wxBitmap bmp(width, height, -1);
13094 wxMemoryDC temp_dc;
13095 temp_dc.SelectObject(bmp);
13098 temp_dc.SetBackground(*wxWHITE_BRUSH);
13099 temp_dc.SetTextBackground(*wxWHITE);
13100 temp_dc.SetTextForeground(*wxBLACK);
13104 temp_dc.SetFont(font);
13107 temp_dc.GetTextExtent(str, &str_w, &str_h);
13109 temp_dc.DrawText(str, 1, 1);
13112 temp_dc.SelectObject(wxNullBitmap);
13115 wxImage img = bmp.ConvertToImage();
13117 int image_width = str_w * 105 / 100;
13118 int image_height = str_h * 105 / 100;
13119 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13120 wxMin(image_height, img.GetHeight()));
13121 wxImage imgs = img.GetSubImage(r);
13125 case GLOBAL_COLOR_SCHEME_DAY:
13129 case GLOBAL_COLOR_SCHEME_DUSK:
13132 case GLOBAL_COLOR_SCHEME_NIGHT:
13139 const int w = imgs.GetWidth();
13140 const int h = imgs.GetHeight();
13141 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13146 for (
int y = 1; y < h - 1; y++) {
13147 for (
int x = 1; x < w - 1; x++) {
13149 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13150 val = (int)(val * val_factor);
13151 index = (y * w) + x;
13164void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13165 Track *active_track = NULL;
13168 active_track = pTrackDraw;
13172 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13175 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13178void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13179 Track *active_track = NULL;
13182 active_track = pTrackDraw;
13186 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13189void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13190 Route *active_route = NULL;
13192 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13193 active_route = pRouteDraw;
13198 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13203 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13206void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13207 Route *active_route = NULL;
13210 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13211 active_route = pRouteDraw;
13215 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13218void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13219 if (!pWayPointMan)
return;
13221 auto node = pWayPointMan->GetWaypointList()->begin();
13223 while (node != pWayPointMan->GetWaypointList()->end()) {
13232 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13236 if (pWP->GetShowWaypointRangeRings() &&
13237 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13238 double factor = 1.00;
13239 if (pWP->GetWaypointRangeRingsStepUnits() ==
13241 factor = 1 / 1.852;
13243 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13244 pWP->GetWaypointRangeRingsStep() / 60.;
13248 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13249 pWP->m_lat + radius, pWP->m_lon + radius);
13250 if (!BltBBox.IntersectOut(radar_box)) {
13261void ChartCanvas::DrawBlinkObjects() {
13263 wxRect update_rect;
13265 if (!pWayPointMan)
return;
13267 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13274 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13277void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13282 wxPoint lAnchorPoint1, lAnchorPoint2;
13296 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13297 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13299 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13300 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13301 dc.SetBrush(*ppBrush);
13305 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13310 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13315 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13320 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13325double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13328 wxPoint lAnchorPoint;
13331 double tlat1, tlon1;
13333 if (pAnchorWatchPoint) {
13334 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13336 dabs = fabs(d1 / 1852.);
13337 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13342 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13343 pow((
double)(lAnchorPoint.y - r1.y), 2));
13346 if (d1 < 0) lpp = -lpp;
13354void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13356 if (
this != wxWindow::FindFocus())
return;
13358 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13360 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13366 if ((type ==
't') || (type ==
'T')) {
13367 if (BBox.Contains(lat, lon)) {
13369 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13375void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13378 wxDateTime this_now = gTimeSource;
13379 bool cur_time = !gTimeSource.IsValid();
13380 if (cur_time) this_now = wxDateTime::Now();
13381 time_t t_this_now = this_now.GetTicks();
13383 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13385 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13386 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13387 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13388 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13390 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13391 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13392 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13393 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13394 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13395 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13397 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13398 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13399 int font_size = wxMax(10, dFont->GetPointSize());
13402 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13403 false, dFont->GetFaceName());
13405 dc.SetPen(*pblack_pen);
13406 dc.SetBrush(*pgreen_brush);
13410 case GLOBAL_COLOR_SCHEME_DAY:
13413 case GLOBAL_COLOR_SCHEME_DUSK:
13416 case GLOBAL_COLOR_SCHEME_NIGHT:
13417 bm = m_bmTideNight;
13424 int bmw = bm.GetWidth();
13425 int bmh = bm.GetHeight();
13427 float scale_factor = 1.0;
13431 float icon_pixelRefDim = 45;
13436 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13438 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13440 scale_factor *= pix_factor;
13447 scale_factor *= user_scale_factor;
13448 scale_factor *= GetContentScaleFactor();
13451 double marge = 0.05;
13452 std::vector<LLBBox> drawn_boxes;
13453 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13457 if ((type ==
't') || (type ==
'T'))
13462 if (BBox.ContainsMarge(lat, lon, marge)) {
13464 if (GetVP().chart_scale < 500000) {
13465 bool bdrawn =
false;
13466 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13467 if (drawn_boxes[i].Contains(lat, lon)) {
13472 if (bdrawn)
continue;
13475 this_box.Set(lat, lon, lat, lon);
13476 this_box.EnLarge(.005);
13477 drawn_boxes.push_back(this_box);
13483 if (GetVP().chart_scale > 500000) {
13484 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13488 dc.SetFont(*plabelFont);
13500 if (
ptcmgr->GetTideFlowSens(
13501 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13505 ptcmgr->GetHightOrLowTide(
13506 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13507 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13519 if (tctime > t_this_now)
13520 ptcmgr->GetHightOrLowTide(
13521 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13522 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13526 ptcmgr->GetHightOrLowTide(
13527 t_this_now, FORWARD_TEN_MINUTES_STEP,
13528 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13542 int width = (int)(12 * scale_factor + 0.5);
13543 int height = (int)(45 * scale_factor + 0.5);
13544 int linew = wxMax(1, (
int)(scale_factor));
13545 int xDraw = r.x - (width / 2);
13546 int yDraw = r.y - (height / 2);
13549 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13550 int hs = (httime > lttime) ? -4 : 4;
13551 hs *= (int)(scale_factor + 0.5);
13552 if (ts > 0.995 || ts < 0.005) hs = 0;
13553 int ht_y = (int)(height * ts);
13556 pblack_pen->SetWidth(linew);
13557 dc.SetPen(*pblack_pen);
13558 dc.SetBrush(*pyelo_brush);
13559 dc.DrawRectangle(xDraw, yDraw, width, height);
13563 dc.SetPen(*pblue_pen);
13564 dc.SetBrush(*pblue_brush);
13565 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13566 (width - (4 * linew)), height - ht_y);
13572 arrow[0].x = xDraw + 2 * linew;
13573 arrow[1].x = xDraw + width / 2;
13574 arrow[2].x = xDraw + width - 2 * linew;
13575 pyelo_pen->SetWidth(linew);
13576 pblue_pen->SetWidth(linew);
13577 if (ts > 0.35 || ts < 0.15)
13579 hl = (int)(height * 0.25) + 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.60 || ts < 0.40)
13591 hl = (int)(height * 0.5) + yDraw;
13593 arrow[1].y = hl + hs;
13596 dc.SetPen(*pyelo_pen);
13598 dc.SetPen(*pblue_pen);
13599 dc.DrawLines(3, arrow);
13601 if (ts < 0.65 || ts > 0.85)
13603 hl = (int)(height * 0.75) + yDraw;
13605 arrow[1].y = hl + hs;
13608 dc.SetPen(*pyelo_pen);
13610 dc.SetPen(*pblue_pen);
13611 dc.DrawLines(3, arrow);
13615 double nowlev_converted = nowlev;
13619 int unit_c = TCDataFactory::findunit(pmsd->unit);
13623 TCDataFactory::known_units[unit_c].conv_factor;
13626 nowlev_converted =
toUsrHeight(nowlev_converted);
13630 s.Printf(
"%3.1f", nowlev_converted);
13634 dc.GetTextExtent(s, &wx1, NULL);
13636 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13651void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13654 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13656 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13662 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13663 if ((BBox.Contains(lat, lon))) {
13665 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13671void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13674 float tcvalue, dir;
13678 double lon_last = 0.;
13679 double lat_last = 0.;
13681 double marge = 0.2;
13682 bool cur_time = !gTimeSource.IsValid();
13684 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13685 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13687 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13689 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13690 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13691 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13692 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13693 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13694 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13695 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13696 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13698 double skew_angle = GetVPRotation();
13700 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13701 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13702 int font_size = wxMax(10, dFont->GetPointSize());
13705 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13706 false, dFont->GetFaceName());
13708 float scale_factor = 1.0;
13714 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13716 float nominal_icon_size_pixels = 15;
13717 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13719 scale_factor *= pix_factor;
13726 scale_factor *= user_scale_factor;
13728 scale_factor *= GetContentScaleFactor();
13731 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13737 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13738 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13743 int dd = (int)(5.0 * scale_factor + 0.5);
13754 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13755 dc.SetPen(*pblack_pen);
13756 dc.SetBrush(*porange_brush);
13757 dc.DrawPolygon(4, d);
13760 dc.SetBrush(*pblack_brush);
13761 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13765 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13779 double a1 = fabs(tcvalue) * 10.;
13781 a1 = wxMax(1.0, a1);
13782 double a2 = log10(a1);
13784 float cscale = scale_factor * a2 * 0.3;
13786 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13787 dc.SetPen(*porange_pen);
13788 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13792 if (bDrawCurrentValues) {
13793 dc.SetFont(*pTCFont);
13794 tcvalue = toUsrSpeed(tcvalue);
13795 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13796 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13822 if (!pvIDX)
return;
13827 if (pCwin && pCwin->IsShown()) {
13835 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13850 pCwin =
new TCWin(
this, x, y, pvIDX);
13868#define NUM_CURRENT_ARROW_POINTS 9
13869static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13870 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13871 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13872 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13874void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13876 if (
scale > 1e-2) {
13877 float sin_rot = sin(rot_angle * PI / 180.);
13878 float cos_rot = cos(rot_angle * PI / 180.);
13882 float xt = CurrentArrowArray[0].x;
13883 float yt = CurrentArrowArray[0].y;
13885 float xp = (xt * cos_rot) - (yt * sin_rot);
13886 float yp = (xt * sin_rot) + (yt * cos_rot);
13887 int x1 = (int)(xp *
scale);
13888 int y1 = (int)(yp *
scale);
13891 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13892 xt = CurrentArrowArray[ip].x;
13893 yt = CurrentArrowArray[ip].y;
13895 float xp = (xt * cos_rot) - (yt * sin_rot);
13896 float yp = (xt * sin_rot) + (yt * cos_rot);
13897 int x2 = (int)(xp *
scale);
13898 int y2 = (int)(yp *
scale);
13900 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13908wxString ChartCanvas::FindValidUploadPort() {
13911 if (!g_uploadConnection.IsEmpty() &&
13912 g_uploadConnection.StartsWith(
"Serial")) {
13913 port = g_uploadConnection;
13919 for (
auto *cp : TheConnectionParams()) {
13920 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13921 port <<
"Serial:" << cp->Port;
13927void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13930 if (NULL == g_pais_query_dialog_active) {
13931 int pos_x = g_ais_query_dialog_x;
13932 int pos_y = g_ais_query_dialog_y;
13934 if (g_pais_query_dialog_active) {
13935 g_pais_query_dialog_active->Destroy();
13941 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13942 wxPoint(pos_x, pos_y));
13944 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13945 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13946 g_pais_query_dialog_active->SetMMSI(mmsi);
13947 g_pais_query_dialog_active->UpdateText();
13948 wxSize sz = g_pais_query_dialog_active->GetSize();
13950 bool b_reset_pos =
false;
13955 RECT frame_title_rect;
13956 frame_title_rect.left = pos_x;
13957 frame_title_rect.top = pos_y;
13958 frame_title_rect.right = pos_x + sz.x;
13959 frame_title_rect.bottom = pos_y + 30;
13961 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13962 b_reset_pos =
true;
13967 wxRect window_title_rect;
13968 window_title_rect.x = pos_x;
13969 window_title_rect.y = pos_y;
13970 window_title_rect.width = sz.x;
13971 window_title_rect.height = 30;
13973 wxRect ClientRect = wxGetClientDisplayRect();
13974 ClientRect.Deflate(
13976 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13980 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13983 g_pais_query_dialog_active->SetMMSI(mmsi);
13984 g_pais_query_dialog_active->UpdateText();
13987 g_pais_query_dialog_active->Show();
13990void ChartCanvas::ToggleCanvasQuiltMode() {
13991 bool cur_mode = GetQuiltMode();
13993 if (!GetQuiltMode())
13994 SetQuiltMode(
true);
13995 else if (GetQuiltMode()) {
13996 SetQuiltMode(
false);
13997 g_sticky_chart = GetQuiltReferenceChartIndex();
14000 if (cur_mode != GetQuiltMode()) {
14001 SetupCanvasQuiltMode();
14010 if (ps52plib) ps52plib->GenerateStateHash();
14012 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14013 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14016void ChartCanvas::DoCanvasStackDelta(
int direction) {
14017 if (!GetQuiltMode()) {
14018 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
14019 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
14020 if ((current_stack_index + direction) < 0)
return;
14022 if (m_bpersistent_quilt ) {
14024 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
14026 if (IsChartQuiltableRef(new_dbIndex)) {
14027 ToggleCanvasQuiltMode();
14028 SelectQuiltRefdbChart(new_dbIndex);
14029 m_bpersistent_quilt =
false;
14032 SelectChartFromStack(current_stack_index + direction);
14035 std::vector<int> piano_chart_index_array =
14036 GetQuiltExtendedStackdbIndexArray();
14037 int refdb = GetQuiltRefChartdbIndex();
14040 int current_index = -1;
14041 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14042 if (refdb == piano_chart_index_array[i]) {
14047 if (current_index == -1)
return;
14050 int target_family = ctet.GetChartFamily();
14052 int new_index = -1;
14053 int check_index = current_index + direction;
14054 bool found =
false;
14055 int check_dbIndex = -1;
14056 int new_dbIndex = -1;
14060 (
unsigned int)check_index < piano_chart_index_array.size() &&
14061 (check_index >= 0)) {
14062 check_dbIndex = piano_chart_index_array[check_index];
14064 if (target_family == cte.GetChartFamily()) {
14066 new_index = check_index;
14067 new_dbIndex = check_dbIndex;
14071 check_index += direction;
14074 if (!found)
return;
14076 if (!IsChartQuiltableRef(new_dbIndex)) {
14077 ToggleCanvasQuiltMode();
14078 SelectdbChart(new_dbIndex);
14079 m_bpersistent_quilt =
true;
14081 SelectQuiltRefChart(new_index);
14086 top_frame::Get()->UpdateGlobalMenuItems();
14087 SetQuiltChartHiLiteIndex(-1);
14098void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14101 switch (event.GetId()) {
14113 DoCanvasStackDelta(1);
14118 DoCanvasStackDelta(-1);
14128 ShowCurrents(!GetbShowCurrent());
14135 ShowTides(!GetbShowTide());
14142 if (0 == m_routeState) {
14149 androidSetRouteAnnunciator(m_routeState == 1);
14155 SetAISCanvasDisplayStyle(-1);
14167void ChartCanvas::SetShowAIS(
bool show) {
14169 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14170 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14173void ChartCanvas::SetAttenAIS(
bool show) {
14174 m_bShowAISScaled = show;
14175 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14176 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14179void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14182 bool bShowAIS_Array[3] = {
true,
true,
false};
14183 bool bShowScaled_Array[3] = {
false,
true,
true};
14184 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14185 _(
"Attenuate less critical AIS targets"),
14186 _(
"Hide AIS Targets")};
14187 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14189 int AIS_Toolbar_Switch = 0;
14190 if (StyleIndx == -1) {
14192 for (
int i = 1; i < ArraySize; i++) {
14193 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14194 (bShowScaled_Array[i] == m_bShowAISScaled))
14195 AIS_Toolbar_Switch = i;
14197 AIS_Toolbar_Switch++;
14198 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14199 AIS_Toolbar_Switch++;
14202 AIS_Toolbar_Switch = StyleIndx;
14205 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14207 int AIS_Toolbar_Switch_Next =
14208 AIS_Toolbar_Switch + 1;
14209 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14210 AIS_Toolbar_Switch_Next++;
14211 if (AIS_Toolbar_Switch_Next >= ArraySize)
14212 AIS_Toolbar_Switch_Next = 0;
14215 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14216 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14219void ChartCanvas::TouchAISToolActive() {}
14221void ChartCanvas::UpdateAISTBTool() {}
14229void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14231 bool b_update =
false;
14232 int cc1_edge_comp = 2;
14233 wxRect rect = m_Compass->
GetRect();
14234 wxSize parent_size = GetSize();
14236 parent_size *= m_displayScale;
14240 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14241 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14242 wxRect compass_rect(compass_pt, rect.GetSize());
14244 m_Compass->Move(compass_pt);
14246 if (m_Compass && m_Compass->IsShown())
14247 m_Compass->UpdateStatus(b_force_new | b_update);
14249 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14250 scaler = wxMax(scaler, 1.0);
14251 wxPoint note_point = wxPoint(
14252 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14253 if (m_notification_button) {
14254 m_notification_button->Move(note_point);
14255 m_notification_button->UpdateStatus();
14258 if (b_force_new | b_update) Refresh();
14261void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14262 ChartTypeEnum New_Type,
14263 ChartFamilyEnum New_Family) {
14264 if (!GetpCurrentStack())
return;
14267 if (index < GetpCurrentStack()->nEntry) {
14270 pTentative_Chart =
ChartData->OpenStackChartConditional(
14271 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14273 if (pTentative_Chart) {
14274 if (m_singleChart) m_singleChart->Deactivate();
14276 m_singleChart = pTentative_Chart;
14277 m_singleChart->Activate();
14279 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14280 GetpCurrentStack(), m_singleChart->GetFullPath());
14293 double best_scale_ppm = GetBestVPScale(m_singleChart);
14294 double rotation = GetVPRotation();
14295 double oldskew = GetVPSkew();
14296 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14298 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14299 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14300 if (fabs(newskew) > 0.0001) rotation = newskew;
14303 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14305 UpdateGPSCompassStatusBox(
true);
14309 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14310 if (idx < 0)
return;
14312 std::vector<int> piano_active_chart_index_array;
14313 piano_active_chart_index_array.push_back(
14314 GetpCurrentStack()->GetCurrentEntrydbIndex());
14315 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14318void ChartCanvas::SelectdbChart(
int dbindex) {
14319 if (!GetpCurrentStack())
return;
14322 if (dbindex >= 0) {
14325 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14327 if (pTentative_Chart) {
14328 if (m_singleChart) m_singleChart->Deactivate();
14330 m_singleChart = pTentative_Chart;
14331 m_singleChart->Activate();
14333 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14334 GetpCurrentStack(), m_singleChart->GetFullPath());
14347 double best_scale_ppm = GetBestVPScale(m_singleChart);
14351 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14361void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14364 if (!GetQuiltMode()) {
14365 if (GetpCurrentStack()) {
14366 int stack_index = -1;
14367 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14368 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14369 if (check_dbIndex < 0)
continue;
14371 ChartData->GetChartTableEntry(check_dbIndex);
14372 if (type == cte.GetChartType()) {
14375 }
else if (family == cte.GetChartFamily()) {
14381 if (stack_index >= 0) {
14382 SelectChartFromStack(stack_index);
14386 int sel_dbIndex = -1;
14387 std::vector<int> piano_chart_index_array =
14388 GetQuiltExtendedStackdbIndexArray();
14389 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14390 int check_dbIndex = piano_chart_index_array[i];
14392 if (type == cte.GetChartType()) {
14393 if (IsChartQuiltableRef(check_dbIndex)) {
14394 sel_dbIndex = check_dbIndex;
14397 }
else if (family == cte.GetChartFamily()) {
14398 if (IsChartQuiltableRef(check_dbIndex)) {
14399 sel_dbIndex = check_dbIndex;
14405 if (sel_dbIndex >= 0) {
14406 SelectQuiltRefdbChart(sel_dbIndex,
false);
14408 AdjustQuiltRefChart();
14415 SetQuiltChartHiLiteIndex(-1);
14420bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14421 return std::find(m_tile_yesshow_index_array.begin(),
14422 m_tile_yesshow_index_array.end(),
14423 index) != m_tile_yesshow_index_array.end();
14426bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14427 return std::find(m_tile_noshow_index_array.begin(),
14428 m_tile_noshow_index_array.end(),
14429 index) != m_tile_noshow_index_array.end();
14432void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14433 if (std::find(m_tile_noshow_index_array.begin(),
14434 m_tile_noshow_index_array.end(),
14435 index) == m_tile_noshow_index_array.end()) {
14436 m_tile_noshow_index_array.push_back(index);
14446void ChartCanvas::HandlePianoClick(
14447 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14450 if (!m_pCurrentStack)
return;
14466 double distance = 25000;
14467 int closest_index = -1;
14468 for (
int chart_index : selected_dbIndex_array) {
14470 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14471 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14474 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14475 if (test_distance < distance) {
14476 distance = test_distance;
14477 closest_index = chart_index;
14481 int selected_dbIndex = selected_dbIndex_array[0];
14482 if (closest_index >= 0) selected_dbIndex = closest_index;
14484 if (!GetQuiltMode()) {
14485 if (m_bpersistent_quilt ) {
14486 if (IsChartQuiltableRef(selected_dbIndex)) {
14487 ToggleCanvasQuiltMode();
14488 SelectQuiltRefdbChart(selected_dbIndex);
14489 m_bpersistent_quilt =
false;
14491 SelectChartFromStack(selected_index);
14494 SelectChartFromStack(selected_index);
14495 g_sticky_chart = selected_dbIndex;
14499 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14503 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14504 bool bfound =
false;
14505 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14506 if (m_tile_noshow_index_array[i] ==
14507 selected_dbIndex) {
14508 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14515 m_tile_noshow_index_array.push_back(selected_dbIndex);
14519 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14520 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14524 if (IsChartQuiltableRef(selected_dbIndex)) {
14530 bool set_scale =
false;
14531 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14532 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14538 SelectQuiltRefdbChart(selected_dbIndex,
true);
14540 SelectQuiltRefdbChart(selected_dbIndex,
false);
14545 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14547 double proposed_scale_onscreen =
14550 if (g_bPreserveScaleOnX) {
14551 proposed_scale_onscreen =
14552 wxMin(proposed_scale_onscreen,
14554 GetCanvasWidth()));
14556 proposed_scale_onscreen =
14557 wxMin(proposed_scale_onscreen,
14559 GetCanvasWidth()));
14561 proposed_scale_onscreen =
14562 wxMax(proposed_scale_onscreen,
14571 ToggleCanvasQuiltMode();
14572 SelectdbChart(selected_dbIndex);
14573 m_bpersistent_quilt =
true;
14578 SetQuiltChartHiLiteIndex(-1);
14580 top_frame::Get()->UpdateGlobalMenuItems();
14581 HideChartInfoWindow();
14586void ChartCanvas::HandlePianoRClick(
14587 int x,
int y,
int selected_index,
14588 const std::vector<int> &selected_dbIndex_array) {
14591 if (!GetpCurrentStack())
return;
14593 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14594 UpdateCanvasControlBar();
14596 SetQuiltChartHiLiteIndex(-1);
14599void ChartCanvas::HandlePianoRollover(
14600 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14601 int n_charts,
int scale) {
14604 if (!GetpCurrentStack())
return;
14609 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14611 if (!GetQuiltMode()) {
14612 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14615 std::vector<int> piano_chart_index_array;
14616 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14617 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14618 if ((GetpCurrentStack()->nEntry > 1) ||
14619 (piano_chart_index_array.size() >= 1)) {
14620 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14622 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14624 }
else if (GetpCurrentStack()->nEntry == 1) {
14626 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14627 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14628 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14630 }
else if ((-1 == selected_index) &&
14631 (0 == selected_dbIndex_array.size())) {
14632 ShowChartInfoWindow(key_location.x, -1);
14636 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14638 if ((GetpCurrentStack()->nEntry > 1) ||
14639 (piano_chart_index_array.size() >= 1)) {
14641 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14642 selected_dbIndex_array);
14643 else if (n_charts == 1)
14644 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14646 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14653void ChartCanvas::ClearPianoRollover() {
14654 ClearQuiltChartHiLiteIndexArray();
14655 ShowChartInfoWindow(0, -1);
14656 std::vector<int> vec;
14657 ShowCompositeInfoWindow(0, 0, 0, vec);
14661void ChartCanvas::UpdateCanvasControlBar() {
14662 if (m_pianoFrozen)
return;
14664 if (!GetpCurrentStack())
return;
14666 if (!g_bShowChartBar)
return;
14669 int sel_family = -1;
14671 std::vector<int> piano_chart_index_array;
14672 std::vector<int> empty_piano_chart_index_array;
14674 wxString old_hash = m_Piano->GetStoredHash();
14676 if (GetQuiltMode()) {
14677 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14678 GetQuiltFullScreendbIndexArray());
14680 std::vector<int> piano_active_chart_index_array =
14681 GetQuiltCandidatedbIndexArray();
14682 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14684 std::vector<int> piano_eclipsed_chart_index_array =
14685 GetQuiltEclipsedStackdbIndexArray();
14686 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14688 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14689 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14691 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14692 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14694 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14695 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14698 if (m_singleChart) {
14699 sel_type = m_singleChart->GetChartType();
14700 sel_family = m_singleChart->GetChartFamily();
14705 std::vector<int> piano_skew_chart_index_array;
14706 std::vector<int> piano_tmerc_chart_index_array;
14707 std::vector<int> piano_poly_chart_index_array;
14709 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14711 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14712 double skew_norm = ctei.GetChartSkew();
14713 if (skew_norm > 180.) skew_norm -= 360.;
14715 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14716 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14719 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14720 if (fabs(skew_norm) > 1.)
14721 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14723 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14724 }
else if (fabs(skew_norm) > 1.)
14725 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14727 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14728 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14729 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14731 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14732 if (new_hash != old_hash) {
14733 m_Piano->FormatKeys();
14734 HideChartInfoWindow();
14735 m_Piano->ResetRollover();
14736 SetQuiltChartHiLiteIndex(-1);
14737 m_brepaint_piano =
true;
14743 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14745 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14746 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14747 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14748 if (e == CHART_FAMILY_RASTER) mask |= 1;
14749 if (e == CHART_FAMILY_VECTOR) {
14750 if (t == CHART_TYPE_CM93COMP)
14757 wxString s_indicated;
14758 if (sel_type == CHART_TYPE_CM93COMP)
14759 s_indicated =
"cm93";
14761 if (sel_family == CHART_FAMILY_RASTER)
14762 s_indicated =
"raster";
14763 else if (sel_family == CHART_FAMILY_VECTOR)
14764 s_indicated =
"vector";
14767 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14770void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14772void ChartCanvas::PianoPopupMenu(
14773 int x,
int y,
int selected_index,
14774 const std::vector<int> &selected_dbIndex_array) {
14775 if (!GetpCurrentStack())
return;
14778 if (!GetQuiltMode())
return;
14780 m_piano_ctx_menu =
new wxMenu();
14782 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14792 menu_selected_dbIndex = selected_dbIndex_array[0];
14793 menu_selected_index = selected_index;
14796 bool b_is_in_noshow =
false;
14797 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14798 if (m_quilt_noshow_index_array[i] ==
14799 menu_selected_dbIndex)
14801 b_is_in_noshow =
true;
14806 if (b_is_in_noshow) {
14807 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14808 _(
"Show This Chart"));
14809 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14810 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14811 }
else if (GetpCurrentStack()->nEntry > 1) {
14812 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14813 _(
"Hide This Chart"));
14814 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14815 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14819 wxPoint pos = wxPoint(x, y - 30);
14822 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14823 PopupMenu(m_piano_ctx_menu, pos);
14825 delete m_piano_ctx_menu;
14826 m_piano_ctx_menu = NULL;
14828 HideChartInfoWindow();
14829 m_Piano->ResetRollover();
14831 SetQuiltChartHiLiteIndex(-1);
14832 ClearQuiltChartHiLiteIndexArray();
14837void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14838 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14839 if (m_quilt_noshow_index_array[i] ==
14840 menu_selected_dbIndex)
14842 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14848void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14849 if (!GetpCurrentStack())
return;
14852 RemoveChartFromQuilt(menu_selected_dbIndex);
14856 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14857 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14859 int i = menu_selected_index + 1;
14860 bool b_success =
false;
14861 while (i < GetpCurrentStack()->nEntry - 1) {
14862 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14863 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14864 SelectQuiltRefChart(i);
14874 i = menu_selected_index - 1;
14876 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14877 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14878 SelectQuiltRefChart(i);
14888void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14890 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14891 if (m_quilt_noshow_index_array[i] ==
14894 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14899 m_quilt_noshow_index_array.push_back(dbIndex);
14902bool ChartCanvas::UpdateS52State() {
14903 bool retval =
false;
14906 ps52plib->SetShowS57Text(m_encShowText);
14907 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14908 ps52plib->m_bShowSoundg = m_encShowDepth;
14909 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14910 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14913 if (!m_encShowLights)
14914 ps52plib->AddObjNoshow(
"LIGHTS");
14916 ps52plib->RemoveObjNoshow(
"LIGHTS");
14917 ps52plib->SetLightsOff(!m_encShowLights);
14918 ps52plib->m_bExtendLightSectors =
true;
14921 ps52plib->SetAnchorOn(m_encShowAnchor);
14922 ps52plib->SetQualityOfData(m_encShowDataQual);
14928void ChartCanvas::SetShowENCDataQual(
bool show) {
14929 m_encShowDataQual = show;
14930 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14931 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14933 m_s52StateHash = 0;
14936void ChartCanvas::SetShowENCText(
bool show) {
14937 m_encShowText = show;
14938 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14939 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14941 m_s52StateHash = 0;
14944void ChartCanvas::SetENCDisplayCategory(
int category) {
14945 m_encDisplayCategory = category;
14946 m_s52StateHash = 0;
14949void ChartCanvas::SetShowENCDepth(
bool show) {
14950 m_encShowDepth = show;
14951 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14952 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14954 m_s52StateHash = 0;
14957void ChartCanvas::SetShowENCLightDesc(
bool show) {
14958 m_encShowLightDesc = show;
14959 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14960 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14962 m_s52StateHash = 0;
14965void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14966 m_encShowBuoyLabels = show;
14967 m_s52StateHash = 0;
14970void ChartCanvas::SetShowENCLights(
bool show) {
14971 m_encShowLights = show;
14972 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14973 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14975 m_s52StateHash = 0;
14978void ChartCanvas::SetShowENCAnchor(
bool show) {
14979 m_encShowAnchor = show;
14980 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14981 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14983 m_s52StateHash = 0;
14986wxRect ChartCanvas::GetMUIBarRect() {
14989 rv = m_muiBar->GetRect();
14995void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14996 if (!GetAlertString().IsEmpty()) {
14997 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14998 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
15000 dc.SetFont(*pfont);
15001 dc.SetPen(*wxTRANSPARENT_PEN);
15003 dc.SetBrush(wxColour(243, 229, 47));
15005 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
15009 wxRect sbr = GetScaleBarRect();
15010 int xp = sbr.x + sbr.width + 10;
15011 int yp = (sbr.y + sbr.height) - h;
15013 int wdraw = w + 10;
15014 dc.DrawRectangle(xp, yp, wdraw, h);
15015 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
15016 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
15026#define BRIGHT_XCALIB
15027#define __OPCPN_USEICC__
15030#ifdef __OPCPN_USEICC__
15031int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15032 double co_green,
double co_blue);
15034wxString temp_file_name;
15038class ocpnCurtain:
public wxDialog
15040 DECLARE_CLASS( ocpnCurtain )
15041 DECLARE_EVENT_TABLE()
15044 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
15046 bool ProcessEvent(wxEvent& event);
15050IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
15052BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
15055ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
15057 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
15060ocpnCurtain::~ocpnCurtain()
15064bool ocpnCurtain::ProcessEvent(wxEvent& event)
15066 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
15067 return GetParent()->GetEventHandler()->ProcessEvent(event);
15072#include <windows.h>
15075typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15076typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15077SetDeviceGammaRamp_ptr_type
15078 g_pSetDeviceGammaRamp;
15079GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15081WORD *g_pSavedGammaMap;
15085int InitScreenBrightness() {
15088 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15092 if (NULL == hGDI32DLL) {
15093 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15095 if (NULL != hGDI32DLL) {
15097 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15098 hGDI32DLL,
"SetDeviceGammaRamp");
15099 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15100 hGDI32DLL,
"GetDeviceGammaRamp");
15103 if ((NULL == g_pSetDeviceGammaRamp) ||
15104 (NULL == g_pGetDeviceGammaRamp)) {
15105 FreeLibrary(hGDI32DLL);
15114 if (!g_pSavedGammaMap) {
15115 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15118 bbr = g_pGetDeviceGammaRamp(
15119 hDC, g_pSavedGammaMap);
15120 ReleaseDC(NULL, hDC);
15125 wxRegKey *pRegKey =
new wxRegKey(
15126 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15127 "NT\\CurrentVersion\\ICM");
15128 if (!pRegKey->Exists()) pRegKey->Create();
15129 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15131 g_brightness_init =
true;
15137 if (NULL == g_pcurtain) {
15138 if (top_frame::Get()->CanSetTransparent()) {
15140 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15141 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15142 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15143 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15150 g_pcurtain->Hide();
15152 HWND hWnd = GetHwndOf(g_pcurtain);
15153 SetWindowLong(hWnd, GWL_EXSTYLE,
15154 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15155 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15156 g_pcurtain->SetTransparent(0);
15158 g_pcurtain->Maximize();
15159 g_pcurtain->Show();
15162 g_pcurtain->Enable();
15163 g_pcurtain->Disable();
15165 top_frame::Get()->Disable();
15166 top_frame::Get()->Enable();
15170 g_brightness_init =
true;
15176 wxString cmd(
"xcalib -version");
15178 wxArrayString output;
15179 long r = wxExecute(cmd, output);
15182 " External application \"xcalib\" not found. Screen brightness "
15185 g_brightness_init =
true;
15190int RestoreScreenBrightness() {
15193 if (g_pSavedGammaMap) {
15194 HDC hDC = GetDC(NULL);
15195 g_pSetDeviceGammaRamp(hDC,
15197 ReleaseDC(NULL, hDC);
15199 free(g_pSavedGammaMap);
15200 g_pSavedGammaMap = NULL;
15204 g_pcurtain->Close();
15205 g_pcurtain->Destroy();
15209 g_brightness_init =
false;
15214#ifdef BRIGHT_XCALIB
15215 if (g_brightness_init) {
15217 cmd =
"xcalib -clear";
15218 wxExecute(cmd, wxEXEC_ASYNC);
15219 g_brightness_init =
false;
15229int SetScreenBrightness(
int brightness) {
15236 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15238 g_pcurtain->Close();
15239 g_pcurtain->Destroy();
15243 InitScreenBrightness();
15245 if (NULL == hGDI32DLL) {
15247 wchar_t wdll_name[80];
15248 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15249 LPCWSTR cstr = wdll_name;
15251 hGDI32DLL = LoadLibrary(cstr);
15253 if (NULL != hGDI32DLL) {
15255 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15256 hGDI32DLL,
"SetDeviceGammaRamp");
15257 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15258 hGDI32DLL,
"GetDeviceGammaRamp");
15261 if ((NULL == g_pSetDeviceGammaRamp) ||
15262 (NULL == g_pGetDeviceGammaRamp)) {
15263 FreeLibrary(hGDI32DLL);
15270 HDC hDC = GetDC(NULL);
15281 int increment = brightness * 256 / 100;
15284 WORD GammaTable[3][256];
15287 for (
int i = 0; i < 256; i++) {
15288 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15289 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15290 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15292 table_val += increment;
15294 if (table_val > 65535) table_val = 65535;
15297 g_pSetDeviceGammaRamp(hDC, GammaTable);
15298 ReleaseDC(NULL, hDC);
15305 if (g_pSavedGammaMap) {
15306 HDC hDC = GetDC(NULL);
15307 g_pSetDeviceGammaRamp(hDC,
15309 ReleaseDC(NULL, hDC);
15312 if (brightness < 100) {
15313 if (NULL == g_pcurtain) InitScreenBrightness();
15316 int sbrite = wxMax(1, brightness);
15317 sbrite = wxMin(100, sbrite);
15319 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15323 g_pcurtain->Close();
15324 g_pcurtain->Destroy();
15334#ifdef BRIGHT_XCALIB
15336 if (!g_brightness_init) {
15337 last_brightness = 100;
15338 g_brightness_init =
true;
15339 temp_file_name = wxFileName::CreateTempFileName(
"");
15340 InitScreenBrightness();
15343#ifdef __OPCPN_USEICC__
15346 if (!CreateSimpleICCProfileFile(
15347 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15348 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15349 wxString cmd(
"xcalib ");
15350 cmd += temp_file_name;
15352 wxExecute(cmd, wxEXEC_ASYNC);
15361 if (brightness > last_brightness) {
15363 cmd =
"xcalib -clear";
15364 wxExecute(cmd, wxEXEC_ASYNC);
15366 ::wxMilliSleep(10);
15368 int brite_adj = wxMax(1, brightness);
15369 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15370 wxExecute(cmd, wxEXEC_ASYNC);
15372 int brite_adj = wxMax(1, brightness);
15373 int factor = (brite_adj * 100) / last_brightness;
15374 factor = wxMax(1, factor);
15376 cmd.Printf(
"xcalib -co %2d -a", factor);
15377 wxExecute(cmd, wxEXEC_ASYNC);
15382 last_brightness = brightness;
15389#ifdef __OPCPN_USEICC__
15391#define MLUT_TAG 0x6d4c5554L
15392#define VCGT_TAG 0x76636774L
15394int GetIntEndian(
unsigned char *s) {
15399 p = (
unsigned char *)&ret;
15402 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15404 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15409unsigned short GetShortEndian(
unsigned char *s) {
15410 unsigned short ret;
15414 p = (
unsigned char *)&ret;
15417 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15419 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15425int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15426 double co_green,
double co_blue) {
15430 fp = fopen(file_name,
"wb");
15431 if (!fp)
return -1;
15437 for (
int i = 0; i < 128; i++) header[i] = 0;
15439 fwrite(header, 128, 1, fp);
15443 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15444 fwrite(&numTags, 1, 4, fp);
15446 int tagName0 = VCGT_TAG;
15447 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15448 fwrite(&tagName, 1, 4, fp);
15450 int tagOffset0 = 128 + 4 *
sizeof(int);
15451 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15452 fwrite(&tagOffset, 1, 4, fp);
15455 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15456 fwrite(&tagSize, 1, 4, fp);
15458 fwrite(&tagName, 1, 4, fp);
15460 fwrite(&tagName, 1, 4, fp);
15465 int gammatype0 = 0;
15466 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15467 fwrite(&gammatype, 1, 4, fp);
15469 int numChannels0 = 3;
15470 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15471 fwrite(&numChannels, 1, 2, fp);
15473 int numEntries0 = 256;
15474 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15475 fwrite(&numEntries, 1, 2, fp);
15477 int entrySize0 = 1;
15478 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15479 fwrite(&entrySize, 1, 2, fp);
15481 unsigned char ramp[256];
15484 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15485 fwrite(ramp, 256, 1, fp);
15488 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15489 fwrite(ramp, 256, 1, fp);
15492 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15493 fwrite(ramp, 256, 1, fp);
Select * pSelectAIS
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetQueryDialog.
std::unique_ptr< HostApi > GetHostApi()
HostApi factory,.
Chart canvas configuration state
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
ChartCanvas * g_focusCanvas
Global instance.
arrayofCanvasPtr g_canvasArray
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Minimal ChartCAnvas interface with very little dependencies.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void CloseTideDialog()
Close any open tide dialog.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
void OnPaint(wxPaintEvent &event)
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void DoMovement(long dt)
Performs a step of smooth movement animation on the chart canvas.
void ShowSingleTideDialog(int x, int y, void *pvIDX)
Display tide/current dialog with single-instance management.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
int PrepareContextSelections(double lat, double lon)
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
EventVar json_msg
Notified with message targeting all plugins.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
bool IsTideDialogOpen() const
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Centers the view on a specific lat/lon position.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Locked down interface published in 5.14.1.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
int station_tz_offset
Offset in seconds to convert from harmonic data (epochs) to the station time zone.
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
Data for a loaded plugin, including dl-loaded library.
int m_cap_flag
PlugIn Capabilities descriptor.
PluginLoader is a backend module without any direct GUI functionality.
const ArrayOfPlugIns * GetPlugInArray()
Return list of currently loaded plugins.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute)
Dialog for displaying query results of S57 objects.
IDX_entry * GetCurrentIDX() const
Represents a single point in a track.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
APConsole * console
Global instance.
Primary navigation console display for route and vessel tracking.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
bool g_bRollover
enable/disable mouse rollover GUI effects
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
double g_display_size_mm
Physical display width (mm)
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
GoToPositionDialog * pGoToPositionDialog
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Hooks into gui available in model.
size_t g_current_monitor
Current monitor displaying main application frame.
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
bool g_b_overzoom_x
Allow high overzoom.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Hotheys help dialog (the '?' button).
GUI constant definitions.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
double AnchorDistFix(double const d, double const AnchorPointMinDist, double const AnchorPointMaxDist)
Return constrained value of d so that AnchorPointMinDist < abs(d) < AnchorPointMaxDist.
MySQL based storage for routes, tracks, etc.
wxString getUsrHeightUnit(int unit)
Get the abbreviation for the preferred height unit.
double toUsrHeight(double m_height, int unit)
Convert height from meters to preferred height units.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
User notifications manager.
Notification Manager GUI.
OCPN_AUIManager * g_pauimgr
Global instance.
Optimized wxBitmap Object.
ChartFamilyEnumPI
Enumeration of chart families (broad categories).
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
int GetChartbarHeight()
Gets height of chart bar in pixels.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Miscellaneous utilities, many of which string related.
Layer to use wxDC or opengl.
options * g_options
Global instance.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
double gHdt
True heading in degrees (0-359.99).
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Purpose: Track and Trackpoint drawing stuff.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
RoutePoint * pAnchorWatchPoint2
Global instance.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RoutePoint * pAnchorWatchPoint1
Global instance.
float g_ChartScaleFactorExp
Global instance.
RouteManagerDialog * pRouteManagerDialog
Global instance.
S57QueryDialog * g_pObjectQueryDialog
Global instance.
S57 object query result window.
Select * pSelect
Global instance.
Select * pSelectTC
Global instance.
Selected route, segment, waypoint, etc.
A single, selected generic item.
SENCThreadManager * g_SencThreadManager
Global instance.
ShapeBaseChartSet gShapeBasemap
global instance
Represents an entry in the chart table, containing information about a single chart.
Tide and currents window.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
Timer identification constants.
Abstract gFrame/MyFrame interface.
ActiveTrack * g_pActiveTrack
global instance
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Track and Trackpoint drawing stuff.
TrackPropDlg * pTrackPropDialog
Global instance.
Framework for Undo features.