35#include <wx/graphics.h>
36#include <wx/clipbrd.h>
37#include <wx/aui/aui.h>
41#include "o_sound/o_sound.h"
48#include "model/geodesic.h"
54#include "model/nav_object_database.h"
116#include "tide_time.h"
123#include "user_colors.h"
125#include "s57_ocpn_utils.h"
128#include "androidUTIL.h"
138#include <wx/msw/msvcrt.h>
147#define printf printf2
149int __cdecl printf2(
const char *format, ...) {
153 va_start(argptr, format);
154 int ret = vsnprintf(str,
sizeof(str), format, argptr);
156 OutputDebugStringA(str);
161#if defined(__MSVC__) && (_MSC_VER < 1700)
162#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
168#define OCPN_ALT_MENUBAR 1
175static bool g_bSmoothRecenter =
true;
176static bool bDrawCurrentValues;
197static bool mouse_leftisdown;
198static bool g_brouteCreating;
199static int r_gamma_mult;
200static int g_gamma_mult;
201static int b_gamma_mult;
202static int gamma_state;
203static bool g_brightness_init;
204static int last_brightness;
205static wxGLContext *g_pGLcontext;
208static wxDialog *g_pcurtain;
210static wxString g_lastS52PLIBPluginMessage;
213#define MAX_BRIGHT 100
220EVT_ACTIVATE(ChartCanvas::OnActivate)
221EVT_SIZE(ChartCanvas::OnSize)
222#ifndef HAVE_WX_GESTURE_EVENTS
223EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
225EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
226EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
227EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
228EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
229EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
230EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
231EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
232EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
233EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
234EVT_KEY_UP(ChartCanvas::OnKeyUp)
235EVT_CHAR(ChartCanvas::OnKeyChar)
236EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
237EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
238EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
239EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
240EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
241EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
242EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
243EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
244EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
245EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
252 m_nmea_log(nmea_log) {
253 parent_frame = frame;
254 m_canvasIndex = canvasIndex;
258 SetBackgroundColour(wxColour(0, 0, 0));
259 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
263 m_bDrawingRoute =
false;
264 m_bRouteEditing =
false;
265 m_bMarkEditing =
false;
266 m_bRoutePoinDragging =
false;
267 m_bIsInRadius =
false;
268 m_bMayToggleMenuBar =
true;
271 m_bShowNavobjects =
true;
273 m_bAppendingRoute =
false;
274 pThumbDIBShow = NULL;
275 m_bShowCurrent =
false;
277 bShowingCurrent =
false;
281 m_b_paint_enable =
true;
284 pss_overlay_bmp = NULL;
285 pss_overlay_mask = NULL;
286 m_bChartDragging =
false;
287 m_bMeasure_Active =
false;
288 m_bMeasure_DistCircle =
false;
289 m_pMeasureRoute = NULL;
290 m_pTrackRolloverWin = NULL;
291 m_pRouteRolloverWin = NULL;
292 m_pAISRolloverWin = NULL;
294 m_disable_edge_pan =
false;
295 m_dragoffsetSet =
false;
299 m_singleChart = NULL;
300 m_upMode = NORTH_UP_MODE;
302 m_bShowAISScaled =
false;
303 m_timed_move_vp_active =
false;
305 m_disable_adjust_on_zoom =
false;
312 m_pSelectedRoute = NULL;
313 m_pSelectedTrack = NULL;
314 m_pRoutePointEditTarget = NULL;
315 m_pFoundPoint = NULL;
316 m_pMouseRoute = NULL;
317 m_prev_pMousePoint = NULL;
318 m_pEditRouteArray = NULL;
319 m_pFoundRoutePoint = NULL;
320 m_FinishRouteOnKillFocus =
true;
322 m_pRolloverRouteSeg = NULL;
323 m_pRolloverTrackSeg = NULL;
324 m_bsectors_shown =
false;
326 m_bbrightdir =
false;
331 m_pos_image_user_day = NULL;
332 m_pos_image_user_dusk = NULL;
333 m_pos_image_user_night = NULL;
334 m_pos_image_user_grey_day = NULL;
335 m_pos_image_user_grey_dusk = NULL;
336 m_pos_image_user_grey_night = NULL;
339 m_rotation_speed = 0;
345 m_pos_image_user_yellow_day = NULL;
346 m_pos_image_user_yellow_dusk = NULL;
347 m_pos_image_user_yellow_night = NULL;
349 SetOwnShipState(SHIP_INVALID);
351 undo =
new Undo(
this);
357 m_focus_indicator_pix = 1;
359 m_pCurrentStack = NULL;
360 m_bpersistent_quilt =
false;
361 m_piano_ctx_menu = NULL;
363 m_NotificationsList = NULL;
364 m_notification_button = NULL;
366 g_ChartNotRenderScaleFactor = 2.0;
367 m_bShowScaleInStatusBar =
true;
370 m_bShowScaleInStatusBar =
false;
371 m_show_focus_bar =
true;
373 m_bShowOutlines =
false;
374 m_bDisplayGrid =
false;
375 m_bShowDepthUnits =
true;
376 m_encDisplayCategory = (int)STANDARD;
378 m_encShowLights =
true;
379 m_encShowAnchor =
true;
380 m_encShowDataQual =
false;
382 m_pQuilt =
new Quilt(
this);
387 g_PrintingInProgress =
false;
389#ifdef HAVE_WX_GESTURE_EVENTS
390 m_oldVPSScale = -1.0;
391 m_popupWanted =
false;
394 m_inLongPress =
false;
397 m_sw_left_down.Start();
398 m_sw_left_up.Start();
402 singleClickEventIsValid =
false;
411 pCursorPencil = NULL;
416 SetCursor(*pCursorArrow);
418 pPanTimer =
new wxTimer(
this, m_MouseDragging);
421 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
422 pMovementTimer->Stop();
424 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
425 pMovementStopTimer->Stop();
427 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
428 pRotDefTimer->Stop();
430 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
431 m_DoubleClickTimer->Stop();
433 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
434 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
435 m_chart_drag_inertia_active =
false;
437 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
438 m_animationActive =
false;
439 m_menuTimer.SetOwner(
this, MENU_TIMER);
440 m_tap_timer.SetOwner(
this, TAP_TIMER);
444 m_panx_target_final = m_pany_target_final = 0;
445 m_panx_target_now = m_pany_target_now = 0;
448 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
449 pCurTrackTimer->Stop();
450 m_curtrack_timer_msec = 10;
452 m_wheelzoom_stop_oneshot = 0;
453 m_last_wheel_dir = 0;
455 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
457 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
459 m_rollover_popup_timer_msec = 20;
461 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
463 m_b_rot_hidef =
true;
468 m_upMode = NORTH_UP_MODE;
469 m_bLookAhead =
false;
473 m_cs = GLOBAL_COLOR_SCHEME_DAY;
476 VPoint.view_scale_ppm = 1;
480 m_canvas_scale_factor = 1.;
482 m_canvas_width = 1000;
484 m_overzoomTextWidth = 0;
485 m_overzoomTextHeight = 0;
494 m_pEM_Fathoms = NULL;
496 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
498 m_pEM_OverZoom = NULL;
500 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
508 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
511 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
514 double factor_dusk = 0.5;
515 double factor_night = 0.25;
518 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
520 int rimg_width = m_os_image_red_day.GetWidth();
521 int rimg_height = m_os_image_red_day.GetHeight();
523 m_os_image_red_dusk = m_os_image_red_day.Copy();
524 m_os_image_red_night = m_os_image_red_day.Copy();
526 for (
int iy = 0; iy < rimg_height; iy++) {
527 for (
int ix = 0; ix < rimg_width; ix++) {
528 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
529 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
530 m_os_image_red_day.GetGreen(ix, iy),
531 m_os_image_red_day.GetBlue(ix, iy));
532 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
533 hsv.value = hsv.value * factor_dusk;
534 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
535 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
537 hsv = wxImage::RGBtoHSV(rgb);
538 hsv.value = hsv.value * factor_night;
539 nrgb = wxImage::HSVtoRGB(hsv);
540 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
546 m_os_image_grey_day =
547 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
549 int gimg_width = m_os_image_grey_day.GetWidth();
550 int gimg_height = m_os_image_grey_day.GetHeight();
552 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
553 m_os_image_grey_night = m_os_image_grey_day.Copy();
555 for (
int iy = 0; iy < gimg_height; iy++) {
556 for (
int ix = 0; ix < gimg_width; ix++) {
557 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
558 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
559 m_os_image_grey_day.GetGreen(ix, iy),
560 m_os_image_grey_day.GetBlue(ix, iy));
561 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
562 hsv.value = hsv.value * factor_dusk;
563 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
564 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
566 hsv = wxImage::RGBtoHSV(rgb);
567 hsv.value = hsv.value * factor_night;
568 nrgb = wxImage::HSVtoRGB(hsv);
569 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
575 m_os_image_yellow_day = m_os_image_red_day.Copy();
577 gimg_width = m_os_image_yellow_day.GetWidth();
578 gimg_height = m_os_image_yellow_day.GetHeight();
580 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
581 m_os_image_yellow_night = m_os_image_red_day.Copy();
583 for (
int iy = 0; iy < gimg_height; iy++) {
584 for (
int ix = 0; ix < gimg_width; ix++) {
585 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
586 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
587 m_os_image_yellow_day.GetGreen(ix, iy),
588 m_os_image_yellow_day.GetBlue(ix, iy));
589 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
590 hsv.hue += 60. / 360.;
591 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
592 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
594 hsv = wxImage::RGBtoHSV(rgb);
595 hsv.value = hsv.value * factor_dusk;
596 hsv.hue += 60. / 360.;
597 nrgb = wxImage::HSVtoRGB(hsv);
598 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
600 hsv = wxImage::RGBtoHSV(rgb);
601 hsv.hue += 60. / 360.;
602 hsv.value = hsv.value * factor_night;
603 nrgb = wxImage::HSVtoRGB(hsv);
604 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
610 m_pos_image_red = &m_os_image_red_day;
611 m_pos_image_yellow = &m_os_image_yellow_day;
612 m_pos_image_grey = &m_os_image_grey_day;
616 m_pBrightPopup = NULL;
619 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
624 m_Piano =
new Piano(
this);
626 m_bShowCompassWin =
true;
628 m_Compass->SetScaleFactor(g_compass_scalefactor);
629 m_Compass->Show(
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) MouseEvent(singleClickEvent);
7728 singleClickEventIsValid =
false;
7729 m_DoubleClickTimer->Stop();
7734bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7735 if (!m_bChartDragging && !m_bDrawingRoute) {
7740 if (m_Compass && m_Compass->IsShown()) {
7742 bool isInCompass = logicalRect.Contains(event.GetPosition());
7743 if (isInCompass || m_mouseWasInCompass) {
7744 if (m_Compass->MouseEvent(event)) {
7745 cursor_region = CENTER;
7746 if (!g_btouch) SetCanvasCursor(event);
7747 m_mouseWasInCompass = isInCompass;
7751 m_mouseWasInCompass = isInCompass;
7754 if (m_notification_button && m_notification_button->IsShown()) {
7756 bool isinButton = logicalRect.Contains(event.GetPosition());
7758 SetCursor(*pCursorArrow);
7759 if (event.LeftDown()) HandleNotificationMouseClick();
7764 if (MouseEventToolbar(event))
return true;
7766 if (MouseEventChartBar(event))
return true;
7768 if (MouseEventMUIBar(event))
return true;
7770 if (MouseEventIENCBar(event))
return true;
7775void ChartCanvas::HandleNotificationMouseClick() {
7776 if (!m_NotificationsList) {
7780 m_NotificationsList->RecalculateSize();
7781 m_NotificationsList->Hide();
7784 if (m_NotificationsList->IsShown()) {
7785 m_NotificationsList->Hide();
7787 m_NotificationsList->RecalculateSize();
7788 m_NotificationsList->ReloadNotificationList();
7789 m_NotificationsList->Show();
7792bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7793 if (!g_bShowChartBar)
return false;
7795 if (!m_Piano->MouseEvent(event))
return false;
7797 cursor_region = CENTER;
7798 if (!g_btouch) SetCanvasCursor(event);
7802bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7803 if (!IsPrimaryCanvas())
return false;
7812 cursor_region = CENTER;
7813 if (!g_btouch) SetCanvasCursor(event);
7817bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7818 if (!IsPrimaryCanvas())
return false;
7831bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7833 if (!m_muiBar->MouseEvent(event))
return false;
7836 cursor_region = CENTER;
7837 if (!g_btouch) SetCanvasCursor(event);
7849 event.GetPosition(&x, &y);
7851 x *= m_displayScale;
7852 y *= m_displayScale;
7854 m_MouseDragging =
event.Dragging();
7860 if (event.Dragging()) {
7861 if ((x == mouse_x) && (y == mouse_y))
return true;
7867 mouse_leftisdown =
event.LeftDown();
7871 cursor_region = CENTER;
7875 if (m_Compass && m_Compass->IsShown() &&
7876 m_Compass->
GetRect().Contains(event.GetPosition())) {
7877 cursor_region = CENTER;
7878 }
else if (x > xr_margin) {
7879 cursor_region = MID_RIGHT;
7880 }
else if (x < xl_margin) {
7881 cursor_region = MID_LEFT;
7882 }
else if (y > yb_margin - chartbar_height &&
7883 y < m_canvas_height - chartbar_height) {
7884 cursor_region = MID_TOP;
7885 }
else if (y < yt_margin) {
7886 cursor_region = MID_BOT;
7888 cursor_region = CENTER;
7891 if (!g_btouch) SetCanvasCursor(event);
7895 leftIsDown =
event.LeftDown();
7898 if (event.LeftDown()) {
7899 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7902 g_bTempShowMenuBar =
false;
7903 top_frame::Get()->ApplyGlobalSettings(
false);
7911 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7912 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7916 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7917 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7920 event.SetEventObject(
this);
7921 if (SendMouseEventToPlugins(event))
7928 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7929 StartChartDragInertia();
7932 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7933 !singleClickEventIsValid) {
7935 if (m_DoubleClickTimer->IsRunning()) {
7936 m_DoubleClickTimer->Stop();
7941 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7942 singleClickEvent = event;
7943 singleClickEventIsValid =
true;
7952 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7953 if (g_click_stop > 0) {
7961 if (GetUpMode() == COURSE_UP_MODE) {
7962 m_b_rot_hidef =
false;
7963 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7965 pRotDefTimer->Stop();
7968 bool bRoll = !g_btouch;
7973 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7974 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7975 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7976 m_RolloverPopupTimer.Start(
7980 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7984 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7993#if !defined(__WXGTK__) && !defined(__WXQT__)
8001 if ((x >= 0) && (y >= 0))
8006 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
8007 wxPoint p = ClientToScreen(wxPoint(x, y));
8013 if (m_routeState >= 2) {
8016 m_bDrawingRoute =
true;
8018 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8023 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
8026 m_bDrawingRoute =
true;
8028 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
8041#if defined(__WXMAC__) || defined(__ANDROID__)
8045 wxClientDC cdc(GetParent());
8057 if (m_pSelectedRoute) {
8059 m_pSelectedRoute->DeSelectRoute();
8061 if (g_bopengl && m_glcc) {
8066 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8069 if (m_pFoundRoutePoint) {
8077 if (g_btouch && m_pRoutePointEditTarget) {
8080 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8084 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8085 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8086 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8087 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8088 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8092 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8095 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8101 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8104 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8105 seltype |= SELTYPE_AISTARGET;
8110 m_pFoundRoutePoint = NULL;
8115 Route *pSelectedActiveRoute = NULL;
8116 Route *pSelectedVizRoute = NULL;
8119 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8120 SelectableItemList SelList =
8121 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8129 bool brp_viz =
false;
8131 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8133 if (pr->IsVisible()) {
8138 if (!brp_viz && prp->IsShared())
8140 brp_viz = prp->IsVisible();
8143 brp_viz = prp->IsVisible();
8145 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8150 m_pSelectedRoute = NULL;
8152 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8155 pSelectedActiveRoute = pr;
8156 pFoundActiveRoutePoint = prp;
8161 if (NULL == pSelectedVizRoute) {
8162 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8164 if (pr->IsVisible()) {
8165 pSelectedVizRoute = pr;
8166 pFoundVizRoutePoint = prp;
8172 delete proute_array;
8177 if (pFoundActiveRoutePoint) {
8178 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8179 m_pSelectedRoute = pSelectedActiveRoute;
8180 }
else if (pFoundVizRoutePoint) {
8181 m_pFoundRoutePoint = pFoundVizRoutePoint;
8182 m_pSelectedRoute = pSelectedVizRoute;
8185 m_pFoundRoutePoint = pFirstVizPoint;
8187 if (m_pSelectedRoute) {
8188 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8189 }
else if (m_pFoundRoutePoint) {
8190 seltype |= SELTYPE_MARKPOINT;
8194 if (m_pFoundRoutePoint) {
8198 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8199 RefreshRect(wp_rect,
true);
8207 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8208 SelectableItemList SelList =
8209 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8211 if (NULL == m_pSelectedRoute)
8216 if (pr->IsVisible()) {
8217 m_pSelectedRoute = pr;
8223 if (m_pSelectedRoute) {
8224 if (NULL == m_pFoundRoutePoint)
8225 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8230 if (g_bopengl && m_glcc) {
8235 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8237 seltype |= SELTYPE_ROUTESEGMENT;
8241 if (pFindTrackSeg) {
8242 m_pSelectedTrack = NULL;
8243 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8244 SelectableItemList SelList =
8245 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8250 if (pt->IsVisible()) {
8251 m_pSelectedTrack = pt;
8255 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8261 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8262 seltype |= SELTYPE_CURRENTPOINT;
8265 else if (pFindTide) {
8266 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8267 seltype |= SELTYPE_TIDEPOINT;
8272 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8277IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8287 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8288 SelectableItemList SelList =
8289 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8292 pFind = *SelList.begin();
8293 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8295 auto node = SelList.begin();
8296 if (SelList.size() > 1) {
8297 for (++node; node != SelList.end(); ++node) {
8300 if (pIDX_candidate->
IDX_type ==
'c') {
8301 pIDX_best_candidate = pIDX_candidate;
8306 pFind = *SelList.begin();
8307 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8310 return pIDX_best_candidate;
8312void ChartCanvas::CallPopupMenu(
int x,
int y) {
8316 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8324 if (SELTYPE_CURRENTPOINT == seltype) {
8330 if (SELTYPE_TIDEPOINT == seltype) {
8336 InvokeCanvasMenu(x, y, seltype);
8339 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8343 m_pSelectedRoute = NULL;
8345 if (m_pFoundRoutePoint) {
8346 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8349 m_pFoundRoutePoint = NULL;
8355bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8363 event.GetPosition(&x, &y);
8369 SelectRadius = g_Platform->GetSelectRadiusPix() /
8370 (m_true_scale_ppm * 1852 * 60);
8377 if (event.LeftDClick() && (cursor_region == CENTER)) {
8378 m_DoubleClickTimer->Start();
8379 singleClickEventIsValid =
false;
8385 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8388 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8391 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8392 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8393 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8399 SelectableItemList rpSelList =
8400 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8401 bool b_onRPtarget =
false;
8404 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8405 b_onRPtarget =
true;
8413 std::unique_ptr<HostApi> host_api =
GetHostApi();
8414 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8416 if (m_pRoutePointEditTarget) {
8418 if ((api_121->GetContextMenuMask() &
8419 api_121->kContextMenuDisableWaypoint))
8421 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8427 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8430 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8431 m_pRoutePointEditTarget = NULL;
8432 RefreshRect(wp_rect,
true);
8436 auto node = rpSelList.begin();
8437 if (node != rpSelList.end()) {
8441 wxArrayPtrVoid *proute_array =
8446 bool brp_viz =
false;
8448 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8450 if (pr->IsVisible()) {
8455 delete proute_array;
8459 brp_viz = frp->IsVisible();
8461 brp_viz = frp->IsVisible();
8464 if ((api_121->GetContextMenuMask() &
8465 api_121->kContextMenuDisableWaypoint))
8468 ShowMarkPropertiesDialog(frp);
8477 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8479 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8482 if (pr->IsVisible()) {
8483 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8488 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8490 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8493 if (pt->IsVisible()) {
8494 ShowTrackPropertiesDialog(pt);
8503 if (m_bShowCurrent) {
8505 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8507 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8509 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8510 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8512 if (pic->m_enabled && pic->m_init_state &&
8513 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8516 if (m_pIDXCandidate) {
8517 info.point_type = CURRENT_STATION;
8521 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8522 return ptcmgr->GetTideOrCurrentMeters(t, idx, value, dir);
8526 if (plugin) plugin->OnTideCurrentClick(info);
8541 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8543 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8545 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8546 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8548 if (pic->m_enabled && pic->m_init_state &&
8549 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8552 if (m_pIDXCandidate) {
8553 info.point_type = TIDE_STATION;
8557 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8558 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8562 if (plugin) plugin->OnTideCurrentClick(info);
8577 ShowObjectQueryWindow(x, y, zlat, zlon);
8582 if (event.LeftDown()) {
8598 bool appending =
false;
8599 bool inserting =
false;
8602 SetCursor(*pCursorPencil);
8606 m_bRouteEditing =
true;
8608 if (m_routeState == 1) {
8609 m_pMouseRoute =
new Route();
8610 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8620 double nearby_radius_meters =
8621 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8624 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8625 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8626 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8627 wxArrayPtrVoid *proute_array =
8632 bool brp_viz =
false;
8634 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8636 if (pr->IsVisible()) {
8641 delete proute_array;
8643 pNearbyPoint->IsShared())
8646 pNearbyPoint->IsVisible();
8648 brp_viz = pNearbyPoint->IsVisible();
8651 wxString msg = _(
"Use nearby waypoint?");
8653 const bool noname(pNearbyPoint->GetName() ==
"");
8656 _(
"Use nearby nameless waypoint and name it M with"
8657 " a unique number?");
8660 m_FinishRouteOnKillFocus =
false;
8662 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8663 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8664 m_FinishRouteOnKillFocus =
true;
8665 if (dlg_return == wxID_YES) {
8667 if (m_pMouseRoute) {
8668 int last_wp_num = m_pMouseRoute->GetnPoints();
8670 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8671 wxString wp_name = wxString::Format(
8672 "M%002i-%s", last_wp_num + 1, guid_short);
8673 pNearbyPoint->SetName(wp_name);
8675 pNearbyPoint->SetName(
"WPXX");
8677 pMousePoint = pNearbyPoint;
8680 if (m_routeState > 1)
8681 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8682 Undo_HasParent, NULL);
8685 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8686 bool procede =
false;
8690 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8696 m_FinishRouteOnKillFocus =
false;
8702 _(
"Insert first part of this route in the new route?");
8703 if (tail->GetIndexOf(pMousePoint) ==
8706 dmsg = _(
"Insert this route in the new route?");
8708 if (tail->GetIndexOf(pMousePoint) > 0) {
8709 dlg_return = OCPNMessageBox(
8710 this, dmsg, _(
"OpenCPN Route Create"),
8711 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8712 m_FinishRouteOnKillFocus =
true;
8714 if (dlg_return == wxID_YES) {
8721 _(
"Append last part of this route to the new route?");
8722 if (tail->GetIndexOf(pMousePoint) == 1)
8724 "Append this route to the new route?");
8729 if (tail->GetLastPoint() != pMousePoint) {
8730 dlg_return = OCPNMessageBox(
8731 this, dmsg, _(
"OpenCPN Route Create"),
8732 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8733 m_FinishRouteOnKillFocus =
true;
8735 if (dlg_return == wxID_YES) {
8746 if (!FindRouteContainingWaypoint(pMousePoint))
8747 pMousePoint->SetShared(
true);
8752 if (NULL == pMousePoint) {
8753 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8755 pMousePoint->SetNameShown(
false);
8759 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8761 if (m_routeState > 1)
8762 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8763 Undo_IsOrphanded, NULL);
8766 if (m_pMouseRoute) {
8767 if (m_routeState == 1) {
8769 m_pMouseRoute->AddPoint(pMousePoint);
8772 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8773 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8774 &rhumbBearing, &rhumbDist);
8775 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8776 rlat, &gcDist, &gcBearing, NULL);
8777 double gcDistNM = gcDist / 1852.0;
8780 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8781 pow(rhumbDist - gcDistNM - 1, 0.5);
8784 msg << _(
"For this leg the Great Circle route is ")
8786 << _(
" shorter than rhumbline.\n\n")
8787 << _(
"Would you like include the Great Circle routing points "
8790 m_FinishRouteOnKillFocus =
false;
8791 m_disable_edge_pan =
true;
8794 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8795 wxYES_NO | wxNO_DEFAULT);
8797 m_disable_edge_pan =
false;
8798 m_FinishRouteOnKillFocus =
true;
8800 if (answer == wxID_YES) {
8802 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8803 wxRealPoint gcCoord;
8805 for (
int i = 1; i <= segmentCount; i++) {
8806 double fraction = (double)i * (1.0 / (
double)segmentCount);
8807 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8808 gcDist * fraction, gcBearing,
8809 &gcCoord.x, &gcCoord.y, NULL);
8811 if (i < segmentCount) {
8812 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8814 gcPoint->SetNameShown(
false);
8816 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8818 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8821 gcPoint = pMousePoint;
8824 m_pMouseRoute->AddPoint(gcPoint);
8825 pSelect->AddSelectableRouteSegment(
8826 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8827 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8828 prevGcPoint = gcPoint;
8831 undo->CancelUndoableAction(
true);
8834 m_pMouseRoute->AddPoint(pMousePoint);
8835 pSelect->AddSelectableRouteSegment(
8836 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8837 pMousePoint, m_pMouseRoute);
8838 undo->AfterUndoableAction(m_pMouseRoute);
8842 m_pMouseRoute->AddPoint(pMousePoint);
8843 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8844 rlon, m_prev_pMousePoint,
8845 pMousePoint, m_pMouseRoute);
8846 undo->AfterUndoableAction(m_pMouseRoute);
8852 m_prev_pMousePoint = pMousePoint;
8860 int connect = tail->GetIndexOf(pMousePoint);
8865 int length = tail->GetnPoints();
8870 start = connect + 1;
8876 m_pMouseRoute->RemovePoint(m_pMouseRoute->GetLastPoint());
8878 for (i = start; i <= stop; i++) {
8879 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8882 m_pMouseRoute->GetnPoints();
8884 top_frame::Get()->RefreshAllCanvas();
8888 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8890 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8891 m_pMouseRoute->FinalizeForRendering();
8893 top_frame::Get()->RefreshAllCanvas();
8897 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8899 SetCursor(*pCursorPencil);
8901 if (!m_pMeasureRoute) {
8902 m_pMeasureRoute =
new Route();
8906 if (m_nMeasureState == 1) {
8913 wxEmptyString, wxEmptyString);
8915 pMousePoint->SetShowWaypointRangeRings(
false);
8917 m_pMeasureRoute->AddPoint(pMousePoint);
8921 m_prev_pMousePoint = pMousePoint;
8925 top_frame::Get()->RefreshAllCanvas();
8930 FindRoutePointsAtCursor(SelectRadius,
true);
8934 m_last_touch_down_pos =
event.GetPosition();
8936 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8944 if (ret)
return true;
8947 if (event.Dragging()) {
8950 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8952 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8954 SelectableItemList SelList =
pSelect->FindSelectionList(
8958 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8963 if (m_pRoutePointEditTarget &&
8964 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8966 SelectableItemList SelList =
pSelect->FindSelectionList(
8970 if (m_pRoutePointEditTarget == frp) {
8971 m_bIsInRadius =
true;
8976 if (!m_dragoffsetSet) {
8978 .PresetDragOffset(
this, mouse_x, mouse_y);
8979 m_dragoffsetSet =
true;
8984 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8985 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8988 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8990 DraggingAllowed =
false;
8992 if (m_pRoutePointEditTarget &&
8993 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8994 DraggingAllowed =
false;
8996 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8998 if (DraggingAllowed) {
8999 if (!undo->InUndoableAction()) {
9000 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9001 Undo_NeedsCopy, m_pFoundPoint);
9007 if (!g_bopengl && m_pEditRouteArray) {
9008 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9009 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9016 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9017 pre_rect.Union(route_rect);
9025 if (CheckEdgePan(x, y,
true, 5, 2))
9033 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9035 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
9036 m_pRoutePointEditTarget,
9037 SELTYPE_DRAGHANDLE);
9038 m_pFoundPoint->m_slat =
9039 m_pRoutePointEditTarget->m_lat;
9040 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9042 m_pRoutePointEditTarget->m_lat =
9044 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
9045 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9046 m_pFoundPoint->m_slat =
9048 m_pFoundPoint->m_slon = new_cursor_lon;
9064 if (m_pEditRouteArray) {
9065 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9067 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9070 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9071 post_rect.Union(route_rect);
9077 pre_rect.Union(post_rect);
9078 RefreshRect(pre_rect,
false);
9080 top_frame::Get()->RefreshCanvasOther(
this);
9081 m_bRoutePoinDragging =
true;
9086 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9087 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9090 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9092 DraggingAllowed =
false;
9094 if (m_pRoutePointEditTarget &&
9095 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9096 DraggingAllowed =
false;
9098 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9100 if (DraggingAllowed) {
9101 if (!undo->InUndoableAction()) {
9102 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9103 Undo_NeedsCopy, m_pFoundPoint);
9117 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9123 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9124 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9125 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9126 (
int)(lppmax - (pre_rect.height / 2)));
9134 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9137 m_pRoutePointEditTarget,
9138 SELTYPE_DRAGHANDLE);
9139 m_pFoundPoint->m_slat =
9140 m_pRoutePointEditTarget->m_lat;
9141 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9143 m_pRoutePointEditTarget->m_lat =
9146 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9159 if (!g_btouch) InvalidateGL();
9165 .CalculateDCRect(m_dc_route,
this, &post_rect);
9166 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9167 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9168 (
int)(lppmax - (post_rect.height / 2)));
9171 pre_rect.Union(post_rect);
9172 RefreshRect(pre_rect,
false);
9174 top_frame::Get()->RefreshCanvasOther(
this);
9175 m_bRoutePoinDragging =
true;
9177 ret = g_btouch ? m_bRoutePoinDragging :
true;
9180 if (ret)
return true;
9183 if (event.LeftUp()) {
9184 bool b_startedit_route =
false;
9185 m_dragoffsetSet =
false;
9188 m_bChartDragging =
false;
9189 m_bIsInRadius =
false;
9196 int dx = x - m_touchdownPos.x;
9197 int dy = y - m_touchdownPos.y;
9198 int dist2 = dx * dx + dy * dy;
9199 bool wasPan = (dist2 > 20 * 20);
9206 m_bedge_pan =
false;
9211 bool appending =
false;
9212 bool inserting =
false;
9218 if (m_pRoutePointEditTarget) {
9224 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9225 RefreshRect(wp_rect,
true);
9227 m_pRoutePointEditTarget = NULL;
9229 m_bRouteEditing =
true;
9231 if (m_routeState == 1) {
9232 m_pMouseRoute =
new Route();
9233 m_pMouseRoute->SetHiLite(50);
9237 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9244 double nearby_radius_meters =
9245 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9248 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9249 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9250 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9253 m_FinishRouteOnKillFocus =
9255 dlg_return = OCPNMessageBox(
9256 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9257 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9258 m_FinishRouteOnKillFocus =
true;
9260 dlg_return = wxID_YES;
9262 if (dlg_return == wxID_YES) {
9263 pMousePoint = pNearbyPoint;
9266 if (m_routeState > 1)
9267 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9268 Undo_HasParent, NULL);
9269 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9271 bool procede =
false;
9275 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9281 m_FinishRouteOnKillFocus =
false;
9282 if (m_routeState == 1) {
9286 _(
"Insert first part of this route in the new route?");
9287 if (tail->GetIndexOf(pMousePoint) ==
9290 dmsg = _(
"Insert this route in the new route?");
9292 if (tail->GetIndexOf(pMousePoint) != 1) {
9294 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9295 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9296 m_FinishRouteOnKillFocus =
true;
9298 if (dlg_return == wxID_YES) {
9305 _(
"Append last part of this route to the new route?");
9306 if (tail->GetIndexOf(pMousePoint) == 1)
9308 "Append this route to the new route?");
9312 if (tail->GetLastPoint() != pMousePoint) {
9314 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9315 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9316 m_FinishRouteOnKillFocus =
true;
9318 if (dlg_return == wxID_YES) {
9329 if (!FindRouteContainingWaypoint(pMousePoint))
9330 pMousePoint->SetShared(
true);
9334 if (NULL == pMousePoint) {
9335 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9337 pMousePoint->SetNameShown(
false);
9339 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9341 if (m_routeState > 1)
9342 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9343 Undo_IsOrphanded, NULL);
9346 if (m_routeState == 1) {
9348 m_pMouseRoute->AddPoint(pMousePoint);
9349 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9353 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9354 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9355 &rhumbBearing, &rhumbDist);
9356 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9357 &gcDist, &gcBearing, NULL);
9358 double gcDistNM = gcDist / 1852.0;
9361 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9362 pow(rhumbDist - gcDistNM - 1, 0.5);
9365 msg << _(
"For this leg the Great Circle route is ")
9367 << _(
" shorter than rhumbline.\n\n")
9368 << _(
"Would you like include the Great Circle routing points "
9372 m_FinishRouteOnKillFocus =
false;
9373 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9374 wxYES_NO | wxNO_DEFAULT);
9375 m_FinishRouteOnKillFocus =
true;
9377 int answer = wxID_NO;
9380 if (answer == wxID_YES) {
9382 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9383 wxRealPoint gcCoord;
9385 for (
int i = 1; i <= segmentCount; i++) {
9386 double fraction = (double)i * (1.0 / (
double)segmentCount);
9387 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9388 gcDist * fraction, gcBearing,
9389 &gcCoord.x, &gcCoord.y, NULL);
9391 if (i < segmentCount) {
9392 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9394 gcPoint->SetNameShown(
false);
9395 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9398 gcPoint = pMousePoint;
9401 m_pMouseRoute->AddPoint(gcPoint);
9402 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9404 pSelect->AddSelectableRouteSegment(
9405 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9406 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9407 prevGcPoint = gcPoint;
9410 undo->CancelUndoableAction(
true);
9413 m_pMouseRoute->AddPoint(pMousePoint);
9414 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9415 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9416 rlon, m_prev_pMousePoint,
9417 pMousePoint, m_pMouseRoute);
9418 undo->AfterUndoableAction(m_pMouseRoute);
9422 m_pMouseRoute->AddPoint(pMousePoint);
9423 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9425 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9426 rlon, m_prev_pMousePoint,
9427 pMousePoint, m_pMouseRoute);
9428 undo->AfterUndoableAction(m_pMouseRoute);
9434 m_prev_pMousePoint = pMousePoint;
9441 int connect = tail->GetIndexOf(pMousePoint);
9446 int length = tail->GetnPoints();
9451 start = connect + 1;
9456 m_pMouseRoute->RemovePoint(
9460 for (i = start; i <= stop; i++) {
9461 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9464 m_pMouseRoute->GetnPoints();
9466 top_frame::Get()->RefreshAllCanvas();
9470 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9472 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9473 m_pMouseRoute->FinalizeForRendering();
9478 }
else if (m_bMeasure_Active && m_nMeasureState)
9481 m_bedge_pan =
false;
9487 int mdx = x - m_touchdownPos.x;
9488 int mdy = y - m_touchdownPos.y;
9489 if (mdx * mdx + mdy * mdy > 20 * 20)
return false;
9492 if (m_nMeasureState == 1) {
9493 m_pMeasureRoute =
new Route();
9499 if (m_pMeasureRoute) {
9502 wxEmptyString, wxEmptyString);
9505 m_pMeasureRoute->AddPoint(pMousePoint);
9509 m_prev_pMousePoint = pMousePoint;
9511 m_pMeasureRoute->GetnPoints();
9515 CancelMeasureRoute();
9521 bool bSelectAllowed =
true;
9523 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9525 bSelectAllowed =
false;
9529 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9530 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9531 significant_drag) ||
9532 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9533 significant_drag)) {
9534 bSelectAllowed =
false;
9542 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9544 if (bSelectAllowed) {
9545 bool b_was_editing_mark = m_bMarkEditing;
9546 bool b_was_editing_route = m_bRouteEditing;
9547 FindRoutePointsAtCursor(SelectRadius,
9553 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9554 m_pRoutePointEditTarget = NULL;
9556 if (!b_was_editing_route) {
9557 if (m_pEditRouteArray) {
9558 b_startedit_route =
true;
9562 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9563 m_pTrackRolloverWin->IsActive(
false);
9565 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9566 m_pRouteRolloverWin->IsActive(
false);
9570 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9572 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9580 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9581 pre_rect.Union(route_rect);
9584 RefreshRect(pre_rect,
true);
9587 b_startedit_route =
false;
9591 if (m_pRoutePointEditTarget) {
9592 if (b_was_editing_mark ||
9593 b_was_editing_route) {
9594 if (m_lastRoutePointEditTarget) {
9598 .EnableDragHandle(
false);
9599 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9600 SELTYPE_DRAGHANDLE);
9604 if (m_pRoutePointEditTarget) {
9607 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9608 wxPoint2DDouble dragHandlePoint =
9610 .GetDragHandlePoint(
this);
9612 dragHandlePoint.m_y, dragHandlePoint.m_x,
9613 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9616 if (m_lastRoutePointEditTarget) {
9620 .EnableDragHandle(
false);
9621 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9622 SELTYPE_DRAGHANDLE);
9625 wxArrayPtrVoid *lastEditRouteArray =
9627 m_lastRoutePointEditTarget);
9628 if (lastEditRouteArray) {
9629 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9631 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9636 delete lastEditRouteArray;
9647 if (m_lastRoutePointEditTarget) {
9650 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9651 RefreshRect(wp_rect,
true);
9654 if (m_pRoutePointEditTarget) {
9657 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9658 RefreshRect(wp_rect,
true);
9666 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9667 bool b_start_rollover =
false;
9671 if (pFind) b_start_rollover =
true;
9674 if (!b_start_rollover && !b_startedit_route) {
9675 SelectableItemList SelList =
pSelect->FindSelectionList(
9679 if (pr && pr->IsVisible()) {
9680 b_start_rollover =
true;
9686 if (!b_start_rollover && !b_startedit_route) {
9687 SelectableItemList SelList =
pSelect->FindSelectionList(
9691 if (tr && tr->IsVisible()) {
9692 b_start_rollover =
true;
9698 if (b_start_rollover)
9699 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9703 bool appending =
false;
9704 bool inserting =
false;
9706 if (m_bRouteEditing ) {
9708 if (m_pRoutePointEditTarget) {
9714 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9715 double nearby_radius_meters =
9716 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9717 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9718 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9719 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9721 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9725 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9727 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9731 std::find(list->begin(), list->end(), pNearbyPoint);
9732 if (pos != list->end()) {
9744 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9749 OCPNMessageBox(
this,
9750 _(
"Replace this RoutePoint by the nearby "
9752 _(
"OpenCPN RoutePoint change"),
9753 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9754 if (dlg_return == wxID_YES) {
9759 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9762 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9764 if (tail && current && (tail != current)) {
9766 connect = tail->GetIndexOf(pNearbyPoint);
9767 int index_current_route =
9768 current->GetIndexOf(m_pRoutePointEditTarget);
9769 index_last = current->GetIndexOf(current->GetLastPoint());
9770 dlg_return1 = wxID_NO;
9772 index_current_route) {
9774 if (connect != tail->GetnPoints()) {
9777 _(
"Last part of route to be appended to dragged "
9781 _(
"Full route to be appended to dragged route?");
9783 dlg_return1 = OCPNMessageBox(
9784 this, dmsg, _(
"OpenCPN Route Create"),
9785 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9786 if (dlg_return1 == wxID_YES) {
9790 }
else if (index_current_route ==
9795 _(
"First part of route to be inserted into dragged "
9797 if (connect == tail->GetnPoints())
9799 "Full route to be inserted into dragged route?");
9801 dlg_return1 = OCPNMessageBox(
9802 this, dmsg, _(
"OpenCPN Route Create"),
9803 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9804 if (dlg_return1 == wxID_YES) {
9811 if (m_pRoutePointEditTarget->IsShared()) {
9813 dlg_return = OCPNMessageBox(
9815 _(
"Do you really want to delete and replace this "
9817 "\n" + _(
"which has been created manually?"),
9818 (
"OpenCPN RoutePoint warning"),
9819 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9822 if (dlg_return == wxID_YES) {
9823 pMousePoint = pNearbyPoint;
9825 pMousePoint->SetShared(
true);
9835 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9837 if (m_pEditRouteArray) {
9838 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9840 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9845 auto pos = std::find(list->begin(), list->end(),
9846 m_pRoutePointEditTarget);
9848 pSelect->DeleteAllSelectableRoutePoints(pr);
9849 pSelect->DeleteAllSelectableRouteSegments(pr);
9852 pos = std::find(list->begin(), list->end(),
9853 m_pRoutePointEditTarget);
9856 pSelect->AddAllSelectableRouteSegments(pr);
9857 pSelect->AddAllSelectableRoutePoints(pr);
9859 pr->FinalizeForRendering();
9860 pr->UpdateSegmentDistances();
9861 if (m_bRoutePoinDragging) {
9863 NavObj_dB::GetInstance().UpdateRoute(pr);
9871 if (m_pEditRouteArray) {
9872 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9874 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9893 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9900 delete m_pRoutePointEditTarget;
9901 m_lastRoutePointEditTarget = NULL;
9902 m_pRoutePointEditTarget = NULL;
9903 undo->AfterUndoableAction(pMousePoint);
9904 undo->InvalidateUndo();
9909 else if (m_bMarkEditing) {
9910 if (m_pRoutePointEditTarget)
9911 if (m_bRoutePoinDragging) {
9913 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9917 if (m_pRoutePointEditTarget)
9918 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9920 if (!m_pRoutePointEditTarget) {
9921 delete m_pEditRouteArray;
9922 m_pEditRouteArray = NULL;
9923 m_bRouteEditing =
false;
9925 m_bRoutePoinDragging =
false;
9932 int length = tail->GetnPoints();
9933 for (
int i = connect + 1; i <= length; i++) {
9934 current->AddPointAndSegment(tail->GetPoint(i),
false);
9937 top_frame::Get()->RefreshAllCanvas();
9940 current->FinalizeForRendering();
9946 pSelect->DeleteAllSelectableRoutePoints(current);
9947 pSelect->DeleteAllSelectableRouteSegments(current);
9948 for (
int i = 1; i < connect; i++) {
9949 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9951 pSelect->AddAllSelectableRouteSegments(current);
9952 pSelect->AddAllSelectableRoutePoints(current);
9953 current->FinalizeForRendering();
9960 if (m_pEditRouteArray) {
9961 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9962 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9975 if (m_bRouteEditing) {
9978 bool appending =
false;
9979 bool inserting =
false;
9982 if (m_pRoutePointEditTarget) {
9983 m_pRoutePointEditTarget->
m_bBlink =
false;
9987 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9988 double nearby_radius_meters =
9989 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9990 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9991 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9992 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9994 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9995 bool duplicate =
false;
9997 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9999 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10003 std::find(list->begin(), list->end(), pNearbyPoint);
10004 if (pos != list->end()) {
10016 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
10021 OCPNMessageBox(
this,
10022 _(
"Replace this RoutePoint by the nearby "
10024 _(
"OpenCPN RoutePoint change"),
10025 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10026 if (dlg_return == wxID_YES) {
10030 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
10033 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
10035 if (tail && current && (tail != current)) {
10037 connect = tail->GetIndexOf(pNearbyPoint);
10038 int index_current_route =
10039 current->GetIndexOf(m_pRoutePointEditTarget);
10040 index_last = current->GetIndexOf(current->GetLastPoint());
10041 dlg_return1 = wxID_NO;
10043 index_current_route) {
10045 if (connect != tail->GetnPoints()) {
10048 _(
"Last part of route to be appended to dragged "
10052 _(
"Full route to be appended to dragged route?");
10054 dlg_return1 = OCPNMessageBox(
10055 this, dmsg, _(
"OpenCPN Route Create"),
10056 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10057 if (dlg_return1 == wxID_YES) {
10061 }
else if (index_current_route ==
10063 if (connect != 1) {
10066 _(
"First part of route to be inserted into dragged "
10068 if (connect == tail->GetnPoints())
10070 "Full route to be inserted into dragged route?");
10072 dlg_return1 = OCPNMessageBox(
10073 this, dmsg, _(
"OpenCPN Route Create"),
10074 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10075 if (dlg_return1 == wxID_YES) {
10082 if (m_pRoutePointEditTarget->IsShared()) {
10083 dlg_return = wxID_NO;
10084 dlg_return = OCPNMessageBox(
10086 _(
"Do you really want to delete and replace this "
10088 "\n" + _(
"which has been created manually?"),
10089 (
"OpenCPN RoutePoint warning"),
10090 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10093 if (dlg_return == wxID_YES) {
10094 pMousePoint = pNearbyPoint;
10096 pMousePoint->SetShared(
true);
10106 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10108 if (m_pEditRouteArray) {
10109 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10111 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10115 auto pos = std::find(list->begin(), list->end(),
10116 m_pRoutePointEditTarget);
10118 pSelect->DeleteAllSelectableRoutePoints(pr);
10119 pSelect->DeleteAllSelectableRouteSegments(pr);
10122 pos = std::find(list->begin(), list->end(),
10123 m_pRoutePointEditTarget);
10124 if (pos != list->end()) list->erase(pos);
10127 pSelect->AddAllSelectableRouteSegments(pr);
10128 pSelect->AddAllSelectableRoutePoints(pr);
10130 pr->FinalizeForRendering();
10131 pr->UpdateSegmentDistances();
10134 if (m_bRoutePoinDragging) {
10139 NavObj_dB::GetInstance().UpdateRoutePoint(
10140 m_pRoutePointEditTarget);
10142 NavObj_dB::GetInstance().UpdateRoute(pr);
10154 int length = tail->GetnPoints();
10155 for (
int i = connect + 1; i <= length; i++) {
10156 current->AddPointAndSegment(tail->GetPoint(i),
false);
10160 top_frame::Get()->RefreshAllCanvas();
10163 current->FinalizeForRendering();
10169 pSelect->DeleteAllSelectableRoutePoints(current);
10170 pSelect->DeleteAllSelectableRouteSegments(current);
10171 for (
int i = 1; i < connect; i++) {
10172 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10174 pSelect->AddAllSelectableRouteSegments(current);
10175 pSelect->AddAllSelectableRoutePoints(current);
10176 current->FinalizeForRendering();
10183 if (m_pEditRouteArray) {
10184 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10186 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10198 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10205 delete m_pRoutePointEditTarget;
10206 m_lastRoutePointEditTarget = NULL;
10207 undo->AfterUndoableAction(pMousePoint);
10208 undo->InvalidateUndo();
10213 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10216 delete m_pEditRouteArray;
10217 m_pEditRouteArray = NULL;
10221 m_bRouteEditing =
false;
10222 m_pRoutePointEditTarget = NULL;
10228 else if (m_bMarkEditing) {
10229 if (m_pRoutePointEditTarget) {
10230 if (m_bRoutePoinDragging) {
10232 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10234 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10239 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10241 RefreshRect(wp_rect,
true);
10244 m_pRoutePointEditTarget = NULL;
10245 m_bMarkEditing =
false;
10250 else if (leftIsDown) {
10251 leftIsDown =
false;
10255 if (!m_bChartDragging && !m_bMeasure_Active) {
10257 m_bChartDragging =
false;
10261 m_bRoutePoinDragging =
false;
10264 if (ret)
return true;
10267 if (event.RightDown()) {
10278 m_FinishRouteOnKillFocus =
false;
10279 CallPopupMenu(mx, my);
10280 m_FinishRouteOnKillFocus =
true;
10290 if (event.ShiftDown()) {
10294 event.GetPosition(&x, &y);
10296 x *= m_displayScale;
10297 y *= m_displayScale;
10303 int wheel_dir =
event.GetWheelRotation();
10306 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10307 wheel_dir = wheel_dir > 0 ? 1 : -1;
10309 double factor = g_mouse_zoom_sensitivity;
10310 if (wheel_dir < 0) factor = 1 / factor;
10313 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10314 if (wheel_dir == m_last_wheel_dir) {
10315 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10320 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10321 m_wheelstopwatch.Start(0);
10326 m_last_wheel_dir = wheel_dir;
10331 if (event.LeftDown()) {
10337 last_drag.x = x, last_drag.y = y;
10338 m_touchdownPos = wxPoint(x, y);
10339 panleftIsDown =
true;
10342 if (event.LeftUp()) {
10343 if (panleftIsDown) {
10345 panleftIsDown =
false;
10348 if (!m_bChartDragging && !m_bMeasure_Active) {
10349 switch (cursor_region) {
10371 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10376 m_bChartDragging =
false;
10382 if (event.Dragging() && event.LeftIsDown()) {
10398 if (g_btouch && !m_inPinch) {
10399 struct timespec now;
10400 clock_gettime(CLOCK_MONOTONIC, &now);
10401 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10403 bool trigger_hold =
false;
10404 if (
false == m_bChartDragging) {
10405 if (m_DragTrigger < 0) {
10408 m_DragTriggerStartTime = tnow;
10409 trigger_hold =
true;
10411 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10412 m_DragTrigger = -1;
10417 if (trigger_hold)
return true;
10419 if (
false == m_bChartDragging) {
10422 last_drag.x = x - 1, last_drag.y = y - 1;
10423 m_bChartDragging =
true;
10424 m_chart_drag_total_time = 0;
10425 m_chart_drag_total_x = 0;
10426 m_chart_drag_total_y = 0;
10427 m_inertia_last_drag_x = x;
10428 m_inertia_last_drag_y = y;
10429 m_drag_vec_x.clear();
10430 m_drag_vec_y.clear();
10431 m_drag_vec_t.clear();
10432 m_last_drag_time = tnow;
10436 uint64_t delta_t = tnow - m_last_drag_time;
10437 double delta_tf = delta_t / 1e9;
10439 m_chart_drag_total_time += delta_tf;
10440 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10441 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10443 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10444 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10445 m_drag_vec_t.push_back(delta_tf);
10447 m_inertia_last_drag_x = x;
10448 m_inertia_last_drag_y = y;
10449 m_last_drag_time = tnow;
10451 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10452 m_bChartDragging =
true;
10453 StartTimedMovement();
10454 m_pan_drag.x += last_drag.x - x;
10455 m_pan_drag.y += last_drag.y - y;
10456 last_drag.x = x, last_drag.y = y;
10458 }
else if (!g_btouch) {
10459 if ((last_drag.x != x) || (last_drag.y != y)) {
10460 if (!m_routeState) {
10463 m_bChartDragging =
true;
10464 StartTimedMovement();
10465 m_pan_drag.x += last_drag.x - x;
10466 m_pan_drag.y += last_drag.y - y;
10467 last_drag.x = x, last_drag.y = y;
10474 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10476 m_DoubleClickTimer->Start();
10477 singleClickEventIsValid =
false;
10485void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10486 if (MouseEventOverlayWindows(event))
return;
10490 bool nm = MouseEventProcessObjects(event);
10494void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10497 wxCursor *ptarget_cursor = pCursorArrow;
10498 if (!pPlugIn_Cursor) {
10499 ptarget_cursor = pCursorArrow;
10500 if ((!m_routeState) &&
10501 (!m_bMeasure_Active) ) {
10502 if (cursor_region == MID_RIGHT) {
10503 ptarget_cursor = pCursorRight;
10504 }
else if (cursor_region == MID_LEFT) {
10505 ptarget_cursor = pCursorLeft;
10506 }
else if (cursor_region == MID_TOP) {
10507 ptarget_cursor = pCursorDown;
10508 }
else if (cursor_region == MID_BOT) {
10509 ptarget_cursor = pCursorUp;
10511 ptarget_cursor = pCursorArrow;
10513 }
else if (m_bMeasure_Active ||
10515 ptarget_cursor = pCursorPencil;
10517 ptarget_cursor = pPlugIn_Cursor;
10520 SetCursor(*ptarget_cursor);
10523void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10524 SetCursor(*pCursorArrow);
10527void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10531 wxArrayString files;
10533 ChartBase *target_chart = GetChartAtCursor();
10534 if (target_chart) {
10535 file.Assign(target_chart->GetFullPath());
10536 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10537 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10540 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10542 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10543 unsigned int im = stackIndexArray.size();
10544 int scale = 2147483647;
10545 if (VPoint.b_quilt && im > 0) {
10546 for (
unsigned int is = 0; is < im; is++) {
10547 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10548 CHART_TYPE_MBTILES) {
10549 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10551 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10552 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10554 .Contains(lat, lon)) {
10555 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10558 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10559 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10567 std::vector<Ais8_001_22 *> area_notices;
10569 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10572 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10573 auto target_data = target.second;
10574 if (!target_data->area_notices.empty()) {
10575 for (
auto &ani : target_data->area_notices) {
10580 for (Ais8_001_22_SubAreaList::iterator sa =
10581 area_notice.sub_areas.begin();
10582 sa != area_notice.sub_areas.end(); ++sa) {
10583 switch (sa->shape) {
10584 case AIS8_001_22_SHAPE_CIRCLE: {
10585 wxPoint target_point;
10587 bbox.Expand(target_point);
10588 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10591 case AIS8_001_22_SHAPE_RECT: {
10592 wxPoint target_point;
10594 bbox.Expand(target_point);
10595 if (sa->e_dim_m > sa->n_dim_m)
10596 bbox.EnLarge(sa->e_dim_m * vp_scale);
10598 bbox.EnLarge(sa->n_dim_m * vp_scale);
10601 case AIS8_001_22_SHAPE_POLYGON:
10602 case AIS8_001_22_SHAPE_POLYLINE: {
10603 for (
int i = 0; i < 4; ++i) {
10604 double lat = sa->latitude;
10605 double lon = sa->longitude;
10606 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10608 wxPoint target_point;
10610 bbox.Expand(target_point);
10614 case AIS8_001_22_SHAPE_SECTOR: {
10615 double lat1 = sa->latitude;
10616 double lon1 = sa->longitude;
10618 wxPoint target_point;
10620 bbox.Expand(target_point);
10621 for (
int i = 0; i < 18; ++i) {
10624 sa->left_bound_deg +
10625 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10626 sa->radius_m / 1852.0, &lat, &lon);
10628 bbox.Expand(target_point);
10630 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10633 bbox.Expand(target_point);
10639 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10640 area_notices.push_back(&area_notice);
10647 if (target_chart || !area_notices.empty() || file.HasName()) {
10649 int sel_rad_pix = 5;
10650 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10655 SetCursor(wxCURSOR_WAIT);
10656 bool lightsVis = m_encShowLights;
10657 if (!lightsVis) SetShowENCLights(
true);
10660 ListOfObjRazRules *rule_list = NULL;
10661 ListOfPI_S57Obj *pi_rule_list = NULL;
10664 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10665 else if (target_plugin_chart)
10666 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10667 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10669 ListOfObjRazRules *overlay_rule_list = NULL;
10670 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10673 if (CHs57_Overlay) {
10674 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10675 zlat, zlon, SelectRadius, &GetVP());
10678 if (!lightsVis) SetShowENCLights(
false);
10681 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10682 wxString face = dFont->GetFaceName();
10686 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10687 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10691 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10699 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10700 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10703 int points = dFont->GetPointSize();
10705 int points = dFont->GetPointSize() + 1;
10709 for (
int i = -2; i < 5; i++) {
10710 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10714 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10716 if (overlay_rule_list && CHs57_Overlay) {
10717 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10718 objText <<
"<hr noshade>";
10721 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10722 an != area_notices.end(); ++an) {
10723 objText <<
"<b>AIS Area Notice:</b> ";
10724 objText << ais8_001_22_notice_names[(*an)->notice_type];
10725 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10726 (*an)->sub_areas.begin();
10727 sa != (*an)->sub_areas.end(); ++sa)
10728 if (!sa->text.empty()) objText << sa->text;
10729 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10730 objText <<
"<hr noshade>";
10734 objText << Chs57->CreateObjDescriptions(rule_list);
10735 else if (target_plugin_chart)
10736 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10739 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10742 wxString AddFiles, filenameOK;
10744 if (!target_plugin_chart) {
10747 AddFiles = wxString::Format(
10748 "<hr noshade><br><b>Additional info files attached to: </b> "
10750 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10752 file.GetFullName());
10754 file.Assign(file.GetPath(),
"");
10755 wxDir dir(file.GetFullPath());
10757 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10759 file.Assign(dir.GetNameWithSep().append(filename));
10760 wxString FormatString =
10761 "<td valign=top><font size=-2><a "
10762 "href=\"%s\">%s</a></font></td>";
10763 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10764 filenameOK = file.GetFullPath();
10766 if (3 * ((
int)filecount / 3) == filecount)
10767 FormatString.Prepend(
"<tr>");
10769 FormatString.Prepend(
10770 "<td>  </td>");
10773 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10774 file.GetFullName());
10777 cont = dir.GetNext(&filename);
10779 objText << AddFiles <<
"</table>";
10781 objText <<
"</font>";
10782 objText <<
"</body></html>";
10784 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10788 if ((!Chs57 && filecount == 1)) {
10790 wxHtmlLinkInfo hli(filenameOK);
10791 wxHtmlLinkEvent hle(1, hli);
10795 if (rule_list) rule_list->Clear();
10798 if (overlay_rule_list) overlay_rule_list->Clear();
10799 delete overlay_rule_list;
10801 if (pi_rule_list) pi_rule_list->Clear();
10802 delete pi_rule_list;
10804 SetCursor(wxCURSOR_ARROW);
10808void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10817 wxSize canvas_size = GetSize();
10824 wxPoint canvas_pos = GetPosition();
10827 bool newFit =
false;
10828 if (canvas_size.x < fitted_size.x) {
10829 fitted_size.x = canvas_size.x - 40;
10830 if (canvas_size.y < fitted_size.y)
10831 fitted_size.y -= 40;
10833 if (canvas_size.y < fitted_size.y) {
10834 fitted_size.y = canvas_size.y - 40;
10835 if (canvas_size.x < fitted_size.x)
10836 fitted_size.x -= 40;
10847 wxString title_base = _(
"Mark Properties");
10849 title_base = _(
"Waypoint Properties");
10854 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10866void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10876 if (g_bresponsive) {
10877 wxSize canvas_size = GetSize();
10878 wxPoint canvas_pos = GetPosition();
10882 if (canvas_size.x < fitted_size.x) {
10883 fitted_size.x = canvas_size.x;
10884 if (canvas_size.y < fitted_size.y)
10885 fitted_size.y -= 20;
10887 if (canvas_size.y < fitted_size.y) {
10888 fitted_size.y = canvas_size.y;
10889 if (canvas_size.x < fitted_size.x)
10890 fitted_size.x -= 20;
10899 wxPoint xxp = ClientToScreen(canvas_pos);
10910void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10922void pupHandler_PasteWaypoint() {
10925 int pasteBuffer = kml.ParsePasteBuffer();
10926 RoutePoint *pasted = kml.GetParsedRoutePoint();
10927 if (!pasted)
return;
10929 double nearby_radius_meters =
10930 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10932 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10933 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10935 int answer = wxID_NO;
10939 "There is an existing waypoint at the same location as the one you are "
10940 "pasting. Would you like to merge the pasted data with it?\n\n");
10941 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10942 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10943 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10946 if (answer == wxID_YES) {
10947 nearPoint->SetName(pasted->GetName());
10953 if (answer == wxID_NO) {
10956 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10959 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10968 top_frame::Get()->InvalidateAllGL();
10969 top_frame::Get()->RefreshAllCanvas(
false);
10972void pupHandler_PasteRoute() {
10975 int pasteBuffer = kml.ParsePasteBuffer();
10976 Route *pasted = kml.GetParsedRoute();
10977 if (!pasted)
return;
10979 double nearby_radius_meters =
10980 g_Platform->GetSelectRadiusPix() / top_frame::Get()->GetCanvasTrueScale();
10986 bool mergepoints =
false;
10987 bool createNewRoute =
true;
10988 int existingWaypointCounter = 0;
10990 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10991 curPoint = pasted->GetPoint(i);
10992 nearPoint = pWayPointMan->GetNearbyWaypoint(
10993 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10995 mergepoints =
true;
10996 existingWaypointCounter++;
11004 int answer = wxID_NO;
11008 "There are existing waypoints at the same location as some of the ones "
11009 "you are pasting. Would you like to just merge the pasted data into "
11011 msg << _(
"Answering 'No' will create all new waypoints for this route.");
11012 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
11013 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
11015 if (answer == wxID_CANCEL) {
11022 if (mergepoints && answer == wxID_YES &&
11023 existingWaypointCounter == pasted->GetnPoints()) {
11026 createNewRoute =
false;
11032 Route *newRoute = 0;
11035 if (createNewRoute) {
11036 newRoute =
new Route();
11040 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
11041 curPoint = pasted->GetPoint(i);
11044 newPoint = pWayPointMan->GetNearbyWaypoint(
11045 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
11046 newPoint->SetName(curPoint->GetName());
11049 if (createNewRoute) newRoute->AddPoint(newPoint);
11055 newPoint->SetIconName(
"circle");
11058 newPoint->SetShared(
false);
11060 newRoute->AddPoint(newPoint);
11061 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11064 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11067 if (i > 1 && createNewRoute)
11068 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11069 curPoint->m_lat, curPoint->m_lon,
11070 prevPoint, newPoint, newRoute);
11071 prevPoint = newPoint;
11074 if (createNewRoute) {
11077 NavObj_dB::GetInstance().InsertRoute(newRoute);
11087 top_frame::Get()->InvalidateAllGL();
11088 top_frame::Get()->RefreshAllCanvas(
false);
11094void pupHandler_PasteTrack() {
11097 int pasteBuffer = kml.ParsePasteBuffer();
11098 Track *pasted = kml.GetParsedTrack();
11099 if (!pasted)
return;
11107 newTrack->SetName(pasted->GetName());
11109 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11110 curPoint = pasted->GetPoint(i);
11114 wxDateTime now = wxDateTime::Now();
11117 newTrack->AddPoint(newPoint);
11120 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11121 newPoint->m_lat, newPoint->m_lon,
11122 prevPoint, newPoint, newTrack);
11124 prevPoint = newPoint;
11129 NavObj_dB::GetInstance().InsertTrack(newTrack);
11131 top_frame::Get()->InvalidateAllGL();
11132 top_frame::Get()->RefreshAllCanvas(
false);
11135bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11138 v[
"CursorPosition_x"] = x;
11139 v[
"CursorPosition_y"] = y;
11142 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11143 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11144 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11149 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11151 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11154#define SELTYPE_UNKNOWN 0x0001
11155#define SELTYPE_ROUTEPOINT 0x0002
11156#define SELTYPE_ROUTESEGMENT 0x0004
11157#define SELTYPE_TIDEPOINT 0x0008
11158#define SELTYPE_CURRENTPOINT 0x0010
11159#define SELTYPE_ROUTECREATE 0x0020
11160#define SELTYPE_AISTARGET 0x0040
11161#define SELTYPE_MARKPOINT 0x0080
11162#define SELTYPE_TRACKSEGMENT 0x0100
11163#define SELTYPE_DRAGHANDLE 0x0200
11166 if (g_bhide_context_menus)
return true;
11168 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11169 m_pIDXCandidate, m_nmea_log);
11172 wxEVT_COMMAND_MENU_SELECTED,
11173 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11179 if (m_inLongPress) {
11180 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11181 m_inLongPress =
false;
11185 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11188 wxEVT_COMMAND_MENU_SELECTED,
11189 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11191 delete m_canvasMenu;
11192 m_canvasMenu = NULL;
11202void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11205 if (m_canvasMenu) {
11206 m_canvasMenu->PopupMenuHandler(event);
11211void ChartCanvas::StartRoute() {
11213 if (g_brouteCreating)
return;
11217 g_brouteCreating =
true;
11219 m_bDrawingRoute =
false;
11220 SetCursor(*pCursorPencil);
11222 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11224 HideGlobalToolbar();
11227 androidSetRouteAnnunciator(
true);
11231wxString ChartCanvas::FinishRoute() {
11233 m_prev_pMousePoint = NULL;
11234 m_bDrawingRoute =
false;
11236 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11239 top_frame::Get()->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11241 androidSetRouteAnnunciator(
false);
11244 SetCursor(*pCursorArrow);
11246 if (m_pMouseRoute) {
11247 if (m_bAppendingRoute) {
11249 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11251 if (m_pMouseRoute->GetnPoints() > 1) {
11253 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11256 m_pMouseRoute = NULL;
11259 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11271 m_bAppendingRoute =
false;
11272 m_pMouseRoute = NULL;
11274 m_pSelectedRoute = NULL;
11276 undo->InvalidateUndo();
11277 top_frame::Get()->RefreshAllCanvas(
true);
11281 ShowGlobalToolbar();
11283 g_brouteCreating =
false;
11288void ChartCanvas::HideGlobalToolbar() {
11289 if (m_canvasIndex == 0) {
11290 m_last_TBviz = top_frame::Get()->SetGlobalToolbarViz(
false);
11294void ChartCanvas::ShowGlobalToolbar() {
11295 if (m_canvasIndex == 0) {
11296 if (m_last_TBviz) top_frame::Get()->SetGlobalToolbarViz(
true);
11300void ChartCanvas::ShowAISTargetList() {
11301 if (NULL == g_pAISTargetList) {
11305 g_pAISTargetList->UpdateAISTargetList();
11308void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11309 if (!m_bShowOutlines)
return;
11313 int nEntry =
ChartData->GetChartTableEntries();
11315 for (
int i = 0; i < nEntry; i++) {
11319 bool b_group_draw =
false;
11320 if (m_groupIndex > 0) {
11321 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11322 int index = pt->GetGroupArray()[ig];
11323 if (m_groupIndex == index) {
11324 b_group_draw =
true;
11329 b_group_draw =
true;
11331 if (b_group_draw) RenderChartOutline(dc, i, vp);
11337 if (VPoint.b_quilt) {
11338 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11339 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11343 }
else if (m_singleChart &&
11344 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11348 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11351 if (zoom_factor > 8.0) {
11352 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11355 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11359 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11363void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11365 if (g_bopengl && m_glcc) {
11367 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11372 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11373 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11376 float plylat, plylon;
11377 float plylat1, plylon1;
11379 int pixx, pixy, pixx1, pixy1;
11382 ChartData->GetDBBoundingBox(dbIndex, box);
11386 if (box.GetLonRange() == 360)
return;
11388 double lon_bias = 0;
11390 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11392 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11394 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11395 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11397 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11398 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11401 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11404 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11405 if (0 == nAuxPlyEntries)
11409 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11410 plylon += lon_bias;
11416 for (
int i = 0; i < nPly - 1; i++) {
11417 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11418 plylon1 += lon_bias;
11424 int pixxs1 = pixx1;
11425 int pixys1 = pixy1;
11427 bool b_skip =
false;
11431 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11432 pow((
double)(pixy1 - pixy), 2)) /
11438 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11443 if (fabs(dist - distgc) > 10000. * 1852.)
11449 ClipResult res = cohen_sutherland_line_clip_i(
11451 if (res != Invisible && !b_skip)
11452 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11460 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11461 plylon1 += lon_bias;
11467 ClipResult res = cohen_sutherland_line_clip_i(
11469 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11476 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11477 for (
int j = 0; j < nAuxPlyEntries; j++) {
11479 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11484 for (
int i = 0; i < nAuxPly - 1; i++) {
11485 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11491 int pixxs1 = pixx1;
11492 int pixys1 = pixy1;
11494 bool b_skip =
false;
11498 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11499 ((pixy1 - pixy) * (pixy1 - pixy))) /
11504 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11509 if (fabs(dist - distgc) > 10000. * 1852.)
11515 ClipResult res = cohen_sutherland_line_clip_i(
11517 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11525 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11530 ClipResult res = cohen_sutherland_line_clip_i(
11532 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11537static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11538 const wxArrayString &legend) {
11539 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11541 int pointsize = dFont->GetPointSize();
11545 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11546 false, dFont->GetFaceName());
11548 dc.SetFont(*psRLI_font);
11555 int hilite_offset = 3;
11557 for (wxString line : legend) {
11560 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11562 dc.GetTextExtent(line, &wl, &hl);
11571 xp = ref_point.x - w;
11573 yp += hilite_offset;
11575 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11577 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11578 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11580 for (wxString line : legend) {
11581 dc.DrawText(line, xp, yp);
11586void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11587 if (!g_bAllowShipToActive)
return;
11593 wxPoint2DDouble pa, pb;
11600 if (rt->
m_width != wxPENSTYLE_INVALID)
11602 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11603 g_shipToActiveStyle, 5)];
11604 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11606 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11609 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11612 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11615 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11616 (
int)pb.m_y, GetVP(),
true);
11620#ifdef USE_ANDROID_GLES2
11621 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11623 if (style != wxPENSTYLE_SOLID) {
11624 if (glChartCanvas::dash_map.find(style) !=
11625 glChartCanvas::dash_map.end()) {
11626 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11630 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11633 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11634 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11640void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11642 if (m_routeState >= 2) route = m_pMouseRoute;
11643 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11644 route = m_pMeasureRoute;
11646 if (!route)
return;
11654 int np = route->GetnPoints();
11656 if (g_btouch && (np > 1)) np--;
11658 render_lat = rp.m_lat;
11659 render_lon = rp.m_lon;
11662 double rhumbBearing, rhumbDist;
11664 &rhumbBearing, &rhumbDist);
11665 double brg = rhumbBearing;
11666 double dist = rhumbDist;
11670 double gcBearing, gcBearing2, gcDist;
11671 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11674 double gcDistm = gcDist / 1852.0;
11677 rhumbBearing = 90.;
11679 wxPoint destPoint, lastPoint;
11682 int milesDiff = rhumbDist - gcDistm;
11683 if (milesDiff > 1) {
11694 for (
int i = 1; i <= milesDiff; i++) {
11695 double p = (double)i * (1.0 / (
double)milesDiff);
11697 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11698 &pLon, &pLat, &gcBearing2);
11700 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11702 lastPoint = destPoint;
11705 if (r_rband.x && r_rband.y) {
11706 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11708 if (m_bMeasure_DistCircle) {
11709 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11710 powf((
float)(r_rband.y - lastPoint.y), 2));
11713 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11714 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11720 wxString routeInfo;
11721 wxArrayString infoArray;
11724 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11730 varBrg = top_frame::Get()->GetMag(brg, latAverage, lonAverage);
11732 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11733 (
int)varBrg, 0x00B0);
11736 infoArray.Add(routeInfo);
11742 routeInfo <<
"Reverse: ";
11744 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11745 (
int)(brg + 180.) % 360, 0x00B0);
11747 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11748 (
int)(varBrg + 180.) % 360, 0x00B0);
11749 infoArray.Add(routeInfo);
11755 s0.Append(_(
"Route") +
": ");
11757 s0.Append(_(
"Layer Route: "));
11760 if (!g_btouch) disp_length += dist;
11766 RouteLegInfo(dc, r_rband, infoArray);
11768 m_brepaint_piano =
true;
11771void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11772 if (!m_bShowVisibleSectors)
return;
11774 if (g_bDeferredInitDone) {
11776 double rhumbBearing, rhumbDist;
11777 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11778 &rhumbBearing, &rhumbDist);
11780 if (rhumbDist > 0.05)
11782 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11783 m_sectorlegsVisible);
11784 m_sector_glat =
gLat;
11785 m_sector_glon =
gLon;
11787 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11791void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11799void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11800 if (!ps52plib)
return;
11802 if (VPoint.b_quilt) {
11803 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11805 if (m_pQuilt->IsQuiltVector()) {
11806 if (ps52plib->GetStateHash() != m_s52StateHash) {
11808 m_s52StateHash = ps52plib->GetStateHash();
11812 if (ps52plib->GetStateHash() != m_s52StateHash) {
11814 m_s52StateHash = ps52plib->GetStateHash();
11819 bool bSendPlibState =
true;
11820 if (VPoint.b_quilt) {
11821 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11824 if (bSendPlibState) {
11826 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11827 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11828 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11829 v[
"OpenCPN Version Date"] = VERSION_DATE;
11830 v[
"OpenCPN Version Full"] = VERSION_FULL;
11833 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11834 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11835 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11836 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11837 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11838 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11839 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11843 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11844 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11848 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11849 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11850 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11851 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11852 ps52plib->m_bShowS57ImportantTextOnly;
11853 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11854 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11855 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11856 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11857 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11860 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11861 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11862 v[
"OpenCPN Scale Factor Exp"] =
11863 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11870 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11871 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11872 g_lastS52PLIBPluginMessage = out;
11879 wxPaintDC dc(
this);
11889 if (!m_b_paint_enable) {
11897 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11899 if (m_glcc && g_bopengl) {
11900 if (!s_in_update) {
11910 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11912 wxRegion ru = GetUpdateRegion();
11914 int rx, ry, rwidth, rheight;
11915 ru.GetBox(rx, ry, rwidth, rheight);
11917#ifdef ocpnUSE_DIBSECTION
11920 wxMemoryDC temp_dc;
11928 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11929 height += m_Piano->GetHeight();
11931 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11935 int thumbx, thumby, thumbsx, thumbsy;
11936 pthumbwin->GetPosition(&thumbx, &thumby);
11937 pthumbwin->GetSize(&thumbsx, &thumbsy);
11938 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11941 rgn_chart.Subtract(rgn_thumbwin);
11942 ru.Subtract(rgn_thumbwin);
11948 wxRegion rgn_blit = ru;
11949 if (g_bShowChartBar) {
11950 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11951 GetClientSize().x, m_Piano->GetHeight());
11954 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11955 if (style->chartStatusWindowTransparent)
11956 m_brepaint_piano =
true;
11958 ru.Subtract(chart_bar_rect);
11962 if (m_Compass && m_Compass->IsShown()) {
11963 wxRect compassRect = m_Compass->
GetRect();
11964 if (ru.Contains(compassRect) != wxOutRegion) {
11965 ru.Subtract(compassRect);
11969 if (m_notification_button) {
11970 wxRect noteRect = m_notification_button->
GetRect();
11971 if (ru.Contains(noteRect) != wxOutRegion) {
11972 ru.Subtract(noteRect);
11977 bool b_newview =
true;
11982 m_cache_vp.IsValid()) {
11988 bool b_rcache_ok =
false;
11989 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11990 b_rcache_ok = !b_newview;
11993 if (VPoint.b_MercatorProjectionOverride)
11994 VPoint.SetProjectionType(PROJECTION_MERCATOR);
12008 if (b_rcache_ok) chart_get_region.Clear();
12011 if (VPoint.b_quilt)
12013 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
12015 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
12020 AbstractPlatform::ShowBusySpinner();
12024 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
12025 (m_working_bm.GetHeight() != svp.
pix_height))
12029 if (fabs(VPoint.
rotation) < 0.01) {
12030 bool b_save =
true;
12035 m_cache_vp.Invalidate();
12049 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
12054 int dy = c_new.y - c_old.y;
12055 int dx = c_new.x - c_old.x;
12060 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12064 temp_dc.SelectObject(m_working_bm);
12066 wxMemoryDC cache_dc;
12067 cache_dc.SelectObject(m_cached_chart_bm);
12071 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12074 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12080 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12083 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12091 update_region.Union(
12094 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12099 update_region.Union(
12102 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12106 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12108 cache_dc.SelectObject(wxNullBitmap);
12112 temp_dc.SelectObject(m_cached_chart_bm);
12115 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12119 temp_dc.SelectObject(m_working_bm);
12120 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12125 temp_dc.SelectObject(m_cached_chart_bm);
12130 temp_dc.SelectObject(m_working_bm);
12131 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12144 wxMemoryDC scratch_dc_0;
12145 scratch_dc_0.SelectObject(m_cached_chart_bm);
12148 scratch_dc_0.SelectObject(wxNullBitmap);
12157 temp_dc.SelectObject(m_working_bm);
12160 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12161 chart_get_all_region);
12164 AbstractPlatform::HideBusySpinner();
12170 if (!m_singleChart) {
12171 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12176 if (!chart_get_region.IsEmpty()) {
12177 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12181 if (temp_dc.IsOk()) {
12186 if (!VPoint.b_quilt) {
12189 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12190 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12197 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12198 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12201 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12203 temp_dc.DestroyClippingRegion();
12208 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12210 if (!backgroundRegion.IsEmpty()) {
12216 wxColour water = pWorldBackgroundChart->water;
12217 if (water.IsOk()) {
12218 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12219 temp_dc.SetBrush(wxBrush(water));
12221 while (upd.HaveRects()) {
12222 wxRect rect = upd.GetRect();
12223 temp_dc.DrawRectangle(rect);
12228 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12229 temp_dc.SetDeviceClippingRegion(*clip_region);
12230 delete clip_region;
12234 SetVPRotation(VPoint.
skew);
12243 wxMemoryDC *pChartDC = &temp_dc;
12244 wxMemoryDC rotd_dc;
12246 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12248 if (!b_rcache_ok) {
12250 wxMemoryDC tbase_dc;
12252 tbase_dc.SelectObject(bm_base);
12254 tbase_dc.SelectObject(wxNullBitmap);
12256 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12259 wxImage base_image;
12260 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12268 bool b_rot_ok =
false;
12269 if (base_image.IsOk()) {
12272 m_b_rot_hidef =
false;
12276 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12277 m_b_rot_hidef, &m_roffset);
12282 rot_vp.IsValid() && (ri.IsOk())) {
12289 m_prot_bm =
new wxBitmap(ri);
12292 m_roffset.x += VPoint.rv_rect.x;
12293 m_roffset.y += VPoint.rv_rect.y;
12296 if (m_prot_bm && m_prot_bm->IsOk()) {
12297 rotd_dc.SelectObject(*m_prot_bm);
12298 pChartDC = &rotd_dc;
12300 pChartDC = &temp_dc;
12301 m_roffset = wxPoint(0, 0);
12304 pChartDC = &temp_dc;
12305 m_roffset = wxPoint(0, 0);
12308 wxPoint offset = m_roffset;
12311 m_cache_vp = VPoint;
12314 wxMemoryDC mscratch_dc;
12315 mscratch_dc.SelectObject(*pscratch_bm);
12317 mscratch_dc.ResetBoundingBox();
12318 mscratch_dc.DestroyClippingRegion();
12319 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12322 wxRegionIterator upd(rgn_blit);
12324 wxRect rect = upd.GetRect();
12326 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12327 rect.x - offset.x, rect.y - offset.y);
12333 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12334 if (
this == wxWindow::FindFocus()) {
12337 wxColour colour = GetGlobalColor(
"BLUE4");
12338 mscratch_dc.SetPen(wxPen(colour));
12339 mscratch_dc.SetBrush(wxBrush(colour));
12341 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12342 mscratch_dc.DrawRectangle(activeRect);
12347 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12348 unsigned int im = stackIndexArray.size();
12349 if (VPoint.b_quilt && im > 0) {
12350 std::vector<int> tiles_to_show;
12351 for (
unsigned int is = 0; is < im; is++) {
12353 ChartData->GetChartTableEntry(stackIndexArray[is]);
12354 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12357 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12358 tiles_to_show.push_back(stackIndexArray[is]);
12362 if (tiles_to_show.size())
12363 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12369 ocpnDC scratch_dc(mscratch_dc);
12370 RenderAlertMessage(mscratch_dc, GetVP());
12376#ifdef ocpnUSE_DIBSECTION
12381 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12382 q_dc.SelectObject(qbm);
12385 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12388 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12389 q_dc.SetBrush(qbr);
12390 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12393 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12396 q_dc.SelectObject(wxNullBitmap);
12405 if( VPoint.b_quilt ) {
12406 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12407 ChartBase *chart = m_pQuilt->GetRefChart();
12408 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12413 ChPI->ClearPLIBTextList();
12416 ps52plib->ClearTextList();
12420 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12422 wxColor maskBackground = wxColour(1,0,0);
12423 t_dc.SelectObject( qbm );
12424 t_dc.SetBackground(wxBrush(maskBackground));
12428 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12431 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12432 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12435 wxRegionIterator upd_final( ru );
12436 while( upd_final ) {
12437 wxRect rect = upd_final.GetRect();
12438 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12442 t_dc.SelectObject( wxNullBitmap );
12448 if (VPoint.b_quilt) {
12449 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12450 ChartBase *chart = m_pQuilt->GetRefChart();
12451 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12455 ChPI->ClearPLIBTextList();
12457 if (ps52plib) ps52plib->ClearTextList();
12462 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12464 if (g_bShowChartBar && m_Piano) {
12465 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12466 GetVP().pix_width, m_Piano->GetHeight());
12469 if (!style->chartStatusWindowTransparent)
12470 chart_all_text_region.Subtract(chart_bar_rect);
12473 if (m_Compass && m_Compass->IsShown()) {
12474 wxRect compassRect = m_Compass->
GetRect();
12475 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12476 chart_all_text_region.Subtract(compassRect);
12480 mscratch_dc.DestroyClippingRegion();
12482 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12483 chart_all_text_region);
12489 ocpnDC scratch_dc(mscratch_dc);
12490 DrawOverlayObjects(scratch_dc, ru);
12493 wxRegionIterator upd_final(rgn_blit);
12494 while (upd_final) {
12495 wxRect rect = upd_final.GetRect();
12496 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12503 temp_dc.SelectObject(wxNullBitmap);
12505 mscratch_dc.SelectObject(wxNullBitmap);
12507 dc.DestroyClippingRegion();
12512void ChartCanvas::PaintCleanup() {
12514 if (m_inPinch)
return;
12525 m_bTCupdate =
false;
12529 WarpPointer(warp_x, warp_y);
12536 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12537 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12541wxColour GetErrorGraphicColor(
double val)
12560 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12561 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12562 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12563 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12564 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12565 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12566 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12567 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12568 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12569 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12570 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12571 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12572 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12573 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12574 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12575 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12576 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12577 else if( val >= 48) c.Set(
"#410000");
12582void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12585 gr_image.InitAlpha();
12587 double maxval = -10000;
12588 double minval = 10000;
12605 maxval = wxMax(maxval, (glat - rlat));
12606 minval = wxMin(minval, (glat - rlat));
12623 double f = ((glat - rlat)-minval)/(maxval - minval);
12625 double dy = (f * 40);
12627 wxColour c = GetErrorGraphicColor(dy);
12628 unsigned char r = c.Red();
12629 unsigned char g = c.Green();
12630 unsigned char b = c.Blue();
12632 gr_image.SetRGB(j, i, r,g,b);
12633 if((glat - rlat )!= 0)
12634 gr_image.SetAlpha(j, i, 128);
12636 gr_image.SetAlpha(j, i, 255);
12643 wxBitmap *pbm =
new wxBitmap(gr_image);
12644 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12645 pbm->SetMask(gr_mask);
12647 pmdc->DrawBitmap(*pbm, 0,0);
12655void ChartCanvas::CancelMouseRoute() {
12657 m_pMouseRoute = NULL;
12658 m_bDrawingRoute =
false;
12661int ChartCanvas::GetNextContextMenuId() {
12662 return CanvasMenuHandler::GetNextContextMenuId();
12665bool ChartCanvas::SetCursor(
const wxCursor &c) {
12667 if (g_bopengl && m_glcc)
12668 return m_glcc->SetCursor(c);
12671 return wxWindow::SetCursor(c);
12674void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12675 if (g_bquiting)
return;
12685 if (!m_RolloverPopupTimer.IsRunning() &&
12686 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12687 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12688 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12689 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12692 if (m_glcc && g_bopengl) {
12695 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12697 m_glcc->Refresh(eraseBackground,
12714 if (m_pCIWin && m_pCIWin->IsShown()) {
12716 m_pCIWin->Refresh(
false);
12724 wxWindow::Refresh(eraseBackground, rect);
12727void ChartCanvas::Update() {
12728 if (m_glcc && g_bopengl) {
12733 wxWindow::Update();
12737 if (!pemboss)
return;
12738 int x = pemboss->x, y = pemboss->y;
12739 const double factor = 200;
12741 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12742 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12743 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12746 wxMemoryDC snip_dc;
12747 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12748 snip_dc.SelectObject(snip_bmp);
12750 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12751 snip_dc.SelectObject(wxNullBitmap);
12753 wxImage snip_img = snip_bmp.ConvertToImage();
12756 unsigned char *pdata = snip_img.GetData();
12758 for (
int y = 0; y < pemboss->height; y++) {
12759 int map_index = (y * pemboss->width);
12760 for (
int x = 0; x < pemboss->width; x++) {
12761 double val = (pemboss->pmap[map_index] * factor) / 256.;
12763 int nred = (int)((*pdata) + val);
12764 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12765 *pdata++ = (
unsigned char)nred;
12767 int ngreen = (int)((*pdata) + val);
12768 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12769 *pdata++ = (
unsigned char)ngreen;
12771 int nblue = (int)((*pdata) + val);
12772 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12773 *pdata++ = (
unsigned char)nblue;
12781 wxBitmap emb_bmp(snip_img);
12784 wxMemoryDC result_dc;
12785 result_dc.SelectObject(emb_bmp);
12788 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12790 result_dc.SelectObject(wxNullBitmap);
12796 if (GetQuiltMode()) {
12798 int refIndex = GetQuiltRefChartdbIndex();
12799 if (refIndex >= 0) {
12801 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12802 if (current_type == CHART_TYPE_MBTILES) {
12803 ChartBase *pChart = m_pQuilt->GetRefChart();
12806 zoom_factor = ptc->GetZoomFactor();
12811 if (zoom_factor <= 3.9)
return NULL;
12813 if (m_singleChart) {
12814 if (zoom_factor <= 3.9)
return NULL;
12819 if (m_pEM_OverZoom) {
12820 m_pEM_OverZoom->x = 4;
12821 m_pEM_OverZoom->y = 0;
12823 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12824 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12827 return m_pEM_OverZoom;
12830void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12843 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12844 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12848 AISDrawAreaNotices(dc, GetVP(),
this);
12850 wxDC *pdc = dc.GetDC();
12852 pdc->DestroyClippingRegion();
12853 wxDCClipper(*pdc, ru);
12856 if (m_bShowNavobjects) {
12857 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12858 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12859 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12860 DrawAnchorWatchPoints(dc);
12862 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12863 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12866 AISDraw(dc, GetVP(),
this);
12870 RenderVisibleSectorLights(dc);
12872 RenderAllChartOutlines(dc, GetVP());
12873 RenderRouteLegs(dc);
12874 RenderShipToActive(dc,
false);
12876 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12878 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12882 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12883 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12886 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12891 RebuildTideSelectList(GetVP().GetBBox());
12892 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12895 if (m_bShowCurrent) {
12896 RebuildCurrentSelectList(GetVP().GetBBox());
12897 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12900 if (!g_PrintingInProgress) {
12901 if (IsPrimaryCanvas()) {
12905 if (IsPrimaryCanvas()) {
12909 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12911 if (m_pTrackRolloverWin) {
12912 m_pTrackRolloverWin->Draw(dc);
12913 m_brepaint_piano =
true;
12916 if (m_pRouteRolloverWin) {
12917 m_pRouteRolloverWin->Draw(dc);
12918 m_brepaint_piano =
true;
12921 if (m_pAISRolloverWin) {
12922 m_pAISRolloverWin->Draw(dc);
12923 m_brepaint_piano =
true;
12925 if (m_brepaint_piano && g_bShowChartBar) {
12926 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12929 if (m_Compass) m_Compass->Paint(dc);
12931 if (!g_CanvasHideNotificationIcon) {
12932 if (IsPrimaryCanvas()) {
12933 auto ¬eman = NotificationManager::GetInstance();
12934 if (m_notification_button) {
12935 if (noteman.GetNotificationCount()) {
12936 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12937 if (m_notification_button->UpdateStatus()) Refresh();
12938 m_notification_button->Show(
true);
12939 m_notification_button->Paint(dc);
12941 m_notification_button->Show(
false);
12948 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12954 if (!m_bShowDepthUnits)
return NULL;
12956 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12958 if (GetQuiltMode()) {
12959 wxString s = m_pQuilt->GetQuiltDepthUnit();
12962 depth_unit_type = DEPTH_UNIT_FEET;
12963 else if (s.StartsWith(
"FATHOMS"))
12964 depth_unit_type = DEPTH_UNIT_FATHOMS;
12965 else if (s.StartsWith(
"METERS"))
12966 depth_unit_type = DEPTH_UNIT_METERS;
12967 else if (s.StartsWith(
"METRES"))
12968 depth_unit_type = DEPTH_UNIT_METERS;
12969 else if (s.StartsWith(
"METRIC"))
12970 depth_unit_type = DEPTH_UNIT_METERS;
12971 else if (s.StartsWith(
"METER"))
12972 depth_unit_type = DEPTH_UNIT_METERS;
12975 if (m_singleChart) {
12976 depth_unit_type = m_singleChart->GetDepthUnitType();
12977 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12978 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12983 switch (depth_unit_type) {
12984 case DEPTH_UNIT_FEET:
12987 case DEPTH_UNIT_METERS:
12988 ped = m_pEM_Meters;
12990 case DEPTH_UNIT_FATHOMS:
12991 ped = m_pEM_Fathoms;
12997 ped->x = (GetVP().
pix_width - ped->width);
12999 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
13000 wxRect r = m_Compass->
GetRect();
13001 ped->y = r.y + r.height;
13008void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
13011 if (style->embossFont == wxEmptyString) {
13012 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13014 font.SetPointSize(60);
13015 font.SetWeight(wxFONTWEIGHT_BOLD);
13017 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13018 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13020 int emboss_width = 500;
13021 int emboss_height = 200;
13025 delete m_pEM_Meters;
13026 delete m_pEM_Fathoms;
13030 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
13032 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
13034 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
13037#define OVERZOOM_TEXT _("OverZoom")
13039void ChartCanvas::SetOverzoomFont() {
13044 if (style->embossFont == wxEmptyString) {
13045 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
13047 font.SetPointSize(40);
13048 font.SetWeight(wxFONTWEIGHT_BOLD);
13050 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
13051 wxFONTWEIGHT_BOLD,
false, style->embossFont);
13053 wxClientDC dc(
this);
13055 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13057 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
13058 font.SetPointSize(font.GetPointSize() - 1);
13060 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
13062 m_overzoomFont = font;
13063 m_overzoomTextWidth = w;
13064 m_overzoomTextHeight = h;
13067void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13068 delete m_pEM_OverZoom;
13070 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13072 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13073 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13076emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13077 int height,
const wxString &str,
13082 wxBitmap bmp(width, height, -1);
13085 wxMemoryDC temp_dc;
13086 temp_dc.SelectObject(bmp);
13089 temp_dc.SetBackground(*wxWHITE_BRUSH);
13090 temp_dc.SetTextBackground(*wxWHITE);
13091 temp_dc.SetTextForeground(*wxBLACK);
13095 temp_dc.SetFont(font);
13098 temp_dc.GetTextExtent(str, &str_w, &str_h);
13100 temp_dc.DrawText(str, 1, 1);
13103 temp_dc.SelectObject(wxNullBitmap);
13106 wxImage img = bmp.ConvertToImage();
13108 int image_width = str_w * 105 / 100;
13109 int image_height = str_h * 105 / 100;
13110 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13111 wxMin(image_height, img.GetHeight()));
13112 wxImage imgs = img.GetSubImage(r);
13116 case GLOBAL_COLOR_SCHEME_DAY:
13120 case GLOBAL_COLOR_SCHEME_DUSK:
13123 case GLOBAL_COLOR_SCHEME_NIGHT:
13130 const int w = imgs.GetWidth();
13131 const int h = imgs.GetHeight();
13132 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13137 for (
int y = 1; y < h - 1; y++) {
13138 for (
int x = 1; x < w - 1; x++) {
13140 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13141 val = (int)(val * val_factor);
13142 index = (y * w) + x;
13155void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13156 Track *active_track = NULL;
13159 active_track = pTrackDraw;
13163 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13166 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13169void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13170 Track *active_track = NULL;
13173 active_track = pTrackDraw;
13177 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13180void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13181 Route *active_route = NULL;
13183 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13184 active_route = pRouteDraw;
13189 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13194 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13197void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13198 Route *active_route = NULL;
13201 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13202 active_route = pRouteDraw;
13206 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13209void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13210 if (!pWayPointMan)
return;
13212 auto node = pWayPointMan->GetWaypointList()->begin();
13214 while (node != pWayPointMan->GetWaypointList()->end()) {
13223 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13227 if (pWP->GetShowWaypointRangeRings() &&
13228 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13229 double factor = 1.00;
13230 if (pWP->GetWaypointRangeRingsStepUnits() ==
13232 factor = 1 / 1.852;
13234 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13235 pWP->GetWaypointRangeRingsStep() / 60.;
13239 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13240 pWP->m_lat + radius, pWP->m_lon + radius);
13241 if (!BltBBox.IntersectOut(radar_box)) {
13252void ChartCanvas::DrawBlinkObjects() {
13254 wxRect update_rect;
13256 if (!pWayPointMan)
return;
13258 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13265 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13268void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13273 wxPoint lAnchorPoint1, lAnchorPoint2;
13287 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13288 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13290 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13291 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13292 dc.SetBrush(*ppBrush);
13296 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13301 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13306 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13311 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13316double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13319 wxPoint lAnchorPoint;
13322 double tlat1, tlon1;
13324 if (pAnchorWatchPoint) {
13325 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13327 dabs = fabs(d1 / 1852.);
13328 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13333 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13334 pow((
double)(lAnchorPoint.y - r1.y), 2));
13337 if (d1 < 0) lpp = -lpp;
13345void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13347 if (
this != wxWindow::FindFocus())
return;
13349 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13351 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13357 if ((type ==
't') || (type ==
'T')) {
13358 if (BBox.Contains(lat, lon)) {
13360 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13366void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13369 wxDateTime this_now = gTimeSource;
13370 bool cur_time = !gTimeSource.IsValid();
13371 if (cur_time) this_now = wxDateTime::Now();
13372 time_t t_this_now = this_now.GetTicks();
13374 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13376 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13377 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13378 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13379 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13381 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13382 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13383 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13384 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13385 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13386 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13388 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13389 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13390 int font_size = wxMax(10, dFont->GetPointSize());
13393 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13394 false, dFont->GetFaceName());
13396 dc.SetPen(*pblack_pen);
13397 dc.SetBrush(*pgreen_brush);
13401 case GLOBAL_COLOR_SCHEME_DAY:
13404 case GLOBAL_COLOR_SCHEME_DUSK:
13407 case GLOBAL_COLOR_SCHEME_NIGHT:
13408 bm = m_bmTideNight;
13415 int bmw = bm.GetWidth();
13416 int bmh = bm.GetHeight();
13418 float scale_factor = 1.0;
13422 float icon_pixelRefDim = 45;
13427 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13429 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13431 scale_factor *= pix_factor;
13438 scale_factor *= user_scale_factor;
13439 scale_factor *= GetContentScaleFactor();
13442 double marge = 0.05;
13443 std::vector<LLBBox> drawn_boxes;
13444 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13448 if ((type ==
't') || (type ==
'T'))
13453 if (BBox.ContainsMarge(lat, lon, marge)) {
13455 if (GetVP().chart_scale < 500000) {
13456 bool bdrawn =
false;
13457 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13458 if (drawn_boxes[i].Contains(lat, lon)) {
13463 if (bdrawn)
continue;
13466 this_box.Set(lat, lon, lat, lon);
13467 this_box.EnLarge(.005);
13468 drawn_boxes.push_back(this_box);
13474 if (GetVP().chart_scale > 500000) {
13475 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13479 dc.SetFont(*plabelFont);
13491 if (
ptcmgr->GetTideFlowSens(
13492 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13496 ptcmgr->GetHightOrLowTide(
13497 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13498 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13510 if (tctime > t_this_now)
13511 ptcmgr->GetHightOrLowTide(
13512 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13513 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13517 ptcmgr->GetHightOrLowTide(
13518 t_this_now, FORWARD_TEN_MINUTES_STEP,
13519 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13533 int width = (int)(12 * scale_factor + 0.5);
13534 int height = (int)(45 * scale_factor + 0.5);
13535 int linew = wxMax(1, (
int)(scale_factor));
13536 int xDraw = r.x - (width / 2);
13537 int yDraw = r.y - (height / 2);
13540 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13541 int hs = (httime > lttime) ? -4 : 4;
13542 hs *= (int)(scale_factor + 0.5);
13543 if (ts > 0.995 || ts < 0.005) hs = 0;
13544 int ht_y = (int)(height * ts);
13547 pblack_pen->SetWidth(linew);
13548 dc.SetPen(*pblack_pen);
13549 dc.SetBrush(*pyelo_brush);
13550 dc.DrawRectangle(xDraw, yDraw, width, height);
13554 dc.SetPen(*pblue_pen);
13555 dc.SetBrush(*pblue_brush);
13556 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13557 (width - (4 * linew)), height - ht_y);
13563 arrow[0].x = xDraw + 2 * linew;
13564 arrow[1].x = xDraw + width / 2;
13565 arrow[2].x = xDraw + width - 2 * linew;
13566 pyelo_pen->SetWidth(linew);
13567 pblue_pen->SetWidth(linew);
13568 if (ts > 0.35 || ts < 0.15)
13570 hl = (int)(height * 0.25) + yDraw;
13572 arrow[1].y = hl + hs;
13575 dc.SetPen(*pyelo_pen);
13577 dc.SetPen(*pblue_pen);
13578 dc.DrawLines(3, arrow);
13580 if (ts > 0.60 || ts < 0.40)
13582 hl = (int)(height * 0.5) + yDraw;
13584 arrow[1].y = hl + hs;
13587 dc.SetPen(*pyelo_pen);
13589 dc.SetPen(*pblue_pen);
13590 dc.DrawLines(3, arrow);
13592 if (ts < 0.65 || ts > 0.85)
13594 hl = (int)(height * 0.75) + yDraw;
13596 arrow[1].y = hl + hs;
13599 dc.SetPen(*pyelo_pen);
13601 dc.SetPen(*pblue_pen);
13602 dc.DrawLines(3, arrow);
13606 double nowlev_converted = nowlev;
13610 int unit_c = TCDataFactory::findunit(pmsd->unit);
13614 TCDataFactory::known_units[unit_c].conv_factor;
13617 nowlev_converted =
toUsrHeight(nowlev_converted);
13621 s.Printf(
"%3.1f", nowlev_converted);
13625 dc.GetTextExtent(s, &wx1, NULL);
13627 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13642void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13645 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13647 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13653 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13654 if ((BBox.Contains(lat, lon))) {
13656 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13662void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13665 float tcvalue, dir;
13669 double lon_last = 0.;
13670 double lat_last = 0.;
13672 double marge = 0.2;
13673 bool cur_time = !gTimeSource.IsValid();
13675 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13676 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13678 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13680 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13681 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13682 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13683 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13684 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13685 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13686 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13687 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13689 double skew_angle = GetVPRotation();
13691 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13692 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13693 int font_size = wxMax(10, dFont->GetPointSize());
13696 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13697 false, dFont->GetFaceName());
13699 float scale_factor = 1.0;
13705 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13707 float nominal_icon_size_pixels = 15;
13708 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13710 scale_factor *= pix_factor;
13717 scale_factor *= user_scale_factor;
13719 scale_factor *= GetContentScaleFactor();
13722 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13728 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13729 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13734 int dd = (int)(5.0 * scale_factor + 0.5);
13745 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13746 dc.SetPen(*pblack_pen);
13747 dc.SetBrush(*porange_brush);
13748 dc.DrawPolygon(4, d);
13751 dc.SetBrush(*pblack_brush);
13752 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13756 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13770 double a1 = fabs(tcvalue) * 10.;
13772 a1 = wxMax(1.0, a1);
13773 double a2 = log10(a1);
13775 float cscale = scale_factor * a2 * 0.3;
13777 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13778 dc.SetPen(*porange_pen);
13779 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13783 if (bDrawCurrentValues) {
13784 dc.SetFont(*pTCFont);
13785 tcvalue = toUsrSpeed(tcvalue);
13786 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13787 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13813 if (!pvIDX)
return;
13818 if (pCwin && pCwin->IsShown()) {
13826 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13841 pCwin =
new TCWin(
this, x, y, pvIDX);
13859#define NUM_CURRENT_ARROW_POINTS 9
13860static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13861 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13862 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13863 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13865void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13867 if (
scale > 1e-2) {
13868 float sin_rot = sin(rot_angle * PI / 180.);
13869 float cos_rot = cos(rot_angle * PI / 180.);
13873 float xt = CurrentArrowArray[0].x;
13874 float yt = CurrentArrowArray[0].y;
13876 float xp = (xt * cos_rot) - (yt * sin_rot);
13877 float yp = (xt * sin_rot) + (yt * cos_rot);
13878 int x1 = (int)(xp *
scale);
13879 int y1 = (int)(yp *
scale);
13882 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13883 xt = CurrentArrowArray[ip].x;
13884 yt = CurrentArrowArray[ip].y;
13886 float xp = (xt * cos_rot) - (yt * sin_rot);
13887 float yp = (xt * sin_rot) + (yt * cos_rot);
13888 int x2 = (int)(xp *
scale);
13889 int y2 = (int)(yp *
scale);
13891 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13899wxString ChartCanvas::FindValidUploadPort() {
13902 if (!g_uploadConnection.IsEmpty() &&
13903 g_uploadConnection.StartsWith(
"Serial")) {
13904 port = g_uploadConnection;
13910 for (
auto *cp : TheConnectionParams()) {
13911 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13912 port <<
"Serial:" << cp->Port;
13918void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13921 if (NULL == g_pais_query_dialog_active) {
13922 int pos_x = g_ais_query_dialog_x;
13923 int pos_y = g_ais_query_dialog_y;
13925 if (g_pais_query_dialog_active) {
13926 g_pais_query_dialog_active->Destroy();
13932 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13933 wxPoint(pos_x, pos_y));
13935 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13936 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13937 g_pais_query_dialog_active->SetMMSI(mmsi);
13938 g_pais_query_dialog_active->UpdateText();
13939 wxSize sz = g_pais_query_dialog_active->GetSize();
13941 bool b_reset_pos =
false;
13946 RECT frame_title_rect;
13947 frame_title_rect.left = pos_x;
13948 frame_title_rect.top = pos_y;
13949 frame_title_rect.right = pos_x + sz.x;
13950 frame_title_rect.bottom = pos_y + 30;
13952 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13953 b_reset_pos =
true;
13958 wxRect window_title_rect;
13959 window_title_rect.x = pos_x;
13960 window_title_rect.y = pos_y;
13961 window_title_rect.width = sz.x;
13962 window_title_rect.height = 30;
13964 wxRect ClientRect = wxGetClientDisplayRect();
13965 ClientRect.Deflate(
13967 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13971 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13974 g_pais_query_dialog_active->SetMMSI(mmsi);
13975 g_pais_query_dialog_active->UpdateText();
13978 g_pais_query_dialog_active->Show();
13981void ChartCanvas::ToggleCanvasQuiltMode() {
13982 bool cur_mode = GetQuiltMode();
13984 if (!GetQuiltMode())
13985 SetQuiltMode(
true);
13986 else if (GetQuiltMode()) {
13987 SetQuiltMode(
false);
13988 g_sticky_chart = GetQuiltReferenceChartIndex();
13991 if (cur_mode != GetQuiltMode()) {
13992 SetupCanvasQuiltMode();
14001 if (ps52plib) ps52plib->GenerateStateHash();
14003 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14004 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14007void ChartCanvas::DoCanvasStackDelta(
int direction) {
14008 if (!GetQuiltMode()) {
14009 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
14010 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
14011 if ((current_stack_index + direction) < 0)
return;
14013 if (m_bpersistent_quilt ) {
14015 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
14017 if (IsChartQuiltableRef(new_dbIndex)) {
14018 ToggleCanvasQuiltMode();
14019 SelectQuiltRefdbChart(new_dbIndex);
14020 m_bpersistent_quilt =
false;
14023 SelectChartFromStack(current_stack_index + direction);
14026 std::vector<int> piano_chart_index_array =
14027 GetQuiltExtendedStackdbIndexArray();
14028 int refdb = GetQuiltRefChartdbIndex();
14031 int current_index = -1;
14032 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14033 if (refdb == piano_chart_index_array[i]) {
14038 if (current_index == -1)
return;
14041 int target_family = ctet.GetChartFamily();
14043 int new_index = -1;
14044 int check_index = current_index + direction;
14045 bool found =
false;
14046 int check_dbIndex = -1;
14047 int new_dbIndex = -1;
14051 (
unsigned int)check_index < piano_chart_index_array.size() &&
14052 (check_index >= 0)) {
14053 check_dbIndex = piano_chart_index_array[check_index];
14055 if (target_family == cte.GetChartFamily()) {
14057 new_index = check_index;
14058 new_dbIndex = check_dbIndex;
14062 check_index += direction;
14065 if (!found)
return;
14067 if (!IsChartQuiltableRef(new_dbIndex)) {
14068 ToggleCanvasQuiltMode();
14069 SelectdbChart(new_dbIndex);
14070 m_bpersistent_quilt =
true;
14072 SelectQuiltRefChart(new_index);
14077 top_frame::Get()->UpdateGlobalMenuItems();
14078 SetQuiltChartHiLiteIndex(-1);
14089void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14092 switch (event.GetId()) {
14104 DoCanvasStackDelta(1);
14109 DoCanvasStackDelta(-1);
14119 ShowCurrents(!GetbShowCurrent());
14126 ShowTides(!GetbShowTide());
14133 if (0 == m_routeState) {
14140 androidSetRouteAnnunciator(m_routeState == 1);
14146 SetAISCanvasDisplayStyle(-1);
14158void ChartCanvas::SetShowAIS(
bool show) {
14160 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14161 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14164void ChartCanvas::SetAttenAIS(
bool show) {
14165 m_bShowAISScaled = show;
14166 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14167 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14170void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14173 bool bShowAIS_Array[3] = {
true,
true,
false};
14174 bool bShowScaled_Array[3] = {
false,
true,
true};
14175 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14176 _(
"Attenuate less critical AIS targets"),
14177 _(
"Hide AIS Targets")};
14178 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14180 int AIS_Toolbar_Switch = 0;
14181 if (StyleIndx == -1) {
14183 for (
int i = 1; i < ArraySize; i++) {
14184 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14185 (bShowScaled_Array[i] == m_bShowAISScaled))
14186 AIS_Toolbar_Switch = i;
14188 AIS_Toolbar_Switch++;
14189 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14190 AIS_Toolbar_Switch++;
14193 AIS_Toolbar_Switch = StyleIndx;
14196 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14198 int AIS_Toolbar_Switch_Next =
14199 AIS_Toolbar_Switch + 1;
14200 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14201 AIS_Toolbar_Switch_Next++;
14202 if (AIS_Toolbar_Switch_Next >= ArraySize)
14203 AIS_Toolbar_Switch_Next = 0;
14206 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14207 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14210void ChartCanvas::TouchAISToolActive() {}
14212void ChartCanvas::UpdateAISTBTool() {}
14220void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14222 bool b_update =
false;
14223 int cc1_edge_comp = 2;
14224 wxRect rect = m_Compass->
GetRect();
14225 wxSize parent_size = GetSize();
14227 parent_size *= m_displayScale;
14231 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14232 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14233 wxRect compass_rect(compass_pt, rect.GetSize());
14235 m_Compass->Move(compass_pt);
14237 if (m_Compass && m_Compass->IsShown())
14238 m_Compass->UpdateStatus(b_force_new | b_update);
14240 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14241 scaler = wxMax(scaler, 1.0);
14242 wxPoint note_point = wxPoint(
14243 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14244 if (m_notification_button) {
14245 m_notification_button->Move(note_point);
14246 m_notification_button->UpdateStatus();
14249 if (b_force_new | b_update) Refresh();
14252void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14253 ChartTypeEnum New_Type,
14254 ChartFamilyEnum New_Family) {
14255 if (!GetpCurrentStack())
return;
14258 if (index < GetpCurrentStack()->nEntry) {
14261 pTentative_Chart =
ChartData->OpenStackChartConditional(
14262 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14264 if (pTentative_Chart) {
14265 if (m_singleChart) m_singleChart->Deactivate();
14267 m_singleChart = pTentative_Chart;
14268 m_singleChart->Activate();
14270 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14271 GetpCurrentStack(), m_singleChart->GetFullPath());
14284 double best_scale_ppm = GetBestVPScale(m_singleChart);
14285 double rotation = GetVPRotation();
14286 double oldskew = GetVPSkew();
14287 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14289 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14290 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14291 if (fabs(newskew) > 0.0001) rotation = newskew;
14294 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14296 UpdateGPSCompassStatusBox(
true);
14300 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14301 if (idx < 0)
return;
14303 std::vector<int> piano_active_chart_index_array;
14304 piano_active_chart_index_array.push_back(
14305 GetpCurrentStack()->GetCurrentEntrydbIndex());
14306 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14309void ChartCanvas::SelectdbChart(
int dbindex) {
14310 if (!GetpCurrentStack())
return;
14313 if (dbindex >= 0) {
14316 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14318 if (pTentative_Chart) {
14319 if (m_singleChart) m_singleChart->Deactivate();
14321 m_singleChart = pTentative_Chart;
14322 m_singleChart->Activate();
14324 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14325 GetpCurrentStack(), m_singleChart->GetFullPath());
14338 double best_scale_ppm = GetBestVPScale(m_singleChart);
14342 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14352void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14355 if (!GetQuiltMode()) {
14356 if (GetpCurrentStack()) {
14357 int stack_index = -1;
14358 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14359 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14360 if (check_dbIndex < 0)
continue;
14362 ChartData->GetChartTableEntry(check_dbIndex);
14363 if (type == cte.GetChartType()) {
14366 }
else if (family == cte.GetChartFamily()) {
14372 if (stack_index >= 0) {
14373 SelectChartFromStack(stack_index);
14377 int sel_dbIndex = -1;
14378 std::vector<int> piano_chart_index_array =
14379 GetQuiltExtendedStackdbIndexArray();
14380 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14381 int check_dbIndex = piano_chart_index_array[i];
14383 if (type == cte.GetChartType()) {
14384 if (IsChartQuiltableRef(check_dbIndex)) {
14385 sel_dbIndex = check_dbIndex;
14388 }
else if (family == cte.GetChartFamily()) {
14389 if (IsChartQuiltableRef(check_dbIndex)) {
14390 sel_dbIndex = check_dbIndex;
14396 if (sel_dbIndex >= 0) {
14397 SelectQuiltRefdbChart(sel_dbIndex,
false);
14399 AdjustQuiltRefChart();
14406 SetQuiltChartHiLiteIndex(-1);
14411bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14412 return std::find(m_tile_yesshow_index_array.begin(),
14413 m_tile_yesshow_index_array.end(),
14414 index) != m_tile_yesshow_index_array.end();
14417bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14418 return std::find(m_tile_noshow_index_array.begin(),
14419 m_tile_noshow_index_array.end(),
14420 index) != m_tile_noshow_index_array.end();
14423void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14424 if (std::find(m_tile_noshow_index_array.begin(),
14425 m_tile_noshow_index_array.end(),
14426 index) == m_tile_noshow_index_array.end()) {
14427 m_tile_noshow_index_array.push_back(index);
14437void ChartCanvas::HandlePianoClick(
14438 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14441 if (!m_pCurrentStack)
return;
14457 double distance = 25000;
14458 int closest_index = -1;
14459 for (
int chart_index : selected_dbIndex_array) {
14461 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14462 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14465 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14466 if (test_distance < distance) {
14467 distance = test_distance;
14468 closest_index = chart_index;
14472 int selected_dbIndex = selected_dbIndex_array[0];
14473 if (closest_index >= 0) selected_dbIndex = closest_index;
14475 if (!GetQuiltMode()) {
14476 if (m_bpersistent_quilt ) {
14477 if (IsChartQuiltableRef(selected_dbIndex)) {
14478 ToggleCanvasQuiltMode();
14479 SelectQuiltRefdbChart(selected_dbIndex);
14480 m_bpersistent_quilt =
false;
14482 SelectChartFromStack(selected_index);
14485 SelectChartFromStack(selected_index);
14486 g_sticky_chart = selected_dbIndex;
14490 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14494 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14495 bool bfound =
false;
14496 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14497 if (m_tile_noshow_index_array[i] ==
14498 selected_dbIndex) {
14499 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14506 m_tile_noshow_index_array.push_back(selected_dbIndex);
14510 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14511 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14515 if (IsChartQuiltableRef(selected_dbIndex)) {
14521 bool set_scale =
false;
14522 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14523 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14529 SelectQuiltRefdbChart(selected_dbIndex,
true);
14531 SelectQuiltRefdbChart(selected_dbIndex,
false);
14536 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14538 double proposed_scale_onscreen =
14541 if (g_bPreserveScaleOnX) {
14542 proposed_scale_onscreen =
14543 wxMin(proposed_scale_onscreen,
14545 GetCanvasWidth()));
14547 proposed_scale_onscreen =
14548 wxMin(proposed_scale_onscreen,
14550 GetCanvasWidth()));
14552 proposed_scale_onscreen =
14553 wxMax(proposed_scale_onscreen,
14562 ToggleCanvasQuiltMode();
14563 SelectdbChart(selected_dbIndex);
14564 m_bpersistent_quilt =
true;
14569 SetQuiltChartHiLiteIndex(-1);
14571 top_frame::Get()->UpdateGlobalMenuItems();
14572 HideChartInfoWindow();
14577void ChartCanvas::HandlePianoRClick(
14578 int x,
int y,
int selected_index,
14579 const std::vector<int> &selected_dbIndex_array) {
14582 if (!GetpCurrentStack())
return;
14584 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14585 UpdateCanvasControlBar();
14587 SetQuiltChartHiLiteIndex(-1);
14590void ChartCanvas::HandlePianoRollover(
14591 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14592 int n_charts,
int scale) {
14595 if (!GetpCurrentStack())
return;
14600 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14602 if (!GetQuiltMode()) {
14603 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14606 std::vector<int> piano_chart_index_array;
14607 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14608 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14609 if ((GetpCurrentStack()->nEntry > 1) ||
14610 (piano_chart_index_array.size() >= 1)) {
14611 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14613 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14615 }
else if (GetpCurrentStack()->nEntry == 1) {
14617 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14618 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14619 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14621 }
else if ((-1 == selected_index) &&
14622 (0 == selected_dbIndex_array.size())) {
14623 ShowChartInfoWindow(key_location.x, -1);
14627 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14629 if ((GetpCurrentStack()->nEntry > 1) ||
14630 (piano_chart_index_array.size() >= 1)) {
14632 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14633 selected_dbIndex_array);
14634 else if (n_charts == 1)
14635 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14637 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14644void ChartCanvas::ClearPianoRollover() {
14645 ClearQuiltChartHiLiteIndexArray();
14646 ShowChartInfoWindow(0, -1);
14647 std::vector<int> vec;
14648 ShowCompositeInfoWindow(0, 0, 0, vec);
14652void ChartCanvas::UpdateCanvasControlBar() {
14653 if (m_pianoFrozen)
return;
14655 if (!GetpCurrentStack())
return;
14657 if (!g_bShowChartBar)
return;
14660 int sel_family = -1;
14662 std::vector<int> piano_chart_index_array;
14663 std::vector<int> empty_piano_chart_index_array;
14665 wxString old_hash = m_Piano->GetStoredHash();
14667 if (GetQuiltMode()) {
14668 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14669 GetQuiltFullScreendbIndexArray());
14671 std::vector<int> piano_active_chart_index_array =
14672 GetQuiltCandidatedbIndexArray();
14673 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14675 std::vector<int> piano_eclipsed_chart_index_array =
14676 GetQuiltEclipsedStackdbIndexArray();
14677 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14679 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14680 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14682 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14683 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14685 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14686 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14689 if (m_singleChart) {
14690 sel_type = m_singleChart->GetChartType();
14691 sel_family = m_singleChart->GetChartFamily();
14696 std::vector<int> piano_skew_chart_index_array;
14697 std::vector<int> piano_tmerc_chart_index_array;
14698 std::vector<int> piano_poly_chart_index_array;
14700 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14702 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14703 double skew_norm = ctei.GetChartSkew();
14704 if (skew_norm > 180.) skew_norm -= 360.;
14706 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14707 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14710 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14711 if (fabs(skew_norm) > 1.)
14712 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14714 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14715 }
else if (fabs(skew_norm) > 1.)
14716 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14718 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14719 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14720 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14722 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14723 if (new_hash != old_hash) {
14724 m_Piano->FormatKeys();
14725 HideChartInfoWindow();
14726 m_Piano->ResetRollover();
14727 SetQuiltChartHiLiteIndex(-1);
14728 m_brepaint_piano =
true;
14734 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14736 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14737 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14738 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14739 if (e == CHART_FAMILY_RASTER) mask |= 1;
14740 if (e == CHART_FAMILY_VECTOR) {
14741 if (t == CHART_TYPE_CM93COMP)
14748 wxString s_indicated;
14749 if (sel_type == CHART_TYPE_CM93COMP)
14750 s_indicated =
"cm93";
14752 if (sel_family == CHART_FAMILY_RASTER)
14753 s_indicated =
"raster";
14754 else if (sel_family == CHART_FAMILY_VECTOR)
14755 s_indicated =
"vector";
14758 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14761void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14763void ChartCanvas::PianoPopupMenu(
14764 int x,
int y,
int selected_index,
14765 const std::vector<int> &selected_dbIndex_array) {
14766 if (!GetpCurrentStack())
return;
14769 if (!GetQuiltMode())
return;
14771 m_piano_ctx_menu =
new wxMenu();
14773 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14783 menu_selected_dbIndex = selected_dbIndex_array[0];
14784 menu_selected_index = selected_index;
14787 bool b_is_in_noshow =
false;
14788 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14789 if (m_quilt_noshow_index_array[i] ==
14790 menu_selected_dbIndex)
14792 b_is_in_noshow =
true;
14797 if (b_is_in_noshow) {
14798 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14799 _(
"Show This Chart"));
14800 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14801 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14802 }
else if (GetpCurrentStack()->nEntry > 1) {
14803 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14804 _(
"Hide This Chart"));
14805 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14806 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14810 wxPoint pos = wxPoint(x, y - 30);
14813 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14814 PopupMenu(m_piano_ctx_menu, pos);
14816 delete m_piano_ctx_menu;
14817 m_piano_ctx_menu = NULL;
14819 HideChartInfoWindow();
14820 m_Piano->ResetRollover();
14822 SetQuiltChartHiLiteIndex(-1);
14823 ClearQuiltChartHiLiteIndexArray();
14828void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14829 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14830 if (m_quilt_noshow_index_array[i] ==
14831 menu_selected_dbIndex)
14833 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14839void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14840 if (!GetpCurrentStack())
return;
14843 RemoveChartFromQuilt(menu_selected_dbIndex);
14847 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14848 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14850 int i = menu_selected_index + 1;
14851 bool b_success =
false;
14852 while (i < GetpCurrentStack()->nEntry - 1) {
14853 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14854 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14855 SelectQuiltRefChart(i);
14865 i = menu_selected_index - 1;
14867 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14868 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14869 SelectQuiltRefChart(i);
14879void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14881 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14882 if (m_quilt_noshow_index_array[i] ==
14885 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14890 m_quilt_noshow_index_array.push_back(dbIndex);
14893bool ChartCanvas::UpdateS52State() {
14894 bool retval =
false;
14897 ps52plib->SetShowS57Text(m_encShowText);
14898 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14899 ps52plib->m_bShowSoundg = m_encShowDepth;
14900 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14901 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14904 if (!m_encShowLights)
14905 ps52plib->AddObjNoshow(
"LIGHTS");
14907 ps52plib->RemoveObjNoshow(
"LIGHTS");
14908 ps52plib->SetLightsOff(!m_encShowLights);
14909 ps52plib->m_bExtendLightSectors =
true;
14912 ps52plib->SetAnchorOn(m_encShowAnchor);
14913 ps52plib->SetQualityOfData(m_encShowDataQual);
14919void ChartCanvas::SetShowENCDataQual(
bool show) {
14920 m_encShowDataQual = show;
14921 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14922 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14924 m_s52StateHash = 0;
14927void ChartCanvas::SetShowENCText(
bool show) {
14928 m_encShowText = show;
14929 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14930 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14932 m_s52StateHash = 0;
14935void ChartCanvas::SetENCDisplayCategory(
int category) {
14936 m_encDisplayCategory = category;
14937 m_s52StateHash = 0;
14940void ChartCanvas::SetShowENCDepth(
bool show) {
14941 m_encShowDepth = show;
14942 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14943 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14945 m_s52StateHash = 0;
14948void ChartCanvas::SetShowENCLightDesc(
bool show) {
14949 m_encShowLightDesc = show;
14950 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14951 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14953 m_s52StateHash = 0;
14956void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14957 m_encShowBuoyLabels = show;
14958 m_s52StateHash = 0;
14961void ChartCanvas::SetShowENCLights(
bool show) {
14962 m_encShowLights = show;
14963 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14964 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14966 m_s52StateHash = 0;
14969void ChartCanvas::SetShowENCAnchor(
bool show) {
14970 m_encShowAnchor = show;
14971 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14972 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14974 m_s52StateHash = 0;
14977wxRect ChartCanvas::GetMUIBarRect() {
14980 rv = m_muiBar->GetRect();
14986void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14987 if (!GetAlertString().IsEmpty()) {
14988 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14989 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14991 dc.SetFont(*pfont);
14992 dc.SetPen(*wxTRANSPARENT_PEN);
14994 dc.SetBrush(wxColour(243, 229, 47));
14996 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
15000 wxRect sbr = GetScaleBarRect();
15001 int xp = sbr.x + sbr.width + 10;
15002 int yp = (sbr.y + sbr.height) - h;
15004 int wdraw = w + 10;
15005 dc.DrawRectangle(xp, yp, wdraw, h);
15006 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
15007 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
15017#define BRIGHT_XCALIB
15018#define __OPCPN_USEICC__
15021#ifdef __OPCPN_USEICC__
15022int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15023 double co_green,
double co_blue);
15025wxString temp_file_name;
15029class ocpnCurtain:
public wxDialog
15031 DECLARE_CLASS( ocpnCurtain )
15032 DECLARE_EVENT_TABLE()
15035 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
15037 bool ProcessEvent(wxEvent& event);
15041IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
15043BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
15046ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
15048 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
15051ocpnCurtain::~ocpnCurtain()
15055bool ocpnCurtain::ProcessEvent(wxEvent& event)
15057 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
15058 return GetParent()->GetEventHandler()->ProcessEvent(event);
15063#include <windows.h>
15066typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15067typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
15068SetDeviceGammaRamp_ptr_type
15069 g_pSetDeviceGammaRamp;
15070GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
15072WORD *g_pSavedGammaMap;
15076int InitScreenBrightness() {
15079 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15083 if (NULL == hGDI32DLL) {
15084 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15086 if (NULL != hGDI32DLL) {
15088 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15089 hGDI32DLL,
"SetDeviceGammaRamp");
15090 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15091 hGDI32DLL,
"GetDeviceGammaRamp");
15094 if ((NULL == g_pSetDeviceGammaRamp) ||
15095 (NULL == g_pGetDeviceGammaRamp)) {
15096 FreeLibrary(hGDI32DLL);
15105 if (!g_pSavedGammaMap) {
15106 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15109 bbr = g_pGetDeviceGammaRamp(
15110 hDC, g_pSavedGammaMap);
15111 ReleaseDC(NULL, hDC);
15116 wxRegKey *pRegKey =
new wxRegKey(
15117 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15118 "NT\\CurrentVersion\\ICM");
15119 if (!pRegKey->Exists()) pRegKey->Create();
15120 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15122 g_brightness_init =
true;
15128 if (NULL == g_pcurtain) {
15129 if (top_frame::Get()->CanSetTransparent()) {
15131 g_pcurtain =
new wxDialog(top_frame::Get()->GetPrimaryCanvasWindow(),
15132 -1,
"", wxPoint(0, 0), ::wxGetDisplaySize(),
15133 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15134 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15141 g_pcurtain->Hide();
15143 HWND hWnd = GetHwndOf(g_pcurtain);
15144 SetWindowLong(hWnd, GWL_EXSTYLE,
15145 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15146 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15147 g_pcurtain->SetTransparent(0);
15149 g_pcurtain->Maximize();
15150 g_pcurtain->Show();
15153 g_pcurtain->Enable();
15154 g_pcurtain->Disable();
15156 top_frame::Get()->Disable();
15157 top_frame::Get()->Enable();
15161 g_brightness_init =
true;
15167 wxString cmd(
"xcalib -version");
15169 wxArrayString output;
15170 long r = wxExecute(cmd, output);
15173 " External application \"xcalib\" not found. Screen brightness "
15176 g_brightness_init =
true;
15181int RestoreScreenBrightness() {
15184 if (g_pSavedGammaMap) {
15185 HDC hDC = GetDC(NULL);
15186 g_pSetDeviceGammaRamp(hDC,
15188 ReleaseDC(NULL, hDC);
15190 free(g_pSavedGammaMap);
15191 g_pSavedGammaMap = NULL;
15195 g_pcurtain->Close();
15196 g_pcurtain->Destroy();
15200 g_brightness_init =
false;
15205#ifdef BRIGHT_XCALIB
15206 if (g_brightness_init) {
15208 cmd =
"xcalib -clear";
15209 wxExecute(cmd, wxEXEC_ASYNC);
15210 g_brightness_init =
false;
15220int SetScreenBrightness(
int brightness) {
15227 if (top_frame::Get()->GetWxGlCanvas() && g_bopengl) {
15229 g_pcurtain->Close();
15230 g_pcurtain->Destroy();
15234 InitScreenBrightness();
15236 if (NULL == hGDI32DLL) {
15238 wchar_t wdll_name[80];
15239 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15240 LPCWSTR cstr = wdll_name;
15242 hGDI32DLL = LoadLibrary(cstr);
15244 if (NULL != hGDI32DLL) {
15246 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15247 hGDI32DLL,
"SetDeviceGammaRamp");
15248 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15249 hGDI32DLL,
"GetDeviceGammaRamp");
15252 if ((NULL == g_pSetDeviceGammaRamp) ||
15253 (NULL == g_pGetDeviceGammaRamp)) {
15254 FreeLibrary(hGDI32DLL);
15261 HDC hDC = GetDC(NULL);
15272 int increment = brightness * 256 / 100;
15275 WORD GammaTable[3][256];
15278 for (
int i = 0; i < 256; i++) {
15279 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15280 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15281 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15283 table_val += increment;
15285 if (table_val > 65535) table_val = 65535;
15288 g_pSetDeviceGammaRamp(hDC, GammaTable);
15289 ReleaseDC(NULL, hDC);
15296 if (g_pSavedGammaMap) {
15297 HDC hDC = GetDC(NULL);
15298 g_pSetDeviceGammaRamp(hDC,
15300 ReleaseDC(NULL, hDC);
15303 if (brightness < 100) {
15304 if (NULL == g_pcurtain) InitScreenBrightness();
15307 int sbrite = wxMax(1, brightness);
15308 sbrite = wxMin(100, sbrite);
15310 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15314 g_pcurtain->Close();
15315 g_pcurtain->Destroy();
15325#ifdef BRIGHT_XCALIB
15327 if (!g_brightness_init) {
15328 last_brightness = 100;
15329 g_brightness_init =
true;
15330 temp_file_name = wxFileName::CreateTempFileName(
"");
15331 InitScreenBrightness();
15334#ifdef __OPCPN_USEICC__
15337 if (!CreateSimpleICCProfileFile(
15338 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15339 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15340 wxString cmd(
"xcalib ");
15341 cmd += temp_file_name;
15343 wxExecute(cmd, wxEXEC_ASYNC);
15352 if (brightness > last_brightness) {
15354 cmd =
"xcalib -clear";
15355 wxExecute(cmd, wxEXEC_ASYNC);
15357 ::wxMilliSleep(10);
15359 int brite_adj = wxMax(1, brightness);
15360 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15361 wxExecute(cmd, wxEXEC_ASYNC);
15363 int brite_adj = wxMax(1, brightness);
15364 int factor = (brite_adj * 100) / last_brightness;
15365 factor = wxMax(1, factor);
15367 cmd.Printf(
"xcalib -co %2d -a", factor);
15368 wxExecute(cmd, wxEXEC_ASYNC);
15373 last_brightness = brightness;
15380#ifdef __OPCPN_USEICC__
15382#define MLUT_TAG 0x6d4c5554L
15383#define VCGT_TAG 0x76636774L
15385int GetIntEndian(
unsigned char *s) {
15390 p = (
unsigned char *)&ret;
15393 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15395 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15400unsigned short GetShortEndian(
unsigned char *s) {
15401 unsigned short ret;
15405 p = (
unsigned char *)&ret;
15408 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15410 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15416int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15417 double co_green,
double co_blue) {
15421 fp = fopen(file_name,
"wb");
15422 if (!fp)
return -1;
15428 for (
int i = 0; i < 128; i++) header[i] = 0;
15430 fwrite(header, 128, 1, fp);
15434 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15435 fwrite(&numTags, 1, 4, fp);
15437 int tagName0 = VCGT_TAG;
15438 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15439 fwrite(&tagName, 1, 4, fp);
15441 int tagOffset0 = 128 + 4 *
sizeof(int);
15442 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15443 fwrite(&tagOffset, 1, 4, fp);
15446 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15447 fwrite(&tagSize, 1, 4, fp);
15449 fwrite(&tagName, 1, 4, fp);
15451 fwrite(&tagName, 1, 4, fp);
15456 int gammatype0 = 0;
15457 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15458 fwrite(&gammatype, 1, 4, fp);
15460 int numChannels0 = 3;
15461 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15462 fwrite(&numChannels, 1, 2, fp);
15464 int numEntries0 = 256;
15465 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15466 fwrite(&numEntries, 1, 2, fp);
15468 int entrySize0 = 1;
15469 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15470 fwrite(&entrySize, 1, 2, fp);
15472 unsigned char ramp[256];
15475 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15476 fwrite(ramp, 256, 1, fp);
15479 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15480 fwrite(ramp, 256, 1, fp);
15483 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15484 fwrite(ramp, 256, 1, fp);
Select * pSelectAIS
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetQueryDialog.
std::unique_ptr< HostApi > GetHostApi()
HostApi factory,.
Chart canvas configuration state
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
ChartCanvas * g_focusCanvas
Global instance.
arrayofCanvasPtr g_canvasArray
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Minimal ChartCAnvas interface with very little dependencies.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void CloseTideDialog()
Close any open tide dialog.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
void OnPaint(wxPaintEvent &event)
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void DoMovement(long dt)
Performs a step of smooth movement animation on the chart canvas.
void ShowSingleTideDialog(int x, int y, void *pvIDX)
Display tide/current dialog with single-instance management.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
int PrepareContextSelections(double lat, double lon)
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
EventVar json_msg
Notified with message targeting all plugins.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
float GetVPScale() override
Return ViewPort scale factor, in physical pixels per meter.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
bool IsTideDialogOpen() const
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Centers the view on a specific lat/lon position.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
int station_tz_offset
Offset in seconds to convert from harmonic data (epochs) to the station time zone.
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
Data for a loaded plugin, including dl-loaded library.
int m_cap_flag
PlugIn Capabilities descriptor.
PluginLoader is a backend module without any direct GUI functionality.
const ArrayOfPlugIns * GetPlugInArray()
Return list of currently loaded plugins.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute)
Dialog for displaying query results of S57 objects.
IDX_entry * GetCurrentIDX() const
Represents a single point in a track.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
APConsole * console
Global instance.
Primary navigation console display for route and vessel tracking.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
bool g_bRollover
enable/disable mouse rollover GUI effects
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
double g_display_size_mm
Physical display width (mm)
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
GoToPositionDialog * pGoToPositionDialog
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Hooks into gui available in model.
size_t g_current_monitor
Current monitor displaying main application frame.
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
bool g_b_overzoom_x
Allow high overzoom.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Hotheys help dialog (the '?' button).
GUI constant definitions.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
double AnchorDistFix(double const d, double const AnchorPointMinDist, double const AnchorPointMaxDist)
Return constrained value of d so that AnchorPointMinDist < abs(d) < AnchorPointMaxDist.
MySQL based storage for routes, tracks, etc.
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.